33 import llvmshims
44#endif
55
6- /// An in-memory representation of a format-independent object file.
7- public class ObjectFile {
6+ /// Enumerates the possible failures that can be thrown initializing
7+ /// a MemoryBuffer.
8+ public enum BinaryFileError : Error {
9+ /// The MemoryBuffer failed to be initialized for a specific reason.
10+ case couldNotCreate( String )
11+ }
12+
13+ /// A `BinaryFile` is a (mostly) architecture-independent representation of an
14+ /// in-memory image file.
15+ public class BinaryFile {
816 let llvm : LLVMBinaryRef
917
10- /// Creates an `ObjectFile` with the contents of a provided memory buffer.
11- /// - parameter memoryBuffer: A memory buffer containing a valid binary
12- /// object file.
13- public init ? ( memoryBuffer: MemoryBuffer , in context: Context = . global) {
14- guard let file = LLVMCreateBinary ( memoryBuffer. llvm, context. llvm) else {
15- return nil
18+ /// The kind of this binary file.
19+ public let kind : Kind
20+
21+ /// The kinds of binary files known to LLVM.
22+ public enum Kind {
23+ /// A static library archive file.
24+ case archive
25+ /// A universal Mach-O binary with multiple component object files for
26+ /// different architectures.
27+ case machOUniversalBinary
28+ /// A COFF imports table file.
29+ case coffImportFile
30+ /// LLVM IR.
31+ case ir
32+ /// A Windows Minidump file.
33+ case minidump
34+ /// A Windows resource file.
35+ case winRes
36+ /// A COFF file.
37+ case coff
38+ /// A 32-bit little-endian ELF binary.
39+ case elf32L
40+ /// A 32-bit big-endian ELF binary.
41+ case elf32B
42+ /// A 64-bit little-endian ELF binary.
43+ case elf64L
44+ /// A 64-bit big-endian ELF binary.
45+ case elf64B
46+ /// A 32-bit little-endian Mach-O binary.
47+ case machO32L
48+ /// A 32-bit big-endian Mach-O binary.
49+ case machO32B
50+ /// A 64-bit little-endian Mach-O binary.
51+ case machO64L
52+ /// A 64-bit big-endian Mach-O binary.
53+ case machO64B
54+ /// A web assembly binary.
55+ case wasm
56+
57+ internal init ( llvm: LLVMBinaryType ) {
58+ switch llvm {
59+ case LLVMBinaryTypeArchive: self = . archive
60+ case LLVMBinaryTypeMachOUniversalBinary: self = . machOUniversalBinary
61+ case LLVMBinaryTypeCOFFImportFile: self = . coff
62+ case LLVMBinaryTypeIR: self = . ir
63+ case LLVMBinaryTypeMinidump: self = . minidump
64+ case LLVMBinaryTypeWinRes: self = . winRes
65+ case LLVMBinaryTypeCOFF: self = . coff
66+ case LLVMBinaryTypeELF32L: self = . elf32L
67+ case LLVMBinaryTypeELF32B: self = . elf32B
68+ case LLVMBinaryTypeELF64L: self = . elf64L
69+ case LLVMBinaryTypeELF64B: self = . elf64B
70+ case LLVMBinaryTypeMachO32L: self = . machO32L
71+ case LLVMBinaryTypeMachO32B: self = . machO32B
72+ case LLVMBinaryTypeMachO64L: self = . machO64L
73+ case LLVMBinaryTypeMachO64B: self = . machO64B
74+ case LLVMBinaryTypeWasm: self = . wasm
75+ default : fatalError ( " unknown comdat selection kind \( llvm) " )
76+ }
77+ }
78+ }
79+
80+ init ( llvm: LLVMBinaryRef ) {
81+ self . llvm = llvm
82+ self . kind = Kind ( llvm: LLVMBinaryGetType ( llvm) )
83+ }
84+
85+ /// Creates a Binary File with the contents of a provided memory buffer.
86+ ///
87+ /// - Parameters:
88+ /// - memoryBuffer: A memory buffer containing a valid binary file.
89+ /// - context: The context to allocate the given binary in.
90+ /// - throws: `BinaryFileError` if there was an error on creation.
91+ public init ( memoryBuffer: MemoryBuffer , in context: Context = . global) throws {
92+ var error : UnsafeMutablePointer < Int8 > ?
93+ self . llvm = LLVMCreateBinary ( memoryBuffer. llvm, context. llvm, & error)
94+ if let error = error {
95+ defer { LLVMDisposeMessage ( error) }
96+ throw BinaryFileError . couldNotCreate ( String ( cString: error) )
1697 }
17- self . llvm = file
98+ self . kind = Kind ( llvm : LLVMBinaryGetType ( self . llvm ) )
1899 }
19100
20101 /// Creates an `ObjectFile` with the contents of the object file at
21102 /// the provided path.
22103 /// - parameter path: The absolute file path on your filesystem.
23- public convenience init ? ( path: String ) {
24- guard let memoryBuffer = try ? MemoryBuffer ( contentsOf: path) else {
25- return nil
26- }
27- self . init ( memoryBuffer: memoryBuffer)
104+ /// - throws: `MemoryBufferError` or `BinaryFileError` if there was an error
105+ /// on creation
106+ public convenience init ( path: String ) throws {
107+ let memoryBuffer = try MemoryBuffer ( contentsOf: path)
108+ try self . init ( memoryBuffer: memoryBuffer)
109+ }
110+
111+
112+ /// Deinitialize this value and dispose of its resources.
113+ deinit {
114+ LLVMDisposeBinary ( llvm)
115+ }
116+ }
117+
118+ /// An in-memory representation of a format-independent object file.
119+ public final class ObjectFile : BinaryFile {
120+ override init ( llvm: LLVMBinaryRef ) {
121+ super. init ( llvm: llvm)
122+ precondition ( self . kind != . machOUniversalBinary,
123+ " File format is not an object file; use MachOUniversalBinaryFile instead " )
124+ }
125+
126+ /// Creates an object file with the contents of a provided memory buffer.
127+ ///
128+ /// - Parameters:
129+ /// - memoryBuffer: A memory buffer containing a valid object file.
130+ /// - context: The context to allocate the given binary in.
131+ /// - throws: `BinaryFileError` if there was an error on creation.
132+ public override init ( memoryBuffer: MemoryBuffer , in context: Context = . global) throws {
133+ try super. init ( memoryBuffer: memoryBuffer, in: context)
134+ precondition ( self . kind != . machOUniversalBinary,
135+ " File format is not an object file; use MachOUniversalBinaryFile instead " )
28136 }
29137
30138 /// Returns a sequence of all the sections in this object file.
@@ -36,10 +144,38 @@ public class ObjectFile {
36144 public var symbols : SymbolSequence {
37145 return SymbolSequence ( llvm: LLVMObjectFileGetSymbols ( llvm) , object: self )
38146 }
147+ }
39148
40- /// Deinitialize this value and dispose of its resources.
41- deinit {
42- LLVMDisposeBinary ( llvm)
149+ /// An in-memory representation of a Mach-O universal binary file.
150+ public final class MachOUniversalBinaryFile : BinaryFile {
151+ /// Creates a Mach-O universal binary file with the contents of a provided
152+ /// memory buffer.
153+ ///
154+ /// - Parameters:
155+ /// - memoryBuffer: A memory buffer containing a valid universal Mach-O file.
156+ /// - context: The context to allocate the given binary in.
157+ /// - throws: `BinaryFileError` if there was an error on creation.
158+ public override init ( memoryBuffer: MemoryBuffer , in context: Context = . global) throws {
159+ try super. init ( memoryBuffer: memoryBuffer, in: context)
160+ precondition ( self . kind == . machOUniversalBinary)
161+ }
162+
163+ /// Retrieves the object file for a specific architecture, if it exists.
164+ ///
165+ /// - Parameters:
166+ /// - architecture: The architecture of a Mach-O file contained in this
167+ /// universal binary file.
168+ /// - Returns: An object file for the given architecture if it exists.
169+ /// - throws: `BinaryFileError` if there was an error on creation.
170+ public func objectFile( for architecture: Triple . Architecture ) throws -> ObjectFile {
171+ var error : UnsafeMutablePointer < Int8 > ?
172+ let archName = architecture. rawValue
173+ let archFile : LLVMBinaryRef = LLVMUniversalBinaryCopyObjectForArchitecture ( self . llvm, archName, archName. count, & error)
174+ if let error = error {
175+ defer { LLVMDisposeMessage ( error) }
176+ throw BinaryFileError . couldNotCreate ( String ( cString: error) )
177+ }
178+ return ObjectFile ( llvm: archFile)
43179 }
44180}
45181
0 commit comments