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