Home | History | Annotate | Download | only in Unwind
      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 {
     95     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>
    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>
    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>
    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>
    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>
    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