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 <vector>
22 
23 #include "libunwind.h"
24 #include "dwarf2.h"
25 
26 #include "AddressSpace.hpp"
27 
28 namespace 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 ///
34 template <typename A>
35 class CFI_Parser {
36 public:
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 {
PrologInfoStackEntrylibunwind::CFI_Parser::PrologInfoStackEntry95     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 
112 private:
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
121 template <typename A>
decodeFDE(A & addressSpace,pint_t fdeStart,FDE_Info * fdeInfo,CIE_Info * cieInfo)122 const 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
176 template <typename A>
findFDE(A & addressSpace,pint_t pc,pint_t ehSectionStart,uint32_t sectionLength,pint_t fdeHint,FDE_Info * fdeInfo,CIE_Info * cieInfo)177 bool 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
256 template <typename A>
parseCIE(A & addressSpace,pint_t cie,CIE_Info * cieInfo)257 const 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
344 template <typename A>
parseFDEInstructions(A & addressSpace,const FDE_Info & fdeInfo,const CIE_Info & cieInfo,pint_t upToPC,PrologInfo * results)345 bool 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
363 template <typename A>
parseInstructions(A & addressSpace,pint_t instructions,pint_t instructionsEnd,const CIE_Info & cieInfo,pint_t pcoffset,PrologInfoStackEntry * & rememberStack,PrologInfo * results)364 bool 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__
725