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 <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19
20#include <vector>
21
22#include "libunwind.h"
23#include "dwarf2.h"
24
25#include "AddressSpace.hpp"
26
27namespace 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///
33template <typename A>
34class CFI_Parser {
35public:
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 = 120
67  };
68  enum RegisterSavedWhere {
69    kRegisterUnused,
70    kRegisterInCFA,
71    kRegisterOffsetFromCFA,
72    kRegisterInRegister,
73    kRegisterAtExpression,
74    kRegisterIsExpression
75  };
76  struct RegisterLocation {
77    RegisterSavedWhere location;
78    int64_t value;
79  };
80  /// Information about a frame layout and registers saved determined
81  /// by "running" the dwarf FDE "instructions"
82  struct PrologInfo {
83    uint32_t          cfaRegister;
84    int32_t           cfaRegisterOffset;  // CFA = (cfaRegister)+cfaRegisterOffset
85    int64_t           cfaExpression;      // CFA = expression
86    uint32_t          spExtraArgSize;
87    uint32_t          codeOffsetAtStackDecrement;
88    bool              registersInOtherRegisters;
89    bool              sameValueUsed;
90    RegisterLocation  savedRegisters[kMaxRegisterNumber];
91  };
92
93  struct PrologInfoStackEntry {
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
111private:
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
120template <typename A>
121const 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
175template <typename A>
176bool 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
255template <typename A>
256const 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
343template <typename A>
344bool 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  bzero(results, 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
362template <typename A>
363bool 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  const bool logDwarf = false;
369  pint_t p = instructions;
370  pint_t codeOffset = 0;
371  PrologInfo initialState = *results;
372  if (logDwarf)
373    fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n",
374            (uint64_t) instructionsEnd);
375
376  // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
377  while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
378    uint64_t reg;
379    uint64_t reg2;
380    int64_t offset;
381    uint64_t length;
382    uint8_t opcode = addressSpace.get8(p);
383    uint8_t operand;
384    PrologInfoStackEntry *entry;
385    ++p;
386    switch (opcode) {
387    case DW_CFA_nop:
388      if (logDwarf)
389        fprintf(stderr, "DW_CFA_nop\n");
390      break;
391    case DW_CFA_set_loc:
392      codeOffset =
393          addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
394      if (logDwarf)
395        fprintf(stderr, "DW_CFA_set_loc\n");
396      break;
397    case DW_CFA_advance_loc1:
398      codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
399      p += 1;
400      if (logDwarf)
401        fprintf(stderr, "DW_CFA_advance_loc1: new offset=%llu\n",
402                        (uint64_t)codeOffset);
403      break;
404    case DW_CFA_advance_loc2:
405      codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
406      p += 2;
407      if (logDwarf)
408        fprintf(stderr, "DW_CFA_advance_loc2: new offset=%llu\n",
409                        (uint64_t)codeOffset);
410      break;
411    case DW_CFA_advance_loc4:
412      codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
413      p += 4;
414      if (logDwarf)
415        fprintf(stderr, "DW_CFA_advance_loc4: new offset=%llu\n",
416                        (uint64_t)codeOffset);
417      break;
418    case DW_CFA_offset_extended:
419      reg = addressSpace.getULEB128(p, instructionsEnd);
420      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
421                                                  * cieInfo.dataAlignFactor;
422      if (reg > kMaxRegisterNumber) {
423        fprintf(stderr,
424                "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
425        return false;
426      }
427      results->savedRegisters[reg].location = kRegisterInCFA;
428      results->savedRegisters[reg].value = offset;
429      if (logDwarf)
430        fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg,
431                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=%lld)\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=%lld)\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=%lld)\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=%lld, reg2=%lld)\n", reg, reg2);
493      break;
494    case DW_CFA_remember_state:
495      // avoid operator new, because that would be an upward dependency
496      entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
497      if (entry != NULL) {
498        entry->next = rememberStack;
499        entry->info = *results;
500        rememberStack = entry;
501      } else {
502        return false;
503      }
504      if (logDwarf)
505        fprintf(stderr, "DW_CFA_remember_state\n");
506      break;
507    case DW_CFA_restore_state:
508      if (rememberStack != NULL) {
509        PrologInfoStackEntry *top = rememberStack;
510        *results = top->info;
511        rememberStack = top->next;
512        free((char *)top);
513      } else {
514        return false;
515      }
516      if (logDwarf)
517        fprintf(stderr, "DW_CFA_restore_state\n");
518      break;
519    case DW_CFA_def_cfa:
520      reg = addressSpace.getULEB128(p, instructionsEnd);
521      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
522      if (reg > kMaxRegisterNumber) {
523        fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
524        return false;
525      }
526      results->cfaRegister = (uint32_t)reg;
527      results->cfaRegisterOffset = (int32_t)offset;
528      if (logDwarf)
529        fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
530      break;
531    case DW_CFA_def_cfa_register:
532      reg = addressSpace.getULEB128(p, instructionsEnd);
533      if (reg > kMaxRegisterNumber) {
534        fprintf(
535            stderr,
536            "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
537        return false;
538      }
539      results->cfaRegister = (uint32_t)reg;
540      if (logDwarf)
541        fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
542      break;
543    case DW_CFA_def_cfa_offset:
544      results->cfaRegisterOffset = (int32_t)
545                                  addressSpace.getULEB128(p, instructionsEnd);
546      results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
547      if (logDwarf)
548        fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n",
549                results->cfaRegisterOffset);
550      break;
551    case DW_CFA_def_cfa_expression:
552      results->cfaRegister = 0;
553      results->cfaExpression = (int64_t)p;
554      length = addressSpace.getULEB128(p, instructionsEnd);
555      p += length;
556      if (logDwarf)
557        fprintf(stderr,
558                "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
559                results->cfaExpression, length);
560      break;
561    case DW_CFA_expression:
562      reg = addressSpace.getULEB128(p, instructionsEnd);
563      if (reg > kMaxRegisterNumber) {
564        fprintf(stderr,
565                "malformed DW_CFA_expression dwarf unwind, reg too big\n");
566        return false;
567      }
568      results->savedRegisters[reg].location = kRegisterAtExpression;
569      results->savedRegisters[reg].value = (int64_t)p;
570      length = addressSpace.getULEB128(p, instructionsEnd);
571      p += length;
572      if (logDwarf)
573        fprintf(stderr,
574                "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
575                reg, results->savedRegisters[reg].value, length);
576      break;
577    case DW_CFA_offset_extended_sf:
578      reg = addressSpace.getULEB128(p, instructionsEnd);
579      if (reg > kMaxRegisterNumber) {
580        fprintf(
581            stderr,
582            "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
583        return false;
584      }
585      offset =
586          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
587      results->savedRegisters[reg].location = kRegisterInCFA;
588      results->savedRegisters[reg].value = offset;
589      if (logDwarf)
590        fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n",
591                reg, offset);
592      break;
593    case DW_CFA_def_cfa_sf:
594      reg = addressSpace.getULEB128(p, instructionsEnd);
595      offset =
596          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
597      if (reg > kMaxRegisterNumber) {
598        fprintf(stderr,
599                "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
600        return false;
601      }
602      results->cfaRegister = (uint32_t)reg;
603      results->cfaRegisterOffset = (int32_t)offset;
604      if (logDwarf)
605        fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg,
606                offset);
607      break;
608    case DW_CFA_def_cfa_offset_sf:
609      results->cfaRegisterOffset = (int32_t)
610        (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
611      results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
612      if (logDwarf)
613        fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n",
614                results->cfaRegisterOffset);
615      break;
616    case DW_CFA_val_offset:
617      reg = addressSpace.getULEB128(p, instructionsEnd);
618      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
619                                                    * cieInfo.dataAlignFactor;
620      results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
621      results->savedRegisters[reg].value = offset;
622      if (logDwarf)
623        fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg,
624                offset);
625      break;
626    case DW_CFA_val_offset_sf:
627      reg = addressSpace.getULEB128(p, instructionsEnd);
628      if (reg > kMaxRegisterNumber) {
629        fprintf(stderr,
630                "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
631        return false;
632      }
633      offset =
634          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
635      results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
636      results->savedRegisters[reg].value = offset;
637      if (logDwarf)
638        fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg,
639                offset);
640      break;
641    case DW_CFA_val_expression:
642      reg = addressSpace.getULEB128(p, instructionsEnd);
643      if (reg > kMaxRegisterNumber) {
644        fprintf(stderr,
645                "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
646        return false;
647      }
648      results->savedRegisters[reg].location = kRegisterIsExpression;
649      results->savedRegisters[reg].value = (int64_t)p;
650      length = addressSpace.getULEB128(p, instructionsEnd);
651      p += length;
652      if (logDwarf)
653        fprintf(
654            stderr,
655            "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
656            reg, results->savedRegisters[reg].value, length);
657      break;
658    case DW_CFA_GNU_args_size:
659      length = addressSpace.getULEB128(p, instructionsEnd);
660      results->spExtraArgSize = (uint32_t)length;
661      if (logDwarf)
662        fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", length);
663      break;
664    case DW_CFA_GNU_negative_offset_extended:
665      reg = addressSpace.getULEB128(p, instructionsEnd);
666      if (reg > kMaxRegisterNumber) {
667        fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf "
668                        "unwind, reg too big\n");
669        return false;
670      }
671      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
672                                                    * cieInfo.dataAlignFactor;
673      results->savedRegisters[reg].location = kRegisterInCFA;
674      results->savedRegisters[reg].value = -offset;
675      if (logDwarf)
676        fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
677      break;
678    default:
679      operand = opcode & 0x3F;
680      switch (opcode & 0xC0) {
681      case DW_CFA_offset:
682        reg = operand;
683        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
684                                                    * cieInfo.dataAlignFactor;
685        results->savedRegisters[reg].location = kRegisterInCFA;
686        results->savedRegisters[reg].value = offset;
687        if (logDwarf)
688          fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand,
689                  offset);
690        break;
691      case DW_CFA_advance_loc:
692        codeOffset += operand * cieInfo.codeAlignFactor;
693        if (logDwarf)
694          fprintf(stderr, "DW_CFA_advance_loc: new offset=%llu\n",
695                                                      (uint64_t)codeOffset);
696        break;
697      case DW_CFA_restore:
698        reg = operand;
699        results->savedRegisters[reg] = initialState.savedRegisters[reg];
700        if (logDwarf)
701          fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
702        break;
703      default:
704        if (logDwarf)
705          fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
706        return false;
707      }
708    }
709  }
710
711  return true;
712}
713
714} // namespace libunwind
715
716#endif // __DWARF_PARSER_HPP__
717