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