]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/projects/libunwind/src/DwarfParser.hpp
MFV r331695, 331700: 9166 zfs storage pool checkpoint
[FreeBSD/FreeBSD.git] / contrib / llvm / projects / libunwind / src / DwarfParser.hpp
1 //===--------------------------- 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 "libunwind.h"
22 #include "dwarf2.h"
23
24 #include "AddressSpace.hpp"
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   };
53
54   /// Information about an FDE (Frame Description Entry)
55   struct FDE_Info {
56     pint_t  fdeStart;
57     pint_t  fdeLength;
58     pint_t  fdeInstructions;
59     pint_t  pcStart;
60     pint_t  pcEnd;
61     pint_t  lsda;
62   };
63
64   enum {
65     kMaxRegisterNumber = _LIBUNWIND_MAX_REGISTER
66   };
67   enum RegisterSavedWhere {
68     kRegisterUnused,
69     kRegisterInCFA,
70     kRegisterOffsetFromCFA,
71     kRegisterInRegister,
72     kRegisterAtExpression,
73     kRegisterIsExpression
74   };
75   struct RegisterLocation {
76     RegisterSavedWhere location;
77     int64_t value;
78   };
79   /// Information about a frame layout and registers saved determined
80   /// by "running" the dwarf FDE "instructions"
81   struct PrologInfo {
82     uint32_t          cfaRegister;
83     int32_t           cfaRegisterOffset;  // CFA = (cfaRegister)+cfaRegisterOffset
84     int64_t           cfaExpression;      // CFA = expression
85     uint32_t          spExtraArgSize;
86     uint32_t          codeOffsetAtStackDecrement;
87     bool              registersInOtherRegisters;
88     bool              sameValueUsed;
89     RegisterLocation  savedRegisters[kMaxRegisterNumber];
90   };
91
92   struct PrologInfoStackEntry {
93     PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
94         : next(n), info(i) {}
95     PrologInfoStackEntry *next;
96     PrologInfo info;
97   };
98
99   static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
100                       uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
101                       CIE_Info *cieInfo);
102   static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
103                                FDE_Info *fdeInfo, CIE_Info *cieInfo);
104   static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
105                                    const CIE_Info &cieInfo, pint_t upToPC,
106                                    PrologInfo *results);
107
108   static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
109
110 private:
111   static bool parseInstructions(A &addressSpace, pint_t instructions,
112                                 pint_t instructionsEnd, const CIE_Info &cieInfo,
113                                 pint_t pcoffset,
114                                 PrologInfoStackEntry *&rememberStack,
115                                 PrologInfo *results);
116 };
117
118 /// Parse a FDE into a CIE_Info and an FDE_Info
119 template <typename A>
120 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
121                                      FDE_Info *fdeInfo, CIE_Info *cieInfo) {
122   pint_t p = fdeStart;
123   pint_t cfiLength = (pint_t)addressSpace.get32(p);
124   p += 4;
125   if (cfiLength == 0xffffffff) {
126     // 0xffffffff means length is really next 8 bytes
127     cfiLength = (pint_t)addressSpace.get64(p);
128     p += 8;
129   }
130   if (cfiLength == 0)
131     return "FDE has zero length"; // end marker
132   uint32_t ciePointer = addressSpace.get32(p);
133   if (ciePointer == 0)
134     return "FDE is really a CIE"; // this is a CIE not an FDE
135   pint_t nextCFI = p + cfiLength;
136   pint_t cieStart = p - ciePointer;
137   const char *err = parseCIE(addressSpace, cieStart, cieInfo);
138   if (err != NULL)
139     return err;
140   p += 4;
141   // parse pc begin and range
142   pint_t pcStart =
143       addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
144   pint_t pcRange =
145       addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
146   // parse rest of info
147   fdeInfo->lsda = 0;
148   // check for augmentation length
149   if (cieInfo->fdesHaveAugmentationData) {
150     pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
151     pint_t endOfAug = p + augLen;
152     if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
153       // peek at value (without indirection).  Zero means no lsda
154       pint_t lsdaStart = p;
155       if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
156           0) {
157         // reset pointer and re-parse lsda address
158         p = lsdaStart;
159         fdeInfo->lsda =
160             addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
161       }
162     }
163     p = endOfAug;
164   }
165   fdeInfo->fdeStart = fdeStart;
166   fdeInfo->fdeLength = nextCFI - fdeStart;
167   fdeInfo->fdeInstructions = p;
168   fdeInfo->pcStart = pcStart;
169   fdeInfo->pcEnd = pcStart + pcRange;
170   return NULL; // success
171 }
172
173 /// Scan an eh_frame section to find an FDE for a pc
174 template <typename A>
175 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
176                             uint32_t sectionLength, pint_t fdeHint,
177                             FDE_Info *fdeInfo, CIE_Info *cieInfo) {
178   //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
179   pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
180   const pint_t ehSectionEnd = p + sectionLength;
181   while (p < ehSectionEnd) {
182     pint_t currentCFI = p;
183     //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
184     pint_t cfiLength = addressSpace.get32(p);
185     p += 4;
186     if (cfiLength == 0xffffffff) {
187       // 0xffffffff means length is really next 8 bytes
188       cfiLength = (pint_t)addressSpace.get64(p);
189       p += 8;
190     }
191     if (cfiLength == 0)
192       return false; // end marker
193     uint32_t id = addressSpace.get32(p);
194     if (id == 0) {
195       // skip over CIEs
196       p += cfiLength;
197     } else {
198       // process FDE to see if it covers pc
199       pint_t nextCFI = p + cfiLength;
200       uint32_t ciePointer = addressSpace.get32(p);
201       pint_t cieStart = p - ciePointer;
202       // validate pointer to CIE is within section
203       if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
204         if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
205           p += 4;
206           // parse pc begin and range
207           pint_t pcStart =
208               addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
209           pint_t pcRange = addressSpace.getEncodedP(
210               p, nextCFI, cieInfo->pointerEncoding & 0x0F);
211           // test if pc is within the function this FDE covers
212           if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
213             // parse rest of info
214             fdeInfo->lsda = 0;
215             // check for augmentation length
216             if (cieInfo->fdesHaveAugmentationData) {
217               pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
218               pint_t endOfAug = p + augLen;
219               if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
220                 // peek at value (without indirection).  Zero means no lsda
221                 pint_t lsdaStart = p;
222                 if (addressSpace.getEncodedP(
223                         p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
224                   // reset pointer and re-parse lsda address
225                   p = lsdaStart;
226                   fdeInfo->lsda = addressSpace
227                       .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
228                 }
229               }
230               p = endOfAug;
231             }
232             fdeInfo->fdeStart = currentCFI;
233             fdeInfo->fdeLength = nextCFI - currentCFI;
234             fdeInfo->fdeInstructions = p;
235             fdeInfo->pcStart = pcStart;
236             fdeInfo->pcEnd = pcStart + pcRange;
237             return true;
238           } else {
239             // pc is not in begin/range, skip this FDE
240           }
241         } else {
242           // malformed CIE, now augmentation describing pc range encoding
243         }
244       } else {
245         // malformed FDE.  CIE is bad
246       }
247       p = nextCFI;
248     }
249   }
250   return false;
251 }
252
253 /// Extract info from a CIE
254 template <typename A>
255 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
256                                     CIE_Info *cieInfo) {
257   cieInfo->pointerEncoding = 0;
258   cieInfo->lsdaEncoding = DW_EH_PE_omit;
259   cieInfo->personalityEncoding = 0;
260   cieInfo->personalityOffsetInCIE = 0;
261   cieInfo->personality = 0;
262   cieInfo->codeAlignFactor = 0;
263   cieInfo->dataAlignFactor = 0;
264   cieInfo->isSignalFrame = false;
265   cieInfo->fdesHaveAugmentationData = false;
266   cieInfo->cieStart = cie;
267   pint_t p = cie;
268   pint_t cieLength = (pint_t)addressSpace.get32(p);
269   p += 4;
270   pint_t cieContentEnd = p + cieLength;
271   if (cieLength == 0xffffffff) {
272     // 0xffffffff means length is really next 8 bytes
273     cieLength = (pint_t)addressSpace.get64(p);
274     p += 8;
275     cieContentEnd = p + cieLength;
276   }
277   if (cieLength == 0)
278     return NULL;
279   // CIE ID is always 0
280   if (addressSpace.get32(p) != 0)
281     return "CIE ID is not zero";
282   p += 4;
283   // Version is always 1 or 3
284   uint8_t version = addressSpace.get8(p);
285   if ((version != 1) && (version != 3))
286     return "CIE version is not 1 or 3";
287   ++p;
288   // save start of augmentation string and find end
289   pint_t strStart = p;
290   while (addressSpace.get8(p) != 0)
291     ++p;
292   ++p;
293   // parse code aligment factor
294   cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
295   // parse data alignment factor
296   cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
297   // parse return address register
298   uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
299   assert(raReg < 255 && "return address register too large");
300   cieInfo->returnAddressRegister = (uint8_t)raReg;
301   // parse augmentation data based on augmentation string
302   const char *result = NULL;
303   if (addressSpace.get8(strStart) == 'z') {
304     // parse augmentation data length
305     addressSpace.getULEB128(p, cieContentEnd);
306     for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
307       switch (addressSpace.get8(s)) {
308       case 'z':
309         cieInfo->fdesHaveAugmentationData = true;
310         break;
311       case 'P':
312         cieInfo->personalityEncoding = addressSpace.get8(p);
313         ++p;
314         cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
315         cieInfo->personality = addressSpace
316             .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
317         break;
318       case 'L':
319         cieInfo->lsdaEncoding = addressSpace.get8(p);
320         ++p;
321         break;
322       case 'R':
323         cieInfo->pointerEncoding = addressSpace.get8(p);
324         ++p;
325         break;
326       case 'S':
327         cieInfo->isSignalFrame = true;
328         break;
329       default:
330         // ignore unknown letters
331         break;
332       }
333     }
334   }
335   cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
336   cieInfo->cieInstructions = p;
337   return result;
338 }
339
340
341 /// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
342 template <typename A>
343 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
344                                          const FDE_Info &fdeInfo,
345                                          const CIE_Info &cieInfo, pint_t upToPC,
346                                          PrologInfo *results) {
347   // clear results
348   memset(results, '\0', sizeof(PrologInfo));
349   PrologInfoStackEntry *rememberStack = NULL;
350
351   // parse CIE then FDE instructions
352   return parseInstructions(addressSpace, cieInfo.cieInstructions,
353                            cieInfo.cieStart + cieInfo.cieLength, cieInfo,
354                            (pint_t)(-1), rememberStack, results) &&
355          parseInstructions(addressSpace, fdeInfo.fdeInstructions,
356                            fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
357                            upToPC - fdeInfo.pcStart, rememberStack, results);
358 }
359
360 /// "run" the dwarf instructions
361 template <typename A>
362 bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
363                                       pint_t instructionsEnd,
364                                       const CIE_Info &cieInfo, pint_t pcoffset,
365                                       PrologInfoStackEntry *&rememberStack,
366                                       PrologInfo *results) {
367   const bool logDwarf = false;
368   pint_t p = instructions;
369   pint_t codeOffset = 0;
370   PrologInfo initialState = *results;
371   if (logDwarf)
372     fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n",
373             (uint64_t)instructionsEnd);
374
375   // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
376   while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
377     uint64_t reg;
378     uint64_t reg2;
379     int64_t offset;
380     uint64_t length;
381     uint8_t opcode = addressSpace.get8(p);
382     uint8_t operand;
383 #if !defined(_LIBUNWIND_NO_HEAP)
384     PrologInfoStackEntry *entry;
385 #endif
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 #if !defined(_LIBUNWIND_NO_HEAP)
498     case DW_CFA_remember_state:
499       // avoid operator new, because that would be an upward dependency
500       entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
501       if (entry != NULL) {
502         entry->next = rememberStack;
503         entry->info = *results;
504         rememberStack = entry;
505       } else {
506         return false;
507       }
508       if (logDwarf)
509         fprintf(stderr, "DW_CFA_remember_state\n");
510       break;
511     case DW_CFA_restore_state:
512       if (rememberStack != NULL) {
513         PrologInfoStackEntry *top = rememberStack;
514         *results = top->info;
515         rememberStack = top->next;
516         free((char *)top);
517       } else {
518         return false;
519       }
520       if (logDwarf)
521         fprintf(stderr, "DW_CFA_restore_state\n");
522       break;
523 #endif
524     case DW_CFA_def_cfa:
525       reg = addressSpace.getULEB128(p, instructionsEnd);
526       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
527       if (reg > kMaxRegisterNumber) {
528         fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
529         return false;
530       }
531       results->cfaRegister = (uint32_t)reg;
532       results->cfaRegisterOffset = (int32_t)offset;
533       if (logDwarf)
534         fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n",
535                 reg, offset);
536       break;
537     case DW_CFA_def_cfa_register:
538       reg = addressSpace.getULEB128(p, instructionsEnd);
539       if (reg > kMaxRegisterNumber) {
540         fprintf(
541             stderr,
542             "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
543         return false;
544       }
545       results->cfaRegister = (uint32_t)reg;
546       if (logDwarf)
547         fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
548       break;
549     case DW_CFA_def_cfa_offset:
550       results->cfaRegisterOffset = (int32_t)
551                                   addressSpace.getULEB128(p, instructionsEnd);
552       results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
553       if (logDwarf)
554         fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n",
555                 results->cfaRegisterOffset);
556       break;
557     case DW_CFA_def_cfa_expression:
558       results->cfaRegister = 0;
559       results->cfaExpression = (int64_t)p;
560       length = addressSpace.getULEB128(p, instructionsEnd);
561       p += length;
562       if (logDwarf)
563         fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64
564                         ", length=%" PRIu64 ")\n",
565                 results->cfaExpression, length);
566       break;
567     case DW_CFA_expression:
568       reg = addressSpace.getULEB128(p, instructionsEnd);
569       if (reg > kMaxRegisterNumber) {
570         fprintf(stderr,
571                 "malformed DW_CFA_expression dwarf unwind, reg too big\n");
572         return false;
573       }
574       results->savedRegisters[reg].location = kRegisterAtExpression;
575       results->savedRegisters[reg].value = (int64_t)p;
576       length = addressSpace.getULEB128(p, instructionsEnd);
577       p += length;
578       if (logDwarf)
579         fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64
580                         ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
581                 reg, results->savedRegisters[reg].value, length);
582       break;
583     case DW_CFA_offset_extended_sf:
584       reg = addressSpace.getULEB128(p, instructionsEnd);
585       if (reg > kMaxRegisterNumber) {
586         fprintf(
587             stderr,
588             "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
589         return false;
590       }
591       offset =
592           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
593       results->savedRegisters[reg].location = kRegisterInCFA;
594       results->savedRegisters[reg].value = offset;
595       if (logDwarf)
596         fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64
597                         ", offset=%" PRId64 ")\n",
598                 reg, offset);
599       break;
600     case DW_CFA_def_cfa_sf:
601       reg = addressSpace.getULEB128(p, instructionsEnd);
602       offset =
603           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
604       if (reg > kMaxRegisterNumber) {
605         fprintf(stderr,
606                 "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
607         return false;
608       }
609       results->cfaRegister = (uint32_t)reg;
610       results->cfaRegisterOffset = (int32_t)offset;
611       if (logDwarf)
612         fprintf(stderr,
613                 "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg,
614                 offset);
615       break;
616     case DW_CFA_def_cfa_offset_sf:
617       results->cfaRegisterOffset = (int32_t)
618         (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
619       results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
620       if (logDwarf)
621         fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n",
622                 results->cfaRegisterOffset);
623       break;
624     case DW_CFA_val_offset:
625       reg = addressSpace.getULEB128(p, instructionsEnd);
626       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
627                                                     * cieInfo.dataAlignFactor;
628       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
629       results->savedRegisters[reg].value = offset;
630       if (logDwarf)
631         fprintf(stderr,
632                 "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg,
633                 offset);
634       break;
635     case DW_CFA_val_offset_sf:
636       reg = addressSpace.getULEB128(p, instructionsEnd);
637       if (reg > kMaxRegisterNumber) {
638         fprintf(stderr,
639                 "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
640         return false;
641       }
642       offset =
643           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
644       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
645       results->savedRegisters[reg].value = offset;
646       if (logDwarf)
647         fprintf(stderr,
648                 "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n",
649                 reg, offset);
650       break;
651     case DW_CFA_val_expression:
652       reg = addressSpace.getULEB128(p, instructionsEnd);
653       if (reg > kMaxRegisterNumber) {
654         fprintf(stderr,
655                 "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
656         return false;
657       }
658       results->savedRegisters[reg].location = kRegisterIsExpression;
659       results->savedRegisters[reg].value = (int64_t)p;
660       length = addressSpace.getULEB128(p, instructionsEnd);
661       p += length;
662       if (logDwarf)
663         fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64
664                         ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
665                 reg, results->savedRegisters[reg].value, length);
666       break;
667     case DW_CFA_GNU_args_size:
668       length = addressSpace.getULEB128(p, instructionsEnd);
669       results->spExtraArgSize = (uint32_t)length;
670       if (logDwarf)
671         fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
672       break;
673     case DW_CFA_GNU_negative_offset_extended:
674       reg = addressSpace.getULEB128(p, instructionsEnd);
675       if (reg > kMaxRegisterNumber) {
676         fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf "
677                         "unwind, reg too big\n");
678         return false;
679       }
680       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
681                                                     * cieInfo.dataAlignFactor;
682       results->savedRegisters[reg].location = kRegisterInCFA;
683       results->savedRegisters[reg].value = -offset;
684       if (logDwarf)
685         fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n",
686                 offset);
687       break;
688     default:
689       operand = opcode & 0x3F;
690       switch (opcode & 0xC0) {
691       case DW_CFA_offset:
692         reg = operand;
693         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
694                                                     * cieInfo.dataAlignFactor;
695         results->savedRegisters[reg].location = kRegisterInCFA;
696         results->savedRegisters[reg].value = offset;
697         if (logDwarf)
698           fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
699                   operand, offset);
700         break;
701       case DW_CFA_advance_loc:
702         codeOffset += operand * cieInfo.codeAlignFactor;
703         if (logDwarf)
704           fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
705                   (uint64_t)codeOffset);
706         break;
707       case DW_CFA_restore:
708         reg = operand;
709         results->savedRegisters[reg] = initialState.savedRegisters[reg];
710         if (logDwarf)
711           fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg);
712         break;
713       default:
714         if (logDwarf)
715           fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
716         return false;
717       }
718     }
719   }
720
721   return true;
722 }
723
724 } // namespace libunwind
725
726 #endif // __DWARF_PARSER_HPP__