1 //===--------------------------- DwarfParser.hpp --------------------------===//
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 #endif
55 };
56
57 /// Information about an FDE (Frame Description Entry)
58 struct FDE_Info {
59 pint_t fdeStart;
60 pint_t fdeLength;
61 pint_t fdeInstructions;
62 pint_t pcStart;
63 pint_t pcEnd;
64 pint_t lsda;
65 };
66
67 enum {
68 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
69 };
70 enum RegisterSavedWhere {
71 kRegisterUnused,
72 kRegisterInCFA,
73 kRegisterOffsetFromCFA,
74 kRegisterInRegister,
75 kRegisterAtExpression,
76 kRegisterIsExpression
77 };
78 struct RegisterLocation {
79 RegisterSavedWhere location;
80 int64_t value;
81 };
82 /// Information about a frame layout and registers saved determined
83 /// by "running" the DWARF FDE "instructions"
84 struct PrologInfo {
85 uint32_t cfaRegister;
86 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
87 int64_t cfaExpression; // CFA = expression
88 uint32_t spExtraArgSize;
89 uint32_t codeOffsetAtStackDecrement;
90 bool registersInOtherRegisters;
91 bool sameValueUsed;
92 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
93 };
94
95 struct PrologInfoStackEntry {
PrologInfoStackEntrylibunwind::CFI_Parser::PrologInfoStackEntry96 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
97 : next(n), info(i) {}
98 PrologInfoStackEntry *next;
99 PrologInfo info;
100 };
101
102 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
103 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
104 CIE_Info *cieInfo);
105 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
106 FDE_Info *fdeInfo, CIE_Info *cieInfo);
107 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
108 const CIE_Info &cieInfo, pint_t upToPC,
109 int arch, PrologInfo *results);
110
111 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
112
113 private:
114 static bool parseInstructions(A &addressSpace, pint_t instructions,
115 pint_t instructionsEnd, const CIE_Info &cieInfo,
116 pint_t pcoffset,
117 PrologInfoStackEntry *&rememberStack, int arch,
118 PrologInfo *results);
119 };
120
121 /// Parse a FDE into a CIE_Info and an FDE_Info
122 template <typename A>
decodeFDE(A & addressSpace,pint_t fdeStart,FDE_Info * fdeInfo,CIE_Info * cieInfo)123 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
124 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
125 pint_t p = fdeStart;
126 pint_t cfiLength = (pint_t)addressSpace.get32(p);
127 p += 4;
128 if (cfiLength == 0xffffffff) {
129 // 0xffffffff means length is really next 8 bytes
130 cfiLength = (pint_t)addressSpace.get64(p);
131 p += 8;
132 }
133 if (cfiLength == 0)
134 return "FDE has zero length"; // end marker
135 uint32_t ciePointer = addressSpace.get32(p);
136 if (ciePointer == 0)
137 return "FDE is really a CIE"; // this is a CIE not an FDE
138 pint_t nextCFI = p + cfiLength;
139 pint_t cieStart = p - ciePointer;
140 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
141 if (err != NULL)
142 return err;
143 p += 4;
144 // Parse pc begin and range.
145 pint_t pcStart =
146 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
147 pint_t pcRange =
148 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
149 // Parse rest of info.
150 fdeInfo->lsda = 0;
151 // Check for augmentation length.
152 if (cieInfo->fdesHaveAugmentationData) {
153 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
154 pint_t endOfAug = p + augLen;
155 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
156 // Peek at value (without indirection). Zero means no LSDA.
157 pint_t lsdaStart = p;
158 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
159 0) {
160 // Reset pointer and re-parse LSDA address.
161 p = lsdaStart;
162 fdeInfo->lsda =
163 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
164 }
165 }
166 p = endOfAug;
167 }
168 fdeInfo->fdeStart = fdeStart;
169 fdeInfo->fdeLength = nextCFI - fdeStart;
170 fdeInfo->fdeInstructions = p;
171 fdeInfo->pcStart = pcStart;
172 fdeInfo->pcEnd = pcStart + pcRange;
173 return NULL; // success
174 }
175
176 /// Scan an eh_frame section to find an FDE for a pc
177 template <typename A>
findFDE(A & addressSpace,pint_t pc,pint_t ehSectionStart,uint32_t sectionLength,pint_t fdeHint,FDE_Info * fdeInfo,CIE_Info * cieInfo)178 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
179 uint32_t sectionLength, pint_t fdeHint,
180 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
181 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
182 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
183 const pint_t ehSectionEnd = p + sectionLength;
184 while (p < ehSectionEnd) {
185 pint_t currentCFI = p;
186 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
187 pint_t cfiLength = addressSpace.get32(p);
188 p += 4;
189 if (cfiLength == 0xffffffff) {
190 // 0xffffffff means length is really next 8 bytes
191 cfiLength = (pint_t)addressSpace.get64(p);
192 p += 8;
193 }
194 if (cfiLength == 0)
195 return false; // end marker
196 uint32_t id = addressSpace.get32(p);
197 if (id == 0) {
198 // Skip over CIEs.
199 p += cfiLength;
200 } else {
201 // Process FDE to see if it covers pc.
202 pint_t nextCFI = p + cfiLength;
203 uint32_t ciePointer = addressSpace.get32(p);
204 pint_t cieStart = p - ciePointer;
205 // Validate pointer to CIE is within section.
206 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
207 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
208 p += 4;
209 // Parse pc begin and range.
210 pint_t pcStart =
211 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
212 pint_t pcRange = addressSpace.getEncodedP(
213 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
214 // Test if pc is within the function this FDE covers.
215 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
216 // parse rest of info
217 fdeInfo->lsda = 0;
218 // check for augmentation length
219 if (cieInfo->fdesHaveAugmentationData) {
220 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
221 pint_t endOfAug = p + augLen;
222 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
223 // Peek at value (without indirection). Zero means no LSDA.
224 pint_t lsdaStart = p;
225 if (addressSpace.getEncodedP(
226 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
227 // Reset pointer and re-parse LSDA address.
228 p = lsdaStart;
229 fdeInfo->lsda = addressSpace
230 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
231 }
232 }
233 p = endOfAug;
234 }
235 fdeInfo->fdeStart = currentCFI;
236 fdeInfo->fdeLength = nextCFI - currentCFI;
237 fdeInfo->fdeInstructions = p;
238 fdeInfo->pcStart = pcStart;
239 fdeInfo->pcEnd = pcStart + pcRange;
240 return true;
241 } else {
242 // pc is not in begin/range, skip this FDE
243 }
244 } else {
245 // Malformed CIE, now augmentation describing pc range encoding.
246 }
247 } else {
248 // malformed FDE. CIE is bad
249 }
250 p = nextCFI;
251 }
252 }
253 return false;
254 }
255
256 /// Extract info from a CIE
257 template <typename A>
parseCIE(A & addressSpace,pint_t cie,CIE_Info * cieInfo)258 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
259 CIE_Info *cieInfo) {
260 cieInfo->pointerEncoding = 0;
261 cieInfo->lsdaEncoding = DW_EH_PE_omit;
262 cieInfo->personalityEncoding = 0;
263 cieInfo->personalityOffsetInCIE = 0;
264 cieInfo->personality = 0;
265 cieInfo->codeAlignFactor = 0;
266 cieInfo->dataAlignFactor = 0;
267 cieInfo->isSignalFrame = false;
268 cieInfo->fdesHaveAugmentationData = false;
269 #if defined(_LIBUNWIND_TARGET_AARCH64)
270 cieInfo->addressesSignedWithBKey = false;
271 #endif
272 cieInfo->cieStart = cie;
273 pint_t p = cie;
274 pint_t cieLength = (pint_t)addressSpace.get32(p);
275 p += 4;
276 pint_t cieContentEnd = p + cieLength;
277 if (cieLength == 0xffffffff) {
278 // 0xffffffff means length is really next 8 bytes
279 cieLength = (pint_t)addressSpace.get64(p);
280 p += 8;
281 cieContentEnd = p + cieLength;
282 }
283 if (cieLength == 0)
284 return NULL;
285 // CIE ID is always 0
286 if (addressSpace.get32(p) != 0)
287 return "CIE ID is not zero";
288 p += 4;
289 // Version is always 1 or 3
290 uint8_t version = addressSpace.get8(p);
291 if ((version != 1) && (version != 3))
292 return "CIE version is not 1 or 3";
293 ++p;
294 // save start of augmentation string and find end
295 pint_t strStart = p;
296 while (addressSpace.get8(p) != 0)
297 ++p;
298 ++p;
299 // parse code aligment factor
300 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
301 // parse data alignment factor
302 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
303 // parse return address register
304 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
305 assert(raReg < 255 && "return address register too large");
306 cieInfo->returnAddressRegister = (uint8_t)raReg;
307 // parse augmentation data based on augmentation string
308 const char *result = NULL;
309 if (addressSpace.get8(strStart) == 'z') {
310 // parse augmentation data length
311 addressSpace.getULEB128(p, cieContentEnd);
312 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
313 switch (addressSpace.get8(s)) {
314 case 'z':
315 cieInfo->fdesHaveAugmentationData = true;
316 break;
317 case 'P':
318 cieInfo->personalityEncoding = addressSpace.get8(p);
319 ++p;
320 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
321 cieInfo->personality = addressSpace
322 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
323 break;
324 case 'L':
325 cieInfo->lsdaEncoding = addressSpace.get8(p);
326 ++p;
327 break;
328 case 'R':
329 cieInfo->pointerEncoding = addressSpace.get8(p);
330 ++p;
331 break;
332 case 'S':
333 cieInfo->isSignalFrame = true;
334 break;
335 #if defined(_LIBUNWIND_TARGET_AARCH64)
336 case 'B':
337 cieInfo->addressesSignedWithBKey = true;
338 break;
339 #endif
340 default:
341 // ignore unknown letters
342 break;
343 }
344 }
345 }
346 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
347 cieInfo->cieInstructions = p;
348 return result;
349 }
350
351
352 /// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
353 template <typename A>
parseFDEInstructions(A & addressSpace,const FDE_Info & fdeInfo,const CIE_Info & cieInfo,pint_t upToPC,int arch,PrologInfo * results)354 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
355 const FDE_Info &fdeInfo,
356 const CIE_Info &cieInfo, pint_t upToPC,
357 int arch, PrologInfo *results) {
358 // clear results
359 memset(results, '\0', sizeof(PrologInfo));
360 PrologInfoStackEntry *rememberStack = NULL;
361
362 // parse CIE then FDE instructions
363 return parseInstructions(addressSpace, cieInfo.cieInstructions,
364 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
365 (pint_t)(-1), rememberStack, arch, results) &&
366 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
367 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
368 upToPC - fdeInfo.pcStart, rememberStack, arch,
369 results);
370 }
371
372 /// "run" the DWARF instructions
373 template <typename A>
parseInstructions(A & addressSpace,pint_t instructions,pint_t instructionsEnd,const CIE_Info & cieInfo,pint_t pcoffset,PrologInfoStackEntry * & rememberStack,int arch,PrologInfo * results)374 bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
375 pint_t instructionsEnd,
376 const CIE_Info &cieInfo, pint_t pcoffset,
377 PrologInfoStackEntry *&rememberStack,
378 int arch, PrologInfo *results) {
379 pint_t p = instructions;
380 pint_t codeOffset = 0;
381 PrologInfo initialState = *results;
382
383 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
384 static_cast<uint64_t>(instructionsEnd));
385
386 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
387 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
388 uint64_t reg;
389 uint64_t reg2;
390 int64_t offset;
391 uint64_t length;
392 uint8_t opcode = addressSpace.get8(p);
393 uint8_t operand;
394 #if !defined(_LIBUNWIND_NO_HEAP)
395 PrologInfoStackEntry *entry;
396 #endif
397 ++p;
398 switch (opcode) {
399 case DW_CFA_nop:
400 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
401 break;
402 case DW_CFA_set_loc:
403 codeOffset =
404 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
405 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
406 break;
407 case DW_CFA_advance_loc1:
408 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
409 p += 1;
410 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
411 static_cast<uint64_t>(codeOffset));
412 break;
413 case DW_CFA_advance_loc2:
414 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
415 p += 2;
416 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
417 static_cast<uint64_t>(codeOffset));
418 break;
419 case DW_CFA_advance_loc4:
420 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
421 p += 4;
422 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
423 static_cast<uint64_t>(codeOffset));
424 break;
425 case DW_CFA_offset_extended:
426 reg = addressSpace.getULEB128(p, instructionsEnd);
427 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
428 * cieInfo.dataAlignFactor;
429 if (reg > kMaxRegisterNumber) {
430 _LIBUNWIND_LOG0(
431 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
432 return false;
433 }
434 results->savedRegisters[reg].location = kRegisterInCFA;
435 results->savedRegisters[reg].value = offset;
436 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
437 "offset=%" PRId64 ")\n",
438 reg, offset);
439 break;
440 case DW_CFA_restore_extended:
441 reg = addressSpace.getULEB128(p, instructionsEnd);
442 if (reg > kMaxRegisterNumber) {
443 _LIBUNWIND_LOG0(
444 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
445 return false;
446 }
447 results->savedRegisters[reg] = initialState.savedRegisters[reg];
448 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
449 break;
450 case DW_CFA_undefined:
451 reg = addressSpace.getULEB128(p, instructionsEnd);
452 if (reg > kMaxRegisterNumber) {
453 _LIBUNWIND_LOG0(
454 "malformed DW_CFA_undefined DWARF unwind, reg too big");
455 return false;
456 }
457 results->savedRegisters[reg].location = kRegisterUnused;
458 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
459 break;
460 case DW_CFA_same_value:
461 reg = addressSpace.getULEB128(p, instructionsEnd);
462 if (reg > kMaxRegisterNumber) {
463 _LIBUNWIND_LOG0(
464 "malformed DW_CFA_same_value DWARF unwind, reg too big");
465 return false;
466 }
467 // <rdar://problem/8456377> DW_CFA_same_value unsupported
468 // "same value" means register was stored in frame, but its current
469 // value has not changed, so no need to restore from frame.
470 // We model this as if the register was never saved.
471 results->savedRegisters[reg].location = kRegisterUnused;
472 // set flag to disable conversion to compact unwind
473 results->sameValueUsed = true;
474 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
475 break;
476 case DW_CFA_register:
477 reg = addressSpace.getULEB128(p, instructionsEnd);
478 reg2 = addressSpace.getULEB128(p, instructionsEnd);
479 if (reg > kMaxRegisterNumber) {
480 _LIBUNWIND_LOG0(
481 "malformed DW_CFA_register DWARF unwind, reg too big");
482 return false;
483 }
484 if (reg2 > kMaxRegisterNumber) {
485 _LIBUNWIND_LOG0(
486 "malformed DW_CFA_register DWARF unwind, reg2 too big");
487 return false;
488 }
489 results->savedRegisters[reg].location = kRegisterInRegister;
490 results->savedRegisters[reg].value = (int64_t)reg2;
491 // set flag to disable conversion to compact unwind
492 results->registersInOtherRegisters = true;
493 _LIBUNWIND_TRACE_DWARF(
494 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
495 break;
496 #if !defined(_LIBUNWIND_NO_HEAP)
497 case DW_CFA_remember_state:
498 // avoid operator new, because that would be an upward dependency
499 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
500 if (entry != NULL) {
501 entry->next = rememberStack;
502 entry->info = *results;
503 rememberStack = entry;
504 } else {
505 return false;
506 }
507 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
508 break;
509 case DW_CFA_restore_state:
510 if (rememberStack != NULL) {
511 PrologInfoStackEntry *top = rememberStack;
512 *results = top->info;
513 rememberStack = top->next;
514 free((char *)top);
515 } else {
516 return false;
517 }
518 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
519 break;
520 #endif
521 case DW_CFA_def_cfa:
522 reg = addressSpace.getULEB128(p, instructionsEnd);
523 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
524 if (reg > kMaxRegisterNumber) {
525 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
526 return false;
527 }
528 results->cfaRegister = (uint32_t)reg;
529 results->cfaRegisterOffset = (int32_t)offset;
530 _LIBUNWIND_TRACE_DWARF(
531 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
532 break;
533 case DW_CFA_def_cfa_register:
534 reg = addressSpace.getULEB128(p, instructionsEnd);
535 if (reg > kMaxRegisterNumber) {
536 _LIBUNWIND_LOG0(
537 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
538 return false;
539 }
540 results->cfaRegister = (uint32_t)reg;
541 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
542 break;
543 case DW_CFA_def_cfa_offset:
544 results->cfaRegisterOffset = (int32_t)
545 addressSpace.getULEB128(p, instructionsEnd);
546 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
547 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
548 results->cfaRegisterOffset);
549 break;
550 case DW_CFA_def_cfa_expression:
551 results->cfaRegister = 0;
552 results->cfaExpression = (int64_t)p;
553 length = addressSpace.getULEB128(p, instructionsEnd);
554 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
555 p += static_cast<pint_t>(length);
556 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
557 ", length=%" PRIu64 ")\n",
558 results->cfaExpression, length);
559 break;
560 case DW_CFA_expression:
561 reg = addressSpace.getULEB128(p, instructionsEnd);
562 if (reg > kMaxRegisterNumber) {
563 _LIBUNWIND_LOG0(
564 "malformed DW_CFA_expression DWARF unwind, reg too big");
565 return false;
566 }
567 results->savedRegisters[reg].location = kRegisterAtExpression;
568 results->savedRegisters[reg].value = (int64_t)p;
569 length = addressSpace.getULEB128(p, instructionsEnd);
570 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
571 p += static_cast<pint_t>(length);
572 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
573 "expression=0x%" PRIx64 ", "
574 "length=%" PRIu64 ")\n",
575 reg, results->savedRegisters[reg].value, length);
576 break;
577 case DW_CFA_offset_extended_sf:
578 reg = addressSpace.getULEB128(p, instructionsEnd);
579 if (reg > kMaxRegisterNumber) {
580 _LIBUNWIND_LOG0(
581 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
582 return false;
583 }
584 offset =
585 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
586 results->savedRegisters[reg].location = kRegisterInCFA;
587 results->savedRegisters[reg].value = offset;
588 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
589 "offset=%" PRId64 ")\n",
590 reg, offset);
591 break;
592 case DW_CFA_def_cfa_sf:
593 reg = addressSpace.getULEB128(p, instructionsEnd);
594 offset =
595 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
596 if (reg > kMaxRegisterNumber) {
597 _LIBUNWIND_LOG0(
598 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
599 return false;
600 }
601 results->cfaRegister = (uint32_t)reg;
602 results->cfaRegisterOffset = (int32_t)offset;
603 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
604 "offset=%" PRId64 ")\n",
605 reg, offset);
606 break;
607 case DW_CFA_def_cfa_offset_sf:
608 results->cfaRegisterOffset = (int32_t)
609 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
610 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
611 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
612 results->cfaRegisterOffset);
613 break;
614 case DW_CFA_val_offset:
615 reg = addressSpace.getULEB128(p, instructionsEnd);
616 if (reg > kMaxRegisterNumber) {
617 _LIBUNWIND_LOG(
618 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
619 ") out of range\n",
620 reg);
621 return false;
622 }
623 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
624 * cieInfo.dataAlignFactor;
625 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
626 results->savedRegisters[reg].value = offset;
627 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
628 "offset=%" PRId64 "\n",
629 reg, offset);
630 break;
631 case DW_CFA_val_offset_sf:
632 reg = addressSpace.getULEB128(p, instructionsEnd);
633 if (reg > kMaxRegisterNumber) {
634 _LIBUNWIND_LOG0(
635 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
636 return false;
637 }
638 offset =
639 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
640 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
641 results->savedRegisters[reg].value = offset;
642 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
643 "offset=%" PRId64 "\n",
644 reg, offset);
645 break;
646 case DW_CFA_val_expression:
647 reg = addressSpace.getULEB128(p, instructionsEnd);
648 if (reg > kMaxRegisterNumber) {
649 _LIBUNWIND_LOG0(
650 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
651 return false;
652 }
653 results->savedRegisters[reg].location = kRegisterIsExpression;
654 results->savedRegisters[reg].value = (int64_t)p;
655 length = addressSpace.getULEB128(p, instructionsEnd);
656 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
657 p += static_cast<pint_t>(length);
658 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
659 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
660 reg, results->savedRegisters[reg].value, length);
661 break;
662 case DW_CFA_GNU_args_size:
663 length = addressSpace.getULEB128(p, instructionsEnd);
664 results->spExtraArgSize = (uint32_t)length;
665 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
666 break;
667 case DW_CFA_GNU_negative_offset_extended:
668 reg = addressSpace.getULEB128(p, instructionsEnd);
669 if (reg > kMaxRegisterNumber) {
670 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
671 "unwind, reg too big");
672 return false;
673 }
674 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
675 * cieInfo.dataAlignFactor;
676 results->savedRegisters[reg].location = kRegisterInCFA;
677 results->savedRegisters[reg].value = -offset;
678 _LIBUNWIND_TRACE_DWARF(
679 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
680 break;
681
682 #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
683 // The same constant is used to represent different instructions on
684 // AArch64 (negate_ra_state) and SPARC (window_save).
685 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
686 "uses the same constant");
687 case DW_CFA_AARCH64_negate_ra_state:
688 switch (arch) {
689 #if defined(_LIBUNWIND_TARGET_AARCH64)
690 case REGISTERS_ARM64:
691 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
692 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
693 break;
694 #endif
695 #if defined(_LIBUNWIND_TARGET_SPARC)
696 // case DW_CFA_GNU_window_save:
697 case REGISTERS_SPARC:
698 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
699 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
700 results->savedRegisters[reg].location = kRegisterInRegister;
701 results->savedRegisters[reg].value =
702 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
703 }
704
705 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
706 results->savedRegisters[reg].location = kRegisterInCFA;
707 results->savedRegisters[reg].value =
708 ((int64_t)reg - UNW_SPARC_L0) * 4;
709 }
710 break;
711 #endif
712 }
713 break;
714 #else
715 (void)arch;
716 #endif
717
718 default:
719 operand = opcode & 0x3F;
720 switch (opcode & 0xC0) {
721 case DW_CFA_offset:
722 reg = operand;
723 if (reg > kMaxRegisterNumber) {
724 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
725 ") out of range",
726 reg);
727 return false;
728 }
729 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
730 * cieInfo.dataAlignFactor;
731 results->savedRegisters[reg].location = kRegisterInCFA;
732 results->savedRegisters[reg].value = offset;
733 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
734 operand, offset);
735 break;
736 case DW_CFA_advance_loc:
737 codeOffset += operand * cieInfo.codeAlignFactor;
738 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
739 static_cast<uint64_t>(codeOffset));
740 break;
741 case DW_CFA_restore:
742 reg = operand;
743 if (reg > kMaxRegisterNumber) {
744 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
745 ") out of range",
746 reg);
747 return false;
748 }
749 results->savedRegisters[reg] = initialState.savedRegisters[reg];
750 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
751 static_cast<uint64_t>(operand));
752 break;
753 default:
754 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
755 return false;
756 }
757 }
758 }
759
760 return true;
761 }
762
763 } // namespace libunwind
764
765 #endif // __DWARF_PARSER_HPP__
766