Skip to content

Commit baaa266

Browse files
authored
Merge pull request #195 from CodaFi/update-binary-test
Update for reviewed APIs
2 parents c6dfcf2 + 2d03dc1 commit baaa266

File tree

5 files changed

+141
-33
lines changed

5 files changed

+141
-33
lines changed

Sources/LLVM/ObjectFile.swift

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public class BinaryFile {
118118
}
119119

120120
/// An in-memory representation of a format-independent object file.
121-
public final class ObjectFile: BinaryFile {
121+
public class ObjectFile: BinaryFile {
122122
override init(llvm: LLVMBinaryRef, buffer: MemoryBuffer) {
123123
super.init(llvm: llvm, buffer: buffer)
124124
precondition(self.kind != .machOUniversalBinary,
@@ -139,17 +139,27 @@ public final class ObjectFile: BinaryFile {
139139

140140
/// Returns a sequence of all the sections in this object file.
141141
public var sections: SectionSequence {
142-
return SectionSequence(llvm: LLVMObjectFileGetSections(llvm), object: self)
142+
return SectionSequence(llvm: LLVMObjectFileCopySectionIterator(llvm), object: self)
143143
}
144144

145145
/// Returns a sequence of all the symbols in this object file.
146146
public var symbols: SymbolSequence {
147-
return SymbolSequence(llvm: LLVMObjectFileGetSymbols(llvm), object: self)
147+
return SymbolSequence(llvm: LLVMObjectFileCopySymbolIterator(llvm), object: self)
148148
}
149149
}
150150

151151
/// An in-memory representation of a Mach-O universal binary file.
152152
public final class MachOUniversalBinaryFile: BinaryFile {
153+
/// Creates an `MachOUniversalBinaryFile` with the contents of the object file at
154+
/// the provided path.
155+
/// - parameter path: The absolute file path on your filesystem.
156+
/// - throws: `MemoryBufferError` or `BinaryFileError` if there was an error
157+
/// on creation
158+
public convenience init(path: String) throws {
159+
let memoryBuffer = try MemoryBuffer(contentsOf: path)
160+
try self.init(memoryBuffer: memoryBuffer)
161+
}
162+
153163
/// Creates a Mach-O universal binary file with the contents of a provided
154164
/// memory buffer.
155165
///
@@ -159,7 +169,9 @@ public final class MachOUniversalBinaryFile: BinaryFile {
159169
/// - throws: `BinaryFileError` if there was an error on creation.
160170
public override init(memoryBuffer: MemoryBuffer, in context: Context = .global) throws {
161171
try super.init(memoryBuffer: memoryBuffer, in: context)
162-
precondition(self.kind == .machOUniversalBinary)
172+
guard self.kind == .machOUniversalBinary else {
173+
throw BinaryFileError.couldNotCreate("File is not a Mach-O universal binary")
174+
}
163175
}
164176

165177
/// Retrieves the object file for a specific architecture, if it exists.
@@ -169,16 +181,37 @@ public final class MachOUniversalBinaryFile: BinaryFile {
169181
/// universal binary file.
170182
/// - Returns: An object file for the given architecture if it exists.
171183
/// - throws: `BinaryFileError` if there was an error on creation.
172-
public func objectFile(for architecture: Triple.Architecture) throws -> ObjectFile {
184+
public func objectFile(for architecture: Triple.Architecture) throws -> Slice {
173185
var error: UnsafeMutablePointer<Int8>?
174186
let archName = architecture.rawValue
175187
let archFile: LLVMBinaryRef = LLVMUniversalBinaryCopyObjectForArchitecture(self.llvm, archName, archName.count, &error)
176188
if let error = error {
177189
defer { LLVMDisposeMessage(error) }
178190
throw BinaryFileError.couldNotCreate(String(cString: error))
179191
}
180-
let buffer = MemoryBuffer(llvm: LLVMBinaryGetMemoryBuffer(archFile))
181-
return ObjectFile(llvm: archFile, buffer: buffer)
192+
let buffer = MemoryBuffer(llvm: LLVMBinaryCopyMemoryBuffer(archFile))
193+
return Slice(parent: self, llvm: archFile, buffer: buffer)
194+
}
195+
196+
/// Represents an architecture-specific slice of a Mach-O universal binary
197+
/// file.
198+
public final class Slice: ObjectFile {
199+
// Maintain a strong reference to our parent binary so the backing buffer
200+
// doesn't disappear on us.
201+
private let parent: MachOUniversalBinaryFile
202+
203+
fileprivate init(parent: MachOUniversalBinaryFile, llvm: LLVMBinaryRef, buffer: MemoryBuffer) {
204+
self.parent = parent
205+
super.init(llvm: llvm, buffer: buffer)
206+
}
207+
208+
private override init(llvm: LLVMBinaryRef, buffer: MemoryBuffer) {
209+
fatalError()
210+
}
211+
212+
private override init(memoryBuffer: MemoryBuffer, in context: Context = .global) throws {
213+
fatalError()
214+
}
182215
}
183216
}
184217

@@ -221,22 +254,26 @@ public struct Section {
221254

222255
/// A sequence for iterating over the sections in an object file.
223256
public class SectionSequence: Sequence {
224-
let llvm: LLVMSectionIteratorRef
257+
let llvm: LLVMSectionIteratorRef?
225258
let objectFile: ObjectFile
226259

227-
init(llvm: LLVMSectionIteratorRef, object: ObjectFile) {
260+
init(llvm: LLVMSectionIteratorRef?, object: ObjectFile) {
228261
self.llvm = llvm
229262
self.objectFile = object
230263
}
231264

232265
/// Makes an iterator that iterates over the sections in an object file.
233266
public func makeIterator() -> AnyIterator<Section> {
234267
return AnyIterator {
235-
if LLVMObjectFileIsSectionIteratorAtEnd(self.objectFile.llvm, self.llvm) != 0 {
268+
guard let it = self.llvm else {
236269
return nil
237270
}
238-
defer { LLVMMoveToNextSection(self.llvm) }
239-
return Section(fromIterator: self.llvm)
271+
272+
if LLVMObjectFileIsSectionIteratorAtEnd(self.objectFile.llvm, it) != 0 {
273+
return nil
274+
}
275+
defer { LLVMMoveToNextSection(it) }
276+
return Section(fromIterator: it)
240277
}
241278
}
242279

@@ -320,10 +357,10 @@ public class RelocationSequence: Sequence {
320357

321358
/// A sequence for iterating over the symbols in an object file.
322359
public class SymbolSequence: Sequence {
323-
let llvm: LLVMSymbolIteratorRef
360+
let llvm: LLVMSymbolIteratorRef?
324361
let object: ObjectFile
325362

326-
init(llvm: LLVMSymbolIteratorRef, object: ObjectFile) {
363+
init(llvm: LLVMSymbolIteratorRef?, object: ObjectFile) {
327364
self.llvm = llvm
328365
self.object = object
329366
}
@@ -332,11 +369,14 @@ public class SymbolSequence: Sequence {
332369
/// file.
333370
public func makeIterator() -> AnyIterator<Symbol> {
334371
return AnyIterator {
335-
if LLVMObjectFileIsSymbolIteratorAtEnd(self.object.llvm, self.llvm) != 0 {
372+
guard let it = self.llvm else {
373+
return nil
374+
}
375+
if LLVMObjectFileIsSymbolIteratorAtEnd(self.object.llvm, it) != 0 {
336376
return nil
337377
}
338-
defer { LLVMMoveToNextSymbol(self.llvm) }
339-
return Symbol(fromIterator: self.llvm)
378+
defer { LLVMMoveToNextSymbol(it) }
379+
return Symbol(fromIterator: it)
340380
}
341381
}
342382

Sources/llvmshims/include/shim.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@ typedef struct LLVMOpaqueBinary *LLVMBinaryRef;
5757

5858
LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR);
5959
LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, LLVMContextRef Context, char **ErrorMessage);
60-
LLVMMemoryBufferRef LLVMBinaryGetMemoryBuffer(LLVMBinaryRef BR);
60+
LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR);
6161
void LLVMDisposeBinary(LLVMBinaryRef BR);
6262

6363
LLVMBinaryRef LLVMUniversalBinaryCopyObjectForArchitecture(LLVMBinaryRef BR, const char *Arch, size_t ArchLen, char **ErrorMessage);
6464

65-
LLVMSectionIteratorRef LLVMObjectFileGetSections(LLVMBinaryRef BR);
65+
LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR);
6666

6767
LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
6868
LLVMSectionIteratorRef SI);
69-
LLVMSymbolIteratorRef LLVMObjectFileGetSymbols(LLVMBinaryRef BR);
69+
LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR);
7070

7171
LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
7272
LLVMSymbolIteratorRef SI);

Sources/llvmshims/src/shim.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@
1010
extern "C" {
1111
typedef struct LLVMOpaqueBinary *LLVMBinaryRef;
1212

13-
size_t LLVMSwiftCountIntrinsics(void);
14-
const char *LLVMSwiftGetIntrinsicAtIndex(size_t index);
13+
// https://reviews.llvm.org/D59697
1514
unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen);
15+
16+
// Not to be upstreamed: They support the hacks that power our dynamic member
17+
// lookup machinery for intrinsics.
18+
const char *LLVMSwiftGetIntrinsicAtIndex(size_t index);
19+
size_t LLVMSwiftCountIntrinsics(void);
20+
21+
// Not to be upstreamed: There's no value in this without a full Triple
22+
// API. And we have chosen to port instead of wrap.
1623
const char *LLVMGetARMCanonicalArchName(const char *Name, size_t NameLen);
1724

1825
typedef enum {
@@ -25,6 +32,7 @@ extern "C" {
2532
LLVMARMProfileKind LLVMARMParseArchProfile(const char *Name, size_t NameLen);
2633
unsigned LLVMARMParseArchVersion(const char *Name, size_t NameLen);
2734

35+
// https://reviews.llvm.org/D60366
2836
typedef enum {
2937
LLVMBinaryTypeArchive,
3038
LLVMBinaryTypeMachOUniversalBinary,
@@ -60,17 +68,21 @@ extern "C" {
6068
} LLVMBinaryType;
6169

6270
LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR);
71+
72+
// https://reviews.llvm.org/D60322
6373
LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, LLVMContextRef Context, char **ErrorMessage);
64-
LLVMMemoryBufferRef LLVMBinaryGetMemoryBuffer(LLVMBinaryRef BR);
74+
LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR);
6575
void LLVMDisposeBinary(LLVMBinaryRef BR);
6676

77+
// https://reviews.llvm.org/D60378
6778
LLVMBinaryRef LLVMUniversalBinaryCopyObjectForArchitecture(LLVMBinaryRef BR, const char *Arch, size_t ArchLen, char **ErrorMessage);
6879

69-
LLVMSectionIteratorRef LLVMObjectFileGetSections(LLVMBinaryRef BR);
80+
// https://reviews.llvm.org/D60407
81+
LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR);
7082

7183
LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
7284
LLVMSectionIteratorRef SI);
73-
LLVMSymbolIteratorRef LLVMObjectFileGetSymbols(LLVMBinaryRef BR);
85+
LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR);
7486

7587
LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
7688
LLVMSymbolIteratorRef SI);
@@ -116,7 +128,7 @@ wrap(const symbol_iterator *SI) {
116128
}
117129

118130
LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) {
119-
class BinaryTypeMapper : public Binary {
131+
class BinaryTypeMapper final : public Binary {
120132
public:
121133
static LLVMBinaryType mapBinaryTypeToLLVMBinaryType(unsigned Kind) {
122134
switch (Kind) {
@@ -169,7 +181,7 @@ LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, LLVMContextRef Contex
169181
return wrap(ObjOrErr.get().release());
170182
}
171183

172-
LLVMMemoryBufferRef LLVMBinaryGetMemoryBuffer(LLVMBinaryRef BR) {
184+
LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR) {
173185
auto Buf = unwrap(BR)->getMemoryBufferRef();
174186
return wrap(llvm::MemoryBuffer::getMemBuffer(
175187
Buf.getBuffer(), Buf.getBufferIdentifier(),
@@ -192,10 +204,12 @@ LLVMBinaryRef LLVMUniversalBinaryCopyObjectForArchitecture(LLVMBinaryRef BR, con
192204
return wrap(ObjOrErr.get().release());
193205
}
194206

195-
LLVMSectionIteratorRef LLVMObjectFileGetSections(LLVMBinaryRef BR) {
207+
LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR) {
196208
auto OF = cast<ObjectFile>(unwrap(BR));
197-
section_iterator SI = OF->section_begin();
198-
return wrap(new section_iterator(SI));
209+
auto sections = OF->sections();
210+
if (sections.begin() == sections.end())
211+
return nullptr;
212+
return wrap(new section_iterator(sections.begin()));
199213
}
200214

201215
LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
@@ -204,10 +218,12 @@ LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
204218
return (*unwrap(SI) == OF->section_end()) ? 1 : 0;
205219
}
206220

207-
LLVMSymbolIteratorRef LLVMObjectFileGetSymbols(LLVMBinaryRef BR) {
221+
LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR) {
208222
auto OF = cast<ObjectFile>(unwrap(BR));
209-
symbol_iterator SI = OF->symbol_begin();
210-
return wrap(new symbol_iterator(SI));
223+
auto symbols = OF->symbols();
224+
if (symbols.begin() == symbols.end())
225+
return nullptr;
226+
return wrap(new symbol_iterator(symbols.begin()));
211227
}
212228

213229
LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,

Tests/LLVMTests/BinarySpec.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import LLVM
2+
import XCTest
3+
import FileCheck
4+
import Foundation
5+
6+
class BinarySpec : XCTestCase {
7+
private func readThisObjectFile() -> ObjectFile {
8+
let result = Result<MachOUniversalBinaryFile, Error>(catching: {
9+
try MachOUniversalBinaryFile(path: Bundle.main.executablePath!)
10+
})
11+
switch result {
12+
case .failure(_):
13+
guard let objectFile = try? ObjectFile(path: Bundle.main.executablePath!) else {
14+
fatalError("Missing object file for host architecture?")
15+
}
16+
return objectFile
17+
case let .success(binary):
18+
guard let objectFile = try? binary.objectFile(for: Triple.default.architecture) else {
19+
fatalError("Missing object file for host architecture?")
20+
}
21+
return objectFile
22+
}
23+
}
24+
25+
func testBinaryLifetimes() {
26+
let objectFile = self.readThisObjectFile()
27+
28+
#if !os(Linux) // Linux has some trouble reading ELF sections.
29+
var hasSections = false
30+
for _ in objectFile.sections {
31+
hasSections = true
32+
break
33+
}
34+
XCTAssertTrue(hasSections)
35+
#endif
36+
37+
var hasSymbols = false
38+
for _ in objectFile.symbols {
39+
hasSymbols = true
40+
break
41+
}
42+
XCTAssertTrue(hasSymbols)
43+
}
44+
45+
#if !os(macOS)
46+
static var allTests = testCase([
47+
("testBinaryLifetimes", testBinaryLifetimes),
48+
])
49+
#endif
50+
}
51+

Tests/LinuxMain.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import XCTest
55
#if !os(macOS)
66
XCTMain([
77
APIntSpec.allTests,
8+
BinarySpec.allTests,
89
BFCSpec.allTests,
910
ConstantSpec.allTests,
1011
DIBuilderSpec.allTests,

0 commit comments

Comments
 (0)