[libunwind] 1d7786d - [libunwind] Support DW_CFA_remember/restore_state without heap allocation.

Daniel Kiss via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 30 09:45:27 PDT 2020


Author: Daniel Kiss
Date: 2020-10-30T17:45:20+01:00
New Revision: 1d7786d45f48b4793baf4e4b903c4476f56ffc94

URL: https://github.com/llvm/llvm-project/commit/1d7786d45f48b4793baf4e4b903c4476f56ffc94
DIFF: https://github.com/llvm/llvm-project/commit/1d7786d45f48b4793baf4e4b903c4476f56ffc94.diff

LOG: [libunwind] Support DW_CFA_remember/restore_state without heap allocation.

This patch just reorganises the code to make possible to use alloca
instead of malloc. This makes possible to use `.cfi_remember_state`/`.cfi_restore_state` on
platforms without heap allocation.
Also it will be safe to backtrace/unwind faults related to the allocator behind malloc.
`_LIBUNWIND_REMEMBER_HEAP_ALLOC ` option reenables the heap usage for `.cfi_remember_state`/`.cfi_restore_state`.
Define _LIBUNWIND_REMEMBER_STACK_ALLOC to force stack allocation.

Reviewed By: #libunwind, mstorsjo

Differential Revision: https://reviews.llvm.org/D85005

Added: 
    

Modified: 
    libunwind/src/DwarfParser.hpp
    libunwind/src/config.h

Removed: 
    


################################################################################
diff  --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 86c0522afd3f..4bfd0451ed5a 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -135,6 +135,24 @@ class CFI_Parser {
     PrologInfo info;
   };
 
+  struct RememberStack {
+    PrologInfoStackEntry *entry;
+    RememberStack() : entry(nullptr) {}
+    ~RememberStack() {
+#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
+      // Clean up rememberStack. Even in the case where every
+      // DW_CFA_remember_state is paired with a DW_CFA_restore_state,
+      // parseInstructions can skip restore opcodes if it reaches the target PC
+      // and stops interpreting, so we have to make sure we don't leak memory.
+      while (entry) {
+        PrologInfoStackEntry *next = entry->next;
+        _LIBUNWIND_REMEMBER_FREE(entry);
+        entry = next;
+      }
+#endif
+    }
+  };
+
   static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
                       uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
                       CIE_Info *cieInfo);
@@ -145,13 +163,6 @@ class CFI_Parser {
                                    int arch, PrologInfo *results);
 
   static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
-
-private:
-  static bool parseInstructions(A &addressSpace, pint_t instructions,
-                                pint_t instructionsEnd, const CIE_Info &cieInfo,
-                                pint_t pcoffset,
-                                PrologInfoStackEntry *&rememberStack, int arch,
-                                PrologInfo *results);
 };
 
 /// Parse a FDE into a CIE_Info and an FDE_Info
@@ -394,418 +405,415 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
                                          const FDE_Info &fdeInfo,
                                          const CIE_Info &cieInfo, pint_t upToPC,
                                          int arch, PrologInfo *results) {
-  PrologInfoStackEntry *rememberStack = NULL;
-
-  // parse CIE then FDE instructions
-  bool returnValue =
-      parseInstructions(addressSpace, cieInfo.cieInstructions,
-                        cieInfo.cieStart + cieInfo.cieLength, cieInfo,
-                        (pint_t)(-1), rememberStack, arch, results) &&
-      parseInstructions(addressSpace, fdeInfo.fdeInstructions,
-                        fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
-                        upToPC - fdeInfo.pcStart, rememberStack, arch, results);
-
-#if !defined(_LIBUNWIND_NO_HEAP)
-  // Clean up rememberStack. Even in the case where every DW_CFA_remember_state
-  // is paired with a DW_CFA_restore_state, parseInstructions can skip restore
-  // opcodes if it reaches the target PC and stops interpreting, so we have to
-  // make sure we don't leak memory.
-  while (rememberStack) {
-    PrologInfoStackEntry *next = rememberStack->next;
-    free(rememberStack);
-    rememberStack = next;
-  }
-#endif
-
-  return returnValue;
-}
+  // Alloca is used for the allocation of the rememberStack entries. It removes
+  // the dependency on new/malloc but the below for loop can not be refactored
+  // into functions. Entry could be saved during the processing of a CIE and
+  // restored by an FDE.
+  RememberStack rememberStack;
+
+  struct ParseInfo {
+    pint_t instructions;
+    pint_t instructionsEnd;
+    pint_t pcoffset;
+  };
 
-/// "run" the DWARF instructions
-template <typename A>
-bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
-                                      pint_t instructionsEnd,
-                                      const CIE_Info &cieInfo, pint_t pcoffset,
-                                      PrologInfoStackEntry *&rememberStack,
-                                      int arch, PrologInfo *results) {
-  pint_t p = instructions;
-  pint_t codeOffset = 0;
-  // initialState initialized as registers in results are modified. Use
-  // PrologInfo accessor functions to avoid reading uninitialized data.
-  PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
-
-  _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
-                         static_cast<uint64_t>(instructionsEnd));
-
-  // see DWARF Spec, section 6.4.2 for details on unwind opcodes
-  while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
-    uint64_t reg;
-    uint64_t reg2;
-    int64_t offset;
-    uint64_t length;
-    uint8_t opcode = addressSpace.get8(p);
-    uint8_t operand;
-#if !defined(_LIBUNWIND_NO_HEAP)
-    PrologInfoStackEntry *entry;
-#endif
-    ++p;
-    switch (opcode) {
-    case DW_CFA_nop:
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
-      break;
-    case DW_CFA_set_loc:
-      codeOffset =
-          addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
-      break;
-    case DW_CFA_advance_loc1:
-      codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
-      p += 1;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
-                             static_cast<uint64_t>(codeOffset));
-      break;
-    case DW_CFA_advance_loc2:
-      codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
-      p += 2;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
-                             static_cast<uint64_t>(codeOffset));
-      break;
-    case DW_CFA_advance_loc4:
-      codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
-      p += 4;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
-                             static_cast<uint64_t>(codeOffset));
-      break;
-    case DW_CFA_offset_extended:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
-                                                  * cieInfo.dataAlignFactor;
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
-        return false;
-      }
-      results->setRegister(reg, kRegisterInCFA, offset, initialState);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
-                             "offset=%" PRId64 ")\n",
-                             reg, offset);
-      break;
-    case DW_CFA_restore_extended:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-            "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
-        return false;
-      }
-      results->restoreRegisterToInitialState(reg, initialState);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
-      break;
-    case DW_CFA_undefined:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_undefined DWARF unwind, reg too big");
-        return false;
-      }
-      results->setRegisterLocation(reg, kRegisterUndefined, initialState);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
-      break;
-    case DW_CFA_same_value:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_same_value DWARF unwind, reg too big");
-        return false;
-      }
-      // <rdar://problem/8456377> DW_CFA_same_value unsupported
-      // "same value" means register was stored in frame, but its current
-      // value has not changed, so no need to restore from frame.
-      // We model this as if the register was never saved.
-      results->setRegisterLocation(reg, kRegisterUnused, initialState);
-      // set flag to disable conversion to compact unwind
-      results->sameValueUsed = true;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
-      break;
-    case DW_CFA_register:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      reg2 = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_register DWARF unwind, reg too big");
-        return false;
-      }
-      if (reg2 > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_register DWARF unwind, reg2 too big");
-        return false;
-      }
-      results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
-                           initialState);
-      // set flag to disable conversion to compact unwind
-      results->registersInOtherRegisters = true;
-      _LIBUNWIND_TRACE_DWARF(
-          "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
-      break;
-#if !defined(_LIBUNWIND_NO_HEAP)
-    case DW_CFA_remember_state:
-      // avoid operator new, because that would be an upward dependency
-      entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
-      if (entry != NULL) {
-        entry->next = rememberStack;
-        entry->info = *results;
-        rememberStack = entry;
-      } else {
-        return false;
-      }
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
-      break;
-    case DW_CFA_restore_state:
-      if (rememberStack != NULL) {
-        PrologInfoStackEntry *top = rememberStack;
-        *results = top->info;
-        rememberStack = top->next;
-        free((char *)top);
-      } else {
-        return false;
-      }
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
-      break;
-#endif
-    case DW_CFA_def_cfa:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
-        return false;
-      }
-      results->cfaRegister = (uint32_t)reg;
-      results->cfaRegisterOffset = (int32_t)offset;
-      _LIBUNWIND_TRACE_DWARF(
-          "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
-      break;
-    case DW_CFA_def_cfa_register:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-            "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
-        return false;
-      }
-      results->cfaRegister = (uint32_t)reg;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
-      break;
-    case DW_CFA_def_cfa_offset:
-      results->cfaRegisterOffset = (int32_t)
-                                  addressSpace.getULEB128(p, instructionsEnd);
-      results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
-                             results->cfaRegisterOffset);
-      break;
-    case DW_CFA_def_cfa_expression:
-      results->cfaRegister = 0;
-      results->cfaExpression = (int64_t)p;
-      length = addressSpace.getULEB128(p, instructionsEnd);
-      assert(length < static_cast<pint_t>(~0) && "pointer overflow");
-      p += static_cast<pint_t>(length);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
-                             ", length=%" PRIu64 ")\n",
-                             results->cfaExpression, length);
-      break;
-    case DW_CFA_expression:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_expression DWARF unwind, reg too big");
-        return false;
-      }
-      results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
-                           initialState);
-      length = addressSpace.getULEB128(p, instructionsEnd);
-      assert(length < static_cast<pint_t>(~0) && "pointer overflow");
-      p += static_cast<pint_t>(length);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
-                             "expression=0x%" PRIx64 ", "
-                             "length=%" PRIu64 ")\n",
-                             reg, results->savedRegisters[reg].value, length);
-      break;
-    case DW_CFA_offset_extended_sf:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-            "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
-        return false;
-      }
-      offset =
-          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
-      results->setRegister(reg, kRegisterInCFA, offset, initialState);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
-                             "offset=%" PRId64 ")\n",
-                             reg, offset);
-      break;
-    case DW_CFA_def_cfa_sf:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      offset =
-          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
-        return false;
-      }
-      results->cfaRegister = (uint32_t)reg;
-      results->cfaRegisterOffset = (int32_t)offset;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
-                             "offset=%" PRId64 ")\n",
-                             reg, offset);
-      break;
-    case DW_CFA_def_cfa_offset_sf:
-      results->cfaRegisterOffset = (int32_t)
-        (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
-      results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
-                             results->cfaRegisterOffset);
-      break;
-    case DW_CFA_val_offset:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG(
-                "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
-                ") out of range\n",
-                reg);
-        return false;
-      }
-      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
-                                                    * cieInfo.dataAlignFactor;
-      results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
-                             "offset=%" PRId64 "\n",
-                             reg, offset);
-      break;
-    case DW_CFA_val_offset_sf:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
-        return false;
-      }
-      offset =
-          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
-      results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
-                             "offset=%" PRId64 "\n",
-                             reg, offset);
-      break;
-    case DW_CFA_val_expression:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0(
-                "malformed DW_CFA_val_expression DWARF unwind, reg too big");
-        return false;
-      }
-      results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
-                           initialState);
-      length = addressSpace.getULEB128(p, instructionsEnd);
-      assert(length < static_cast<pint_t>(~0) && "pointer overflow");
-      p += static_cast<pint_t>(length);
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
-                             "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
-                             reg, results->savedRegisters[reg].value, length);
-      break;
-    case DW_CFA_GNU_args_size:
-      length = addressSpace.getULEB128(p, instructionsEnd);
-      results->spExtraArgSize = (uint32_t)length;
-      _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
-      break;
-    case DW_CFA_GNU_negative_offset_extended:
-      reg = addressSpace.getULEB128(p, instructionsEnd);
-      if (reg > kMaxRegisterNumber) {
-        _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
-                        "unwind, reg too big");
-        return false;
+  ParseInfo parseInfoArray[] = {
+      {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
+       (pint_t)(-1)},
+      {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
+       upToPC - fdeInfo.pcStart}};
+
+  for (const auto &info : parseInfoArray) {
+    pint_t p = info.instructions;
+    pint_t instructionsEnd = info.instructionsEnd;
+    pint_t pcoffset = info.pcoffset;
+    pint_t codeOffset = 0;
+
+    // initialState initialized as registers in results are modified. Use
+    // PrologInfo accessor functions to avoid reading uninitialized data.
+    PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
+
+    _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
+                           ")\n",
+                           static_cast<uint64_t>(instructionsEnd));
+
+    // see DWARF Spec, section 6.4.2 for details on unwind opcodes
+    while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
+      uint64_t reg;
+      uint64_t reg2;
+      int64_t offset;
+      uint64_t length;
+      uint8_t opcode = addressSpace.get8(p);
+      uint8_t operand;
+
+      ++p;
+      switch (opcode) {
+      case DW_CFA_nop:
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
+        break;
+      case DW_CFA_set_loc:
+        codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
+                                              cieInfo.pointerEncoding);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
+        break;
+      case DW_CFA_advance_loc1:
+        codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+        p += 1;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
+                               static_cast<uint64_t>(codeOffset));
+        break;
+      case DW_CFA_advance_loc2:
+        codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+        p += 2;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
+                               static_cast<uint64_t>(codeOffset));
+        break;
+      case DW_CFA_advance_loc4:
+        codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+        p += 4;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
+                               static_cast<uint64_t>(codeOffset));
+        break;
+      case DW_CFA_offset_extended:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterInCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_restore_extended:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
+          return false;
+        }
+        results->restoreRegisterToInitialState(reg, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
+                               reg);
+        break;
+      case DW_CFA_undefined:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_undefined DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegisterLocation(reg, kRegisterUndefined, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
+        break;
+      case DW_CFA_same_value:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_same_value DWARF unwind, reg too big");
+          return false;
+        }
+        // <rdar://problem/8456377> DW_CFA_same_value unsupported
+        // "same value" means register was stored in frame, but its current
+        // value has not changed, so no need to restore from frame.
+        // We model this as if the register was never saved.
+        results->setRegisterLocation(reg, kRegisterUnused, initialState);
+        // set flag to disable conversion to compact unwind
+        results->sameValueUsed = true;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
+        break;
+      case DW_CFA_register:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        reg2 = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_register DWARF unwind, reg too big");
+          return false;
+        }
+        if (reg2 > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_register DWARF unwind, reg2 too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
+                             initialState);
+        // set flag to disable conversion to compact unwind
+        results->registersInOtherRegisters = true;
+        _LIBUNWIND_TRACE_DWARF(
+            "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
+        break;
+      case DW_CFA_remember_state: {
+        // Avoid operator new because that would be an upward dependency.
+        // Avoid malloc because it needs heap allocation.
+        PrologInfoStackEntry *entry =
+            (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
+                sizeof(PrologInfoStackEntry));
+        if (entry != NULL) {
+          entry->next = rememberStack.entry;
+          entry->info = *results;
+          rememberStack.entry = entry;
+        } else {
+          return false;
+        }
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
+        break;
       }
-      offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
-                                                    * cieInfo.dataAlignFactor;
-      results->setRegister(reg, kRegisterInCFA, -offset, initialState);
-      _LIBUNWIND_TRACE_DWARF(
-          "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
-      break;
+      case DW_CFA_restore_state:
+        if (rememberStack.entry != NULL) {
+          PrologInfoStackEntry *top = rememberStack.entry;
+          *results = top->info;
+          rememberStack.entry = top->next;
+          _LIBUNWIND_REMEMBER_FREE(top);
+        } else {
+          return false;
+        }
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
+        break;
+      case DW_CFA_def_cfa:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
+          return false;
+        }
+        results->cfaRegister = (uint32_t)reg;
+        results->cfaRegisterOffset = (int32_t)offset;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
+                               ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_def_cfa_register:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
+          return false;
+        }
+        results->cfaRegister = (uint32_t)reg;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
+        break;
+      case DW_CFA_def_cfa_offset:
+        results->cfaRegisterOffset =
+            (int32_t)addressSpace.getULEB128(p, instructionsEnd);
+        results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
+                               results->cfaRegisterOffset);
+        break;
+      case DW_CFA_def_cfa_expression:
+        results->cfaRegister = 0;
+        results->cfaExpression = (int64_t)p;
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+        p += static_cast<pint_t>(length);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
+                               ", length=%" PRIu64 ")\n",
+                               results->cfaExpression, length);
+        break;
+      case DW_CFA_expression:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_expression DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
+                             initialState);
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+        p += static_cast<pint_t>(length);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
+                               "expression=0x%" PRIx64 ", "
+                               "length=%" PRIu64 ")\n",
+                               reg, results->savedRegisters[reg].value, length);
+        break;
+      case DW_CFA_offset_extended_sf:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
+          return false;
+        }
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterInCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_def_cfa_sf:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
+          return false;
+        }
+        results->cfaRegister = (uint32_t)reg;
+        results->cfaRegisterOffset = (int32_t)offset;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_def_cfa_offset_sf:
+        results->cfaRegisterOffset =
+            (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
+                      cieInfo.dataAlignFactor);
+        results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
+                               results->cfaRegisterOffset);
+        break;
+      case DW_CFA_val_offset:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG(
+              "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
+              ") out of range\n",
+              reg);
+          return false;
+        }
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 "\n",
+                               reg, offset);
+        break;
+      case DW_CFA_val_offset_sf:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
+          return false;
+        }
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 "\n",
+                               reg, offset);
+        break;
+      case DW_CFA_val_expression:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_val_expression DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
+                             initialState);
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+        p += static_cast<pint_t>(length);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
+                               "expression=0x%" PRIx64 ", length=%" PRIu64
+                               ")\n",
+                               reg, results->savedRegisters[reg].value, length);
+        break;
+      case DW_CFA_GNU_args_size:
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        results->spExtraArgSize = (uint32_t)length;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
+        break;
+      case DW_CFA_GNU_negative_offset_extended:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
+                          "unwind, reg too big");
+          return false;
+        }
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterInCFA, -offset, initialState);
+        _LIBUNWIND_TRACE_DWARF(
+            "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
+        break;
 
 #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
-    // The same constant is used to represent 
diff erent instructions on
-    // AArch64 (negate_ra_state) and SPARC (window_save).
-    static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
-                  "uses the same constant");
-    case DW_CFA_AARCH64_negate_ra_state:
-      switch (arch) {
+        // The same constant is used to represent 
diff erent instructions on
+        // AArch64 (negate_ra_state) and SPARC (window_save).
+        static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
+                      "uses the same constant");
+      case DW_CFA_AARCH64_negate_ra_state:
+        switch (arch) {
 #if defined(_LIBUNWIND_TARGET_AARCH64)
         case REGISTERS_ARM64: {
           int64_t value =
               results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
-          results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, initialState);
+          results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value,
+                                    initialState);
           _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
         } break;
 #endif
 
 #if defined(_LIBUNWIND_TARGET_SPARC)
-      // case DW_CFA_GNU_window_save:
-      case REGISTERS_SPARC:
-        _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
-        for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
-          results->setRegister(reg, kRegisterInRegister,
-                               ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
-                               initialState);
-        }
+        // case DW_CFA_GNU_window_save:
+        case REGISTERS_SPARC:
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
+          for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
+            results->setRegister(reg, kRegisterInRegister,
+                                 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
+                                 initialState);
+          }
 
-        for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
-          results->setRegister(reg, kRegisterInCFA,
-                               ((int64_t)reg - UNW_SPARC_L0) * 4, initialState);
+          for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+            results->setRegister(reg, kRegisterInCFA,
+                                 ((int64_t)reg - UNW_SPARC_L0) * 4,
+                                 initialState);
+          }
+          break;
+#endif
         }
         break;
-#endif
-      }
-      break;
 #else
-      (void)arch;
+        (void)arch;
 #endif
 
-    default:
-      operand = opcode & 0x3F;
-      switch (opcode & 0xC0) {
-      case DW_CFA_offset:
-        reg = operand;
-        if (reg > kMaxRegisterNumber) {
-          _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
-                         ") out of range",
-                  reg);
-          return false;
-        }
-        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
-                                                    * cieInfo.dataAlignFactor;
-        results->setRegister(reg, kRegisterInCFA, offset, initialState);
-        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
-                               operand, offset);
-        break;
-      case DW_CFA_advance_loc:
-        codeOffset += operand * cieInfo.codeAlignFactor;
-        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
-                               static_cast<uint64_t>(codeOffset));
-        break;
-      case DW_CFA_restore:
-        reg = operand;
-        if (reg > kMaxRegisterNumber) {
-          _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
-                         ") out of range",
-                  reg);
+      default:
+        operand = opcode & 0x3F;
+        switch (opcode & 0xC0) {
+        case DW_CFA_offset:
+          reg = operand;
+          if (reg > kMaxRegisterNumber) {
+            _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
+                           ") out of range",
+                           reg);
+            return false;
+          }
+          offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                   cieInfo.dataAlignFactor;
+          results->setRegister(reg, kRegisterInCFA, offset, initialState);
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
+                                 operand, offset);
+          break;
+        case DW_CFA_advance_loc:
+          codeOffset += operand * cieInfo.codeAlignFactor;
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
+                                 static_cast<uint64_t>(codeOffset));
+          break;
+        case DW_CFA_restore:
+          reg = operand;
+          if (reg > kMaxRegisterNumber) {
+            _LIBUNWIND_LOG(
+                "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
+                ") out of range",
+                reg);
+            return false;
+          }
+          results->restoreRegisterToInitialState(reg, initialState);
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
+                                 static_cast<uint64_t>(operand));
+          break;
+        default:
+          _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
           return false;
         }
-        results->restoreRegisterToInitialState(reg, initialState);
-        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
-                               static_cast<uint64_t>(operand));
-        break;
-      default:
-        _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
-        return false;
       }
     }
   }
-
   return true;
 }
 

diff  --git a/libunwind/src/config.h b/libunwind/src/config.h
index 0885dccda07e..e20d51a20212 100644
--- a/libunwind/src/config.h
+++ b/libunwind/src/config.h
@@ -120,6 +120,29 @@
 #define PPC64_HAS_VMX
 #endif
 
+#ifndef _LIBUNWIND_REMEMBER_HEAP_ALLOC
+#if defined(_LIBUNWIND_REMEMBER_STACK_ALLOC) || defined(__APPLE__) ||          \
+    defined(__linux__) || defined(__ANDROID__) || defined(__MINGW32__) ||      \
+    defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) alloca(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr)                                         \
+  do {                                                                         \
+  } while (0)
+#elif defined(_WIN32)
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) _malloca(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) _freea(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#else
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#endif
+#else /* _LIBUNWIND_REMEMBER_HEAP_ALLOC */
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#endif
+
 #if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
 #define _LIBUNWIND_ABORT(msg)                                                  \
   do {                                                                         \


        


More information about the cfe-commits mailing list