1//===--------------------------- DwarfParser.hpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8//  Parses DWARF CFIs (FDEs and CIEs).
9//
10//===----------------------------------------------------------------------===//
11
12#ifndef __DWARF_PARSER_HPP__
13#define __DWARF_PARSER_HPP__
14
15#include <inttypes.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19
20#include "libunwind.h"
21#include "dwarf2.h"
22#include "Registers.hpp"
23
24#include "config.h"
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#if defined(_LIBUNWIND_TARGET_AARCH64)
53    bool      addressesSignedWithBKey;
54#endif
55  };
56
57  /// Information about an FDE (Frame Description Entry)
58  struct FDE_Info {
59    pint_t  fdeStart;
60    pint_t  fdeLength;
61    pint_t  fdeInstructions;
62    pint_t  pcStart;
63    pint_t  pcEnd;
64    pint_t  lsda;
65  };
66
67  enum {
68    kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
69  };
70  enum RegisterSavedWhere {
71    kRegisterUnused,
72    kRegisterInCFA,
73    kRegisterOffsetFromCFA,
74    kRegisterInRegister,
75    kRegisterAtExpression,
76    kRegisterIsExpression
77  };
78  struct RegisterLocation {
79    RegisterSavedWhere location;
80    int64_t value;
81  };
82  /// Information about a frame layout and registers saved determined
83  /// by "running" the DWARF FDE "instructions"
84  struct PrologInfo {
85    uint32_t          cfaRegister;
86    int32_t           cfaRegisterOffset;  // CFA = (cfaRegister)+cfaRegisterOffset
87    int64_t           cfaExpression;      // CFA = expression
88    uint32_t          spExtraArgSize;
89    uint32_t          codeOffsetAtStackDecrement;
90    bool              registersInOtherRegisters;
91    bool              sameValueUsed;
92    RegisterLocation  savedRegisters[kMaxRegisterNumber + 1];
93  };
94
95  struct PrologInfoStackEntry {
96    PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
97        : next(n), info(i) {}
98    PrologInfoStackEntry *next;
99    PrologInfo info;
100  };
101
102  static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
103                      uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
104                      CIE_Info *cieInfo);
105  static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
106                               FDE_Info *fdeInfo, CIE_Info *cieInfo);
107  static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
108                                   const CIE_Info &cieInfo, pint_t upToPC,
109                                   int arch, PrologInfo *results);
110
111  static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
112
113private:
114  static bool parseInstructions(A &addressSpace, pint_t instructions,
115                                pint_t instructionsEnd, const CIE_Info &cieInfo,
116                                pint_t pcoffset,
117                                PrologInfoStackEntry *&rememberStack, int arch,
118                                PrologInfo *results);
119};
120
121/// Parse a FDE into a CIE_Info and an FDE_Info
122template <typename A>
123const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
124                                     FDE_Info *fdeInfo, CIE_Info *cieInfo) {
125  pint_t p = fdeStart;
126  pint_t cfiLength = (pint_t)addressSpace.get32(p);
127  p += 4;
128  if (cfiLength == 0xffffffff) {
129    // 0xffffffff means length is really next 8 bytes
130    cfiLength = (pint_t)addressSpace.get64(p);
131    p += 8;
132  }
133  if (cfiLength == 0)
134    return "FDE has zero length"; // end marker
135  uint32_t ciePointer = addressSpace.get32(p);
136  if (ciePointer == 0)
137    return "FDE is really a CIE"; // this is a CIE not an FDE
138  pint_t nextCFI = p + cfiLength;
139  pint_t cieStart = p - ciePointer;
140  const char *err = parseCIE(addressSpace, cieStart, cieInfo);
141  if (err != NULL)
142    return err;
143  p += 4;
144  // Parse pc begin and range.
145  pint_t pcStart =
146      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
147  pint_t pcRange =
148      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
149  // Parse rest of info.
150  fdeInfo->lsda = 0;
151  // Check for augmentation length.
152  if (cieInfo->fdesHaveAugmentationData) {
153    pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
154    pint_t endOfAug = p + augLen;
155    if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
156      // Peek at value (without indirection).  Zero means no LSDA.
157      pint_t lsdaStart = p;
158      if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
159          0) {
160        // Reset pointer and re-parse LSDA address.
161        p = lsdaStart;
162        fdeInfo->lsda =
163            addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
164      }
165    }
166    p = endOfAug;
167  }
168  fdeInfo->fdeStart = fdeStart;
169  fdeInfo->fdeLength = nextCFI - fdeStart;
170  fdeInfo->fdeInstructions = p;
171  fdeInfo->pcStart = pcStart;
172  fdeInfo->pcEnd = pcStart + pcRange;
173  return NULL; // success
174}
175
176/// Scan an eh_frame section to find an FDE for a pc
177template <typename A>
178bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
179                            uint32_t sectionLength, pint_t fdeHint,
180                            FDE_Info *fdeInfo, CIE_Info *cieInfo) {
181  //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
182  pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
183  const pint_t ehSectionEnd = p + sectionLength;
184  while (p < ehSectionEnd) {
185    pint_t currentCFI = p;
186    //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
187    pint_t cfiLength = addressSpace.get32(p);
188    p += 4;
189    if (cfiLength == 0xffffffff) {
190      // 0xffffffff means length is really next 8 bytes
191      cfiLength = (pint_t)addressSpace.get64(p);
192      p += 8;
193    }
194    if (cfiLength == 0)
195      return false; // end marker
196    uint32_t id = addressSpace.get32(p);
197    if (id == 0) {
198      // Skip over CIEs.
199      p += cfiLength;
200    } else {
201      // Process FDE to see if it covers pc.
202      pint_t nextCFI = p + cfiLength;
203      uint32_t ciePointer = addressSpace.get32(p);
204      pint_t cieStart = p - ciePointer;
205      // Validate pointer to CIE is within section.
206      if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
207        if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
208          p += 4;
209          // Parse pc begin and range.
210          pint_t pcStart =
211              addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
212          pint_t pcRange = addressSpace.getEncodedP(
213              p, nextCFI, cieInfo->pointerEncoding & 0x0F);
214          // Test if pc is within the function this FDE covers.
215          if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
216            // parse rest of info
217            fdeInfo->lsda = 0;
218            // check for augmentation length
219            if (cieInfo->fdesHaveAugmentationData) {
220              pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
221              pint_t endOfAug = p + augLen;
222              if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
223                // Peek at value (without indirection).  Zero means no LSDA.
224                pint_t lsdaStart = p;
225                if (addressSpace.getEncodedP(
226                        p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
227                  // Reset pointer and re-parse LSDA address.
228                  p = lsdaStart;
229                  fdeInfo->lsda = addressSpace
230                      .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
231                }
232              }
233              p = endOfAug;
234            }
235            fdeInfo->fdeStart = currentCFI;
236            fdeInfo->fdeLength = nextCFI - currentCFI;
237            fdeInfo->fdeInstructions = p;
238            fdeInfo->pcStart = pcStart;
239            fdeInfo->pcEnd = pcStart + pcRange;
240            return true;
241          } else {
242            // pc is not in begin/range, skip this FDE
243          }
244        } else {
245          // Malformed CIE, now augmentation describing pc range encoding.
246        }
247      } else {
248        // malformed FDE.  CIE is bad
249      }
250      p = nextCFI;
251    }
252  }
253  return false;
254}
255
256/// Extract info from a CIE
257template <typename A>
258const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
259                                    CIE_Info *cieInfo) {
260  cieInfo->pointerEncoding = 0;
261  cieInfo->lsdaEncoding = DW_EH_PE_omit;
262  cieInfo->personalityEncoding = 0;
263  cieInfo->personalityOffsetInCIE = 0;
264  cieInfo->personality = 0;
265  cieInfo->codeAlignFactor = 0;
266  cieInfo->dataAlignFactor = 0;
267  cieInfo->isSignalFrame = false;
268  cieInfo->fdesHaveAugmentationData = false;
269#if defined(_LIBUNWIND_TARGET_AARCH64)
270  cieInfo->addressesSignedWithBKey = false;
271#endif
272  cieInfo->cieStart = cie;
273  pint_t p = cie;
274  pint_t cieLength = (pint_t)addressSpace.get32(p);
275  p += 4;
276  pint_t cieContentEnd = p + cieLength;
277  if (cieLength == 0xffffffff) {
278    // 0xffffffff means length is really next 8 bytes
279    cieLength = (pint_t)addressSpace.get64(p);
280    p += 8;
281    cieContentEnd = p + cieLength;
282  }
283  if (cieLength == 0)
284    return NULL;
285  // CIE ID is always 0
286  if (addressSpace.get32(p) != 0)
287    return "CIE ID is not zero";
288  p += 4;
289  // Version is always 1 or 3
290  uint8_t version = addressSpace.get8(p);
291  if ((version != 1) && (version != 3))
292    return "CIE version is not 1 or 3";
293  ++p;
294  // save start of augmentation string and find end
295  pint_t strStart = p;
296  while (addressSpace.get8(p) != 0)
297    ++p;
298  ++p;
299  // parse code aligment factor
300  cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
301  // parse data alignment factor
302  cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
303  // parse return address register
304  uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
305  assert(raReg < 255 && "return address register too large");
306  cieInfo->returnAddressRegister = (uint8_t)raReg;
307  // parse augmentation data based on augmentation string
308  const char *result = NULL;
309  if (addressSpace.get8(strStart) == 'z') {
310    // parse augmentation data length
311    addressSpace.getULEB128(p, cieContentEnd);
312    for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
313      switch (addressSpace.get8(s)) {
314      case 'z':
315        cieInfo->fdesHaveAugmentationData = true;
316        break;
317      case 'P':
318        cieInfo->personalityEncoding = addressSpace.get8(p);
319        ++p;
320        cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
321        cieInfo->personality = addressSpace
322            .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
323        break;
324      case 'L':
325        cieInfo->lsdaEncoding = addressSpace.get8(p);
326        ++p;
327        break;
328      case 'R':
329        cieInfo->pointerEncoding = addressSpace.get8(p);
330        ++p;
331        break;
332      case 'S':
333        cieInfo->isSignalFrame = true;
334        break;
335#if defined(_LIBUNWIND_TARGET_AARCH64)
336      case 'B':
337        cieInfo->addressesSignedWithBKey = true;
338        break;
339#endif
340      default:
341        // ignore unknown letters
342        break;
343      }
344    }
345  }
346  cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
347  cieInfo->cieInstructions = p;
348  return result;
349}
350
351
352/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
353template <typename A>
354bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
355                                         const FDE_Info &fdeInfo,
356                                         const CIE_Info &cieInfo, pint_t upToPC,
357                                         int arch, PrologInfo *results) {
358  // clear results
359  memset(results, '\0', sizeof(PrologInfo));
360  PrologInfoStackEntry *rememberStack = NULL;
361
362  // parse CIE then FDE instructions
363  return parseInstructions(addressSpace, cieInfo.cieInstructions,
364                           cieInfo.cieStart + cieInfo.cieLength, cieInfo,
365                           (pint_t)(-1), rememberStack, arch, results) &&
366         parseInstructions(addressSpace, fdeInfo.fdeInstructions,
367                           fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
368                           upToPC - fdeInfo.pcStart, rememberStack, arch,
369                           results);
370}
371
372/// "run" the DWARF instructions
373template <typename A>
374bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
375                                      pint_t instructionsEnd,
376                                      const CIE_Info &cieInfo, pint_t pcoffset,
377                                      PrologInfoStackEntry *&rememberStack,
378                                      int arch, PrologInfo *results) {
379  pint_t p = instructions;
380  pint_t codeOffset = 0;
381  PrologInfo initialState = *results;
382
383  _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
384                         static_cast<uint64_t>(instructionsEnd));
385
386  // see DWARF Spec, section 6.4.2 for details on unwind opcodes
387  while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
388    uint64_t reg;
389    uint64_t reg2;
390    int64_t offset;
391    uint64_t length;
392    uint8_t opcode = addressSpace.get8(p);
393    uint8_t operand;
394#if !defined(_LIBUNWIND_NO_HEAP)
395    PrologInfoStackEntry *entry;
396#endif
397    ++p;
398    switch (opcode) {
399    case DW_CFA_nop:
400      _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
401      break;
402    case DW_CFA_set_loc:
403      codeOffset =
404          addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
405      _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
406      break;
407    case DW_CFA_advance_loc1:
408      codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
409      p += 1;
410      _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
411                             static_cast<uint64_t>(codeOffset));
412      break;
413    case DW_CFA_advance_loc2:
414      codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
415      p += 2;
416      _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
417                             static_cast<uint64_t>(codeOffset));
418      break;
419    case DW_CFA_advance_loc4:
420      codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
421      p += 4;
422      _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
423                             static_cast<uint64_t>(codeOffset));
424      break;
425    case DW_CFA_offset_extended:
426      reg = addressSpace.getULEB128(p, instructionsEnd);
427      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
428                                                  * cieInfo.dataAlignFactor;
429      if (reg > kMaxRegisterNumber) {
430        _LIBUNWIND_LOG0(
431                "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
432        return false;
433      }
434      results->savedRegisters[reg].location = kRegisterInCFA;
435      results->savedRegisters[reg].value = offset;
436      _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
437                             "offset=%" PRId64 ")\n",
438                             reg, offset);
439      break;
440    case DW_CFA_restore_extended:
441      reg = addressSpace.getULEB128(p, instructionsEnd);
442      if (reg > kMaxRegisterNumber) {
443        _LIBUNWIND_LOG0(
444            "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
445        return false;
446      }
447      results->savedRegisters[reg] = initialState.savedRegisters[reg];
448      _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
449      break;
450    case DW_CFA_undefined:
451      reg = addressSpace.getULEB128(p, instructionsEnd);
452      if (reg > kMaxRegisterNumber) {
453        _LIBUNWIND_LOG0(
454                "malformed DW_CFA_undefined DWARF unwind, reg too big");
455        return false;
456      }
457      results->savedRegisters[reg].location = kRegisterUnused;
458      _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
459      break;
460    case DW_CFA_same_value:
461      reg = addressSpace.getULEB128(p, instructionsEnd);
462      if (reg > kMaxRegisterNumber) {
463        _LIBUNWIND_LOG0(
464                "malformed DW_CFA_same_value DWARF unwind, reg too big");
465        return false;
466      }
467      // <rdar://problem/8456377> DW_CFA_same_value unsupported
468      // "same value" means register was stored in frame, but its current
469      // value has not changed, so no need to restore from frame.
470      // We model this as if the register was never saved.
471      results->savedRegisters[reg].location = kRegisterUnused;
472      // set flag to disable conversion to compact unwind
473      results->sameValueUsed = true;
474      _LIBUNWIND_TRACE_DWARF("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        _LIBUNWIND_LOG0(
481                "malformed DW_CFA_register DWARF unwind, reg too big");
482        return false;
483      }
484      if (reg2 > kMaxRegisterNumber) {
485        _LIBUNWIND_LOG0(
486                "malformed DW_CFA_register DWARF unwind, reg2 too big");
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      _LIBUNWIND_TRACE_DWARF(
494          "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
495      break;
496#if !defined(_LIBUNWIND_NO_HEAP)
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      _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
508      break;
509    case DW_CFA_restore_state:
510      if (rememberStack != NULL) {
511        PrologInfoStackEntry *top = rememberStack;
512        *results = top->info;
513        rememberStack = top->next;
514        free((char *)top);
515      } else {
516        return false;
517      }
518      _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
519      break;
520#endif
521    case DW_CFA_def_cfa:
522      reg = addressSpace.getULEB128(p, instructionsEnd);
523      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
524      if (reg > kMaxRegisterNumber) {
525        _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
526        return false;
527      }
528      results->cfaRegister = (uint32_t)reg;
529      results->cfaRegisterOffset = (int32_t)offset;
530      _LIBUNWIND_TRACE_DWARF(
531          "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
532      break;
533    case DW_CFA_def_cfa_register:
534      reg = addressSpace.getULEB128(p, instructionsEnd);
535      if (reg > kMaxRegisterNumber) {
536        _LIBUNWIND_LOG0(
537            "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
538        return false;
539      }
540      results->cfaRegister = (uint32_t)reg;
541      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\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      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
548                             results->cfaRegisterOffset);
549      break;
550    case DW_CFA_def_cfa_expression:
551      results->cfaRegister = 0;
552      results->cfaExpression = (int64_t)p;
553      length = addressSpace.getULEB128(p, instructionsEnd);
554      assert(length < static_cast<pint_t>(~0) && "pointer overflow");
555      p += static_cast<pint_t>(length);
556      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
557                             ", length=%" PRIu64 ")\n",
558                             results->cfaExpression, length);
559      break;
560    case DW_CFA_expression:
561      reg = addressSpace.getULEB128(p, instructionsEnd);
562      if (reg > kMaxRegisterNumber) {
563        _LIBUNWIND_LOG0(
564                "malformed DW_CFA_expression DWARF unwind, reg too big");
565        return false;
566      }
567      results->savedRegisters[reg].location = kRegisterAtExpression;
568      results->savedRegisters[reg].value = (int64_t)p;
569      length = addressSpace.getULEB128(p, instructionsEnd);
570      assert(length < static_cast<pint_t>(~0) && "pointer overflow");
571      p += static_cast<pint_t>(length);
572      _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
573                             "expression=0x%" PRIx64 ", "
574                             "length=%" PRIu64 ")\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        _LIBUNWIND_LOG0(
581            "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
582        return false;
583      }
584      offset =
585          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
586      results->savedRegisters[reg].location = kRegisterInCFA;
587      results->savedRegisters[reg].value = offset;
588      _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
589                             "offset=%" PRId64 ")\n",
590                             reg, offset);
591      break;
592    case DW_CFA_def_cfa_sf:
593      reg = addressSpace.getULEB128(p, instructionsEnd);
594      offset =
595          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
596      if (reg > kMaxRegisterNumber) {
597        _LIBUNWIND_LOG0(
598                "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
599        return false;
600      }
601      results->cfaRegister = (uint32_t)reg;
602      results->cfaRegisterOffset = (int32_t)offset;
603      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
604                             "offset=%" PRId64 ")\n",
605                             reg, offset);
606      break;
607    case DW_CFA_def_cfa_offset_sf:
608      results->cfaRegisterOffset = (int32_t)
609        (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
610      results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
611      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
612                             results->cfaRegisterOffset);
613      break;
614    case DW_CFA_val_offset:
615      reg = addressSpace.getULEB128(p, instructionsEnd);
616      if (reg > kMaxRegisterNumber) {
617        _LIBUNWIND_LOG(
618                "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
619                ") out of range\n",
620                reg);
621        return false;
622      }
623      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
624                                                    * cieInfo.dataAlignFactor;
625      results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
626      results->savedRegisters[reg].value = offset;
627      _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
628                             "offset=%" PRId64 "\n",
629                             reg, offset);
630      break;
631    case DW_CFA_val_offset_sf:
632      reg = addressSpace.getULEB128(p, instructionsEnd);
633      if (reg > kMaxRegisterNumber) {
634        _LIBUNWIND_LOG0(
635                "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
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      _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
643                             "offset=%" PRId64 "\n",
644                             reg, offset);
645      break;
646    case DW_CFA_val_expression:
647      reg = addressSpace.getULEB128(p, instructionsEnd);
648      if (reg > kMaxRegisterNumber) {
649        _LIBUNWIND_LOG0(
650                "malformed DW_CFA_val_expression DWARF unwind, reg too big");
651        return false;
652      }
653      results->savedRegisters[reg].location = kRegisterIsExpression;
654      results->savedRegisters[reg].value = (int64_t)p;
655      length = addressSpace.getULEB128(p, instructionsEnd);
656      assert(length < static_cast<pint_t>(~0) && "pointer overflow");
657      p += static_cast<pint_t>(length);
658      _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
659                             "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
660                             reg, results->savedRegisters[reg].value, length);
661      break;
662    case DW_CFA_GNU_args_size:
663      length = addressSpace.getULEB128(p, instructionsEnd);
664      results->spExtraArgSize = (uint32_t)length;
665      _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
666      break;
667    case DW_CFA_GNU_negative_offset_extended:
668      reg = addressSpace.getULEB128(p, instructionsEnd);
669      if (reg > kMaxRegisterNumber) {
670        _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
671                        "unwind, reg too big");
672        return false;
673      }
674      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
675                                                    * cieInfo.dataAlignFactor;
676      results->savedRegisters[reg].location = kRegisterInCFA;
677      results->savedRegisters[reg].value = -offset;
678      _LIBUNWIND_TRACE_DWARF(
679          "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
680      break;
681
682#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
683    // The same constant is used to represent different instructions on
684    // AArch64 (negate_ra_state) and SPARC (window_save).
685    static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
686                  "uses the same constant");
687    case DW_CFA_AARCH64_negate_ra_state:
688      switch (arch) {
689#if defined(_LIBUNWIND_TARGET_AARCH64)
690      case REGISTERS_ARM64:
691        results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
692        _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
693        break;
694#endif
695#if defined(_LIBUNWIND_TARGET_SPARC)
696      // case DW_CFA_GNU_window_save:
697      case REGISTERS_SPARC:
698        _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
699        for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
700          results->savedRegisters[reg].location = kRegisterInRegister;
701          results->savedRegisters[reg].value =
702              ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
703        }
704
705        for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
706          results->savedRegisters[reg].location = kRegisterInCFA;
707          results->savedRegisters[reg].value =
708              ((int64_t)reg - UNW_SPARC_L0) * 4;
709        }
710        break;
711#endif
712      }
713      break;
714#else
715      (void)arch;
716#endif
717
718    default:
719      operand = opcode & 0x3F;
720      switch (opcode & 0xC0) {
721      case DW_CFA_offset:
722        reg = operand;
723        if (reg > kMaxRegisterNumber) {
724          _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
725                         ") out of range",
726                  reg);
727          return false;
728        }
729        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
730                                                    * cieInfo.dataAlignFactor;
731        results->savedRegisters[reg].location = kRegisterInCFA;
732        results->savedRegisters[reg].value = offset;
733        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
734                               operand, offset);
735        break;
736      case DW_CFA_advance_loc:
737        codeOffset += operand * cieInfo.codeAlignFactor;
738        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
739                               static_cast<uint64_t>(codeOffset));
740        break;
741      case DW_CFA_restore:
742        reg = operand;
743        if (reg > kMaxRegisterNumber) {
744          _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
745                         ") out of range",
746                  reg);
747          return false;
748        }
749        results->savedRegisters[reg] = initialState.savedRegisters[reg];
750        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
751                               static_cast<uint64_t>(operand));
752        break;
753      default:
754        _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
755        return false;
756      }
757    }
758  }
759
760  return true;
761}
762
763} // namespace libunwind
764
765#endif // __DWARF_PARSER_HPP__
766