1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | // |
8 | // Parses DWARF CFIs (FDEs and CIEs). |
9 | // |
10 | //===----------------------------------------------------------------------===// |
11 | |
12 | #ifndef __DWARF_PARSER_HPP__ |
13 | #define __DWARF_PARSER_HPP__ |
14 | |
15 | #include <inttypes.h> |
16 | #include <stdint.h> |
17 | #include <stdio.h> |
18 | #include <stdlib.h> |
19 | |
20 | #include "libunwind.h" |
21 | #include "dwarf2.h" |
22 | #include "Registers.hpp" |
23 | |
24 | #include "config.h" |
25 | |
26 | namespace libunwind { |
27 | |
28 | /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. |
29 | /// See DWARF Spec for details: |
30 | /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html |
31 | /// |
32 | template <typename A> |
33 | class CFI_Parser { |
34 | public: |
35 | typedef typename A::pint_t pint_t; |
36 | |
37 | /// Information encoded in a CIE (Common Information Entry) |
38 | struct CIE_Info { |
39 | pint_t cieStart; |
40 | pint_t cieLength; |
41 | pint_t cieInstructions; |
42 | uint8_t pointerEncoding; |
43 | uint8_t lsdaEncoding; |
44 | uint8_t personalityEncoding; |
45 | uint8_t personalityOffsetInCIE; |
46 | pint_t personality; |
47 | uint32_t codeAlignFactor; |
48 | int dataAlignFactor; |
49 | bool isSignalFrame; |
50 | bool fdesHaveAugmentationData; |
51 | uint8_t returnAddressRegister; |
52 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
53 | bool addressesSignedWithBKey; |
54 | bool mteTaggedFrame; |
55 | #endif |
56 | }; |
57 | |
58 | /// Information about an FDE (Frame Description Entry) |
59 | struct FDE_Info { |
60 | pint_t fdeStart; |
61 | pint_t fdeLength; |
62 | pint_t fdeInstructions; |
63 | pint_t pcStart; |
64 | pint_t pcEnd; |
65 | pint_t lsda; |
66 | }; |
67 | |
68 | enum { |
69 | kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER |
70 | }; |
71 | enum RegisterSavedWhere { |
72 | kRegisterUnused, |
73 | kRegisterUndefined, |
74 | kRegisterInCFA, |
75 | kRegisterInCFADecrypt, // sparc64 specific |
76 | kRegisterOffsetFromCFA, |
77 | kRegisterInRegister, |
78 | kRegisterAtExpression, |
79 | kRegisterIsExpression |
80 | }; |
81 | struct RegisterLocation { |
82 | RegisterSavedWhere location; |
83 | bool initialStateSaved; |
84 | int64_t value; |
85 | }; |
86 | /// Information about a frame layout and registers saved determined |
87 | /// by "running" the DWARF FDE "instructions" |
88 | struct PrologInfo { |
89 | uint32_t cfaRegister; |
90 | int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset |
91 | int64_t cfaExpression; // CFA = expression |
92 | uint32_t ; |
93 | RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; |
94 | enum class InitializeTime { kLazy, kNormal }; |
95 | |
96 | // When saving registers, this data structure is lazily initialized. |
97 | PrologInfo(InitializeTime IT = InitializeTime::kNormal) { |
98 | if (IT == InitializeTime::kNormal) |
99 | memset(this, 0, sizeof(*this)); |
100 | } |
101 | void checkSaveRegister(uint64_t reg, PrologInfo &initialState) { |
102 | if (!savedRegisters[reg].initialStateSaved) { |
103 | initialState.savedRegisters[reg] = savedRegisters[reg]; |
104 | savedRegisters[reg].initialStateSaved = true; |
105 | } |
106 | } |
107 | void setRegister(uint64_t reg, RegisterSavedWhere newLocation, |
108 | int64_t newValue, PrologInfo &initialState) { |
109 | checkSaveRegister(reg, initialState); |
110 | savedRegisters[reg].location = newLocation; |
111 | savedRegisters[reg].value = newValue; |
112 | } |
113 | void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation, |
114 | PrologInfo &initialState) { |
115 | checkSaveRegister(reg, initialState); |
116 | savedRegisters[reg].location = newLocation; |
117 | } |
118 | void setRegisterValue(uint64_t reg, int64_t newValue, |
119 | PrologInfo &initialState) { |
120 | checkSaveRegister(reg, initialState); |
121 | savedRegisters[reg].value = newValue; |
122 | } |
123 | void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) { |
124 | if (savedRegisters[reg].initialStateSaved) |
125 | savedRegisters[reg] = initialState.savedRegisters[reg]; |
126 | // else the register still holds its initial state |
127 | } |
128 | }; |
129 | |
130 | struct PrologInfoStackEntry { |
131 | PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) |
132 | : next(n), info(i) {} |
133 | PrologInfoStackEntry *next; |
134 | PrologInfo info; |
135 | }; |
136 | |
137 | struct RememberStack { |
138 | PrologInfoStackEntry *entry; |
139 | RememberStack() : entry(nullptr) {} |
140 | ~RememberStack() { |
141 | #if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED) |
142 | // Clean up rememberStack. Even in the case where every |
143 | // DW_CFA_remember_state is paired with a DW_CFA_restore_state, |
144 | // parseInstructions can skip restore opcodes if it reaches the target PC |
145 | // and stops interpreting, so we have to make sure we don't leak memory. |
146 | while (entry) { |
147 | PrologInfoStackEntry *next = entry->next; |
148 | _LIBUNWIND_REMEMBER_FREE(entry); |
149 | entry = next; |
150 | } |
151 | #endif |
152 | } |
153 | }; |
154 | |
155 | static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, |
156 | size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, |
157 | CIE_Info *cieInfo); |
158 | static const char *decodeFDE(A &addressSpace, pint_t fdeStart, |
159 | FDE_Info *fdeInfo, CIE_Info *cieInfo, |
160 | bool useCIEInfo = false); |
161 | static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, |
162 | const CIE_Info &cieInfo, pint_t upToPC, |
163 | int arch, PrologInfo *results); |
164 | |
165 | static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); |
166 | }; |
167 | |
168 | /// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is |
169 | /// true, treat cieInfo as already-parsed CIE_Info (whose start offset |
170 | /// must match the one specified by the FDE) rather than parsing the |
171 | /// one indicated within the FDE. |
172 | template <typename A> |
173 | const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, |
174 | FDE_Info *fdeInfo, CIE_Info *cieInfo, |
175 | bool useCIEInfo) { |
176 | pint_t p = fdeStart; |
177 | pint_t cfiLength = (pint_t)addressSpace.get32(p); |
178 | p += 4; |
179 | if (cfiLength == 0xffffffff) { |
180 | // 0xffffffff means length is really next 8 bytes |
181 | cfiLength = (pint_t)addressSpace.get64(p); |
182 | p += 8; |
183 | } |
184 | if (cfiLength == 0) |
185 | return "FDE has zero length" ; // zero terminator |
186 | uint32_t ciePointer = addressSpace.get32(p); |
187 | if (ciePointer == 0) |
188 | return "FDE is really a CIE" ; // this is a CIE not an FDE |
189 | pint_t nextCFI = p + cfiLength; |
190 | pint_t cieStart = p - ciePointer; |
191 | if (useCIEInfo) { |
192 | if (cieInfo->cieStart != cieStart) |
193 | return "CIE start does not match" ; |
194 | } else { |
195 | const char *err = parseCIE(addressSpace, cie: cieStart, cieInfo); |
196 | if (err != NULL) |
197 | return err; |
198 | } |
199 | p += 4; |
200 | // Parse pc begin and range. |
201 | pint_t pcStart = |
202 | addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); |
203 | pint_t pcRange = |
204 | addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); |
205 | // Parse rest of info. |
206 | fdeInfo->lsda = 0; |
207 | // Check for augmentation length. |
208 | if (cieInfo->fdesHaveAugmentationData) { |
209 | pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); |
210 | pint_t endOfAug = p + augLen; |
211 | if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { |
212 | // Peek at value (without indirection). Zero means no LSDA. |
213 | pint_t lsdaStart = p; |
214 | if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != |
215 | 0) { |
216 | // Reset pointer and re-parse LSDA address. |
217 | p = lsdaStart; |
218 | fdeInfo->lsda = |
219 | addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); |
220 | } |
221 | } |
222 | p = endOfAug; |
223 | } |
224 | fdeInfo->fdeStart = fdeStart; |
225 | fdeInfo->fdeLength = nextCFI - fdeStart; |
226 | fdeInfo->fdeInstructions = p; |
227 | fdeInfo->pcStart = pcStart; |
228 | fdeInfo->pcEnd = pcStart + pcRange; |
229 | return NULL; // success |
230 | } |
231 | |
232 | /// Scan an eh_frame section to find an FDE for a pc |
233 | template <typename A> |
234 | bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, |
235 | size_t sectionLength, pint_t fdeHint, |
236 | FDE_Info *fdeInfo, CIE_Info *cieInfo) { |
237 | //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); |
238 | pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; |
239 | const pint_t ehSectionEnd = (sectionLength == SIZE_MAX) |
240 | ? static_cast<pint_t>(-1) |
241 | : (ehSectionStart + sectionLength); |
242 | while (p < ehSectionEnd) { |
243 | pint_t currentCFI = p; |
244 | //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); |
245 | pint_t cfiLength = addressSpace.get32(p); |
246 | p += 4; |
247 | if (cfiLength == 0xffffffff) { |
248 | // 0xffffffff means length is really next 8 bytes |
249 | cfiLength = (pint_t)addressSpace.get64(p); |
250 | p += 8; |
251 | } |
252 | if (cfiLength == 0) |
253 | return false; // zero terminator |
254 | uint32_t id = addressSpace.get32(p); |
255 | if (id == 0) { |
256 | // Skip over CIEs. |
257 | p += cfiLength; |
258 | } else { |
259 | // Process FDE to see if it covers pc. |
260 | pint_t nextCFI = p + cfiLength; |
261 | uint32_t ciePointer = addressSpace.get32(p); |
262 | pint_t cieStart = p - ciePointer; |
263 | // Validate pointer to CIE is within section. |
264 | if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { |
265 | if (parseCIE(addressSpace, cie: cieStart, cieInfo) == NULL) { |
266 | p += 4; |
267 | // Parse pc begin and range. |
268 | pint_t pcStart = |
269 | addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); |
270 | pint_t pcRange = addressSpace.getEncodedP( |
271 | p, nextCFI, cieInfo->pointerEncoding & 0x0F); |
272 | // Test if pc is within the function this FDE covers. |
273 | if ((pcStart < pc) && (pc <= pcStart + pcRange)) { |
274 | // parse rest of info |
275 | fdeInfo->lsda = 0; |
276 | // check for augmentation length |
277 | if (cieInfo->fdesHaveAugmentationData) { |
278 | pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); |
279 | pint_t endOfAug = p + augLen; |
280 | if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { |
281 | // Peek at value (without indirection). Zero means no LSDA. |
282 | pint_t lsdaStart = p; |
283 | if (addressSpace.getEncodedP( |
284 | p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { |
285 | // Reset pointer and re-parse LSDA address. |
286 | p = lsdaStart; |
287 | fdeInfo->lsda = addressSpace |
288 | .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); |
289 | } |
290 | } |
291 | p = endOfAug; |
292 | } |
293 | fdeInfo->fdeStart = currentCFI; |
294 | fdeInfo->fdeLength = nextCFI - currentCFI; |
295 | fdeInfo->fdeInstructions = p; |
296 | fdeInfo->pcStart = pcStart; |
297 | fdeInfo->pcEnd = pcStart + pcRange; |
298 | return true; |
299 | } else { |
300 | // pc is not in begin/range, skip this FDE |
301 | } |
302 | } else { |
303 | // Malformed CIE, now augmentation describing pc range encoding. |
304 | } |
305 | } else { |
306 | // malformed FDE. CIE is bad |
307 | } |
308 | p = nextCFI; |
309 | } |
310 | } |
311 | return false; |
312 | } |
313 | |
314 | /// Extract info from a CIE |
315 | template <typename A> |
316 | const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie, |
317 | CIE_Info *cieInfo) { |
318 | cieInfo->pointerEncoding = 0; |
319 | cieInfo->lsdaEncoding = DW_EH_PE_omit; |
320 | cieInfo->personalityEncoding = 0; |
321 | cieInfo->personalityOffsetInCIE = 0; |
322 | cieInfo->personality = 0; |
323 | cieInfo->codeAlignFactor = 0; |
324 | cieInfo->dataAlignFactor = 0; |
325 | cieInfo->isSignalFrame = false; |
326 | cieInfo->fdesHaveAugmentationData = false; |
327 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
328 | cieInfo->addressesSignedWithBKey = false; |
329 | cieInfo->mteTaggedFrame = false; |
330 | #endif |
331 | cieInfo->cieStart = cie; |
332 | pint_t p = cie; |
333 | pint_t cieLength = (pint_t)addressSpace.get32(p); |
334 | p += 4; |
335 | pint_t cieContentEnd = p + cieLength; |
336 | if (cieLength == 0xffffffff) { |
337 | // 0xffffffff means length is really next 8 bytes |
338 | cieLength = (pint_t)addressSpace.get64(p); |
339 | p += 8; |
340 | cieContentEnd = p + cieLength; |
341 | } |
342 | if (cieLength == 0) |
343 | return NULL; |
344 | // CIE ID is always 0 |
345 | if (addressSpace.get32(p) != 0) |
346 | return "CIE ID is not zero" ; |
347 | p += 4; |
348 | // Version is always 1 or 3 |
349 | uint8_t version = addressSpace.get8(p); |
350 | if ((version != 1) && (version != 3)) |
351 | return "CIE version is not 1 or 3" ; |
352 | ++p; |
353 | // save start of augmentation string and find end |
354 | pint_t strStart = p; |
355 | while (addressSpace.get8(p) != 0) |
356 | ++p; |
357 | ++p; |
358 | // parse code alignment factor |
359 | cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); |
360 | // parse data alignment factor |
361 | cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); |
362 | // parse return address register |
363 | uint64_t raReg = (version == 1) ? addressSpace.get8(p++) |
364 | : addressSpace.getULEB128(p, cieContentEnd); |
365 | assert(raReg < 255 && "return address register too large" ); |
366 | cieInfo->returnAddressRegister = (uint8_t)raReg; |
367 | // parse augmentation data based on augmentation string |
368 | const char *result = NULL; |
369 | if (addressSpace.get8(strStart) == 'z') { |
370 | // parse augmentation data length |
371 | addressSpace.getULEB128(p, cieContentEnd); |
372 | for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { |
373 | switch (addressSpace.get8(s)) { |
374 | case 'z': |
375 | cieInfo->fdesHaveAugmentationData = true; |
376 | break; |
377 | case 'P': |
378 | cieInfo->personalityEncoding = addressSpace.get8(p); |
379 | ++p; |
380 | cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); |
381 | cieInfo->personality = addressSpace |
382 | .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); |
383 | break; |
384 | case 'L': |
385 | cieInfo->lsdaEncoding = addressSpace.get8(p); |
386 | ++p; |
387 | break; |
388 | case 'R': |
389 | cieInfo->pointerEncoding = addressSpace.get8(p); |
390 | ++p; |
391 | break; |
392 | case 'S': |
393 | cieInfo->isSignalFrame = true; |
394 | break; |
395 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
396 | case 'B': |
397 | cieInfo->addressesSignedWithBKey = true; |
398 | break; |
399 | case 'G': |
400 | cieInfo->mteTaggedFrame = true; |
401 | break; |
402 | #endif |
403 | default: |
404 | // ignore unknown letters |
405 | break; |
406 | } |
407 | } |
408 | } |
409 | cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; |
410 | cieInfo->cieInstructions = p; |
411 | return result; |
412 | } |
413 | |
414 | |
415 | /// "run" the DWARF instructions and create the abstract PrologInfo for an FDE |
416 | template <typename A> |
417 | bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, |
418 | const FDE_Info &fdeInfo, |
419 | const CIE_Info &cieInfo, pint_t upToPC, |
420 | int arch, PrologInfo *results) { |
421 | // Alloca is used for the allocation of the rememberStack entries. It removes |
422 | // the dependency on new/malloc but the below for loop can not be refactored |
423 | // into functions. Entry could be saved during the processing of a CIE and |
424 | // restored by an FDE. |
425 | RememberStack rememberStack; |
426 | |
427 | struct ParseInfo { |
428 | pint_t instructions; |
429 | pint_t instructionsEnd; |
430 | pint_t pcoffset; |
431 | }; |
432 | |
433 | ParseInfo parseInfoArray[] = { |
434 | {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, |
435 | (pint_t)(-1)}, |
436 | {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, |
437 | upToPC - fdeInfo.pcStart}}; |
438 | |
439 | for (const auto &info : parseInfoArray) { |
440 | pint_t p = info.instructions; |
441 | pint_t instructionsEnd = info.instructionsEnd; |
442 | pint_t pcoffset = info.pcoffset; |
443 | pint_t codeOffset = 0; |
444 | |
445 | // initialState initialized as registers in results are modified. Use |
446 | // PrologInfo accessor functions to avoid reading uninitialized data. |
447 | PrologInfo initialState(PrologInfo::InitializeTime::kLazy); |
448 | |
449 | _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64 |
450 | ")\n" , |
451 | static_cast<uint64_t>(instructionsEnd)); |
452 | |
453 | // see DWARF Spec, section 6.4.2 for details on unwind opcodes |
454 | while ((p < instructionsEnd) && (codeOffset < pcoffset)) { |
455 | uint64_t reg; |
456 | uint64_t reg2; |
457 | int64_t offset; |
458 | uint64_t length; |
459 | uint8_t opcode = addressSpace.get8(p); |
460 | uint8_t operand; |
461 | |
462 | ++p; |
463 | switch (opcode) { |
464 | case DW_CFA_nop: |
465 | _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n" ); |
466 | break; |
467 | case DW_CFA_set_loc: |
468 | codeOffset = addressSpace.getEncodedP(p, instructionsEnd, |
469 | cieInfo.pointerEncoding); |
470 | _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n" ); |
471 | break; |
472 | case DW_CFA_advance_loc1: |
473 | codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); |
474 | p += 1; |
475 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n" , |
476 | static_cast<uint64_t>(codeOffset)); |
477 | break; |
478 | case DW_CFA_advance_loc2: |
479 | codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); |
480 | p += 2; |
481 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n" , |
482 | static_cast<uint64_t>(codeOffset)); |
483 | break; |
484 | case DW_CFA_advance_loc4: |
485 | codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); |
486 | p += 4; |
487 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n" , |
488 | static_cast<uint64_t>(codeOffset)); |
489 | break; |
490 | case DW_CFA_offset_extended: |
491 | reg = addressSpace.getULEB128(p, instructionsEnd); |
492 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * |
493 | cieInfo.dataAlignFactor; |
494 | if (reg > kMaxRegisterNumber) { |
495 | _LIBUNWIND_LOG0( |
496 | "malformed DW_CFA_offset_extended DWARF unwind, reg too big" ); |
497 | return false; |
498 | } |
499 | results->setRegister(reg, kRegisterInCFA, offset, initialState); |
500 | _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " |
501 | "offset=%" PRId64 ")\n" , |
502 | reg, offset); |
503 | break; |
504 | case DW_CFA_restore_extended: |
505 | reg = addressSpace.getULEB128(p, instructionsEnd); |
506 | if (reg > kMaxRegisterNumber) { |
507 | _LIBUNWIND_LOG0( |
508 | "malformed DW_CFA_restore_extended DWARF unwind, reg too big" ); |
509 | return false; |
510 | } |
511 | results->restoreRegisterToInitialState(reg, initialState); |
512 | _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n" , |
513 | reg); |
514 | break; |
515 | case DW_CFA_undefined: |
516 | reg = addressSpace.getULEB128(p, instructionsEnd); |
517 | if (reg > kMaxRegisterNumber) { |
518 | _LIBUNWIND_LOG0( |
519 | "malformed DW_CFA_undefined DWARF unwind, reg too big" ); |
520 | return false; |
521 | } |
522 | results->setRegisterLocation(reg, kRegisterUndefined, initialState); |
523 | _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n" , reg); |
524 | break; |
525 | case DW_CFA_same_value: |
526 | reg = addressSpace.getULEB128(p, instructionsEnd); |
527 | if (reg > kMaxRegisterNumber) { |
528 | _LIBUNWIND_LOG0( |
529 | "malformed DW_CFA_same_value DWARF unwind, reg too big" ); |
530 | return false; |
531 | } |
532 | // <rdar://problem/8456377> DW_CFA_same_value unsupported |
533 | // "same value" means register was stored in frame, but its current |
534 | // value has not changed, so no need to restore from frame. |
535 | // We model this as if the register was never saved. |
536 | results->setRegisterLocation(reg, kRegisterUnused, initialState); |
537 | _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n" , reg); |
538 | break; |
539 | case DW_CFA_register: |
540 | reg = addressSpace.getULEB128(p, instructionsEnd); |
541 | reg2 = addressSpace.getULEB128(p, instructionsEnd); |
542 | if (reg > kMaxRegisterNumber) { |
543 | _LIBUNWIND_LOG0( |
544 | "malformed DW_CFA_register DWARF unwind, reg too big" ); |
545 | return false; |
546 | } |
547 | if (reg2 > kMaxRegisterNumber) { |
548 | _LIBUNWIND_LOG0( |
549 | "malformed DW_CFA_register DWARF unwind, reg2 too big" ); |
550 | return false; |
551 | } |
552 | results->setRegister(reg, kRegisterInRegister, (int64_t)reg2, |
553 | initialState); |
554 | _LIBUNWIND_TRACE_DWARF( |
555 | "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n" , reg, reg2); |
556 | break; |
557 | case DW_CFA_remember_state: { |
558 | // Avoid operator new because that would be an upward dependency. |
559 | // Avoid malloc because it needs heap allocation. |
560 | PrologInfoStackEntry *entry = |
561 | (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC( |
562 | sizeof(PrologInfoStackEntry)); |
563 | if (entry != NULL) { |
564 | entry->next = rememberStack.entry; |
565 | entry->info = *results; |
566 | rememberStack.entry = entry; |
567 | } else { |
568 | return false; |
569 | } |
570 | _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n" ); |
571 | break; |
572 | } |
573 | case DW_CFA_restore_state: |
574 | if (rememberStack.entry != NULL) { |
575 | PrologInfoStackEntry *top = rememberStack.entry; |
576 | *results = top->info; |
577 | rememberStack.entry = top->next; |
578 | _LIBUNWIND_REMEMBER_FREE(top); |
579 | } else { |
580 | return false; |
581 | } |
582 | _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n" ); |
583 | break; |
584 | case DW_CFA_def_cfa: |
585 | reg = addressSpace.getULEB128(p, instructionsEnd); |
586 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); |
587 | if (reg > kMaxRegisterNumber) { |
588 | _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big" ); |
589 | return false; |
590 | } |
591 | results->cfaRegister = (uint32_t)reg; |
592 | results->cfaRegisterOffset = (int32_t)offset; |
593 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 |
594 | ")\n" , |
595 | reg, offset); |
596 | break; |
597 | case DW_CFA_def_cfa_register: |
598 | reg = addressSpace.getULEB128(p, instructionsEnd); |
599 | if (reg > kMaxRegisterNumber) { |
600 | _LIBUNWIND_LOG0( |
601 | "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big" ); |
602 | return false; |
603 | } |
604 | results->cfaRegister = (uint32_t)reg; |
605 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n" , reg); |
606 | break; |
607 | case DW_CFA_def_cfa_offset: |
608 | results->cfaRegisterOffset = |
609 | (int32_t)addressSpace.getULEB128(p, instructionsEnd); |
610 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n" , |
611 | results->cfaRegisterOffset); |
612 | break; |
613 | case DW_CFA_def_cfa_expression: |
614 | results->cfaRegister = 0; |
615 | results->cfaExpression = (int64_t)p; |
616 | length = addressSpace.getULEB128(p, instructionsEnd); |
617 | assert(length < static_cast<pint_t>(~0) && "pointer overflow" ); |
618 | p += static_cast<pint_t>(length); |
619 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 |
620 | ", length=%" PRIu64 ")\n" , |
621 | results->cfaExpression, length); |
622 | break; |
623 | case DW_CFA_expression: |
624 | reg = addressSpace.getULEB128(p, instructionsEnd); |
625 | if (reg > kMaxRegisterNumber) { |
626 | _LIBUNWIND_LOG0( |
627 | "malformed DW_CFA_expression DWARF unwind, reg too big" ); |
628 | return false; |
629 | } |
630 | results->setRegister(reg, kRegisterAtExpression, (int64_t)p, |
631 | initialState); |
632 | length = addressSpace.getULEB128(p, instructionsEnd); |
633 | assert(length < static_cast<pint_t>(~0) && "pointer overflow" ); |
634 | p += static_cast<pint_t>(length); |
635 | _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " |
636 | "expression=0x%" PRIx64 ", " |
637 | "length=%" PRIu64 ")\n" , |
638 | reg, results->savedRegisters[reg].value, length); |
639 | break; |
640 | case DW_CFA_offset_extended_sf: |
641 | reg = addressSpace.getULEB128(p, instructionsEnd); |
642 | if (reg > kMaxRegisterNumber) { |
643 | _LIBUNWIND_LOG0( |
644 | "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big" ); |
645 | return false; |
646 | } |
647 | offset = addressSpace.getSLEB128(p, instructionsEnd) * |
648 | cieInfo.dataAlignFactor; |
649 | results->setRegister(reg, kRegisterInCFA, offset, initialState); |
650 | _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " |
651 | "offset=%" PRId64 ")\n" , |
652 | reg, offset); |
653 | break; |
654 | case DW_CFA_def_cfa_sf: |
655 | reg = addressSpace.getULEB128(p, instructionsEnd); |
656 | offset = addressSpace.getSLEB128(p, instructionsEnd) * |
657 | cieInfo.dataAlignFactor; |
658 | if (reg > kMaxRegisterNumber) { |
659 | _LIBUNWIND_LOG0( |
660 | "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big" ); |
661 | return false; |
662 | } |
663 | results->cfaRegister = (uint32_t)reg; |
664 | results->cfaRegisterOffset = (int32_t)offset; |
665 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " |
666 | "offset=%" PRId64 ")\n" , |
667 | reg, offset); |
668 | break; |
669 | case DW_CFA_def_cfa_offset_sf: |
670 | results->cfaRegisterOffset = |
671 | (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) * |
672 | cieInfo.dataAlignFactor); |
673 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n" , |
674 | results->cfaRegisterOffset); |
675 | break; |
676 | case DW_CFA_val_offset: |
677 | reg = addressSpace.getULEB128(p, instructionsEnd); |
678 | if (reg > kMaxRegisterNumber) { |
679 | _LIBUNWIND_LOG( |
680 | "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 |
681 | ") out of range\n" , |
682 | reg); |
683 | return false; |
684 | } |
685 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * |
686 | cieInfo.dataAlignFactor; |
687 | results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); |
688 | _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " |
689 | "offset=%" PRId64 "\n" , |
690 | reg, offset); |
691 | break; |
692 | case DW_CFA_val_offset_sf: |
693 | reg = addressSpace.getULEB128(p, instructionsEnd); |
694 | if (reg > kMaxRegisterNumber) { |
695 | _LIBUNWIND_LOG0( |
696 | "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big" ); |
697 | return false; |
698 | } |
699 | offset = addressSpace.getSLEB128(p, instructionsEnd) * |
700 | cieInfo.dataAlignFactor; |
701 | results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); |
702 | _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " |
703 | "offset=%" PRId64 "\n" , |
704 | reg, offset); |
705 | break; |
706 | case DW_CFA_val_expression: |
707 | reg = addressSpace.getULEB128(p, instructionsEnd); |
708 | if (reg > kMaxRegisterNumber) { |
709 | _LIBUNWIND_LOG0( |
710 | "malformed DW_CFA_val_expression DWARF unwind, reg too big" ); |
711 | return false; |
712 | } |
713 | results->setRegister(reg, kRegisterIsExpression, (int64_t)p, |
714 | initialState); |
715 | length = addressSpace.getULEB128(p, instructionsEnd); |
716 | assert(length < static_cast<pint_t>(~0) && "pointer overflow" ); |
717 | p += static_cast<pint_t>(length); |
718 | _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " |
719 | "expression=0x%" PRIx64 ", length=%" PRIu64 |
720 | ")\n" , |
721 | reg, results->savedRegisters[reg].value, length); |
722 | break; |
723 | case DW_CFA_GNU_args_size: |
724 | length = addressSpace.getULEB128(p, instructionsEnd); |
725 | results->spExtraArgSize = (uint32_t)length; |
726 | _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n" , length); |
727 | break; |
728 | case DW_CFA_GNU_negative_offset_extended: |
729 | reg = addressSpace.getULEB128(p, instructionsEnd); |
730 | if (reg > kMaxRegisterNumber) { |
731 | _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " |
732 | "unwind, reg too big" ); |
733 | return false; |
734 | } |
735 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * |
736 | cieInfo.dataAlignFactor; |
737 | results->setRegister(reg, kRegisterInCFA, -offset, initialState); |
738 | _LIBUNWIND_TRACE_DWARF( |
739 | "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n" , offset); |
740 | break; |
741 | |
742 | #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \ |
743 | defined(_LIBUNWIND_TARGET_SPARC64) |
744 | // The same constant is used to represent different instructions on |
745 | // AArch64 (negate_ra_state) and SPARC (window_save). |
746 | static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, |
747 | "uses the same constant" ); |
748 | case DW_CFA_AARCH64_negate_ra_state: |
749 | switch (arch) { |
750 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
751 | case REGISTERS_ARM64: { |
752 | int64_t value = |
753 | results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1; |
754 | results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value, |
755 | initialState); |
756 | _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n" ); |
757 | } break; |
758 | #endif |
759 | |
760 | #if defined(_LIBUNWIND_TARGET_SPARC) |
761 | // case DW_CFA_GNU_window_save: |
762 | case REGISTERS_SPARC: |
763 | _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n" ); |
764 | for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { |
765 | results->setRegister(reg, kRegisterInRegister, |
766 | ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0, |
767 | initialState); |
768 | } |
769 | |
770 | for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { |
771 | results->setRegister(reg, kRegisterInCFA, |
772 | ((int64_t)reg - UNW_SPARC_L0) * 4, |
773 | initialState); |
774 | } |
775 | break; |
776 | #endif |
777 | |
778 | #if defined(_LIBUNWIND_TARGET_SPARC64) |
779 | // case DW_CFA_GNU_window_save: |
780 | case REGISTERS_SPARC64: |
781 | // Don't save %o0-%o7 on sparc64. |
782 | // https://reviews.llvm.org/D32450#736405 |
783 | |
784 | for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { |
785 | if (reg == UNW_SPARC_I7) |
786 | results->setRegister( |
787 | reg, kRegisterInCFADecrypt, |
788 | static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)), |
789 | initialState); |
790 | else |
791 | results->setRegister( |
792 | reg, kRegisterInCFA, |
793 | static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)), |
794 | initialState); |
795 | } |
796 | _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n" ); |
797 | break; |
798 | #endif |
799 | } |
800 | break; |
801 | |
802 | #else |
803 | (void)arch; |
804 | #endif |
805 | |
806 | default: |
807 | operand = opcode & 0x3F; |
808 | switch (opcode & 0xC0) { |
809 | case DW_CFA_offset: |
810 | reg = operand; |
811 | if (reg > kMaxRegisterNumber) { |
812 | _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 |
813 | ") out of range" , |
814 | reg); |
815 | return false; |
816 | } |
817 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * |
818 | cieInfo.dataAlignFactor; |
819 | results->setRegister(reg, kRegisterInCFA, offset, initialState); |
820 | _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n" , |
821 | operand, offset); |
822 | break; |
823 | case DW_CFA_advance_loc: |
824 | codeOffset += operand * cieInfo.codeAlignFactor; |
825 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n" , |
826 | static_cast<uint64_t>(codeOffset)); |
827 | break; |
828 | case DW_CFA_restore: |
829 | reg = operand; |
830 | if (reg > kMaxRegisterNumber) { |
831 | _LIBUNWIND_LOG( |
832 | "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 |
833 | ") out of range" , |
834 | reg); |
835 | return false; |
836 | } |
837 | results->restoreRegisterToInitialState(reg, initialState); |
838 | _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n" , |
839 | static_cast<uint64_t>(operand)); |
840 | break; |
841 | default: |
842 | _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n" , opcode); |
843 | return false; |
844 | } |
845 | } |
846 | } |
847 | } |
848 | return true; |
849 | } |
850 | |
851 | } // namespace libunwind |
852 | |
853 | #endif // __DWARF_PARSER_HPP__ |
854 | |