Skip to content

Commit 95dd11f

Browse files
committed
Redo the bindings to llvm::object::Binary
The existing bindings violate the ownership contract of the C++ API and can result in silent use-after-moves. Use our shims until the fixes to this API are upstreamed
1 parent 1c0a7e0 commit 95dd11f

File tree

3 files changed

+245
-9
lines changed

3 files changed

+245
-9
lines changed

Sources/LLVM/ObjectFile.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
#if SWIFT_PACKAGE
22
import cllvm
3+
import llvmshims
34
#endif
45

56
/// An in-memory representation of a format-independent object file.
67
public class ObjectFile {
7-
let llvm: LLVMObjectFileRef
8+
let llvm: LLVMBinaryRef
89

910
/// Creates an `ObjectFile` with the contents of a provided memory buffer.
1011
/// - parameter memoryBuffer: A memory buffer containing a valid binary
1112
/// object file.
12-
public init?(memoryBuffer: MemoryBuffer) {
13-
guard let file = LLVMCreateObjectFile(memoryBuffer.llvm) else {
13+
public init?(memoryBuffer: MemoryBuffer, in context: Context = .global) {
14+
guard let file = LLVMCreateBinary(memoryBuffer.llvm, context.llvm) else {
1415
return nil
1516
}
1617
self.llvm = file
@@ -20,7 +21,6 @@ public class ObjectFile {
2021
/// the provided path.
2122
/// - parameter path: The absolute file path on your filesystem.
2223
public convenience init?(path: String) {
23-
2424
guard let memoryBuffer = try? MemoryBuffer(contentsOf: path) else {
2525
return nil
2626
}
@@ -29,17 +29,17 @@ public class ObjectFile {
2929

3030
/// Returns a sequence of all the sections in this object file.
3131
public var sections: SectionSequence {
32-
return SectionSequence(llvm: LLVMGetSections(llvm), object: self)
32+
return SectionSequence(llvm: LLVMObjectFileGetSections(llvm), object: self)
3333
}
3434

3535
/// Returns a sequence of all the symbols in this object file.
3636
public var symbols: SymbolSequence {
37-
return SymbolSequence(llvm: LLVMGetSymbols(llvm), object: self)
37+
return SymbolSequence(llvm: LLVMObjectFileGetSymbols(llvm), object: self)
3838
}
3939

4040
/// Deinitialize this value and dispose of its resources.
4141
deinit {
42-
LLVMDisposeObjectFile(llvm)
42+
LLVMDisposeBinary(llvm)
4343
}
4444
}
4545

@@ -93,7 +93,7 @@ public class SectionSequence: Sequence {
9393
/// Makes an iterator that iterates over the sections in an object file.
9494
public func makeIterator() -> AnyIterator<Section> {
9595
return AnyIterator {
96-
if LLVMIsSectionIteratorAtEnd(self.objectFile.llvm, self.llvm) != 0 {
96+
if LLVMObjectFileIsSectionIteratorAtEnd(self.objectFile.llvm, self.llvm) != 0 {
9797
return nil
9898
}
9999
defer { LLVMMoveToNextSection(self.llvm) }
@@ -193,7 +193,7 @@ public class SymbolSequence: Sequence {
193193
/// file.
194194
public func makeIterator() -> AnyIterator<Symbol> {
195195
return AnyIterator {
196-
if LLVMIsSymbolIteratorAtEnd(self.object.llvm, self.llvm) != 0 {
196+
if LLVMObjectFileIsSymbolIteratorAtEnd(self.object.llvm, self.llvm) != 0 {
197197
return nil
198198
}
199199
defer { LLVMMoveToNextSymbol(self.llvm) }

Sources/llvmshims/include/shim.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <stddef.h>
2+
#include "llvm-c/Types.h"
3+
#include "llvm-c/Object.h"
24

35
#ifndef LLVMSWIFT_LLVM_SHIM_H
46
#define LLVMSWIFT_LLVM_SHIM_H
@@ -17,4 +19,56 @@ typedef enum {
1719
LLVMARMProfileKind LLVMARMParseArchProfile(const char *Name, size_t NameLen);
1820
unsigned LLVMARMParseArchVersion(const char *Name, size_t NameLen);
1921

22+
typedef enum {
23+
LLVMBinaryTypeArchive,
24+
LLVMBinaryTypeMachOUniversalBinary,
25+
LLVMBinaryTypeCOFFImportFile,
26+
// LLVM IR
27+
LLVMBinaryTypeIR,
28+
LLVMBinaryTypeMinidump,
29+
30+
// Windows resource (.res) file.
31+
LLVMBinaryTypeWinRes,
32+
33+
// Object and children.
34+
LLVMBinaryTypeCOFF,
35+
36+
// ELF 32-bit, little endian
37+
LLVMBinaryTypeELF32L,
38+
// ELF 32-bit, big endian
39+
LLVMBinaryTypeELF32B,
40+
// ELF 64-bit, little endian
41+
LLVMBinaryTypeELF64L,
42+
// ELF 64-bit, big endian
43+
LLVMBinaryTypeELF64B,
44+
45+
// MachO 32-bit, little endian
46+
LLVMBinaryTypeMachO32L,
47+
// MachO 32-bit, big endian
48+
LLVMBinaryTypeMachO32B,
49+
// MachO 64-bit, little endian
50+
LLVMBinaryTypeMachO64L,
51+
// MachO 64-bit, big endian
52+
LLVMBinaryTypeMachO64B,
53+
54+
LLVMBinaryTypeWasm,
55+
} LLVMBinaryType;
56+
57+
typedef struct LLVMOpaqueBinary *LLVMBinaryRef;
58+
59+
LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR);
60+
LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, LLVMContextRef Context);
61+
void LLVMDisposeBinary(LLVMBinaryRef BR);
62+
63+
LLVMBinaryRef LLVMUniversalBinaryGetObjectForArchitecture(LLVMBinaryRef BR, const char *Arch, size_t ArchLen);
64+
65+
LLVMSectionIteratorRef LLVMObjectFileGetSections(LLVMBinaryRef BR);
66+
67+
LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
68+
LLVMSectionIteratorRef SI);
69+
LLVMSymbolIteratorRef LLVMObjectFileGetSymbols(LLVMBinaryRef BR);
70+
71+
LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
72+
LLVMSymbolIteratorRef SI);
73+
2074
#endif /* LLVMSWIFT_LLVM_SHIM_H */

Sources/llvmshims/src/shim.cpp

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
#include "llvm-c/Object.h"
12
#include "llvm/IR/Intrinsics.h"
23
#include "llvm/IR/Function.h"
34
#include "llvm/Support/ARMTargetParser.h"
5+
#include "llvm/Object/MachOUniversal.h"
6+
#include "llvm/Object/ObjectFile.h"
7+
#include "llvm/ADT/SmallVector.h"
48

59
extern "C" {
10+
typedef struct LLVMOpaqueBinary *LLVMBinaryRef;
11+
612
size_t LLVMSwiftCountIntrinsics(void);
713
const char *LLVMSwiftGetIntrinsicAtIndex(size_t index);
814
unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen);
@@ -17,6 +23,180 @@ extern "C" {
1723

1824
LLVMARMProfileKind LLVMARMParseArchProfile(const char *Name, size_t NameLen);
1925
unsigned LLVMARMParseArchVersion(const char *Name, size_t NameLen);
26+
27+
typedef enum {
28+
LLVMBinaryTypeArchive,
29+
LLVMBinaryTypeMachOUniversalBinary,
30+
LLVMBinaryTypeCOFFImportFile,
31+
// LLVM IR
32+
LLVMBinaryTypeIR,
33+
LLVMBinaryTypeMinidump,
34+
35+
// Windows resource (.res) file.
36+
LLVMBinaryTypeWinRes,
37+
38+
// Object and children.
39+
LLVMBinaryTypeCOFF,
40+
41+
// ELF 32-bit, little endian
42+
LLVMBinaryTypeELF32L,
43+
// ELF 32-bit, big endian
44+
LLVMBinaryTypeELF32B,
45+
// ELF 64-bit, little endian
46+
LLVMBinaryTypeELF64L,
47+
// ELF 64-bit, big endian
48+
LLVMBinaryTypeELF64B,
49+
50+
// MachO 32-bit, little endian
51+
LLVMBinaryTypeMachO32L,
52+
// MachO 32-bit, big endian
53+
LLVMBinaryTypeMachO32B,
54+
// MachO 64-bit, little endian
55+
LLVMBinaryTypeMachO64L,
56+
// MachO 64-bit, big endian
57+
LLVMBinaryTypeMachO64B,
58+
59+
LLVMBinaryTypeWasm,
60+
} LLVMBinaryType;
61+
62+
LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR);
63+
LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, LLVMContextRef Context);
64+
void LLVMDisposeBinary(LLVMBinaryRef BR);
65+
66+
LLVMBinaryRef LLVMUniversalBinaryGetObjectForArchitecture(LLVMBinaryRef BR, const char *Arch, size_t ArchLen);
67+
68+
LLVMSectionIteratorRef LLVMObjectFileGetSections(LLVMBinaryRef BR);
69+
70+
LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
71+
LLVMSectionIteratorRef SI);
72+
LLVMSymbolIteratorRef LLVMObjectFileGetSymbols(LLVMBinaryRef BR);
73+
74+
LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
75+
LLVMSymbolIteratorRef SI);
76+
}
77+
78+
using namespace llvm;
79+
using namespace llvm::object;
80+
81+
inline Binary *unwrap(LLVMBinaryRef OF) {
82+
return reinterpret_cast<Binary *>(OF);
83+
}
84+
85+
inline static LLVMBinaryRef wrap(const Binary *OF) {
86+
return reinterpret_cast<LLVMBinaryRef>(const_cast<Binary *>(OF));
87+
}
88+
89+
inline static section_iterator *unwrap(LLVMSectionIteratorRef SI) {
90+
return reinterpret_cast<section_iterator*>(SI);
91+
}
92+
93+
inline static LLVMSectionIteratorRef
94+
wrap(const section_iterator *SI) {
95+
return reinterpret_cast<LLVMSectionIteratorRef>
96+
(const_cast<section_iterator*>(SI));
97+
}
98+
99+
inline static symbol_iterator *unwrap(LLVMSymbolIteratorRef SI) {
100+
return reinterpret_cast<symbol_iterator*>(SI);
101+
}
102+
103+
inline static LLVMSymbolIteratorRef
104+
wrap(const symbol_iterator *SI) {
105+
return reinterpret_cast<LLVMSymbolIteratorRef>
106+
(const_cast<symbol_iterator*>(SI));
107+
}
108+
109+
LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) {
110+
switch (unwrap(BR)->getType()) {
111+
case 0: //ID_Archive:
112+
return LLVMBinaryTypeArchive;
113+
case 1: //ID_MachOUniversalBinary:
114+
return LLVMBinaryTypeMachOUniversalBinary;
115+
case 2: //ID_COFFImportFile:
116+
return LLVMBinaryTypeCOFFImportFile;
117+
case 3: //ID_IR:
118+
return LLVMBinaryTypeIR;
119+
case 4: //ID_Minidump:
120+
return LLVMBinaryTypeMinidump;
121+
case 5: //ID_WinRes:
122+
return LLVMBinaryTypeWinRes;
123+
case 7: //ID_COFF:
124+
return LLVMBinaryTypeCOFF;
125+
case 8: //ID_ELF32L:
126+
return LLVMBinaryTypeELF32L;
127+
case 9: //ID_ELF32B:
128+
return LLVMBinaryTypeELF32B;
129+
case 10: //ID_ELF64L:
130+
return LLVMBinaryTypeELF64L;
131+
case 11: //ID_ELF64B:
132+
return LLVMBinaryTypeELF64B;
133+
case 12: //ID_MachO32L:
134+
return LLVMBinaryTypeMachO32L;
135+
case 13: //ID_MachO32B:
136+
return LLVMBinaryTypeMachO32B;
137+
case 14: //ID_MachO64L:
138+
return LLVMBinaryTypeMachO64L;
139+
case 15: //ID_MachO64B:
140+
return LLVMBinaryTypeMachO64B;
141+
case 16: //ID_Wasm:
142+
return LLVMBinaryTypeWasm;
143+
default:
144+
llvm_unreachable("Unknown binary kind!");
145+
}
146+
}
147+
148+
LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, LLVMContextRef Context) {
149+
std::unique_ptr<llvm::MemoryBuffer> Buf(unwrap(MemBuf));
150+
Expected<std::unique_ptr<Binary>> ObjOrErr(
151+
createBinary(Buf->getMemBufferRef(), unwrap(Context)));
152+
if (!ObjOrErr) {
153+
// TODO: Actually report errors helpfully.
154+
consumeError(ObjOrErr.takeError());
155+
return nullptr;
156+
}
157+
158+
return wrap(ObjOrErr.get().release());
159+
}
160+
161+
void LLVMDisposeBinary(LLVMBinaryRef BR) {
162+
delete unwrap(BR);
163+
}
164+
165+
LLVMBinaryRef LLVMUniversalBinaryGetObjectForArchitecture(LLVMBinaryRef BR, const char *Arch, size_t ArchLen) {
166+
assert(LLVMBinaryGetType(BR) == LLVMBinaryTypeMachOUniversalBinary);
167+
auto universal = cast<MachOUniversalBinary>(unwrap(BR));
168+
Expected<std::unique_ptr<ObjectFile>> ObjOrErr(
169+
universal->getObjectForArch({Arch, ArchLen}));
170+
if (!ObjOrErr) {
171+
// TODO: Actually report errors helpfully.
172+
consumeError(ObjOrErr.takeError());
173+
return nullptr;
174+
}
175+
return wrap(ObjOrErr.get().release());
176+
}
177+
178+
LLVMSectionIteratorRef LLVMObjectFileGetSections(LLVMBinaryRef BR) {
179+
auto OF = cast<ObjectFile>(unwrap(BR));
180+
section_iterator SI = OF->section_begin();
181+
return wrap(new section_iterator(SI));
182+
}
183+
184+
LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
185+
LLVMSectionIteratorRef SI) {
186+
auto OF = cast<ObjectFile>(unwrap(BR));
187+
return (*unwrap(SI) == OF->section_end()) ? 1 : 0;
188+
}
189+
190+
LLVMSymbolIteratorRef LLVMObjectFileGetSymbols(LLVMBinaryRef BR) {
191+
auto OF = cast<ObjectFile>(unwrap(BR));
192+
symbol_iterator SI = OF->symbol_begin();
193+
return wrap(new symbol_iterator(SI));
194+
}
195+
196+
LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
197+
LLVMSymbolIteratorRef SI) {
198+
auto OF = cast<ObjectFile>(unwrap(BR));
199+
return (*unwrap(SI) == OF->symbol_end()) ? 1 : 0;
20200
}
21201

22202
size_t LLVMSwiftCountIntrinsics(void) {
@@ -42,3 +222,5 @@ unsigned LLVMARMParseArchVersion(const char *Name, size_t NameLen) {
42222
const char *LLVMGetARMCanonicalArchName(const char *Name, size_t NameLen) {
43223
return llvm::ARM::getCanonicalArchName({Name, NameLen}).data();
44224
}
225+
226+

0 commit comments

Comments
 (0)