Loading libunwindstack/DwarfCfa.cpp +33 −3 Original line number Original line Diff line number Diff line Loading @@ -26,7 +26,9 @@ #include <unwindstack/DwarfError.h> #include <unwindstack/DwarfError.h> #include <unwindstack/DwarfLocation.h> #include <unwindstack/DwarfLocation.h> #include <unwindstack/Elf.h> #include <unwindstack/Log.h> #include <unwindstack/Log.h> #include <unwindstack/MachineArm64.h> #include "DwarfCfa.h" #include "DwarfCfa.h" #include "DwarfEncoding.h" #include "DwarfEncoding.h" Loading Loading @@ -204,8 +206,12 @@ template <typename AddressType> bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc) { uint64_t* cur_pc) { const auto* cfa = &DwarfCfaInfo::kTable[op]; const auto* cfa = &DwarfCfaInfo::kTable[op]; if (cfa->name[0] == '\0') { if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) { if (op == 0x2d) { log(indent, "Illegal (Only valid on aarch64)"); } else { log(indent, "Illegal"); log(indent, "Illegal"); } log(indent, "Raw Data: 0x%02x", op); log(indent, "Raw Data: 0x%02x", op); return true; return true; } } Loading Loading @@ -514,6 +520,24 @@ bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* l return true; return true; } } template <typename AddressType> bool DwarfCfa<AddressType>::cfa_aarch64_negate_ra_state(dwarf_loc_regs_t* loc_regs) { // Only supported on aarch64. if (arch_ != ARCH_ARM64) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } auto cfa_location = loc_regs->find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE); if (cfa_location == loc_regs->end()) { (*loc_regs)[Arm64Reg::ARM64_PREG_RA_SIGN_STATE] = {.type = DWARF_LOCATION_PSEUDO_REGISTER, .values = {1}}; } else { cfa_location->second.values[0] ^= 1; } return true; } const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { { { // 0x00 DW_CFA_nop // 0x00 DW_CFA_nop Loading Loading @@ -699,7 +723,13 @@ const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { {"", 0, 0, {}, {}}, // 0x2a illegal cfa {"", 0, 0, {}, {}}, // 0x2a illegal cfa {"", 0, 0, {}, {}}, // 0x2b illegal cfa {"", 0, 0, {}, {}}, // 0x2b illegal cfa {"", 0, 0, {}, {}}, // 0x2c illegal cfa {"", 0, 0, {}, {}}, // 0x2c illegal cfa {"", 0, 0, {}, {}}, // 0x2d DW_CFA_GNU_window_save (Treat as illegal) { "DW_CFA_AARCH64_negate_ra_state", // 0x2d DW_CFA_AARCH64_negate_ra_state 3, 0, {}, {}, }, { { "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size 2, 2, Loading libunwindstack/DwarfCfa.h +10 −3 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,9 @@ namespace unwindstack { namespace unwindstack { // Forward declarations. enum ArchEnum : uint8_t; // DWARF Standard home: http://dwarfstd.org/ // DWARF Standard home: http://dwarfstd.org/ // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf // See section 6.4.2.1 for a description of the DW_CFA_xxx values. // See section 6.4.2.1 for a description of the DW_CFA_xxx values. Loading Loading @@ -72,7 +75,8 @@ class DwarfCfa { typedef typename std::make_signed<AddressType>::type SignedType; typedef typename std::make_signed<AddressType>::type SignedType; public: public: DwarfCfa(DwarfMemory* memory, const DwarfFde* fde) : memory_(memory), fde_(fde) {} DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch) : memory_(memory), fde_(fde), arch_(arch) {} virtual ~DwarfCfa() = default; virtual ~DwarfCfa() = default; bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, Loading @@ -99,6 +103,7 @@ class DwarfCfa { DwarfErrorData last_error_; DwarfErrorData last_error_; DwarfMemory* memory_; DwarfMemory* memory_; const DwarfFde* fde_; const DwarfFde* fde_; ArchEnum arch_; AddressType cur_pc_; AddressType cur_pc_; const dwarf_loc_regs_t* cie_loc_regs_ = nullptr; const dwarf_loc_regs_t* cie_loc_regs_ = nullptr; Loading Loading @@ -128,6 +133,7 @@ class DwarfCfa { bool cfa_val_offset_sf(dwarf_loc_regs_t*); bool cfa_val_offset_sf(dwarf_loc_regs_t*); bool cfa_val_expression(dwarf_loc_regs_t*); bool cfa_val_expression(dwarf_loc_regs_t*); bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*); bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*); bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*); using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*); using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*); constexpr static process_func kCallbackTable[64] = { constexpr static process_func kCallbackTable[64] = { Loading Loading @@ -221,8 +227,9 @@ class DwarfCfa { nullptr, nullptr, // 0x2c illegal cfa // 0x2c illegal cfa nullptr, nullptr, // 0x2d DW_CFA_GNU_window_save (Treat this as illegal) // 0x2d DW_CFA_AARCH64_negate_ra_state (aarch64 only) nullptr, // DW_CFA_GNU_window_save on other architectures. &DwarfCfa::cfa_aarch64_negate_ra_state, // 0x2e DW_CFA_GNU_args_size // 0x2e DW_CFA_GNU_args_size &DwarfCfa::cfa_nop, &DwarfCfa::cfa_nop, // 0x2f DW_CFA_GNU_negative_offset_extended // 0x2f DW_CFA_GNU_negative_offset_extended Loading libunwindstack/DwarfSection.cpp +22 −7 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfSection.h> #include <unwindstack/DwarfSection.h> #include <unwindstack/DwarfStructs.h> #include <unwindstack/DwarfStructs.h> #include <unwindstack/Elf.h> #include <unwindstack/Log.h> #include <unwindstack/Log.h> #include <unwindstack/Memory.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> #include <unwindstack/Regs.h> Loading Loading @@ -49,7 +50,7 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f // Now get the location information for this pc. // Now get the location information for this pc. dwarf_loc_regs_t loc_regs; dwarf_loc_regs_t loc_regs; if (!GetCfaLocationInfo(pc, fde, &loc_regs)) { if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) { return false; return false; } } loc_regs.cie = fde->cie; loc_regs.cie = fde->cie; Loading Loading @@ -464,6 +465,13 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3 eval_info->return_address_undefined = true; eval_info->return_address_undefined = true; } } break; break; case DWARF_LOCATION_PSEUDO_REGISTER: { if (!eval_info->regs_info.regs->SetPseudoRegister(reg, loc->values[0])) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } break; } default: default: break; break; } } Loading Loading @@ -491,6 +499,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me // Always set the dex pc to zero when evaluating. // Always set the dex pc to zero when evaluating. cur_regs->set_dex_pc(0); cur_regs->set_dex_pc(0); // Reset necessary pseudo registers before evaluation. // This is needed for ARM64, for example. regs->ResetPseudoRegisters(); EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs, EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs, .cie = cie, .cie = cie, .regular_memory = regular_memory, .regular_memory = regular_memory, Loading Loading @@ -527,9 +539,11 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me AddressType* reg_ptr; AddressType* reg_ptr; if (reg >= cur_regs->total_regs()) { if (reg >= cur_regs->total_regs()) { if (entry.second.type != DWARF_LOCATION_PSEUDO_REGISTER) { // Skip this unknown register. // Skip this unknown register. continue; continue; } } } reg_ptr = eval_info.regs_info.Save(reg); reg_ptr = eval_info.regs_info.Save(reg); if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { Loading @@ -554,8 +568,8 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me template <typename AddressType> template <typename AddressType> bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) { dwarf_loc_regs_t* loc_regs, ArchEnum arch) { DwarfCfa<AddressType> cfa(&memory_, fde); DwarfCfa<AddressType> cfa(&memory_, fde, arch); // Look for the cached copy of the cie data. // Look for the cached copy of the cie data. auto reg_entry = cie_loc_regs_.find(fde->cie_offset); auto reg_entry = cie_loc_regs_.find(fde->cie_offset); Loading @@ -576,8 +590,9 @@ bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfF } } template <typename AddressType> template <typename AddressType> bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) { bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, DwarfCfa<AddressType> cfa(&memory_, fde); ArchEnum arch) { DwarfCfa<AddressType> cfa(&memory_, fde, arch); // Always print the cie information. // Always print the cie information. const DwarfCie* cie = fde->cie; const DwarfCie* cie = fde->cie; Loading libunwindstack/RegsArm64.cpp +52 −1 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,10 @@ namespace unwindstack { namespace unwindstack { RegsArm64::RegsArm64() RegsArm64::RegsArm64() : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) { ResetPseudoRegisters(); pac_mask_ = 0; } ArchEnum RegsArm64::Arch() { ArchEnum RegsArm64::Arch() { return ARCH_ARM64; return ARCH_ARM64; Loading @@ -45,6 +48,23 @@ uint64_t RegsArm64::sp() { } } void RegsArm64::set_pc(uint64_t pc) { void RegsArm64::set_pc(uint64_t pc) { // If the target is aarch64 then the return address may have been // signed using the Armv8.3-A Pointer Authentication extension. The // original return address can be restored by stripping out the // authentication code using a mask or xpaclri. xpaclri is a NOP on // pre-Armv8.3-A architectures. if ((0 != pc) && IsRASigned()) { if (pac_mask_) { pc &= ~pac_mask_; #if defined(__aarch64__) } else { register uint64_t x30 __asm("x30") = pc; // This is XPACLRI. asm("hint 0x7" : "+r"(x30)); pc = x30; #endif } } regs_[ARM64_REG_PC] = pc; regs_[ARM64_REG_PC] = pc; } } Loading Loading @@ -144,6 +164,37 @@ bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* proce return true; return true; } } void RegsArm64::ResetPseudoRegisters(void) { // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0. this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0); } bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) { if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value; return true; } return false; } bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) { if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST]; return true; } return false; } bool RegsArm64::IsRASigned() { uint64_t value; auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value); return (result && (value != 0)); } void RegsArm64::SetPACMask(uint64_t mask) { pac_mask_ = mask; } Regs* RegsArm64::Clone() { Regs* RegsArm64::Clone() { return new RegsArm64(*this); return new RegsArm64(*this); } } Loading libunwindstack/include/unwindstack/DwarfLocation.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ enum DwarfLocationEnum : uint8_t { DWARF_LOCATION_REGISTER, DWARF_LOCATION_REGISTER, DWARF_LOCATION_EXPRESSION, DWARF_LOCATION_EXPRESSION, DWARF_LOCATION_VAL_EXPRESSION, DWARF_LOCATION_VAL_EXPRESSION, DWARF_LOCATION_PSEUDO_REGISTER, }; }; struct DwarfLocation { struct DwarfLocation { Loading Loading
libunwindstack/DwarfCfa.cpp +33 −3 Original line number Original line Diff line number Diff line Loading @@ -26,7 +26,9 @@ #include <unwindstack/DwarfError.h> #include <unwindstack/DwarfError.h> #include <unwindstack/DwarfLocation.h> #include <unwindstack/DwarfLocation.h> #include <unwindstack/Elf.h> #include <unwindstack/Log.h> #include <unwindstack/Log.h> #include <unwindstack/MachineArm64.h> #include "DwarfCfa.h" #include "DwarfCfa.h" #include "DwarfEncoding.h" #include "DwarfEncoding.h" Loading Loading @@ -204,8 +206,12 @@ template <typename AddressType> bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc) { uint64_t* cur_pc) { const auto* cfa = &DwarfCfaInfo::kTable[op]; const auto* cfa = &DwarfCfaInfo::kTable[op]; if (cfa->name[0] == '\0') { if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) { if (op == 0x2d) { log(indent, "Illegal (Only valid on aarch64)"); } else { log(indent, "Illegal"); log(indent, "Illegal"); } log(indent, "Raw Data: 0x%02x", op); log(indent, "Raw Data: 0x%02x", op); return true; return true; } } Loading Loading @@ -514,6 +520,24 @@ bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* l return true; return true; } } template <typename AddressType> bool DwarfCfa<AddressType>::cfa_aarch64_negate_ra_state(dwarf_loc_regs_t* loc_regs) { // Only supported on aarch64. if (arch_ != ARCH_ARM64) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } auto cfa_location = loc_regs->find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE); if (cfa_location == loc_regs->end()) { (*loc_regs)[Arm64Reg::ARM64_PREG_RA_SIGN_STATE] = {.type = DWARF_LOCATION_PSEUDO_REGISTER, .values = {1}}; } else { cfa_location->second.values[0] ^= 1; } return true; } const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { { { // 0x00 DW_CFA_nop // 0x00 DW_CFA_nop Loading Loading @@ -699,7 +723,13 @@ const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { {"", 0, 0, {}, {}}, // 0x2a illegal cfa {"", 0, 0, {}, {}}, // 0x2a illegal cfa {"", 0, 0, {}, {}}, // 0x2b illegal cfa {"", 0, 0, {}, {}}, // 0x2b illegal cfa {"", 0, 0, {}, {}}, // 0x2c illegal cfa {"", 0, 0, {}, {}}, // 0x2c illegal cfa {"", 0, 0, {}, {}}, // 0x2d DW_CFA_GNU_window_save (Treat as illegal) { "DW_CFA_AARCH64_negate_ra_state", // 0x2d DW_CFA_AARCH64_negate_ra_state 3, 0, {}, {}, }, { { "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size 2, 2, Loading
libunwindstack/DwarfCfa.h +10 −3 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,9 @@ namespace unwindstack { namespace unwindstack { // Forward declarations. enum ArchEnum : uint8_t; // DWARF Standard home: http://dwarfstd.org/ // DWARF Standard home: http://dwarfstd.org/ // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf // See section 6.4.2.1 for a description of the DW_CFA_xxx values. // See section 6.4.2.1 for a description of the DW_CFA_xxx values. Loading Loading @@ -72,7 +75,8 @@ class DwarfCfa { typedef typename std::make_signed<AddressType>::type SignedType; typedef typename std::make_signed<AddressType>::type SignedType; public: public: DwarfCfa(DwarfMemory* memory, const DwarfFde* fde) : memory_(memory), fde_(fde) {} DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch) : memory_(memory), fde_(fde), arch_(arch) {} virtual ~DwarfCfa() = default; virtual ~DwarfCfa() = default; bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, Loading @@ -99,6 +103,7 @@ class DwarfCfa { DwarfErrorData last_error_; DwarfErrorData last_error_; DwarfMemory* memory_; DwarfMemory* memory_; const DwarfFde* fde_; const DwarfFde* fde_; ArchEnum arch_; AddressType cur_pc_; AddressType cur_pc_; const dwarf_loc_regs_t* cie_loc_regs_ = nullptr; const dwarf_loc_regs_t* cie_loc_regs_ = nullptr; Loading Loading @@ -128,6 +133,7 @@ class DwarfCfa { bool cfa_val_offset_sf(dwarf_loc_regs_t*); bool cfa_val_offset_sf(dwarf_loc_regs_t*); bool cfa_val_expression(dwarf_loc_regs_t*); bool cfa_val_expression(dwarf_loc_regs_t*); bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*); bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*); bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*); using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*); using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*); constexpr static process_func kCallbackTable[64] = { constexpr static process_func kCallbackTable[64] = { Loading Loading @@ -221,8 +227,9 @@ class DwarfCfa { nullptr, nullptr, // 0x2c illegal cfa // 0x2c illegal cfa nullptr, nullptr, // 0x2d DW_CFA_GNU_window_save (Treat this as illegal) // 0x2d DW_CFA_AARCH64_negate_ra_state (aarch64 only) nullptr, // DW_CFA_GNU_window_save on other architectures. &DwarfCfa::cfa_aarch64_negate_ra_state, // 0x2e DW_CFA_GNU_args_size // 0x2e DW_CFA_GNU_args_size &DwarfCfa::cfa_nop, &DwarfCfa::cfa_nop, // 0x2f DW_CFA_GNU_negative_offset_extended // 0x2f DW_CFA_GNU_negative_offset_extended Loading
libunwindstack/DwarfSection.cpp +22 −7 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfSection.h> #include <unwindstack/DwarfSection.h> #include <unwindstack/DwarfStructs.h> #include <unwindstack/DwarfStructs.h> #include <unwindstack/Elf.h> #include <unwindstack/Log.h> #include <unwindstack/Log.h> #include <unwindstack/Memory.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> #include <unwindstack/Regs.h> Loading Loading @@ -49,7 +50,7 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f // Now get the location information for this pc. // Now get the location information for this pc. dwarf_loc_regs_t loc_regs; dwarf_loc_regs_t loc_regs; if (!GetCfaLocationInfo(pc, fde, &loc_regs)) { if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) { return false; return false; } } loc_regs.cie = fde->cie; loc_regs.cie = fde->cie; Loading Loading @@ -464,6 +465,13 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3 eval_info->return_address_undefined = true; eval_info->return_address_undefined = true; } } break; break; case DWARF_LOCATION_PSEUDO_REGISTER: { if (!eval_info->regs_info.regs->SetPseudoRegister(reg, loc->values[0])) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } break; } default: default: break; break; } } Loading Loading @@ -491,6 +499,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me // Always set the dex pc to zero when evaluating. // Always set the dex pc to zero when evaluating. cur_regs->set_dex_pc(0); cur_regs->set_dex_pc(0); // Reset necessary pseudo registers before evaluation. // This is needed for ARM64, for example. regs->ResetPseudoRegisters(); EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs, EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs, .cie = cie, .cie = cie, .regular_memory = regular_memory, .regular_memory = regular_memory, Loading Loading @@ -527,9 +539,11 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me AddressType* reg_ptr; AddressType* reg_ptr; if (reg >= cur_regs->total_regs()) { if (reg >= cur_regs->total_regs()) { if (entry.second.type != DWARF_LOCATION_PSEUDO_REGISTER) { // Skip this unknown register. // Skip this unknown register. continue; continue; } } } reg_ptr = eval_info.regs_info.Save(reg); reg_ptr = eval_info.regs_info.Save(reg); if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { Loading @@ -554,8 +568,8 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me template <typename AddressType> template <typename AddressType> bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) { dwarf_loc_regs_t* loc_regs, ArchEnum arch) { DwarfCfa<AddressType> cfa(&memory_, fde); DwarfCfa<AddressType> cfa(&memory_, fde, arch); // Look for the cached copy of the cie data. // Look for the cached copy of the cie data. auto reg_entry = cie_loc_regs_.find(fde->cie_offset); auto reg_entry = cie_loc_regs_.find(fde->cie_offset); Loading @@ -576,8 +590,9 @@ bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfF } } template <typename AddressType> template <typename AddressType> bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) { bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, DwarfCfa<AddressType> cfa(&memory_, fde); ArchEnum arch) { DwarfCfa<AddressType> cfa(&memory_, fde, arch); // Always print the cie information. // Always print the cie information. const DwarfCie* cie = fde->cie; const DwarfCie* cie = fde->cie; Loading
libunwindstack/RegsArm64.cpp +52 −1 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,10 @@ namespace unwindstack { namespace unwindstack { RegsArm64::RegsArm64() RegsArm64::RegsArm64() : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) { ResetPseudoRegisters(); pac_mask_ = 0; } ArchEnum RegsArm64::Arch() { ArchEnum RegsArm64::Arch() { return ARCH_ARM64; return ARCH_ARM64; Loading @@ -45,6 +48,23 @@ uint64_t RegsArm64::sp() { } } void RegsArm64::set_pc(uint64_t pc) { void RegsArm64::set_pc(uint64_t pc) { // If the target is aarch64 then the return address may have been // signed using the Armv8.3-A Pointer Authentication extension. The // original return address can be restored by stripping out the // authentication code using a mask or xpaclri. xpaclri is a NOP on // pre-Armv8.3-A architectures. if ((0 != pc) && IsRASigned()) { if (pac_mask_) { pc &= ~pac_mask_; #if defined(__aarch64__) } else { register uint64_t x30 __asm("x30") = pc; // This is XPACLRI. asm("hint 0x7" : "+r"(x30)); pc = x30; #endif } } regs_[ARM64_REG_PC] = pc; regs_[ARM64_REG_PC] = pc; } } Loading Loading @@ -144,6 +164,37 @@ bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* proce return true; return true; } } void RegsArm64::ResetPseudoRegisters(void) { // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0. this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0); } bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) { if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value; return true; } return false; } bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) { if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST]; return true; } return false; } bool RegsArm64::IsRASigned() { uint64_t value; auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value); return (result && (value != 0)); } void RegsArm64::SetPACMask(uint64_t mask) { pac_mask_ = mask; } Regs* RegsArm64::Clone() { Regs* RegsArm64::Clone() { return new RegsArm64(*this); return new RegsArm64(*this); } } Loading
libunwindstack/include/unwindstack/DwarfLocation.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ enum DwarfLocationEnum : uint8_t { DWARF_LOCATION_REGISTER, DWARF_LOCATION_REGISTER, DWARF_LOCATION_EXPRESSION, DWARF_LOCATION_EXPRESSION, DWARF_LOCATION_VAL_EXPRESSION, DWARF_LOCATION_VAL_EXPRESSION, DWARF_LOCATION_PSEUDO_REGISTER, }; }; struct DwarfLocation { struct DwarfLocation { Loading