Home | History | Annotate | Download | only in src
      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 + 1];
     91   };
     92 
     93   struct PrologInfoStackEntry {
     94     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>
    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>
    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>
    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>
    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>
    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       if (reg > kMaxRegisterNumber) {
    609         fprintf(stderr,
    610                 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
    611                 ") out of range\n",
    612                 reg);
    613         return false;
    614       }
    615       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
    616                                                     * cieInfo.dataAlignFactor;
    617       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
    618       results->savedRegisters[reg].value = offset;
    619       _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
    620                              "offset=%" PRId64 "\n",
    621                              reg, offset);
    622       break;
    623     case DW_CFA_val_offset_sf:
    624       reg = addressSpace.getULEB128(p, instructionsEnd);
    625       if (reg > kMaxRegisterNumber) {
    626         fprintf(stderr,
    627                 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big\n");
    628         return false;
    629       }
    630       offset =
    631           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
    632       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
    633       results->savedRegisters[reg].value = offset;
    634       _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
    635                              "offset=%" PRId64 "\n",
    636                              reg, offset);
    637       break;
    638     case DW_CFA_val_expression:
    639       reg = addressSpace.getULEB128(p, instructionsEnd);
    640       if (reg > kMaxRegisterNumber) {
    641         fprintf(stderr,
    642                 "malformed DW_CFA_val_expression DWARF unwind, reg too big\n");
    643         return false;
    644       }
    645       results->savedRegisters[reg].location = kRegisterIsExpression;
    646       results->savedRegisters[reg].value = (int64_t)p;
    647       length = addressSpace.getULEB128(p, instructionsEnd);
    648       assert(length < std::numeric_limits<pint_t>::max() && "pointer overflow");
    649       p += static_cast<pint_t>(length);
    650       _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
    651                              "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
    652                              reg, results->savedRegisters[reg].value, length);
    653       break;
    654     case DW_CFA_GNU_args_size:
    655       length = addressSpace.getULEB128(p, instructionsEnd);
    656       results->spExtraArgSize = (uint32_t)length;
    657       _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
    658       break;
    659     case DW_CFA_GNU_negative_offset_extended:
    660       reg = addressSpace.getULEB128(p, instructionsEnd);
    661       if (reg > kMaxRegisterNumber) {
    662         fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended DWARF "
    663                         "unwind, reg too big\n");
    664         return false;
    665       }
    666       offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
    667                                                     * cieInfo.dataAlignFactor;
    668       results->savedRegisters[reg].location = kRegisterInCFA;
    669       results->savedRegisters[reg].value = -offset;
    670       _LIBUNWIND_TRACE_DWARF(
    671           "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
    672       break;
    673     default:
    674       operand = opcode & 0x3F;
    675       switch (opcode & 0xC0) {
    676       case DW_CFA_offset:
    677         reg = operand;
    678         if (reg > kMaxRegisterNumber) {
    679           fprintf(stderr, "malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
    680                           ") out of range\n",
    681                   reg);
    682           return false;
    683         }
    684         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
    685                                                     * cieInfo.dataAlignFactor;
    686         results->savedRegisters[reg].location = kRegisterInCFA;
    687         results->savedRegisters[reg].value = offset;
    688         _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
    689                                operand, offset);
    690         break;
    691       case DW_CFA_advance_loc:
    692         codeOffset += operand * cieInfo.codeAlignFactor;
    693         _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
    694                                static_cast<uint64_t>(codeOffset));
    695         break;
    696       case DW_CFA_restore:
    697         reg = operand;
    698         if (reg > kMaxRegisterNumber) {
    699           fprintf(stderr, "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
    700                           ") out of range\n",
    701                   reg);
    702           return false;
    703         }
    704         results->savedRegisters[reg] = initialState.savedRegisters[reg];
    705         _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
    706                                static_cast<uint64_t>(operand));
    707         break;
    708       default:
    709         _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
    710         return false;
    711       }
    712     }
    713   }
    714 
    715   return true;
    716 }
    717 
    718 } // namespace libunwind
    719 
    720 #endif // __DWARF_PARSER_HPP__
    721