Changeset View
Changeset View
Standalone View
Standalone View
src/DwarfParser.hpp
Show All 14 Lines | |||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include "libunwind.h" | #include "libunwind.h" | ||||
#include "dwarf2.h" | #include "dwarf2.h" | ||||
#include "Registers.hpp" | |||||
#include "config.h" | #include "config.h" | ||||
namespace libunwind { | namespace libunwind { | ||||
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. | /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. | ||||
/// See DWARF Spec for details: | /// See DWARF Spec for details: | ||||
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html | /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | #endif | ||||
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, | static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, | ||||
uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, | uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, | ||||
CIE_Info *cieInfo); | CIE_Info *cieInfo); | ||||
static const char *decodeFDE(A &addressSpace, pint_t fdeStart, | static const char *decodeFDE(A &addressSpace, pint_t fdeStart, | ||||
FDE_Info *fdeInfo, CIE_Info *cieInfo); | FDE_Info *fdeInfo, CIE_Info *cieInfo); | ||||
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, | static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, | ||||
const CIE_Info &cieInfo, pint_t upToPC, | const CIE_Info &cieInfo, pint_t upToPC, | ||||
PrologInfo *results); | unsigned arch, PrologInfo *results); | ||||
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); | static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); | ||||
private: | private: | ||||
static bool parseInstructions(A &addressSpace, pint_t instructions, | static bool parseInstructions(A &addressSpace, pint_t instructions, | ||||
pint_t instructionsEnd, const CIE_Info &cieInfo, | pint_t instructionsEnd, const CIE_Info &cieInfo, | ||||
pint_t pcoffset, | pint_t pcoffset, | ||||
PrologInfoStackEntry *&rememberStack, | PrologInfoStackEntry *&rememberStack, | ||||
PrologInfo *results); | unsigned arch, PrologInfo *results); | ||||
}; | }; | ||||
/// Parse a FDE into a CIE_Info and an FDE_Info | /// Parse a FDE into a CIE_Info and an FDE_Info | ||||
template <typename A> | template <typename A> | ||||
const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, | const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, | ||||
FDE_Info *fdeInfo, CIE_Info *cieInfo) { | FDE_Info *fdeInfo, CIE_Info *cieInfo) { | ||||
pint_t p = fdeStart; | pint_t p = fdeStart; | ||||
pint_t cfiLength = (pint_t)addressSpace.get32(p); | pint_t cfiLength = (pint_t)addressSpace.get32(p); | ||||
▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE | /// "run" the DWARF instructions and create the abstact PrologInfo for an FDE | ||||
template <typename A> | template <typename A> | ||||
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, | bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, | ||||
const FDE_Info &fdeInfo, | const FDE_Info &fdeInfo, | ||||
const CIE_Info &cieInfo, pint_t upToPC, | const CIE_Info &cieInfo, pint_t upToPC, | ||||
PrologInfo *results) { | unsigned arch, PrologInfo *results) { | ||||
// clear results | // clear results | ||||
memset(results, '\0', sizeof(PrologInfo)); | memset(results, '\0', sizeof(PrologInfo)); | ||||
PrologInfoStackEntry *rememberStack = NULL; | PrologInfoStackEntry *rememberStack = NULL; | ||||
// parse CIE then FDE instructions | // parse CIE then FDE instructions | ||||
return parseInstructions(addressSpace, cieInfo.cieInstructions, | return parseInstructions(addressSpace, cieInfo.cieInstructions, | ||||
cieInfo.cieStart + cieInfo.cieLength, cieInfo, | cieInfo.cieStart + cieInfo.cieLength, cieInfo, | ||||
(pint_t)(-1), rememberStack, results) && | (pint_t)(-1), rememberStack, arch, results) && | ||||
parseInstructions(addressSpace, fdeInfo.fdeInstructions, | parseInstructions(addressSpace, fdeInfo.fdeInstructions, | ||||
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, | fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, | ||||
upToPC - fdeInfo.pcStart, rememberStack, results); | upToPC - fdeInfo.pcStart, rememberStack, arch, | ||||
results); | |||||
} | } | ||||
/// "run" the DWARF instructions | /// "run" the DWARF instructions | ||||
template <typename A> | template <typename A> | ||||
bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, | bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, | ||||
pint_t instructionsEnd, | pint_t instructionsEnd, | ||||
const CIE_Info &cieInfo, pint_t pcoffset, | const CIE_Info &cieInfo, pint_t pcoffset, | ||||
PrologInfoStackEntry *&rememberStack, | PrologInfoStackEntry *&rememberStack, | ||||
PrologInfo *results) { | unsigned arch, PrologInfo *results) { | ||||
pint_t p = instructions; | pint_t p = instructions; | ||||
pint_t codeOffset = 0; | pint_t codeOffset = 0; | ||||
PrologInfo initialState = *results; | PrologInfo initialState = *results; | ||||
_LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", | _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", | ||||
static_cast<uint64_t>(instructionsEnd)); | static_cast<uint64_t>(instructionsEnd)); | ||||
// see DWARF Spec, section 6.4.2 for details on unwind opcodes | // see DWARF Spec, section 6.4.2 for details on unwind opcodes | ||||
▲ Show 20 Lines • Show All 287 Lines • ▼ Show 20 Lines | case DW_CFA_GNU_negative_offset_extended: | ||||
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) | ||||
* cieInfo.dataAlignFactor; | * cieInfo.dataAlignFactor; | ||||
results->savedRegisters[reg].location = kRegisterInCFA; | results->savedRegisters[reg].location = kRegisterInCFA; | ||||
results->savedRegisters[reg].value = -offset; | results->savedRegisters[reg].value = -offset; | ||||
_LIBUNWIND_TRACE_DWARF( | _LIBUNWIND_TRACE_DWARF( | ||||
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); | "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); | ||||
break; | break; | ||||
#if defined(_LIBUNWIND_TARGET_AARCH64) | #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) | ||||
// The same constant is used to represent different instructions on | |||||
mgorny: Could you add a `static_assert` that verifies that the constants indeed have the same value? | |||||
// AArch64 (negate_ra_state) and SPARC (window_save). | |||||
case DW_CFA_AARCH64_negate_ra_state: | case DW_CFA_AARCH64_negate_ra_state: | ||||
Not Done ReplyInline Actions/var/tmp/portage/sys-libs/llvm-libunwind-9999/work/llvm-libunwind-9999/src/DwarfParser.hpp:686:75: error: macro "static_assert" requires 2 argument s, but only 1 given static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save); ^ mgorny: ```
/var/tmp/portage/sys-libs/llvm-libunwind-9999/work/llvm-libunwind-9999/src/DwarfParser.hpp… | |||||
switch (arch) { | |||||
#if defined(_LIBUNWIND_TARGET_AARCH64) | |||||
case REGISTERS_ARM64: | |||||
results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; | results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; | ||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); | _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); | ||||
break; | break; | ||||
#endif | #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->savedRegisters[reg].location = kRegisterInRegister; | |||||
results->savedRegisters[reg].value = | |||||
(reg - UNW_SPARC_O0) + UNW_SPARC_I0; | |||||
Not Done ReplyInline ActionsCould you put this before the execution of the op please? compnerd: Could you put this before the execution of the op please? | |||||
Sure. But for the other ops the trace printout is placed after the op, so this would break that pattern? dcederman: Sure. But for the other ops the trace printout is placed after the op, so this would break that… | |||||
} | |||||
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { | |||||
results->savedRegisters[reg].location = kRegisterInCFA; | |||||
results->savedRegisters[reg].value = (reg - UNW_SPARC_L0) * 4; | |||||
} | |||||
break; | |||||
#endif | |||||
} | |||||
break; | |||||
#endif | |||||
Not Done ReplyInline ActionsShould this be wrapped in #ifdef _LIBUNWIND_TARGET_SPARC ? mclow.lists: Should this be wrapped in `#ifdef _LIBUNWIND_TARGET_SPARC ` ? | |||||
Not Done ReplyInline ActionsYes, it probably should. I will fix that. dcederman: Yes, it probably should. I will fix that. | |||||
default: | default: | ||||
operand = opcode & 0x3F; | operand = opcode & 0x3F; | ||||
switch (opcode & 0xC0) { | switch (opcode & 0xC0) { | ||||
case DW_CFA_offset: | case DW_CFA_offset: | ||||
reg = operand; | reg = operand; | ||||
if (reg > kMaxRegisterNumber) { | if (reg > kMaxRegisterNumber) { | ||||
_LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 | _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 | ||||
") out of range", | ") out of range", | ||||
Show All 40 Lines |
Could you add a static_assert that verifies that the constants indeed have the same value?