aboutsummaryrefslogtreecommitdiff
path: root/libunwind/src/DwarfParser.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'libunwind/src/DwarfParser.hpp')
-rw-r--r--libunwind/src/DwarfParser.hpp811
1 files changed, 407 insertions, 404 deletions
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index d05ac468367f..de0eb6de9d70 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -69,6 +69,7 @@ public:
};
enum RegisterSavedWhere {
kRegisterUnused,
+ kRegisterUndefined,
kRegisterInCFA,
kRegisterOffsetFromCFA,
kRegisterInRegister,
@@ -87,9 +88,6 @@ public:
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
- uint32_t codeOffsetAtStackDecrement;
- bool registersInOtherRegisters;
- bool sameValueUsed;
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
enum class InitializeTime { kLazy, kNormal };
@@ -134,8 +132,26 @@ public:
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,
- uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+ uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
CIE_Info *cieInfo);
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
FDE_Info *fdeInfo, CIE_Info *cieInfo);
@@ -144,13 +160,6 @@ public:
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
@@ -166,7 +175,7 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
p += 8;
}
if (cfiLength == 0)
- return "FDE has zero length"; // end marker
+ return "FDE has zero length"; // zero terminator
uint32_t ciePointer = addressSpace.get32(p);
if (ciePointer == 0)
return "FDE is really a CIE"; // this is a CIE not an FDE
@@ -211,11 +220,13 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
/// Scan an eh_frame section to find an FDE for a pc
template <typename A>
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
- uint32_t sectionLength, pint_t fdeHint,
+ uintptr_t sectionLength, pint_t fdeHint,
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
- const pint_t ehSectionEnd = p + sectionLength;
+ const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
+ ? static_cast<pint_t>(-1)
+ : (ehSectionStart + sectionLength);
while (p < ehSectionEnd) {
pint_t currentCFI = p;
//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
@@ -227,7 +238,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
p += 8;
}
if (cfiLength == 0)
- return false; // end marker
+ return false; // zero terminator
uint32_t id = addressSpace.get32(p);
if (id == 0) {
// Skip over CIEs.
@@ -336,7 +347,8 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
// parse data alignment factor
cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
// parse return address register
- uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
+ uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
+ : addressSpace.getULEB128(p, cieContentEnd);
assert(raReg < 255 && "return address register too large");
cieInfo->returnAddressRegister = (uint8_t)raReg;
// parse augmentation data based on augmentation string
@@ -390,418 +402,409 @@ 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, kRegisterUnused, 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);
+ _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);
+ _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);
+ _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);
+ _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 different 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 different 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;
}