• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <limits>
21 
22 #include "libunwind.h"
23 #include "dwarf2.h"
24 
25 #include "config.h"
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 = _LIBUNWIND_HIGHEST_DWARF_REGISTER
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   memset(results, '\0', 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   pint_t p = instructions;
369   pint_t codeOffset = 0;
370   PrologInfo initialState = *results;
371 
372   _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
373                          static_cast<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       _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
390       break;
391     case DW_CFA_set_loc:
392       codeOffset =
393           addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
394       _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
395       break;
396     case DW_CFA_advance_loc1:
397       codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
398       p += 1;
399       _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
400                              static_cast<uint64_t>(codeOffset));
401       break;
402     case DW_CFA_advance_loc2:
403       codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
404       p += 2;
405       _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
406                              static_cast<uint64_t>(codeOffset));
407       break;
408     case DW_CFA_advance_loc4:
409       codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
410       p += 4;
411       _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
412                              static_cast<uint64_t>(codeOffset));
413       break;
414     case DW_CFA_offset_extended:
415       reg = addressSpace.getULEB128(p, instructionsEnd);
416       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
417                                                   * cieInfo.dataAlignFactor;
418       if (reg > kMaxRegisterNumber) {
419         fprintf(stderr,
420                 "malformed DW_CFA_offset_extended DWARF unwind, reg too big\n");
421         return false;
422       }
423       results->savedRegisters[reg].location = kRegisterInCFA;
424       results->savedRegisters[reg].value = offset;
425       _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
426                              "offset=%" PRId64 ")\n",
427                              reg, offset);
428       break;
429     case DW_CFA_restore_extended:
430       reg = addressSpace.getULEB128(p, instructionsEnd);
431       if (reg > kMaxRegisterNumber) {
432         fprintf(
433             stderr,
434             "malformed DW_CFA_restore_extended DWARF unwind, reg too big\n");
435         return false;
436       }
437       results->savedRegisters[reg] = initialState.savedRegisters[reg];
438       _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
439       break;
440     case DW_CFA_undefined:
441       reg = addressSpace.getULEB128(p, instructionsEnd);
442       if (reg > kMaxRegisterNumber) {
443         fprintf(stderr,
444                 "malformed DW_CFA_undefined DWARF unwind, reg too big\n");
445         return false;
446       }
447       results->savedRegisters[reg].location = kRegisterUnused;
448       _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
449       break;
450     case DW_CFA_same_value:
451       reg = addressSpace.getULEB128(p, instructionsEnd);
452       if (reg > kMaxRegisterNumber) {
453         fprintf(stderr,
454                 "malformed DW_CFA_same_value DWARF unwind, reg too big\n");
455         return false;
456       }
457       // <rdar://problem/8456377> DW_CFA_same_value unsupported
458       // "same value" means register was stored in frame, but its current
459       // value has not changed, so no need to restore from frame.
460       // We model this as if the register was never saved.
461       results->savedRegisters[reg].location = kRegisterUnused;
462       // set flag to disable conversion to compact unwind
463       results->sameValueUsed = true;
464       _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
465       break;
466     case DW_CFA_register:
467       reg = addressSpace.getULEB128(p, instructionsEnd);
468       reg2 = addressSpace.getULEB128(p, instructionsEnd);
469       if (reg > kMaxRegisterNumber) {
470         fprintf(stderr,
471                 "malformed DW_CFA_register DWARF unwind, reg too big\n");
472         return false;
473       }
474       if (reg2 > kMaxRegisterNumber) {
475         fprintf(stderr,
476                 "malformed DW_CFA_register DWARF unwind, reg2 too big\n");
477         return false;
478       }
479       results->savedRegisters[reg].location = kRegisterInRegister;
480       results->savedRegisters[reg].value = (int64_t)reg2;
481       // set flag to disable conversion to compact unwind
482       results->registersInOtherRegisters = true;
483       _LIBUNWIND_TRACE_DWARF(
484           "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
485       break;
486 #if !defined(_LIBUNWIND_NO_HEAP)
487     case DW_CFA_remember_state:
488       // avoid operator new, because that would be an upward dependency
489       entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
490       if (entry != NULL) {
491         entry->next = rememberStack;
492         entry->info = *results;
493         rememberStack = entry;
494       } else {
495         return false;
496       }
497       _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
498       break;
499     case DW_CFA_restore_state:
500       if (rememberStack != NULL) {
501         PrologInfoStackEntry *top = rememberStack;
502         *results = top->info;
503         rememberStack = top->next;
504         free((char *)top);
505       } else {
506         return false;
507       }
508       _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
509       break;
510 #endif
511     case DW_CFA_def_cfa:
512       reg = addressSpace.getULEB128(p, instructionsEnd);
513       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
514       if (reg > kMaxRegisterNumber) {
515         fprintf(stderr, "malformed DW_CFA_def_cfa DWARF unwind, reg too big\n");
516         return false;
517       }
518       results->cfaRegister = (uint32_t)reg;
519       results->cfaRegisterOffset = (int32_t)offset;
520       _LIBUNWIND_TRACE_DWARF(
521           "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
522       break;
523     case DW_CFA_def_cfa_register:
524       reg = addressSpace.getULEB128(p, instructionsEnd);
525       if (reg > kMaxRegisterNumber) {
526         fprintf(
527             stderr,
528             "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big\n");
529         return false;
530       }
531       results->cfaRegister = (uint32_t)reg;
532       _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
533       break;
534     case DW_CFA_def_cfa_offset:
535       results->cfaRegisterOffset = (int32_t)
536                                   addressSpace.getULEB128(p, instructionsEnd);
537       results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
538       _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
539                              results->cfaRegisterOffset);
540       break;
541     case DW_CFA_def_cfa_expression:
542       results->cfaRegister = 0;
543       results->cfaExpression = (int64_t)p;
544       length = addressSpace.getULEB128(p, instructionsEnd);
545       assert(length < std::numeric_limits<pint_t>::max() && "pointer overflow");
546       p += static_cast<pint_t>(length);
547       _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
548                              ", length=%" PRIu64 ")\n",
549                              results->cfaExpression, length);
550       break;
551     case DW_CFA_expression:
552       reg = addressSpace.getULEB128(p, instructionsEnd);
553       if (reg > kMaxRegisterNumber) {
554         fprintf(stderr,
555                 "malformed DW_CFA_expression DWARF unwind, reg too big\n");
556         return false;
557       }
558       results->savedRegisters[reg].location = kRegisterAtExpression;
559       results->savedRegisters[reg].value = (int64_t)p;
560       length = addressSpace.getULEB128(p, instructionsEnd);
561       assert(length < std::numeric_limits<pint_t>::max() && "pointer overflow");
562       p += static_cast<pint_t>(length);
563       _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
564                              "expression=0x%" PRIx64 ", "
565                              "length=%" PRIu64 ")\n",
566                              reg, results->savedRegisters[reg].value, length);
567       break;
568     case DW_CFA_offset_extended_sf:
569       reg = addressSpace.getULEB128(p, instructionsEnd);
570       if (reg > kMaxRegisterNumber) {
571         fprintf(
572             stderr,
573             "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big\n");
574         return false;
575       }
576       offset =
577           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
578       results->savedRegisters[reg].location = kRegisterInCFA;
579       results->savedRegisters[reg].value = offset;
580       _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
581                              "offset=%" PRId64 ")\n",
582                              reg, offset);
583       break;
584     case DW_CFA_def_cfa_sf:
585       reg = addressSpace.getULEB128(p, instructionsEnd);
586       offset =
587           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
588       if (reg > kMaxRegisterNumber) {
589         fprintf(stderr,
590                 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big\n");
591         return false;
592       }
593       results->cfaRegister = (uint32_t)reg;
594       results->cfaRegisterOffset = (int32_t)offset;
595       _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
596                              "offset=%" PRId64 ")\n",
597                              reg, offset);
598       break;
599     case DW_CFA_def_cfa_offset_sf:
600       results->cfaRegisterOffset = (int32_t)
601         (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
602       results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
603       _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
604                              results->cfaRegisterOffset);
605       break;
606     case DW_CFA_val_offset:
607       reg = addressSpace.getULEB128(p, instructionsEnd);
608       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
609                                                     * cieInfo.dataAlignFactor;
610       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
611       results->savedRegisters[reg].value = offset;
612       _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
613                              "offset=%" PRId64 "\n",
614                              reg, offset);
615       break;
616     case DW_CFA_val_offset_sf:
617       reg = addressSpace.getULEB128(p, instructionsEnd);
618       if (reg > kMaxRegisterNumber) {
619         fprintf(stderr,
620                 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big\n");
621         return false;
622       }
623       offset =
624           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
625       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
626       results->savedRegisters[reg].value = offset;
627       _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
628                              "offset=%" PRId64 "\n",
629                              reg, offset);
630       break;
631     case DW_CFA_val_expression:
632       reg = addressSpace.getULEB128(p, instructionsEnd);
633       if (reg > kMaxRegisterNumber) {
634         fprintf(stderr,
635                 "malformed DW_CFA_val_expression DWARF unwind, reg too big\n");
636         return false;
637       }
638       results->savedRegisters[reg].location = kRegisterIsExpression;
639       results->savedRegisters[reg].value = (int64_t)p;
640       length = addressSpace.getULEB128(p, instructionsEnd);
641       assert(length < std::numeric_limits<pint_t>::max() && "pointer overflow");
642       p += static_cast<pint_t>(length);
643       _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
644                              "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
645                              reg, results->savedRegisters[reg].value, length);
646       break;
647     case DW_CFA_GNU_args_size:
648       length = addressSpace.getULEB128(p, instructionsEnd);
649       results->spExtraArgSize = (uint32_t)length;
650       _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
651       break;
652     case DW_CFA_GNU_negative_offset_extended:
653       reg = addressSpace.getULEB128(p, instructionsEnd);
654       if (reg > kMaxRegisterNumber) {
655         fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended DWARF "
656                         "unwind, reg too big\n");
657         return false;
658       }
659       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
660                                                     * cieInfo.dataAlignFactor;
661       results->savedRegisters[reg].location = kRegisterInCFA;
662       results->savedRegisters[reg].value = -offset;
663       _LIBUNWIND_TRACE_DWARF(
664           "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
665       break;
666     default:
667       operand = opcode & 0x3F;
668       switch (opcode & 0xC0) {
669       case DW_CFA_offset:
670         reg = operand;
671         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
672                                                     * cieInfo.dataAlignFactor;
673         results->savedRegisters[reg].location = kRegisterInCFA;
674         results->savedRegisters[reg].value = offset;
675         _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
676                                operand, offset);
677         break;
678       case DW_CFA_advance_loc:
679         codeOffset += operand * cieInfo.codeAlignFactor;
680         _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
681                                static_cast<uint64_t>(codeOffset));
682         break;
683       case DW_CFA_restore:
684         reg = operand;
685         results->savedRegisters[reg] = initialState.savedRegisters[reg];
686         _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
687                                static_cast<uint64_t>(operand));
688         break;
689       default:
690         _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
691         return false;
692       }
693     }
694   }
695 
696   return true;
697 }
698 
699 } // namespace libunwind
700 
701 #endif // __DWARF_PARSER_HPP__
702