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