clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name EHFrameSupport.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/libLLVM/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Analysis -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ASMParser -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/BinaryFormat -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Bitcode -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Bitcode -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Bitstream -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /include/llvm/CodeGen -I /include/llvm/CodeGen/PBQP -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/IR -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/IR -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Coroutines -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ProfileData/Coverage -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/CodeView -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/DWARF -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/MSF -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/PDB -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Demangle -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ExecutionEngine -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ExecutionEngine/JITLink -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ExecutionEngine/Orc -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend/OpenACC -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend/OpenMP -I /include/llvm/CodeGen/GlobalISel -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/IRReader -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/InstCombine -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/Transforms/InstCombine -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/LTO -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Linker -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/MC -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/MC/MCParser -I /include/llvm/CodeGen/MIRParser -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Object -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Option -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Passes -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ProfileData -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Scalar -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ADT -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Support -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/Symbolize -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Target -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Utils -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Vectorize -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/IPO -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/libLLVM/../include -I /usr/src/gnu/usr.bin/clang/libLLVM/obj -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/libLLVM/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "EHFrameSupportImpl.h" |
11 | |
12 | #include "llvm/BinaryFormat/Dwarf.h" |
13 | #include "llvm/Config/config.h" |
14 | #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" |
15 | #include "llvm/Support/DynamicLibrary.h" |
16 | |
17 | #define DEBUG_TYPE "jitlink" |
18 | |
19 | namespace llvm { |
20 | namespace jitlink { |
21 | |
22 | EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName) |
23 | : EHFrameSectionName(EHFrameSectionName) {} |
24 | |
25 | Error EHFrameSplitter::operator()(LinkGraph &G) { |
26 | auto *EHFrame = G.findSectionByName(EHFrameSectionName); |
27 | |
28 | if (!EHFrame) { |
29 | LLVM_DEBUG({ |
30 | dbgs() << "EHFrameSplitter: No " << EHFrameSectionName |
31 | << " section. Nothing to do\n"; |
32 | }); |
33 | return Error::success(); |
34 | } |
35 | |
36 | LLVM_DEBUG({ |
37 | dbgs() << "EHFrameSplitter: Processing " << EHFrameSectionName << "...\n"; |
38 | }); |
39 | |
40 | DenseMap<Block *, LinkGraph::SplitBlockCache> Caches; |
41 | |
42 | { |
43 | |
44 | for (auto *B : EHFrame->blocks()) |
45 | Caches[B] = LinkGraph::SplitBlockCache::value_type(); |
46 | for (auto *Sym : EHFrame->symbols()) |
47 | Caches[&Sym->getBlock()]->push_back(Sym); |
48 | for (auto *B : EHFrame->blocks()) |
49 | llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) { |
50 | return LHS->getOffset() > RHS->getOffset(); |
51 | }); |
52 | } |
53 | |
54 | |
55 | |
56 | |
57 | for (auto &KV : Caches) { |
58 | auto &B = *KV.first; |
59 | auto &BCache = KV.second; |
60 | if (auto Err = processBlock(G, B, BCache)) |
61 | return Err; |
62 | } |
63 | |
64 | return Error::success(); |
65 | } |
66 | |
67 | Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B, |
68 | LinkGraph::SplitBlockCache &Cache) { |
69 | LLVM_DEBUG({ |
70 | dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress()) |
71 | << "\n"; |
72 | }); |
73 | |
74 | |
75 | if (B.isZeroFill()) |
76 | return make_error<JITLinkError>("Unexpected zero-fill block in " + |
77 | EHFrameSectionName + " section"); |
78 | |
79 | if (B.getSize() == 0) { |
80 | LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); |
81 | return Error::success(); |
82 | } |
83 | |
84 | BinaryStreamReader BlockReader( |
85 | StringRef(B.getContent().data(), B.getContent().size()), |
86 | G.getEndianness()); |
87 | |
88 | while (true) { |
89 | uint64_t RecordStartOffset = BlockReader.getOffset(); |
90 | |
91 | LLVM_DEBUG({ |
92 | dbgs() << " Processing CFI record at " |
93 | << formatv("{0:x16}", B.getAddress()) << "\n"; |
94 | }); |
95 | |
96 | uint32_t Length; |
97 | if (auto Err = BlockReader.readInteger(Length)) |
98 | return Err; |
99 | if (Length != 0xffffffff) { |
100 | if (auto Err = BlockReader.skip(Length)) |
101 | return Err; |
102 | } else { |
103 | uint64_t ExtendedLength; |
104 | if (auto Err = BlockReader.readInteger(ExtendedLength)) |
105 | return Err; |
106 | if (auto Err = BlockReader.skip(ExtendedLength)) |
107 | return Err; |
108 | } |
109 | |
110 | |
111 | if (BlockReader.empty()) { |
112 | LLVM_DEBUG(dbgs() << " Extracted " << B << "\n"); |
113 | return Error::success(); |
114 | } |
115 | |
116 | uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset; |
117 | auto &NewBlock = G.splitBlock(B, BlockSize); |
118 | (void)NewBlock; |
119 | LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n"); |
120 | } |
121 | } |
122 | |
123 | EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName, |
124 | unsigned PointerSize, Edge::Kind Delta64, |
125 | Edge::Kind Delta32, Edge::Kind NegDelta32) |
126 | : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize), |
127 | Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {} |
128 | |
129 | Error EHFrameEdgeFixer::operator()(LinkGraph &G) { |
130 | auto *EHFrame = G.findSectionByName(EHFrameSectionName); |
131 | |
132 | if (!EHFrame) { |
| 1 | Assuming 'EHFrame' is non-null | |
|
| |
133 | LLVM_DEBUG({ |
134 | dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName |
135 | << " section. Nothing to do\n"; |
136 | }); |
137 | return Error::success(); |
138 | } |
139 | |
140 | |
141 | if (G.getPointerSize() != 4 && G.getPointerSize() != 8) |
| 3 | | Assuming the condition is false | |
|
142 | return make_error<JITLinkError>( |
143 | "EHFrameEdgeFixer only supports 32 and 64 bit targets"); |
144 | |
145 | LLVM_DEBUG({ |
| 4 | | Loop condition is false. Exiting loop | |
|
146 | dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n"; |
147 | }); |
148 | |
149 | ParseContext PC(G); |
150 | |
151 | |
152 | |
153 | for (auto &Sec : G.sections()) { |
154 | PC.AddrToSyms.addSymbols(Sec.symbols()); |
155 | if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(), |
156 | BlockAddressMap::includeNonNull)) |
157 | return Err; |
158 | } |
159 | |
160 | |
161 | |
162 | std::vector<Block *> EHFrameBlocks; |
163 | for (auto *B : EHFrame->blocks()) |
164 | EHFrameBlocks.push_back(B); |
165 | llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) { |
166 | return LHS->getAddress() < RHS->getAddress(); |
167 | }); |
168 | |
169 | |
170 | for (auto *B : EHFrameBlocks) |
171 | if (auto Err = processBlock(PC, *B)) |
| 5 | | Calling 'EHFrameEdgeFixer::processBlock' | |
|
172 | return Err; |
173 | |
174 | return Error::success(); |
175 | } |
176 | |
177 | Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) { |
178 | |
179 | LLVM_DEBUG({ |
| 6 | | Loop condition is false. Exiting loop | |
|
180 | dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress()) |
181 | << "\n"; |
182 | }); |
183 | |
184 | |
185 | if (B.isZeroFill()) |
| |
186 | return make_error<JITLinkError>("Unexpected zero-fill block in " + |
187 | EHFrameSectionName + " section"); |
188 | |
189 | if (B.getSize() == 0) { |
| 8 | | Assuming the condition is false | |
|
| |
190 | LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); |
191 | return Error::success(); |
192 | } |
193 | |
194 | |
195 | BlockEdgeMap BlockEdges; |
196 | for (auto &E : B.edges()) |
197 | if (E.isRelocation()) { |
198 | if (BlockEdges.count(E.getOffset())) |
199 | return make_error<JITLinkError>( |
200 | "Multiple relocations at offset " + |
201 | formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName + |
202 | " block at address " + formatv("{0:x16}", B.getAddress())); |
203 | |
204 | BlockEdges[E.getOffset()] = EdgeTarget(E); |
205 | } |
206 | |
207 | CIEInfosMap CIEInfos; |
208 | BinaryStreamReader BlockReader( |
209 | StringRef(B.getContent().data(), B.getContent().size()), |
210 | PC.G.getEndianness()); |
211 | while (!BlockReader.empty()) { |
| 10 | | Loop condition is true. Entering loop body | |
|
212 | size_t RecordStartOffset = BlockReader.getOffset(); |
213 | |
214 | LLVM_DEBUG({ |
| 11 | | Loop condition is false. Exiting loop | |
|
215 | dbgs() << " Processing CFI record at " |
216 | << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n"; |
217 | }); |
218 | |
219 | |
220 | size_t RecordRemaining; |
221 | { |
222 | uint32_t Length; |
223 | if (auto Err = BlockReader.readInteger(Length)) |
| |
224 | return Err; |
225 | |
226 | |
227 | if (Length != 0xffffffff) |
| 13 | | Assuming 'Length' is not equal to -1 | |
|
| |
228 | RecordRemaining = Length; |
229 | else { |
230 | uint64_t ExtendedLength; |
231 | if (auto Err = BlockReader.readInteger(ExtendedLength)) |
232 | return Err; |
233 | RecordRemaining = ExtendedLength; |
234 | } |
235 | } |
236 | |
237 | if (BlockReader.bytesRemaining() < RecordRemaining) |
| 15 | | Assuming the condition is false | |
|
| |
238 | return make_error<JITLinkError>( |
239 | "Incomplete CFI record at " + |
240 | formatv("{0:x16}", B.getAddress() + RecordStartOffset)); |
241 | |
242 | |
243 | uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset; |
244 | uint32_t CIEDelta; |
245 | if (auto Err = BlockReader.readInteger(CIEDelta)) |
| |
246 | return Err; |
247 | |
248 | if (CIEDelta == 0) { |
| 18 | | Assuming 'CIEDelta' is not equal to 0 | |
|
| |
249 | if (auto Err = processCIE(PC, B, RecordStartOffset, |
250 | CIEDeltaFieldOffset + RecordRemaining, |
251 | CIEDeltaFieldOffset)) |
252 | return Err; |
253 | } else { |
254 | if (auto Err = processFDE(PC, B, RecordStartOffset, |
| 20 | | Calling 'EHFrameEdgeFixer::processFDE' | |
|
255 | CIEDeltaFieldOffset + RecordRemaining, |
256 | CIEDeltaFieldOffset, CIEDelta, BlockEdges)) |
257 | return Err; |
258 | } |
259 | |
260 | |
261 | BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset + |
262 | RecordRemaining); |
263 | } |
264 | |
265 | return Error::success(); |
266 | } |
267 | |
268 | Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B, |
269 | size_t RecordOffset, size_t RecordLength, |
270 | size_t CIEDeltaFieldOffset) { |
271 | |
272 | LLVM_DEBUG(dbgs() << " Record is CIE\n"); |
273 | |
274 | auto RecordContent = B.getContent().slice(RecordOffset, RecordLength); |
275 | BinaryStreamReader RecordReader( |
276 | StringRef(RecordContent.data(), RecordContent.size()), |
277 | PC.G.getEndianness()); |
278 | |
279 | |
280 | RecordReader.setOffset(CIEDeltaFieldOffset + 4); |
281 | |
282 | auto &CIESymbol = |
283 | PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false); |
284 | CIEInformation CIEInfo(CIESymbol); |
285 | |
286 | uint8_t Version = 0; |
287 | if (auto Err = RecordReader.readInteger(Version)) |
288 | return Err; |
289 | |
290 | if (Version != 0x01) |
291 | return make_error<JITLinkError>("Bad CIE version " + Twine(Version) + |
292 | " (should be 0x01) in eh-frame"); |
293 | |
294 | auto AugInfo = parseAugmentationString(RecordReader); |
295 | if (!AugInfo) |
296 | return AugInfo.takeError(); |
297 | |
298 | |
299 | if (AugInfo->EHDataFieldPresent) |
300 | if (auto Err = RecordReader.skip(PC.G.getPointerSize())) |
301 | return Err; |
302 | |
303 | |
304 | { |
305 | uint64_t CodeAlignmentFactor = 0; |
306 | if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor)) |
307 | return Err; |
308 | if (CodeAlignmentFactor != 1) |
309 | return make_error<JITLinkError>("Unsupported CIE code alignment factor " + |
310 | Twine(CodeAlignmentFactor) + |
311 | " (expected 1)"); |
312 | } |
313 | |
314 | |
315 | { |
316 | int64_t DataAlignmentFactor = 0; |
317 | if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor)) |
318 | return Err; |
319 | if (DataAlignmentFactor != -8) |
320 | return make_error<JITLinkError>("Unsupported CIE data alignment factor " + |
321 | Twine(DataAlignmentFactor) + |
322 | " (expected -8)"); |
323 | } |
324 | |
325 | |
326 | if (auto Err = RecordReader.skip(1)) |
327 | return Err; |
328 | |
329 | uint64_t AugmentationDataLength = 0; |
330 | if (auto Err = RecordReader.readULEB128(AugmentationDataLength)) |
331 | return Err; |
332 | |
333 | uint32_t AugmentationDataStartOffset = RecordReader.getOffset(); |
334 | |
335 | uint8_t *NextField = &AugInfo->Fields[0]; |
336 | while (uint8_t Field = *NextField++) { |
337 | switch (Field) { |
338 | case 'L': { |
339 | CIEInfo.FDEsHaveLSDAField = true; |
340 | uint8_t LSDAPointerEncoding; |
341 | if (auto Err = RecordReader.readInteger(LSDAPointerEncoding)) |
342 | return Err; |
343 | if (!isSupportedPointerEncoding(LSDAPointerEncoding)) |
344 | return make_error<JITLinkError>( |
345 | "Unsupported LSDA pointer encoding " + |
346 | formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " + |
347 | formatv("{0:x16}", CIESymbol.getAddress())); |
348 | CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding; |
349 | break; |
350 | } |
351 | case 'P': { |
352 | uint8_t PersonalityPointerEncoding = 0; |
353 | if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding)) |
354 | return Err; |
355 | if (PersonalityPointerEncoding != |
356 | (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | |
357 | dwarf::DW_EH_PE_sdata4)) |
358 | return make_error<JITLinkError>( |
359 | "Unspported personality pointer " |
360 | "encoding " + |
361 | formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " + |
362 | formatv("{0:x16}", CIESymbol.getAddress())); |
363 | uint32_t PersonalityPointerAddress; |
364 | if (auto Err = RecordReader.readInteger(PersonalityPointerAddress)) |
365 | return Err; |
366 | break; |
367 | } |
368 | case 'R': { |
369 | uint8_t FDEPointerEncoding; |
370 | if (auto Err = RecordReader.readInteger(FDEPointerEncoding)) |
371 | return Err; |
372 | if (!isSupportedPointerEncoding(FDEPointerEncoding)) |
373 | return make_error<JITLinkError>( |
374 | "Unsupported FDE pointer encoding " + |
375 | formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " + |
376 | formatv("{0:x16}", CIESymbol.getAddress())); |
377 | CIEInfo.FDEPointerEncoding = FDEPointerEncoding; |
378 | break; |
379 | } |
380 | default: |
381 | llvm_unreachable("Invalid augmentation string field"); |
382 | } |
383 | } |
384 | |
385 | if (RecordReader.getOffset() - AugmentationDataStartOffset > |
386 | AugmentationDataLength) |
387 | return make_error<JITLinkError>("Read past the end of the augmentation " |
388 | "data while parsing fields"); |
389 | |
390 | assert(!PC.CIEInfos.count(CIESymbol.getAddress()) && |
391 | "Multiple CIEs recorded at the same address?"); |
392 | PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo); |
393 | |
394 | return Error::success(); |
395 | } |
396 | |
397 | Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B, |
398 | size_t RecordOffset, size_t RecordLength, |
399 | size_t CIEDeltaFieldOffset, |
400 | uint32_t CIEDelta, |
401 | BlockEdgeMap &BlockEdges) { |
402 | LLVM_DEBUG(dbgs() << " Record is FDE\n"); |
| 21 | | Loop condition is false. Exiting loop | |
|
403 | |
404 | JITTargetAddress RecordAddress = B.getAddress() + RecordOffset; |
405 | |
406 | auto RecordContent = B.getContent().slice(RecordOffset, RecordLength); |
407 | BinaryStreamReader RecordReader( |
408 | StringRef(RecordContent.data(), RecordContent.size()), |
409 | PC.G.getEndianness()); |
410 | |
411 | |
412 | RecordReader.setOffset(CIEDeltaFieldOffset + 4); |
413 | |
414 | auto &FDESymbol = |
415 | PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false); |
416 | |
417 | CIEInformation *CIEInfo = nullptr; |
418 | |
419 | { |
420 | |
421 | auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset); |
422 | JITTargetAddress CIEAddress = |
423 | RecordAddress + CIEDeltaFieldOffset - CIEDelta; |
424 | if (CIEEdgeItr == BlockEdges.end()) { |
| |
425 | |
426 | LLVM_DEBUG({ |
427 | dbgs() << " Adding edge at " |
428 | << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) |
429 | << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n"; |
430 | }); |
431 | if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress)) |
432 | CIEInfo = *CIEInfoOrErr; |
433 | else |
434 | return CIEInfoOrErr.takeError(); |
435 | assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set"); |
436 | B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset, |
437 | *CIEInfo->CIESymbol, 0); |
438 | } else { |
439 | LLVM_DEBUG({ |
| 23 | | Loop condition is false. Exiting loop | |
|
440 | dbgs() << " Already has edge at " |
441 | << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) |
442 | << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n"; |
443 | }); |
444 | auto &EI = CIEEdgeItr->second; |
445 | if (EI.Addend) |
| 24 | | Assuming field 'Addend' is 0 | |
|
| |
446 | return make_error<JITLinkError>( |
447 | "CIE edge at " + |
448 | formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) + |
449 | " has non-zero addend"); |
450 | if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress())) |
| |
451 | CIEInfo = *CIEInfoOrErr; |
452 | else |
453 | return CIEInfoOrErr.takeError(); |
454 | } |
455 | } |
456 | |
457 | { |
458 | |
459 | Block *PCBeginBlock = nullptr; |
460 | JITTargetAddress PCBeginFieldOffset = RecordReader.getOffset(); |
461 | auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset); |
462 | if (PCEdgeItr == BlockEdges.end()) { |
| |
463 | auto PCBeginPtrInfo = |
464 | readEncodedPointer(CIEInfo->FDEPointerEncoding, |
| 28 | | Calling 'EHFrameEdgeFixer::readEncodedPointer' | |
|
465 | RecordAddress + PCBeginFieldOffset, RecordReader); |
466 | if (!PCBeginPtrInfo) |
467 | return PCBeginPtrInfo.takeError(); |
468 | JITTargetAddress PCBegin = PCBeginPtrInfo->first; |
469 | Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second; |
470 | LLVM_DEBUG({ |
471 | dbgs() << " Adding edge at " |
472 | << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset) |
473 | << " to PC at " << formatv("{0:x16}", PCBegin) << "\n"; |
474 | }); |
475 | auto PCBeginSym = getOrCreateSymbol(PC, PCBegin); |
476 | if (!PCBeginSym) |
477 | return PCBeginSym.takeError(); |
478 | B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym, |
479 | 0); |
480 | PCBeginBlock = &PCBeginSym->getBlock(); |
481 | } else { |
482 | auto &EI = PCEdgeItr->second; |
483 | LLVM_DEBUG({ |
484 | dbgs() << " Already has edge at " |
485 | << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset) |
486 | << " to PC at " << formatv("{0:x16}", EI.Target->getAddress()); |
487 | if (EI.Addend) |
488 | dbgs() << " + " << formatv("{0:x16}", EI.Addend); |
489 | dbgs() << "\n"; |
490 | }); |
491 | |
492 | |
493 | if (!EI.Target->isDefined()) { |
494 | auto EdgeAddr = RecordAddress + PCBeginFieldOffset; |
495 | return make_error<JITLinkError>("FDE edge at " + |
496 | formatv("{0:x16}", EdgeAddr) + |
497 | " points at external block"); |
498 | } |
499 | PCBeginBlock = &EI.Target->getBlock(); |
500 | if (auto Err = RecordReader.skip( |
501 | getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding))) |
502 | return Err; |
503 | } |
504 | |
505 | |
506 | |
507 | assert(PCBeginBlock && "PC-begin block not recorded"); |
508 | LLVM_DEBUG({ |
509 | dbgs() << " Adding keep-alive edge from target at " |
510 | << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at " |
511 | << formatv("{0:x16}", RecordAddress) << "\n"; |
512 | }); |
513 | PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0); |
514 | } |
515 | |
516 | |
517 | if (auto Err = RecordReader.skip( |
518 | getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding))) |
519 | return Err; |
520 | |
521 | if (CIEInfo->FDEsHaveLSDAField) { |
522 | uint64_t AugmentationDataSize; |
523 | if (auto Err = RecordReader.readULEB128(AugmentationDataSize)) |
524 | return Err; |
525 | |
526 | JITTargetAddress LSDAFieldOffset = RecordReader.getOffset(); |
527 | auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset); |
528 | if (LSDAEdgeItr == BlockEdges.end()) { |
529 | auto LSDAPointerInfo = |
530 | readEncodedPointer(CIEInfo->LSDAPointerEncoding, |
531 | RecordAddress + LSDAFieldOffset, RecordReader); |
532 | if (!LSDAPointerInfo) |
533 | return LSDAPointerInfo.takeError(); |
534 | JITTargetAddress LSDA = LSDAPointerInfo->first; |
535 | Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second; |
536 | auto LSDASym = getOrCreateSymbol(PC, LSDA); |
537 | if (!LSDASym) |
538 | return LSDASym.takeError(); |
539 | LLVM_DEBUG({ |
540 | dbgs() << " Adding edge at " |
541 | << formatv("{0:x16}", RecordAddress + LSDAFieldOffset) |
542 | << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n"; |
543 | }); |
544 | B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0); |
545 | } else { |
546 | LLVM_DEBUG({ |
547 | auto &EI = LSDAEdgeItr->second; |
548 | dbgs() << " Already has edge at " |
549 | << formatv("{0:x16}", RecordAddress + LSDAFieldOffset) |
550 | << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress()); |
551 | if (EI.Addend) |
552 | dbgs() << " + " << formatv("{0:x16}", EI.Addend); |
553 | dbgs() << "\n"; |
554 | }); |
555 | if (auto Err = RecordReader.skip(AugmentationDataSize)) |
556 | return Err; |
557 | } |
558 | } else { |
559 | LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n"); |
560 | } |
561 | |
562 | return Error::success(); |
563 | } |
564 | |
565 | Expected<EHFrameEdgeFixer::AugmentationInfo> |
566 | EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) { |
567 | AugmentationInfo AugInfo; |
568 | uint8_t NextChar; |
569 | uint8_t *NextField = &AugInfo.Fields[0]; |
570 | |
571 | if (auto Err = RecordReader.readInteger(NextChar)) |
572 | return std::move(Err); |
573 | |
574 | while (NextChar != 0) { |
575 | switch (NextChar) { |
576 | case 'z': |
577 | AugInfo.AugmentationDataPresent = true; |
578 | break; |
579 | case 'e': |
580 | if (auto Err = RecordReader.readInteger(NextChar)) |
581 | return std::move(Err); |
582 | if (NextChar != 'h') |
583 | return make_error<JITLinkError>("Unrecognized substring e" + |
584 | Twine(NextChar) + |
585 | " in augmentation string"); |
586 | AugInfo.EHDataFieldPresent = true; |
587 | break; |
588 | case 'L': |
589 | case 'P': |
590 | case 'R': |
591 | *NextField++ = NextChar; |
592 | break; |
593 | default: |
594 | return make_error<JITLinkError>("Unrecognized character " + |
595 | Twine(NextChar) + |
596 | " in augmentation string"); |
597 | } |
598 | |
599 | if (auto Err = RecordReader.readInteger(NextChar)) |
600 | return std::move(Err); |
601 | } |
602 | |
603 | return std::move(AugInfo); |
604 | } |
605 | |
606 | bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) { |
607 | using namespace dwarf; |
608 | |
609 | |
610 | if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel) |
611 | return false; |
612 | |
613 | |
614 | if (PointerEncoding & DW_EH_PE_indirect) |
615 | return false; |
616 | |
617 | |
618 | switch (PointerEncoding & 0xf) { |
619 | case DW_EH_PE_absptr: |
620 | case DW_EH_PE_udata4: |
621 | case DW_EH_PE_udata8: |
622 | case DW_EH_PE_sdata4: |
623 | case DW_EH_PE_sdata8: |
624 | return true; |
625 | } |
626 | |
627 | return false; |
628 | } |
629 | |
630 | unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) { |
631 | using namespace dwarf; |
632 | |
633 | assert(isSupportedPointerEncoding(PointerEncoding) && |
634 | "Unsupported pointer encoding"); |
635 | switch (PointerEncoding & 0xf) { |
636 | case DW_EH_PE_absptr: |
637 | return PointerSize; |
638 | case DW_EH_PE_udata4: |
639 | case DW_EH_PE_sdata4: |
640 | return 4; |
641 | case DW_EH_PE_udata8: |
642 | case DW_EH_PE_sdata8: |
643 | return 8; |
644 | default: |
645 | llvm_unreachable("Unsupported encoding"); |
646 | } |
647 | } |
648 | |
649 | Expected<std::pair<JITTargetAddress, Edge::Kind>> |
650 | EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding, |
651 | JITTargetAddress PointerFieldAddress, |
652 | BinaryStreamReader &RecordReader) { |
653 | static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t), |
654 | "Result must be able to hold a uint64_t"); |
655 | assert(isSupportedPointerEncoding(PointerEncoding) && |
656 | "Unsupported pointer encoding"); |
657 | |
658 | using namespace dwarf; |
659 | |
660 | |
661 | |
662 | |
663 | uint8_t EffectiveType = PointerEncoding & 0xf; |
664 | if (EffectiveType == DW_EH_PE_absptr) |
| 29 | | Assuming 'EffectiveType' is not equal to DW_EH_PE_absptr | |
|
| |
665 | EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4; |
666 | |
667 | JITTargetAddress Addr; |
668 | Edge::Kind PointerEdgeKind; |
| 31 | | 'PointerEdgeKind' declared without an initial value | |
|
669 | switch (EffectiveType) { |
| 32 | | 'Default' branch taken. Execution continues on line 704 | |
|
670 | case DW_EH_PE_udata4: { |
671 | uint32_t Val; |
672 | if (auto Err = RecordReader.readInteger(Val)) |
673 | return std::move(Err); |
674 | Addr = PointerFieldAddress + Val; |
675 | PointerEdgeKind = Delta32; |
676 | break; |
677 | } |
678 | case DW_EH_PE_udata8: { |
679 | uint64_t Val; |
680 | if (auto Err = RecordReader.readInteger(Val)) |
681 | return std::move(Err); |
682 | Addr = PointerFieldAddress + Val; |
683 | PointerEdgeKind = Delta64; |
684 | break; |
685 | } |
686 | case DW_EH_PE_sdata4: { |
687 | int32_t Val; |
688 | if (auto Err = RecordReader.readInteger(Val)) |
689 | return std::move(Err); |
690 | Addr = PointerFieldAddress + Val; |
691 | PointerEdgeKind = Delta32; |
692 | break; |
693 | } |
694 | case DW_EH_PE_sdata8: { |
695 | int64_t Val; |
696 | if (auto Err = RecordReader.readInteger(Val)) |
697 | return std::move(Err); |
698 | Addr = PointerFieldAddress + Val; |
699 | PointerEdgeKind = Delta64; |
700 | break; |
701 | } |
702 | } |
703 | |
704 | if (PointerEdgeKind == Edge::Invalid) |
| 33 | | The left operand of '==' is a garbage value |
|
705 | return make_error<JITLinkError>( |
706 | "Unspported edge kind for encoded pointer at " + |
707 | formatv("{0:x}", PointerFieldAddress)); |
708 | |
709 | return std::make_pair(Addr, Delta64); |
710 | } |
711 | |
712 | Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC, |
713 | JITTargetAddress Addr) { |
714 | Symbol *CanonicalSym = nullptr; |
715 | |
716 | auto UpdateCanonicalSym = [&](Symbol *Sym) { |
717 | if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() || |
718 | Sym->getScope() < CanonicalSym->getScope() || |
719 | (Sym->hasName() && !CanonicalSym->hasName()) || |
720 | Sym->getName() < CanonicalSym->getName()) |
721 | CanonicalSym = Sym; |
722 | }; |
723 | |
724 | if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr)) |
725 | for (auto *Sym : *SymbolsAtAddr) |
726 | UpdateCanonicalSym(Sym); |
727 | |
728 | |
729 | if (CanonicalSym) |
730 | return *CanonicalSym; |
731 | |
732 | |
733 | auto *B = PC.AddrToBlock.getBlockCovering(Addr); |
734 | if (!B) |
735 | return make_error<JITLinkError>("No symbol or block covering address " + |
736 | formatv("{0:x16}", Addr)); |
737 | |
738 | return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false); |
739 | } |
740 | |
741 | char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0}; |
742 | |
743 | EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName) |
744 | : EHFrameSectionName(EHFrameSectionName) {} |
745 | |
746 | Error EHFrameNullTerminator::operator()(LinkGraph &G) { |
747 | auto *EHFrame = G.findSectionByName(EHFrameSectionName); |
748 | |
749 | if (!EHFrame) |
750 | return Error::success(); |
751 | |
752 | LLVM_DEBUG({ |
753 | dbgs() << "EHFrameNullTerminator adding null terminator to " |
754 | << EHFrameSectionName << "\n"; |
755 | }); |
756 | |
757 | auto &NullTerminatorBlock = G.createContentBlock( |
758 | *EHFrame, NullTerminatorBlockContent, 0xfffffffffffffffc, 1, 0); |
759 | G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true); |
760 | return Error::success(); |
761 | } |
762 | |
763 | EHFrameRegistrar::~EHFrameRegistrar() {} |
764 | |
765 | Error InProcessEHFrameRegistrar::registerEHFrames( |
766 | JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) { |
767 | return orc::registerEHFrameSection( |
768 | jitTargetAddressToPointer<void *>(EHFrameSectionAddr), |
769 | EHFrameSectionSize); |
770 | } |
771 | |
772 | Error InProcessEHFrameRegistrar::deregisterEHFrames( |
773 | JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) { |
774 | return orc::deregisterEHFrameSection( |
775 | jitTargetAddressToPointer<void *>(EHFrameSectionAddr), |
776 | EHFrameSectionSize); |
777 | } |
778 | |
779 | LinkGraphPassFunction |
780 | createEHFrameRecorderPass(const Triple &TT, |
781 | StoreFrameRangeFunction StoreRangeAddress) { |
782 | const char *EHFrameSectionName = nullptr; |
783 | if (TT.getObjectFormat() == Triple::MachO) |
784 | EHFrameSectionName = "__TEXT,__eh_frame"; |
785 | else |
786 | EHFrameSectionName = ".eh_frame"; |
787 | |
788 | auto RecordEHFrame = |
789 | [EHFrameSectionName, |
790 | StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error { |
791 | |
792 | |
793 | JITTargetAddress Addr = 0; |
794 | size_t Size = 0; |
795 | if (auto *S = G.findSectionByName(EHFrameSectionName)) { |
796 | auto R = SectionRange(*S); |
797 | Addr = R.getStart(); |
798 | Size = R.getSize(); |
799 | } |
800 | if (Addr == 0 && Size != 0) |
801 | return make_error<JITLinkError>( |
802 | StringRef(EHFrameSectionName) + |
803 | " section can not have zero address with non-zero size"); |
804 | StoreFrameRange(Addr, Size); |
805 | return Error::success(); |
806 | }; |
807 | |
808 | return RecordEHFrame; |
809 | } |
810 | |
811 | } |
812 | } |