master
  1//===----------------------------------------------------------------------===//
  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    bool      mteTaggedFrame;
 55#endif
 56  };
 57
 58  /// Information about an FDE (Frame Description Entry)
 59  struct FDE_Info {
 60    pint_t  fdeStart;
 61    pint_t  fdeLength;
 62    pint_t  fdeInstructions;
 63    pint_t  pcStart;
 64    pint_t  pcEnd;
 65    pint_t  lsda;
 66  };
 67
 68  enum {
 69    kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
 70  };
 71  enum RegisterSavedWhere {
 72    kRegisterUnused,
 73    kRegisterUndefined,
 74    kRegisterInCFA,
 75    kRegisterInCFADecrypt, // sparc64 specific
 76    kRegisterOffsetFromCFA,
 77    kRegisterInRegister,
 78    kRegisterAtExpression,
 79    kRegisterIsExpression
 80  };
 81  struct RegisterLocation {
 82    RegisterSavedWhere location;
 83    bool initialStateSaved;
 84    int64_t value;
 85  };
 86  /// Information about a frame layout and registers saved determined
 87  /// by "running" the DWARF FDE "instructions"
 88  struct PrologInfo {
 89    uint32_t          cfaRegister;
 90    int32_t           cfaRegisterOffset;  // CFA = (cfaRegister)+cfaRegisterOffset
 91    int64_t           cfaExpression;      // CFA = expression
 92    uint32_t          spExtraArgSize;
 93    RegisterLocation  savedRegisters[kMaxRegisterNumber + 1];
 94#if defined(_LIBUNWIND_TARGET_AARCH64)
 95    pint_t ptrAuthDiversifier;
 96#endif
 97    enum class InitializeTime { kLazy, kNormal };
 98
 99    // When saving registers, this data structure is lazily initialized.
100    PrologInfo(InitializeTime IT = InitializeTime::kNormal) {
101      if (IT == InitializeTime::kNormal)
102        memset(this, 0, sizeof(*this));
103    }
104    void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {
105      if (!savedRegisters[reg].initialStateSaved) {
106        initialState.savedRegisters[reg] = savedRegisters[reg];
107        savedRegisters[reg].initialStateSaved = true;
108      }
109    }
110    void setRegister(uint64_t reg, RegisterSavedWhere newLocation,
111                     int64_t newValue, PrologInfo &initialState) {
112      checkSaveRegister(reg, initialState);
113      savedRegisters[reg].location = newLocation;
114      savedRegisters[reg].value = newValue;
115    }
116    void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,
117                             PrologInfo &initialState) {
118      checkSaveRegister(reg, initialState);
119      savedRegisters[reg].location = newLocation;
120    }
121    void setRegisterValue(uint64_t reg, int64_t newValue,
122                          PrologInfo &initialState) {
123      checkSaveRegister(reg, initialState);
124      savedRegisters[reg].value = newValue;
125    }
126    void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {
127      if (savedRegisters[reg].initialStateSaved)
128        savedRegisters[reg] = initialState.savedRegisters[reg];
129      // else the register still holds its initial state
130    }
131  };
132
133  struct PrologInfoStackEntry {
134    PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
135        : next(n), info(i) {}
136    PrologInfoStackEntry *next;
137    PrologInfo info;
138  };
139
140  struct RememberStack {
141    PrologInfoStackEntry *entry;
142    RememberStack() : entry(nullptr) {}
143    ~RememberStack() {
144#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
145      // Clean up rememberStack. Even in the case where every
146      // DW_CFA_remember_state is paired with a DW_CFA_restore_state,
147      // parseInstructions can skip restore opcodes if it reaches the target PC
148      // and stops interpreting, so we have to make sure we don't leak memory.
149      while (entry) {
150        PrologInfoStackEntry *next = entry->next;
151        _LIBUNWIND_REMEMBER_FREE(entry);
152        entry = next;
153      }
154#endif
155    }
156  };
157
158  static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
159                      size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
160                      CIE_Info *cieInfo);
161  static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
162                               FDE_Info *fdeInfo, CIE_Info *cieInfo,
163                               bool useCIEInfo = false);
164  static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
165                                   const CIE_Info &cieInfo, pint_t upToPC,
166                                   int arch, PrologInfo *results);
167
168  static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
169};
170
171/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is
172/// true, treat cieInfo as already-parsed CIE_Info (whose start offset
173/// must match the one specified by the FDE) rather than parsing the
174/// one indicated within the FDE.
175template <typename A>
176const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
177                                     FDE_Info *fdeInfo, CIE_Info *cieInfo,
178                                     bool useCIEInfo) {
179  pint_t p = fdeStart;
180  pint_t cfiLength = (pint_t)addressSpace.get32(p);
181  p += 4;
182  if (cfiLength == 0xffffffff) {
183    // 0xffffffff means length is really next 8 bytes
184    cfiLength = (pint_t)addressSpace.get64(p);
185    p += 8;
186  }
187  if (cfiLength == 0)
188    return "FDE has zero length"; // zero terminator
189  uint32_t ciePointer = addressSpace.get32(p);
190  if (ciePointer == 0)
191    return "FDE is really a CIE"; // this is a CIE not an FDE
192  pint_t nextCFI = p + cfiLength;
193  pint_t cieStart = p - ciePointer;
194  if (useCIEInfo) {
195    if (cieInfo->cieStart != cieStart)
196      return "CIE start does not match";
197  } else {
198    const char *err = parseCIE(addressSpace, cieStart, cieInfo);
199    if (err != NULL)
200      return err;
201  }
202  p += 4;
203  // Parse pc begin and range.
204  pint_t pcStart =
205      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
206  pint_t pcRange =
207      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
208  // Parse rest of info.
209  fdeInfo->lsda = 0;
210  // Check for augmentation length.
211  if (cieInfo->fdesHaveAugmentationData) {
212    pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
213    pint_t endOfAug = p + augLen;
214    if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
215      // Peek at value (without indirection).  Zero means no LSDA.
216      pint_t lsdaStart = p;
217      if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
218          0) {
219        // Reset pointer and re-parse LSDA address.
220        p = lsdaStart;
221        fdeInfo->lsda =
222            addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
223      }
224    }
225    p = endOfAug;
226  }
227  fdeInfo->fdeStart = fdeStart;
228  fdeInfo->fdeLength = nextCFI - fdeStart;
229  fdeInfo->fdeInstructions = p;
230  fdeInfo->pcStart = pcStart;
231  fdeInfo->pcEnd = pcStart + pcRange;
232  return NULL; // success
233}
234
235/// Scan an eh_frame section to find an FDE for a pc
236template <typename A>
237bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
238                            size_t sectionLength, pint_t fdeHint,
239                            FDE_Info *fdeInfo, CIE_Info *cieInfo) {
240  //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
241  pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
242  const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
243                                  ? static_cast<pint_t>(-1)
244                                  : (ehSectionStart + sectionLength);
245  while (p < ehSectionEnd) {
246    pint_t currentCFI = p;
247    //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
248    pint_t cfiLength = addressSpace.get32(p);
249    p += 4;
250    if (cfiLength == 0xffffffff) {
251      // 0xffffffff means length is really next 8 bytes
252      cfiLength = (pint_t)addressSpace.get64(p);
253      p += 8;
254    }
255    if (cfiLength == 0)
256      return false; // zero terminator
257    uint32_t id = addressSpace.get32(p);
258    if (id == 0) {
259      // Skip over CIEs.
260      p += cfiLength;
261    } else {
262      // Process FDE to see if it covers pc.
263      pint_t nextCFI = p + cfiLength;
264      uint32_t ciePointer = addressSpace.get32(p);
265      pint_t cieStart = p - ciePointer;
266      // Validate pointer to CIE is within section.
267      if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
268        if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
269          p += 4;
270          // Parse pc begin and range.
271          pint_t pcStart =
272              addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
273          pint_t pcRange = addressSpace.getEncodedP(
274              p, nextCFI, cieInfo->pointerEncoding & 0x0F);
275          // Test if pc is within the function this FDE covers.
276          if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
277            // parse rest of info
278            fdeInfo->lsda = 0;
279            // check for augmentation length
280            if (cieInfo->fdesHaveAugmentationData) {
281              pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
282              pint_t endOfAug = p + augLen;
283              if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
284                // Peek at value (without indirection).  Zero means no LSDA.
285                pint_t lsdaStart = p;
286                if (addressSpace.getEncodedP(
287                        p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
288                  // Reset pointer and re-parse LSDA address.
289                  p = lsdaStart;
290                  fdeInfo->lsda = addressSpace
291                      .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
292                }
293              }
294              p = endOfAug;
295            }
296            fdeInfo->fdeStart = currentCFI;
297            fdeInfo->fdeLength = nextCFI - currentCFI;
298            fdeInfo->fdeInstructions = p;
299            fdeInfo->pcStart = pcStart;
300            fdeInfo->pcEnd = pcStart + pcRange;
301            return true;
302          } else {
303            // pc is not in begin/range, skip this FDE
304          }
305        } else {
306          // Malformed CIE, now augmentation describing pc range encoding.
307        }
308      } else {
309        // malformed FDE.  CIE is bad
310      }
311      p = nextCFI;
312    }
313  }
314  return false;
315}
316
317/// Extract info from a CIE
318template <typename A>
319const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
320                                    CIE_Info *cieInfo) {
321  cieInfo->pointerEncoding = 0;
322  cieInfo->lsdaEncoding = DW_EH_PE_omit;
323  cieInfo->personalityEncoding = 0;
324  cieInfo->personalityOffsetInCIE = 0;
325  cieInfo->personality = 0;
326  cieInfo->codeAlignFactor = 0;
327  cieInfo->dataAlignFactor = 0;
328  cieInfo->isSignalFrame = false;
329  cieInfo->fdesHaveAugmentationData = false;
330#if defined(_LIBUNWIND_TARGET_AARCH64)
331  cieInfo->addressesSignedWithBKey = false;
332  cieInfo->mteTaggedFrame = false;
333#endif
334  cieInfo->cieStart = cie;
335  pint_t p = cie;
336  pint_t cieLength = (pint_t)addressSpace.get32(p);
337  p += 4;
338  pint_t cieContentEnd = p + cieLength;
339  if (cieLength == 0xffffffff) {
340    // 0xffffffff means length is really next 8 bytes
341    cieLength = (pint_t)addressSpace.get64(p);
342    p += 8;
343    cieContentEnd = p + cieLength;
344  }
345  if (cieLength == 0)
346    return NULL;
347  // CIE ID is always 0
348  if (addressSpace.get32(p) != 0)
349    return "CIE ID is not zero";
350  p += 4;
351  // Version is always 1 or 3
352  uint8_t version = addressSpace.get8(p);
353  if ((version != 1) && (version != 3))
354    return "CIE version is not 1 or 3";
355  ++p;
356  // save start of augmentation string and find end
357  pint_t strStart = p;
358  while (addressSpace.get8(p) != 0)
359    ++p;
360  ++p;
361  // parse code alignment factor
362  cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
363  // parse data alignment factor
364  cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
365  // parse return address register
366  uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
367                                  : addressSpace.getULEB128(p, cieContentEnd);
368  assert(raReg < 255 && "return address register too large");
369  cieInfo->returnAddressRegister = (uint8_t)raReg;
370  // parse augmentation data based on augmentation string
371  const char *result = NULL;
372  if (addressSpace.get8(strStart) == 'z') {
373    // parse augmentation data length
374    addressSpace.getULEB128(p, cieContentEnd);
375    for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
376      switch (addressSpace.get8(s)) {
377      case 'z':
378        cieInfo->fdesHaveAugmentationData = true;
379        break;
380      case 'P':
381        cieInfo->personalityEncoding = addressSpace.get8(p);
382        ++p;
383        cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
384        cieInfo->personality = addressSpace
385            .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
386        break;
387      case 'L':
388        cieInfo->lsdaEncoding = addressSpace.get8(p);
389        ++p;
390        break;
391      case 'R':
392        cieInfo->pointerEncoding = addressSpace.get8(p);
393        ++p;
394        break;
395      case 'S':
396        cieInfo->isSignalFrame = true;
397        break;
398#if defined(_LIBUNWIND_TARGET_AARCH64)
399      case 'B':
400        cieInfo->addressesSignedWithBKey = true;
401        break;
402      case 'G':
403        cieInfo->mteTaggedFrame = true;
404        break;
405#endif
406      default:
407        // ignore unknown letters
408        break;
409      }
410    }
411  }
412  cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
413  cieInfo->cieInstructions = p;
414  return result;
415}
416
417
418/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
419template <typename A>
420bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
421                                         const FDE_Info &fdeInfo,
422                                         const CIE_Info &cieInfo, pint_t upToPC,
423                                         int arch, PrologInfo *results) {
424  // Alloca is used for the allocation of the rememberStack entries. It removes
425  // the dependency on new/malloc but the below for loop can not be refactored
426  // into functions. Entry could be saved during the processing of a CIE and
427  // restored by an FDE.
428  RememberStack rememberStack;
429
430  struct ParseInfo {
431    pint_t instructions;
432    pint_t instructionsEnd;
433    pint_t pcoffset;
434  };
435
436  ParseInfo parseInfoArray[] = {
437      {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
438       (pint_t)(-1)},
439      {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
440       upToPC - fdeInfo.pcStart}};
441
442  for (const auto &info : parseInfoArray) {
443    pint_t p = info.instructions;
444    pint_t instructionsEnd = info.instructionsEnd;
445    pint_t pcoffset = info.pcoffset;
446    pint_t codeOffset = 0;
447
448    // initialState initialized as registers in results are modified. Use
449    // PrologInfo accessor functions to avoid reading uninitialized data.
450    PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
451
452    _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
453                           ")\n",
454                           static_cast<uint64_t>(instructionsEnd));
455
456    // see DWARF Spec, section 6.4.2 for details on unwind opcodes
457    while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
458      uint64_t reg;
459      uint64_t reg2;
460      int64_t offset;
461      uint64_t length;
462      uint8_t opcode = addressSpace.get8(p);
463      uint8_t operand;
464
465      ++p;
466      switch (opcode) {
467      case DW_CFA_nop:
468        _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
469        break;
470      case DW_CFA_set_loc:
471        codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
472                                              cieInfo.pointerEncoding);
473        _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
474        break;
475      case DW_CFA_advance_loc1:
476        codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
477        p += 1;
478        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
479                               static_cast<uint64_t>(codeOffset));
480        break;
481      case DW_CFA_advance_loc2:
482        codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
483        p += 2;
484        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
485                               static_cast<uint64_t>(codeOffset));
486        break;
487      case DW_CFA_advance_loc4:
488        codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
489        p += 4;
490        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
491                               static_cast<uint64_t>(codeOffset));
492        break;
493      case DW_CFA_offset_extended:
494        reg = addressSpace.getULEB128(p, instructionsEnd);
495        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
496                 cieInfo.dataAlignFactor;
497        if (reg > kMaxRegisterNumber) {
498          _LIBUNWIND_LOG0(
499              "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
500          return false;
501        }
502        results->setRegister(reg, kRegisterInCFA, offset, initialState);
503        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
504                               "offset=%" PRId64 ")\n",
505                               reg, offset);
506        break;
507      case DW_CFA_restore_extended:
508        reg = addressSpace.getULEB128(p, instructionsEnd);
509        if (reg > kMaxRegisterNumber) {
510          _LIBUNWIND_LOG0(
511              "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
512          return false;
513        }
514        results->restoreRegisterToInitialState(reg, initialState);
515        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
516                               reg);
517        break;
518      case DW_CFA_undefined:
519        reg = addressSpace.getULEB128(p, instructionsEnd);
520        if (reg > kMaxRegisterNumber) {
521          _LIBUNWIND_LOG0(
522              "malformed DW_CFA_undefined DWARF unwind, reg too big");
523          return false;
524        }
525        results->setRegisterLocation(reg, kRegisterUndefined, initialState);
526        _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
527        break;
528      case DW_CFA_same_value:
529        reg = addressSpace.getULEB128(p, instructionsEnd);
530        if (reg > kMaxRegisterNumber) {
531          _LIBUNWIND_LOG0(
532              "malformed DW_CFA_same_value DWARF unwind, reg too big");
533          return false;
534        }
535        // <rdar://problem/8456377> DW_CFA_same_value unsupported
536        // "same value" means register was stored in frame, but its current
537        // value has not changed, so no need to restore from frame.
538        // We model this as if the register was never saved.
539        results->setRegisterLocation(reg, kRegisterUnused, initialState);
540        _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
541        break;
542      case DW_CFA_register:
543        reg = addressSpace.getULEB128(p, instructionsEnd);
544        reg2 = addressSpace.getULEB128(p, instructionsEnd);
545        if (reg > kMaxRegisterNumber) {
546          _LIBUNWIND_LOG0(
547              "malformed DW_CFA_register DWARF unwind, reg too big");
548          return false;
549        }
550        if (reg2 > kMaxRegisterNumber) {
551          _LIBUNWIND_LOG0(
552              "malformed DW_CFA_register DWARF unwind, reg2 too big");
553          return false;
554        }
555        results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
556                             initialState);
557        _LIBUNWIND_TRACE_DWARF(
558            "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
559        break;
560      case DW_CFA_remember_state: {
561        // Avoid operator new because that would be an upward dependency.
562        // Avoid malloc because it needs heap allocation.
563        PrologInfoStackEntry *entry =
564            (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
565                sizeof(PrologInfoStackEntry));
566        if (entry != NULL) {
567          entry->next = rememberStack.entry;
568          entry->info = *results;
569          rememberStack.entry = entry;
570        } else {
571          return false;
572        }
573        _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
574        break;
575      }
576      case DW_CFA_restore_state:
577        if (rememberStack.entry != NULL) {
578          PrologInfoStackEntry *top = rememberStack.entry;
579          *results = top->info;
580          rememberStack.entry = top->next;
581          _LIBUNWIND_REMEMBER_FREE(top);
582        } else {
583          return false;
584        }
585        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
586        break;
587      case DW_CFA_def_cfa:
588        reg = addressSpace.getULEB128(p, instructionsEnd);
589        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
590        if (reg > kMaxRegisterNumber) {
591          _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
592          return false;
593        }
594        results->cfaRegister = (uint32_t)reg;
595        results->cfaRegisterOffset = (int32_t)offset;
596        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
597                               ")\n",
598                               reg, offset);
599        break;
600      case DW_CFA_def_cfa_register:
601        reg = addressSpace.getULEB128(p, instructionsEnd);
602        if (reg > kMaxRegisterNumber) {
603          _LIBUNWIND_LOG0(
604              "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
605          return false;
606        }
607        results->cfaRegister = (uint32_t)reg;
608        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
609        break;
610      case DW_CFA_def_cfa_offset:
611        results->cfaRegisterOffset =
612            (int32_t)addressSpace.getULEB128(p, instructionsEnd);
613        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
614                               results->cfaRegisterOffset);
615        break;
616      case DW_CFA_def_cfa_expression:
617        results->cfaRegister = 0;
618        results->cfaExpression = (int64_t)p;
619        length = addressSpace.getULEB128(p, instructionsEnd);
620        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
621        p += static_cast<pint_t>(length);
622        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
623                               ", length=%" PRIu64 ")\n",
624                               results->cfaExpression, length);
625        break;
626      case DW_CFA_expression:
627        reg = addressSpace.getULEB128(p, instructionsEnd);
628        if (reg > kMaxRegisterNumber) {
629          _LIBUNWIND_LOG0(
630              "malformed DW_CFA_expression DWARF unwind, reg too big");
631          return false;
632        }
633        results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
634                             initialState);
635        length = addressSpace.getULEB128(p, instructionsEnd);
636        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
637        p += static_cast<pint_t>(length);
638        _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
639                               "expression=0x%" PRIx64 ", "
640                               "length=%" PRIu64 ")\n",
641                               reg, results->savedRegisters[reg].value, length);
642        break;
643      case DW_CFA_offset_extended_sf:
644        reg = addressSpace.getULEB128(p, instructionsEnd);
645        if (reg > kMaxRegisterNumber) {
646          _LIBUNWIND_LOG0(
647              "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
648          return false;
649        }
650        offset = addressSpace.getSLEB128(p, instructionsEnd) *
651                 cieInfo.dataAlignFactor;
652        results->setRegister(reg, kRegisterInCFA, offset, initialState);
653        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
654                               "offset=%" PRId64 ")\n",
655                               reg, offset);
656        break;
657      case DW_CFA_def_cfa_sf:
658        reg = addressSpace.getULEB128(p, instructionsEnd);
659        offset = addressSpace.getSLEB128(p, instructionsEnd) *
660                 cieInfo.dataAlignFactor;
661        if (reg > kMaxRegisterNumber) {
662          _LIBUNWIND_LOG0(
663              "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
664          return false;
665        }
666        results->cfaRegister = (uint32_t)reg;
667        results->cfaRegisterOffset = (int32_t)offset;
668        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
669                               "offset=%" PRId64 ")\n",
670                               reg, offset);
671        break;
672      case DW_CFA_def_cfa_offset_sf:
673        results->cfaRegisterOffset =
674            (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
675                      cieInfo.dataAlignFactor);
676        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
677                               results->cfaRegisterOffset);
678        break;
679      case DW_CFA_val_offset:
680        reg = addressSpace.getULEB128(p, instructionsEnd);
681        if (reg > kMaxRegisterNumber) {
682          _LIBUNWIND_LOG(
683              "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
684              ") out of range\n",
685              reg);
686          return false;
687        }
688        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
689                 cieInfo.dataAlignFactor;
690        results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
691        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
692                               "offset=%" PRId64 "\n",
693                               reg, offset);
694        break;
695      case DW_CFA_val_offset_sf:
696        reg = addressSpace.getULEB128(p, instructionsEnd);
697        if (reg > kMaxRegisterNumber) {
698          _LIBUNWIND_LOG0(
699              "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
700          return false;
701        }
702        offset = addressSpace.getSLEB128(p, instructionsEnd) *
703                 cieInfo.dataAlignFactor;
704        results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
705        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
706                               "offset=%" PRId64 "\n",
707                               reg, offset);
708        break;
709      case DW_CFA_val_expression:
710        reg = addressSpace.getULEB128(p, instructionsEnd);
711        if (reg > kMaxRegisterNumber) {
712          _LIBUNWIND_LOG0(
713              "malformed DW_CFA_val_expression DWARF unwind, reg too big");
714          return false;
715        }
716        results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
717                             initialState);
718        length = addressSpace.getULEB128(p, instructionsEnd);
719        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
720        p += static_cast<pint_t>(length);
721        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
722                               "expression=0x%" PRIx64 ", length=%" PRIu64
723                               ")\n",
724                               reg, results->savedRegisters[reg].value, length);
725        break;
726      case DW_CFA_GNU_args_size:
727        length = addressSpace.getULEB128(p, instructionsEnd);
728        results->spExtraArgSize = (uint32_t)length;
729        _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
730        break;
731      case DW_CFA_GNU_negative_offset_extended:
732        reg = addressSpace.getULEB128(p, instructionsEnd);
733        if (reg > kMaxRegisterNumber) {
734          _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
735                          "unwind, reg too big");
736          return false;
737        }
738        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
739                 cieInfo.dataAlignFactor;
740        results->setRegister(reg, kRegisterInCFA, -offset, initialState);
741        _LIBUNWIND_TRACE_DWARF(
742            "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
743        break;
744
745#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
746    defined(_LIBUNWIND_TARGET_SPARC64)
747        // The same constant is used to represent different instructions on
748        // AArch64 (negate_ra_state) and SPARC (window_save).
749        static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
750                      "uses the same constant");
751      case DW_CFA_AARCH64_negate_ra_state:
752        switch (arch) {
753#if defined(_LIBUNWIND_TARGET_AARCH64)
754        case REGISTERS_ARM64: {
755          int64_t value =
756              results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;
757          results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
758                                    initialState);
759          _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
760        } break;
761#endif
762
763#if defined(_LIBUNWIND_TARGET_SPARC)
764        // case DW_CFA_GNU_window_save:
765        case REGISTERS_SPARC:
766          _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
767          for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
768            results->setRegister(reg, kRegisterInRegister,
769                                 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
770                                 initialState);
771          }
772
773          for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
774            results->setRegister(reg, kRegisterInCFA,
775                                 ((int64_t)reg - UNW_SPARC_L0) * 4,
776                                 initialState);
777          }
778          break;
779#endif
780
781#if defined(_LIBUNWIND_TARGET_SPARC64)
782        // case DW_CFA_GNU_window_save:
783        case REGISTERS_SPARC64:
784          // Don't save %o0-%o7 on sparc64.
785          // https://reviews.llvm.org/D32450#736405
786
787          for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
788            if (reg == UNW_SPARC_I7)
789              results->setRegister(
790                  reg, kRegisterInCFADecrypt,
791                  static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
792                  initialState);
793            else
794              results->setRegister(
795                  reg, kRegisterInCFA,
796                  static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
797                  initialState);
798          }
799          _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
800          break;
801#endif
802        }
803        break;
804
805#if defined(_LIBUNWIND_TARGET_AARCH64)
806      case DW_CFA_AARCH64_negate_ra_state_with_pc: {
807        int64_t value =
808            results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
809        results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
810                                  initialState);
811        // When calculating the value of the PC, it is assumed that the CFI
812        // instruction is placed before the signing instruction, however it is
813        // placed after. Because of this, we need to take into account the CFI
814        // instruction is one instruction call later than expected, and reduce
815        // the PC value by 4 bytes to compensate.
816        results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
817        _LIBUNWIND_TRACE_DWARF(
818            "DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
819            static_cast<uint64_t>(results->ptrAuthDiversifier));
820      } break;
821#endif
822
823#else
824        (void)arch;
825#endif
826
827      default:
828        operand = opcode & 0x3F;
829        switch (opcode & 0xC0) {
830        case DW_CFA_offset:
831          reg = operand;
832          if (reg > kMaxRegisterNumber) {
833            _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
834                           ") out of range",
835                           reg);
836            return false;
837          }
838          offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
839                   cieInfo.dataAlignFactor;
840          results->setRegister(reg, kRegisterInCFA, offset, initialState);
841          _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
842                                 operand, offset);
843          break;
844        case DW_CFA_advance_loc:
845          codeOffset += operand * cieInfo.codeAlignFactor;
846          _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
847                                 static_cast<uint64_t>(codeOffset));
848          break;
849        case DW_CFA_restore:
850          reg = operand;
851          if (reg > kMaxRegisterNumber) {
852            _LIBUNWIND_LOG(
853                "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
854                ") out of range",
855                reg);
856            return false;
857          }
858          results->restoreRegisterToInitialState(reg, initialState);
859          _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
860                                 static_cast<uint64_t>(operand));
861          break;
862        default:
863          _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
864          return false;
865        }
866      }
867    }
868  }
869  return true;
870}
871
872} // namespace libunwind
873
874#endif // __DWARF_PARSER_HPP__