diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp index 6b0646fbc..65638aea3 100644 --- a/libunwindstack/ArmExidx.cpp +++ b/libunwindstack/ArmExidx.cpp @@ -57,6 +57,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) { uint32_t data; if (!elf_memory_->Read32(entry_offset + 4, &data)) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = entry_offset + 4; return false; } if (data == 1) { @@ -97,6 +98,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) { uint32_t addr = (entry_offset + 4) + signed_data; if (!elf_memory_->Read32(addr, &data)) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = addr; return false; } @@ -128,6 +130,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) { addr += 4; if (!elf_memory_->Read32(addr, &data)) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = addr; return false; } num_table_words = (data >> 24) & 0xff; @@ -145,6 +148,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) { for (size_t i = 0; i < num_table_words; i++) { if (!elf_memory_->Read32(addr, &data)) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = addr; return false; } data_.push_back((data >> 24) & 0xff); @@ -216,6 +220,7 @@ inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) { if (registers & (1 << reg)) { if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = cfa_; return false; } cfa_ += 4; @@ -284,6 +289,7 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) { for (size_t i = 4; i <= 4 + (byte & 0x7); i++) { if (!process_memory_->Read32(cfa_, &(*regs_)[i])) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = cfa_; return false; } cfa_ += 4; @@ -291,6 +297,7 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) { if (byte & 0x8) { if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = cfa_; return false; } cfa_ += 4; @@ -357,6 +364,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() { if (byte & (1 << reg)) { if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) { status_ = ARM_STATUS_READ_FAILED; + status_address_ = cfa_; return false; } cfa_ += 4; diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h index f4361d43c..96756a017 100644 --- a/libunwindstack/ArmExidx.h +++ b/libunwindstack/ArmExidx.h @@ -61,6 +61,7 @@ class ArmExidx { std::deque* data() { return &data_; } ArmStatus status() { return status_; } + uint64_t status_address() { return status_address_; } RegsArm* regs() { return regs_; } @@ -97,6 +98,7 @@ class ArmExidx { uint32_t cfa_ = 0; std::deque data_; ArmStatus status_ = ARM_STATUS_NONE; + uint64_t status_address_ = 0; Memory* elf_memory_; Memory* process_memory_; diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h index 2d216d78c..9643d7670 100644 --- a/libunwindstack/Check.h +++ b/libunwindstack/Check.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _LIBUNWINDSTACK_ERROR_H -#define _LIBUNWINDSTACK_ERROR_H +#ifndef _LIBUNWINDSTACK_CHECK_H +#define _LIBUNWINDSTACK_CHECK_H #include @@ -31,4 +31,4 @@ namespace unwindstack { } // namespace unwindstack -#endif // _LIBUNWINDSTACK_ERROR_H +#endif // _LIBUNWINDSTACK_CHECK_H diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp index b1d55bae4..4fc95c766 100644 --- a/libunwindstack/DwarfCfa.cpp +++ b/libunwindstack/DwarfCfa.cpp @@ -23,12 +23,12 @@ #include +#include #include #include #include "DwarfCfa.h" #include "DwarfEncoding.h" -#include "DwarfError.h" #include "DwarfOp.h" namespace unwindstack { @@ -44,7 +44,8 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, (*loc_regs)[entry.first] = entry.second; } } - last_error_ = DWARF_ERROR_NONE; + last_error_.code = DWARF_ERROR_NONE; + last_error_.address = 0; memory_->set_cur_offset(start_offset); uint64_t cfa_offset; @@ -54,7 +55,8 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, // Read the cfa information. uint8_t cfa_value; if (!memory_->ReadBytes(&cfa_value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_->cur_offset(); return false; } uint8_t cfa_low = cfa_value & 0x3f; @@ -66,7 +68,8 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, case 2: { uint64_t offset; if (!memory_->ReadULEB128(&offset)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_->cur_offset(); return false; } SignedType signed_offset = @@ -78,7 +81,7 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, case 3: { if (cie_loc_regs_ == nullptr) { log(0, "restore while processing cie"); - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } @@ -93,7 +96,7 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, case 0: { const auto handle_func = DwarfCfa::kCallbackTable[cfa_low]; if (handle_func == nullptr) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } @@ -102,7 +105,8 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, if (cfa->operands[i] == DW_EH_PE_block) { uint64_t block_length; if (!memory_->ReadULEB128(&block_length)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_->cur_offset(); return false; } operands_.push_back(block_length); @@ -111,7 +115,8 @@ bool DwarfCfa::GetLocationInfo(uint64_t pc, uint64_t start_offset, } uint64_t value; if (!memory_->ReadEncodedValue(cfa->operands[i], &value)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_->cur_offset(); return false; } operands_.push_back(value); @@ -334,7 +339,7 @@ bool DwarfCfa::cfa_restore(dwarf_loc_regs_t* loc_regs) { AddressType reg = operands_[0]; if (cie_loc_regs_ == nullptr) { log(0, "restore while processing cie"); - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } auto reg_entry = cie_loc_regs_->find(reg); @@ -396,7 +401,7 @@ bool DwarfCfa::cfa_def_cfa_register(dwarf_loc_regs_t* loc_regs) { auto cfa_location = loc_regs->find(CFA_REG); if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) { log(0, "Attempt to set new register, but cfa is not already set to a register."); - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } @@ -410,7 +415,7 @@ bool DwarfCfa::cfa_def_cfa_offset(dwarf_loc_regs_t* loc_regs) { auto cfa_location = loc_regs->find(CFA_REG); if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) { log(0, "Attempt to set offset, but cfa is not set to a register."); - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } cfa_location->second.values[1] = operands_[0]; @@ -454,7 +459,7 @@ bool DwarfCfa::cfa_def_cfa_offset_sf(dwarf_loc_regs_t* loc_regs) { auto cfa_location = loc_regs->find(CFA_REG); if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) { log(0, "Attempt to set offset, but cfa is not set to a register."); - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } SignedType offset = static_cast(operands_[0]) * fde_->cie->data_alignment_factor; diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h index 62b9b7ac0..16c66e296 100644 --- a/libunwindstack/DwarfCfa.h +++ b/libunwindstack/DwarfCfa.h @@ -24,12 +24,11 @@ #include #include +#include #include #include #include -#include "DwarfError.h" - namespace unwindstack { // DWARF Standard home: http://dwarfstd.org/ @@ -75,7 +74,9 @@ class DwarfCfa { bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset, uint64_t end_offset); - DwarfError last_error() { return last_error_; } + const DwarfErrorData& last_error() { return last_error_; } + DwarfErrorCode LastErrorCode() { return last_error_.code; } + uint64_t LastErrorAddress() { return last_error_.address; } AddressType cur_pc() { return cur_pc_; } @@ -89,7 +90,7 @@ class DwarfCfa { bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc); private: - DwarfError last_error_; + DwarfErrorData last_error_; DwarfMemory* memory_; const DwarfFde* fde_; diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp index e0f1eedf2..a131abea2 100644 --- a/libunwindstack/DwarfEhFrameWithHdr.cpp +++ b/libunwindstack/DwarfEhFrameWithHdr.cpp @@ -16,12 +16,12 @@ #include +#include #include #include #include "Check.h" #include "DwarfEhFrameWithHdr.h" -#include "DwarfError.h" namespace unwindstack { @@ -36,14 +36,15 @@ bool DwarfEhFrameWithHdr::Init(uint64_t offset, uint64_t size) { // Read the first four bytes all at once. if (!memory_.ReadBytes(data, 4)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } version_ = data[0]; if (version_ != 1) { // Unknown version. - last_error_ = DWARF_ERROR_UNSUPPORTED_VERSION; + last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION; return false; } @@ -54,18 +55,20 @@ bool DwarfEhFrameWithHdr::Init(uint64_t offset, uint64_t size) { memory_.set_pc_offset(memory_.cur_offset()); if (!memory_.template ReadEncodedValue(ptr_encoding_, &ptr_offset_)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } memory_.set_pc_offset(memory_.cur_offset()); if (!memory_.template ReadEncodedValue(fde_count_encoding, &fde_count_)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (fde_count_ == 0) { - last_error_ = DWARF_ERROR_NO_FDES; + last_error_.code = DWARF_ERROR_NO_FDES; return false; } @@ -101,7 +104,8 @@ DwarfEhFrameWithHdr::GetFdeInfoFromIndex(size_t index) { uint64_t value; if (!memory_.template ReadEncodedValue(table_encoding_, &value) || !memory_.template ReadEncodedValue(table_encoding_, &info->offset)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); fde_info_.erase(index); return nullptr; } @@ -147,7 +151,9 @@ bool DwarfEhFrameWithHdr::GetFdeOffsetBinary(uint64_t pc, uint64_t* template bool DwarfEhFrameWithHdr::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) { CHECK(fde_count_ != 0); - last_error_ = DWARF_ERROR_NONE; + last_error_.code = DWARF_ERROR_NONE; + last_error_.address = 0; + // We can do a binary search if the pc is in the range of the elements // that have already been cached. if (!fde_info_.empty()) { @@ -176,14 +182,16 @@ bool DwarfEhFrameWithHdr::GetFdeOffsetSequential(uint64_t pc, uint6 memory_.set_pc_offset(memory_.cur_offset()); uint64_t value; if (!memory_.template ReadEncodedValue(table_encoding_, &value)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } FdeInfo* info = &fde_info_[current]; if (!memory_.template ReadEncodedValue(table_encoding_, &info->offset)) { fde_info_.erase(current); - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } info->pc = value + 4; diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp index 3b3d340f4..dcf04e6ff 100644 --- a/libunwindstack/DwarfOp.cpp +++ b/libunwindstack/DwarfOp.cpp @@ -22,12 +22,12 @@ #include +#include #include #include #include #include -#include "DwarfError.h" #include "DwarfOp.h" namespace unwindstack { @@ -48,7 +48,7 @@ bool DwarfOp::Eval(uint64_t start, uint64_t end, uint8_t dwarf_vers // To protect against a branch that creates an infinite loop, // terminate if the number of iterations gets too high. if (iterations++ == 1000) { - last_error_ = DWARF_ERROR_TOO_MANY_ITERATIONS; + last_error_.code = DWARF_ERROR_TOO_MANY_ITERATIONS; return false; } } @@ -57,28 +57,29 @@ bool DwarfOp::Eval(uint64_t start, uint64_t end, uint8_t dwarf_vers template bool DwarfOp::Decode(uint8_t dwarf_version) { - last_error_ = DWARF_ERROR_NONE; + last_error_.code = DWARF_ERROR_NONE; if (!memory_->ReadBytes(&cur_op_, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_->cur_offset(); return false; } const auto* op = &kCallbackTable[cur_op_]; const auto handle_func = op->handle_func; if (handle_func == nullptr) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } // Check for an unsupported opcode. if (dwarf_version < op->supported_version) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } // Make sure that the required number of stack elements is available. if (stack_.size() < op->num_required_stack_values) { - last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID; + last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID; return false; } @@ -86,7 +87,8 @@ bool DwarfOp::Decode(uint8_t dwarf_version) { for (size_t i = 0; i < op->num_operands; i++) { uint64_t value; if (!memory_->ReadEncodedValue(op->operands[i], &value)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_->cur_offset(); return false; } operands_.push_back(value); @@ -142,7 +144,8 @@ bool DwarfOp::op_deref() { AddressType addr = StackPop(); AddressType value; if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = addr; return false; } stack_.push_front(value); @@ -153,14 +156,15 @@ template bool DwarfOp::op_deref_size() { AddressType bytes_to_read = OperandAt(0); if (bytes_to_read > sizeof(AddressType) || bytes_to_read == 0) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } // Read the address and dereference it. AddressType addr = StackPop(); AddressType value = 0; if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = addr; return false; } stack_.push_front(value); @@ -198,7 +202,7 @@ template bool DwarfOp::op_pick() { AddressType index = OperandAt(0); if (index > StackSize()) { - last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID; + last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID; return false; } stack_.push_front(StackAt(index)); @@ -243,7 +247,7 @@ template bool DwarfOp::op_div() { AddressType top = StackPop(); if (top == 0) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } SignedType signed_divisor = static_cast(top); @@ -263,7 +267,7 @@ template bool DwarfOp::op_mod() { AddressType top = StackPop(); if (top == 0) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } stack_[0] %= top; @@ -431,7 +435,7 @@ template bool DwarfOp::op_breg() { uint16_t reg = cur_op() - 0x70; if (reg >= regs_->total_regs()) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } stack_.push_front((*regs_)[reg] + OperandAt(0)); @@ -442,7 +446,7 @@ template bool DwarfOp::op_bregx() { AddressType reg = OperandAt(0); if (reg >= regs_->total_regs()) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } stack_.push_front((*regs_)[reg] + OperandAt(1)); @@ -456,7 +460,7 @@ bool DwarfOp::op_nop() { template bool DwarfOp::op_not_implemented() { - last_error_ = DWARF_ERROR_NOT_IMPLEMENTED; + last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED; return false; } diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h index c29bf35df..40b7b23b7 100644 --- a/libunwindstack/DwarfOp.h +++ b/libunwindstack/DwarfOp.h @@ -24,8 +24,9 @@ #include #include +#include + #include "DwarfEncoding.h" -#include "DwarfError.h" namespace unwindstack { @@ -72,7 +73,9 @@ class DwarfOp { void set_regs(RegsImpl* regs) { regs_ = regs; } - DwarfError last_error() { return last_error_; } + const DwarfErrorData& last_error() { return last_error_; } + DwarfErrorCode LastErrorCode() { return last_error_.code; } + uint64_t LastErrorAddress() { return last_error_.address; } bool is_register() { return is_register_; } @@ -96,7 +99,7 @@ class DwarfOp { RegsImpl* regs_; bool is_register_ = false; - DwarfError last_error_ = DWARF_ERROR_NONE; + DwarfErrorData last_error_{DWARF_ERROR_NONE, 0}; uint8_t cur_op_; std::vector operands_; std::deque stack_; diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 04a1faefa..4e94f887d 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -26,7 +27,6 @@ #include "DwarfCfa.h" #include "DwarfEncoding.h" -#include "DwarfError.h" #include "DwarfOp.h" #include "DwarfDebugFrame.h" @@ -36,7 +36,7 @@ namespace unwindstack { constexpr uint64_t DEX_PC_REG = 0x20444558; -DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {} +DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {} const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) { uint64_t fde_offset; @@ -52,15 +52,15 @@ const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) { if (pc < fde->pc_end) { return fde; } - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return nullptr; } bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) { - last_error_ = DWARF_ERROR_NONE; + last_error_.code = DWARF_ERROR_NONE; const DwarfFde* fde = GetFdeFromPc(pc); if (fde == nullptr || fde->cie == nullptr) { - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } @@ -87,12 +87,12 @@ bool DwarfSectionImpl::EvalExpression(const DwarfLocation& loc, uin return false; } if (op.StackSize() == 0) { - last_error_ = DWARF_ERROR_ILLEGAL_STATE; + last_error_.code = DWARF_ERROR_ILLEGAL_STATE; return false; } // We don't support an expression that evaluates to a register number. if (op.is_register()) { - last_error_ = DWARF_ERROR_NOT_IMPLEMENTED; + last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED; return false; } *value = op.StackAt(0); @@ -119,7 +119,8 @@ bool DwarfSectionImpl::EvalRegister(const DwarfLocation* loc, uint3 switch (loc->type) { case DWARF_LOCATION_OFFSET: if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = eval_info->cfa + loc->values[0]; return false; } break; @@ -129,7 +130,7 @@ bool DwarfSectionImpl::EvalRegister(const DwarfLocation* loc, uint3 case DWARF_LOCATION_REGISTER: { uint32_t cur_reg = loc->values[0]; if (cur_reg >= eval_info->cur_regs->total_regs()) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg]; @@ -158,7 +159,8 @@ bool DwarfSectionImpl::EvalRegister(const DwarfLocation* loc, uint3 } if (loc->type == DWARF_LOCATION_EXPRESSION) { if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = value; return false; } } else { @@ -183,14 +185,14 @@ bool DwarfSectionImpl::Eval(const DwarfCie* cie, Memory* regular_me bool* finished) { RegsImpl* cur_regs = reinterpret_cast*>(regs); if (cie->return_address_register >= cur_regs->total_regs()) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } // Get the cfa value; auto cfa_entry = loc_regs.find(CFA_REG); if (cfa_entry == loc_regs.end()) { - last_error_ = DWARF_ERROR_CFA_NOT_DEFINED; + last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED; return false; } @@ -206,7 +208,7 @@ bool DwarfSectionImpl::Eval(const DwarfCie* cie, Memory* regular_me switch (loc->type) { case DWARF_LOCATION_REGISTER: if (loc->values[0] >= cur_regs->total_regs()) { - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } // If the stack pointer register is the CFA, and the stack @@ -227,7 +229,8 @@ bool DwarfSectionImpl::Eval(const DwarfCie* cie, Memory* regular_me } if (loc->type == DWARF_LOCATION_EXPRESSION) { if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = value; return false; } } else { @@ -236,7 +239,7 @@ bool DwarfSectionImpl::Eval(const DwarfCie* cie, Memory* regular_me break; } default: - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } @@ -305,7 +308,8 @@ template bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { uint32_t length32; if (!memory_.ReadBytes(&length32, sizeof(length32))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } // Set the default for the lsda encoding. @@ -315,7 +319,8 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { // 64 bit Cie uint64_t length64; if (!memory_.ReadBytes(&length64, sizeof(length64))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -324,12 +329,13 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { uint64_t cie_id; if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (cie_id != cie64_value_) { // This is not a Cie, something has gone horribly wrong. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } } else { @@ -339,24 +345,26 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { uint32_t cie_id; if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (cie_id != cie32_value_) { // This is not a Cie, something has gone horribly wrong. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } } if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (cie->version != 1 && cie->version != 3 && cie->version != 4) { // Unrecognized version. - last_error_ = DWARF_ERROR_UNSUPPORTED_VERSION; + last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION; return false; } @@ -364,7 +372,8 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { char aug_value; do { if (!memory_.ReadBytes(&aug_value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } cie->augmentation_string.push_back(aug_value); @@ -376,20 +385,23 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { // Segment Size if (!memory_.ReadBytes(&cie->segment_size, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } // Code Alignment Factor if (!memory_.ReadULEB128(&cie->code_alignment_factor)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } // Data Alignment Factor if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -397,12 +409,14 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { // Return Address is a single byte. uint8_t return_address_register; if (!memory_.ReadBytes(&return_address_register, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } cie->return_address_register = return_address_register; } else if (!memory_.ReadULEB128(&cie->return_address_register)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -413,7 +427,8 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { uint64_t aug_length; if (!memory_.ReadULEB128(&aug_length)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } cie->cfa_instructions_offset = memory_.cur_offset() + aug_length; @@ -422,24 +437,28 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { switch (cie->augmentation_string[i]) { case 'L': if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } break; case 'P': { uint8_t encoding; if (!memory_.ReadBytes(&encoding, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (!memory_.ReadEncodedValue(encoding, &cie->personality_handler)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } break; case 'R': if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } break; @@ -467,7 +486,8 @@ template bool DwarfSectionImpl::FillInFde(DwarfFde* fde) { uint32_t length32; if (!memory_.ReadBytes(&length32, sizeof(length32))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -475,19 +495,21 @@ bool DwarfSectionImpl::FillInFde(DwarfFde* fde) { // 64 bit Fde. uint64_t length64; if (!memory_.ReadBytes(&length64, sizeof(length64))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } fde->cfa_instructions_end = memory_.cur_offset() + length64; uint64_t value64; if (!memory_.ReadBytes(&value64, sizeof(value64))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (value64 == cie64_value_) { // This is a Cie, this means something has gone wrong. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } @@ -500,12 +522,13 @@ bool DwarfSectionImpl::FillInFde(DwarfFde* fde) { uint32_t value32; if (!memory_.ReadBytes(&value32, sizeof(value32))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (value32 == cie32_value_) { // This is a Cie, this means something has gone wrong. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } @@ -528,13 +551,15 @@ bool DwarfSectionImpl::FillInFde(DwarfFde* fde) { memory_.set_cur_offset(cur_offset); if (!memory_.ReadEncodedValue(cie->fde_address_encoding & 0xf, &fde->pc_start)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } fde->pc_start = AdjustPcFromFde(fde->pc_start); if (!memory_.ReadEncodedValue(cie->fde_address_encoding & 0xf, &fde->pc_end)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } fde->pc_end += fde->pc_start; @@ -542,13 +567,15 @@ bool DwarfSectionImpl::FillInFde(DwarfFde* fde) { // Augmentation Size uint64_t aug_length; if (!memory_.ReadULEB128(&aug_length)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } uint64_t cur_offset = memory_.cur_offset(); if (!memory_.ReadEncodedValue(cie->lsda_encoding, &fde->lsda_address)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -619,7 +646,8 @@ template bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) { uint8_t version; if (!memory_.ReadBytes(&version, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } // Read the augmentation string. @@ -628,7 +656,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e bool get_encoding = false; do { if (!memory_.ReadBytes(&aug_value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (aug_value == 'R') { @@ -643,7 +672,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e // Read the segment size. if (!memory_.ReadBytes(segment_size, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } else { @@ -659,7 +689,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e uint8_t value; do { if (!memory_.ReadBytes(&value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } while (value & 0x80); @@ -667,7 +698,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e // Skip data alignment factor do { if (!memory_.ReadBytes(&value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } while (value & 0x80); @@ -679,7 +711,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e // Skip return address register. do { if (!memory_.ReadBytes(&value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } while (value & 0x80); @@ -688,7 +721,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e // Skip the augmentation length. do { if (!memory_.ReadBytes(&value, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } while (value & 0x80); @@ -696,7 +730,8 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e for (size_t i = 1; i < aug_string.size(); i++) { if (aug_string[i] == 'R') { if (!memory_.ReadBytes(encoding, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } // Got the encoding, that's all we are looking for. @@ -706,12 +741,14 @@ bool DwarfSectionImpl::GetCieInfo(uint8_t* segment_size, uint8_t* e } else if (aug_string[i] == 'P') { uint8_t encoding; if (!memory_.ReadBytes(&encoding, 1)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } uint64_t value; if (!memory_.template ReadEncodedValue(encoding, &value)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } } @@ -730,14 +767,16 @@ bool DwarfSectionImpl::AddFdeInfo(uint64_t entry_offset, uint8_t se uint64_t start; if (!memory_.template ReadEncodedValue(encoding & 0xf, &start)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } start = AdjustPcFromFde(start); uint64_t length; if (!memory_.template ReadEncodedValue(encoding & 0xf, &length)) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } if (length != 0) { @@ -764,7 +803,8 @@ bool DwarfSectionImpl::CreateSortedFdeList() { // Figure out the entry length and type. uint32_t value32; if (!memory_.ReadBytes(&value32, sizeof(value32))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -772,14 +812,16 @@ bool DwarfSectionImpl::CreateSortedFdeList() { if (value32 == static_cast(-1)) { uint64_t value64; if (!memory_.ReadBytes(&value64, sizeof(value64))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } next_entry_offset = memory_.cur_offset() + value64; // Read the Cie Id of a Cie or the pointer of the Fde. if (!memory_.ReadBytes(&value64, sizeof(value64))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -794,7 +836,7 @@ bool DwarfSectionImpl::CreateSortedFdeList() { uint64_t last_cie_offset = GetCieOffsetFromFde64(value64); if (last_cie_offset != cie_offset) { // This means that this Fde is not following the Cie. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } @@ -808,7 +850,8 @@ bool DwarfSectionImpl::CreateSortedFdeList() { // Read the Cie Id of a Cie or the pointer of the Fde. if (!memory_.ReadBytes(&value32, sizeof(value32))) { - last_error_ = DWARF_ERROR_MEMORY_INVALID; + last_error_.code = DWARF_ERROR_MEMORY_INVALID; + last_error_.address = memory_.cur_offset(); return false; } @@ -823,7 +866,7 @@ bool DwarfSectionImpl::CreateSortedFdeList() { uint64_t last_cie_offset = GetCieOffsetFromFde32(value32); if (last_cie_offset != cie_offset) { // This means that this Fde is not following the Cie. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 220e549aa..f120da2b2 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -134,6 +134,26 @@ bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) { return true; } +void Elf::GetLastError(ErrorData* data) { + if (valid_) { + *data = interface_->last_error(); + } +} + +ErrorCode Elf::GetLastErrorCode() { + if (valid_) { + return interface_->LastErrorCode(); + } + return ERROR_NONE; +} + +uint64_t Elf::GetLastErrorAddress() { + if (valid_) { + return interface_->LastErrorAddress(); + } + return 0; +} + // The relative pc is always relative to the start of the map from which it comes. bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory, bool* finished) { diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 17cc16a9f..e41308171 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -160,6 +161,8 @@ template bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) { EhdrType ehdr; if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = 0; return false; } @@ -201,6 +204,9 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) { PhdrType phdr; if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = + offset + reinterpret_cast(&phdr.p_type) - reinterpret_cast(&phdr); return false; } @@ -213,6 +219,9 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) { // Get the flags first, if this isn't an executable header, ignore it. if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_flags) - + reinterpret_cast(&phdr); return false; } if ((phdr.p_flags & PF_X) == 0) { @@ -220,12 +229,21 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) } if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_vaddr) - + reinterpret_cast(&phdr); return false; } if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_offset) - + reinterpret_cast(&phdr); return false; } if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_memsz) - + reinterpret_cast(&phdr); return false; } pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr, @@ -238,11 +256,17 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) case PT_GNU_EH_FRAME: if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_offset) - + reinterpret_cast(&phdr); return false; } // This is really the pointer to the .eh_frame_hdr section. eh_frame_hdr_offset_ = phdr.p_offset; if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_memsz) - + reinterpret_cast(&phdr); return false; } eh_frame_hdr_size_ = phdr.p_memsz; @@ -250,14 +274,23 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) case PT_DYNAMIC: if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_offset) - + reinterpret_cast(&phdr); return false; } dynamic_offset_ = phdr.p_offset; if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_vaddr) - + reinterpret_cast(&phdr); return false; } dynamic_vaddr_ = phdr.p_vaddr; if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&phdr.p_memsz) - + reinterpret_cast(&phdr); return false; } dynamic_size_ = phdr.p_memsz; @@ -290,31 +323,47 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { offset += ehdr.e_shentsize; for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = + offset + reinterpret_cast(&shdr.sh_type) - reinterpret_cast(&shdr); return false; } if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset; return false; } // Need to go get the information about the section that contains // the string terminated names. ShdrType str_shdr; if (shdr.sh_link >= ehdr.e_shnum) { + last_error_.code = ERROR_UNWIND_INFO; return false; } uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize; if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = str_offset + reinterpret_cast(&str_shdr.sh_type) - + reinterpret_cast(&str_shdr); return false; } if (str_shdr.sh_type != SHT_STRTAB) { + last_error_.code = ERROR_UNWIND_INFO; return false; } if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset, sizeof(str_shdr.sh_offset))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = str_offset + reinterpret_cast(&str_shdr.sh_offset) - + reinterpret_cast(&str_shdr); return false; } if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = str_offset + reinterpret_cast(&str_shdr.sh_size) - + reinterpret_cast(&str_shdr); return false; } symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, @@ -322,6 +371,9 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) { // Look for the .debug_frame and .gnu_debugdata. if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset + reinterpret_cast(&shdr.sh_name) - + reinterpret_cast(&shdr); return false; } if (shdr.sh_name < sec_size) { @@ -377,6 +429,8 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) { uint64_t max_offset = offset + dynamic_size_; for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) { if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset; return false; } @@ -434,8 +488,12 @@ bool ElfInterface::GetGlobalVariableWithTemplate(const std::string& name, uint64 bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory, bool* finished) { + last_error_.code = ERROR_NONE; + last_error_.address = 0; + // Adjust the load bias to get the real relative pc. if (pc < load_bias) { + last_error_.code = ERROR_UNWIND_INFO; return false; } uint64_t adjusted_pc = pc - load_bias; @@ -458,6 +516,46 @@ bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* pro gnu_debugdata_interface_->Step(pc, 0, regs, process_memory, finished)) { return true; } + + // Set the error code based on the first error encountered. + DwarfSection* section = nullptr; + if (debug_frame_ != nullptr) { + section = debug_frame_.get(); + } else if (eh_frame_ != nullptr) { + section = eh_frame_.get(); + } else if (gnu_debugdata_interface_ != nullptr) { + last_error_ = gnu_debugdata_interface_->last_error(); + return false; + } else { + return false; + } + + // Convert the DWARF ERROR to an external error. + DwarfErrorCode code = section->LastErrorCode(); + switch (code) { + case DWARF_ERROR_NONE: + last_error_.code = ERROR_NONE; + break; + + case DWARF_ERROR_MEMORY_INVALID: + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = section->LastErrorAddress(); + break; + + case DWARF_ERROR_ILLEGAL_VALUE: + case DWARF_ERROR_ILLEGAL_STATE: + case DWARF_ERROR_STACK_INDEX_NOT_VALID: + case DWARF_ERROR_TOO_MANY_ITERATIONS: + case DWARF_ERROR_CFA_NOT_DEFINED: + case DWARF_ERROR_NO_FDES: + last_error_.code = ERROR_UNWIND_INFO; + break; + + case DWARF_ERROR_NOT_IMPLEMENTED: + case DWARF_ERROR_UNSUPPORTED_VERSION: + last_error_.code = ERROR_UNSUPPORTED; + break; + } return false; } diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp index 5d99bd791..616d1b1a1 100644 --- a/libunwindstack/ElfInterfaceArm.cpp +++ b/libunwindstack/ElfInterfaceArm.cpp @@ -28,6 +28,7 @@ namespace unwindstack { bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) { if (start_offset_ == 0 || total_entries_ == 0) { + last_error_.code = ERROR_UNWIND_INFO; return false; } @@ -56,12 +57,15 @@ bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) { *entry_offset = start_offset_ + (last - 1) * 8; return true; } + last_error_.code = ERROR_UNWIND_INFO; return false; } bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) { uint32_t data; if (!memory_->Read32(offset, &data)) { + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = offset; return false; } @@ -106,6 +110,7 @@ bool ElfInterfaceArm::StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Mem bool* finished) { // Adjust the load bias to get the real relative pc. if (pc < load_bias) { + last_error_.code = ERROR_UNWIND_INFO; return false; } pc -= load_bias; @@ -139,6 +144,30 @@ bool ElfInterfaceArm::StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Mem *finished = true; return true; } + + if (!return_value) { + switch (arm.status()) { + case ARM_STATUS_NONE: + case ARM_STATUS_NO_UNWIND: + case ARM_STATUS_FINISH: + last_error_.code = ERROR_NONE; + break; + + case ARM_STATUS_RESERVED: + case ARM_STATUS_SPARE: + case ARM_STATUS_TRUNCATED: + case ARM_STATUS_MALFORMED: + case ARM_STATUS_INVALID_ALIGNMENT: + case ARM_STATUS_INVALID_PERSONALITY: + last_error_.code = ERROR_UNWIND_INFO; + break; + + case ARM_STATUS_READ_FAILED: + last_error_.code = ERROR_MEMORY_INVALID; + last_error_.address = arm.status_address(); + break; + } + } return return_value; } diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index d71177290..f70ed7b2a 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -78,6 +78,8 @@ static bool ShouldStop(const std::vector* map_suffixes_to_ignore, void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, const std::vector* map_suffixes_to_ignore) { frames_.clear(); + last_error_.code = ERROR_NONE; + last_error_.address = 0; bool return_address_attempt = false; bool adjust_pc = false; @@ -95,6 +97,7 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, rel_pc = regs_->pc(); adjusted_rel_pc = rel_pc; adjusted_pc = rel_pc; + last_error_.code = ERROR_INVALID_MAP; } else { if (ShouldStop(map_suffixes_to_ignore, map_info->name)) { break; @@ -155,6 +158,7 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, bool finished; stepped = elf->Step(rel_pc, adjusted_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished); + elf->GetLastError(&last_error_); if (stepped && finished) { break; } @@ -180,10 +184,14 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, } } else { return_address_attempt = false; + if (max_frames_ == frames_.size()) { + last_error_.code = ERROR_MAX_FRAMES_EXCEEDED; + } } // If the pc and sp didn't change, then consider everything stopped. if (cur_pc == regs_->pc() && cur_sp == regs_->sp()) { + last_error_.code = ERROR_REPEATED_FRAME; break; } } diff --git a/libunwindstack/include/unwindstack/DwarfError.h b/libunwindstack/include/unwindstack/DwarfError.h new file mode 100644 index 000000000..763e2cbfe --- /dev/null +++ b/libunwindstack/include/unwindstack/DwarfError.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_DWARF_ERROR_H +#define _LIBUNWINDSTACK_DWARF_ERROR_H + +#include + +namespace unwindstack { + +enum DwarfErrorCode : uint8_t { + DWARF_ERROR_NONE, + DWARF_ERROR_MEMORY_INVALID, + DWARF_ERROR_ILLEGAL_VALUE, + DWARF_ERROR_ILLEGAL_STATE, + DWARF_ERROR_STACK_INDEX_NOT_VALID, + DWARF_ERROR_NOT_IMPLEMENTED, + DWARF_ERROR_TOO_MANY_ITERATIONS, + DWARF_ERROR_CFA_NOT_DEFINED, + DWARF_ERROR_UNSUPPORTED_VERSION, + DWARF_ERROR_NO_FDES, +}; + +struct DwarfErrorData { + DwarfErrorCode code; + uint64_t address; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_DWARF_ERROR_H diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index e0004aa46..03f40d699 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,6 @@ namespace unwindstack { // Forward declarations. -enum DwarfError : uint8_t; class Memory; class Regs; @@ -72,7 +72,8 @@ class DwarfSection { iterator begin() { return iterator(this, 0); } iterator end() { return iterator(this, fde_count_); } - DwarfError last_error() { return last_error_; } + DwarfErrorCode LastErrorCode() { return last_error_.code; } + uint64_t LastErrorAddress() { return last_error_.address; } virtual bool Init(uint64_t offset, uint64_t size) = 0; @@ -100,7 +101,7 @@ class DwarfSection { protected: DwarfMemory memory_; - DwarfError last_error_; + DwarfErrorData last_error_{DWARF_ERROR_NONE, 0}; uint32_t cie32_value_ = 0; uint64_t cie64_value_ = 0; diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index 5f343916a..e562d6de9 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h @@ -72,6 +72,10 @@ class Elf { bool IsValidPc(uint64_t pc); + void GetLastError(ErrorData* data); + ErrorCode GetLastErrorCode(); + uint64_t GetLastErrorAddress(); + bool valid() { return valid_; } uint32_t machine_type() { return machine_type_; } diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index faa61ee97..ea9ec9dac 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -26,6 +26,7 @@ #include #include +#include namespace unwindstack { @@ -90,6 +91,10 @@ class ElfInterface { DwarfSection* eh_frame() { return eh_frame_.get(); } DwarfSection* debug_frame() { return debug_frame_.get(); } + const ErrorData& last_error() { return last_error_; } + ErrorCode LastErrorCode() { return last_error_.code; } + uint64_t LastErrorAddress() { return last_error_.address; } + template static uint64_t GetLoadBias(Memory* memory); @@ -144,6 +149,8 @@ class ElfInterface { uint8_t soname_type_ = SONAME_UNKNOWN; std::string soname_; + ErrorData last_error_{ERROR_NONE, 0}; + std::unique_ptr eh_frame_; std::unique_ptr debug_frame_; // The Elf object owns the gnu_debugdata interface object. diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h new file mode 100644 index 000000000..6ed0e0fb0 --- /dev/null +++ b/libunwindstack/include/unwindstack/Error.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_ERROR_H +#define _LIBUNWINDSTACK_ERROR_H + +#include + +namespace unwindstack { + +enum ErrorCode : uint8_t { + ERROR_NONE, // No error. + ERROR_MEMORY_INVALID, // Memory read failed. + ERROR_UNWIND_INFO, // Unable to use unwind information to unwind. + ERROR_UNSUPPORTED, // Encountered unsupported feature. + ERROR_INVALID_MAP, // Unwind in an invalid map. + ERROR_MAX_FRAMES_EXCEEDED, // The number of frames exceed the total allowed. + ERROR_REPEATED_FRAME, // The last frame has the same pc/sp as the next. +}; + +struct ErrorData { + ErrorCode code; + uint64_t address; // Only valid when code is ERROR_MEMORY_INVALID. + // Indicates the failing address. +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_ERROR_H diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index 32858ae52..a7b57e6a7 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -74,6 +75,9 @@ class Unwinder { void SetJitDebug(JitDebug* jit_debug, ArchEnum arch); + ErrorCode LastErrorCode() { return last_error_.code; } + uint64_t LastErrorAddress() { return last_error_.address; } + private: void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc); @@ -83,6 +87,7 @@ class Unwinder { std::vector frames_; std::shared_ptr process_memory_; JitDebug* jit_debug_ = nullptr; + ErrorData last_error_; }; } // namespace unwindstack diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp index caad13165..8d0f0e599 100644 --- a/libunwindstack/tests/ArmExidxExtractTest.cpp +++ b/libunwindstack/tests/ArmExidxExtractTest.cpp @@ -257,22 +257,27 @@ TEST_F(ArmExidxExtractTest, second_read_not_compact) { TEST_F(ArmExidxExtractTest, read_failures) { ASSERT_FALSE(exidx_->ExtractEntryData(0x5000)); ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status()); + EXPECT_EQ(0x5004U, exidx_->status_address()); elf_memory_.SetData32(0x5000, 0x100); ASSERT_FALSE(exidx_->ExtractEntryData(0x5000)); ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status()); + EXPECT_EQ(0x5004U, exidx_->status_address()); elf_memory_.SetData32(0x5004, 0x100); ASSERT_FALSE(exidx_->ExtractEntryData(0x5000)); ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status()); + EXPECT_EQ(0x5104U, exidx_->status_address()); elf_memory_.SetData32(0x5104, 0x1); ASSERT_FALSE(exidx_->ExtractEntryData(0x5000)); ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status()); + EXPECT_EQ(0x5108U, exidx_->status_address()); elf_memory_.SetData32(0x5108, 0x01010203); ASSERT_FALSE(exidx_->ExtractEntryData(0x5000)); ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status()); + EXPECT_EQ(0x510cU, exidx_->status_address()); } TEST_F(ArmExidxExtractTest, malformed) { diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp index 73a67ac6a..68dc30cd9 100644 --- a/libunwindstack/tests/DwarfCfaTest.cpp +++ b/libunwindstack/tests/DwarfCfaTest.cpp @@ -21,13 +21,13 @@ #include +#include #include #include #include #include #include "DwarfCfa.h" -#include "DwarfError.h" #include "LogFake.h" #include "MemoryFake.h" @@ -78,7 +78,7 @@ TYPED_TEST_P(DwarfCfaTest, cfa_illegal) { dwarf_loc_regs_t loc_regs; ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode()); ASSERT_EQ(0x2001U, this->dmem_->cur_offset()); ASSERT_EQ("", GetFakeLogPrint()); @@ -198,7 +198,7 @@ TYPED_TEST_P(DwarfCfaTest, cfa_restore) { dwarf_loc_regs_t loc_regs; ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode()); ASSERT_EQ(0x2001U, this->dmem_->cur_offset()); ASSERT_EQ(0U, loc_regs.size()); @@ -227,7 +227,7 @@ TYPED_TEST_P(DwarfCfaTest, cfa_restore_extended) { dwarf_loc_regs_t loc_regs; ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4000, 0x4002, &loc_regs)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode()); ASSERT_EQ(0x4002U, this->dmem_->cur_offset()); ASSERT_EQ(0U, loc_regs.size()); @@ -594,7 +594,7 @@ TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_register) { // This fails because the cfa is not defined as a register. ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs)); ASSERT_EQ(0U, loc_regs.size()); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode()); ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n", GetFakeLogPrint()); @@ -637,7 +637,7 @@ TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_offset) { // This fails because the cfa is not defined as a register. ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs)); ASSERT_EQ(0U, loc_regs.size()); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode()); ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n", GetFakeLogPrint()); @@ -679,7 +679,7 @@ TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_offset_sf) { // This fails because the cfa is not defined as a register. ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode()); ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n", GetFakeLogPrint()); diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp index 243198e4f..c28a41edb 100644 --- a/libunwindstack/tests/DwarfDebugFrameTest.cpp +++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp @@ -19,9 +19,10 @@ #include #include +#include + #include "DwarfDebugFrame.h" #include "DwarfEncoding.h" -#include "DwarfError.h" #include "LogFake.h" #include "MemoryFake.h" @@ -142,7 +143,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init32_fde_not_following_cie) { this->memory_.SetData32(0x510c, 0x200); ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) { @@ -267,7 +268,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init64_fde_not_following_cie) { this->memory_.SetData64(0x511c, 0x200); ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) { @@ -404,11 +405,11 @@ TYPED_TEST_P(DwarfDebugFrameTest, GetFdeOffsetFromPc) { this->debug_frame_->TestSetFdeCount(0); uint64_t fde_offset; ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset)); - ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode()); this->debug_frame_->TestSetFdeCount(9); ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset)); - ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode()); // Odd number of elements. for (size_t i = 0; i < 9; i++) { TypeParam pc = 0x1000 * (i + 1); @@ -422,7 +423,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, GetFdeOffsetFromPc) { EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i; ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset)) << "Failed at index " << i; - ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode()); } // Even number of elements. @@ -444,7 +445,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, GetFdeOffsetFromPc) { EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i; ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset)) << "Failed at index " << i; - ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode()); } } diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp index 3a629f886..a73db6580 100644 --- a/libunwindstack/tests/DwarfEhFrameTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameTest.cpp @@ -19,9 +19,10 @@ #include #include +#include + #include "DwarfEhFrame.h" #include "DwarfEncoding.h" -#include "DwarfError.h" #include "LogFake.h" #include "MemoryFake.h" @@ -142,7 +143,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) { this->memory_.SetData32(0x510c, 0x200); ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfEhFrameTest, Init64) { @@ -228,7 +229,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) { this->memory_.SetData64(0x511c, 0x200); ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfEhFrameTest, Init_version1) { @@ -320,11 +321,11 @@ TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) { this->eh_frame_->TestSetFdeCount(0); uint64_t fde_offset; ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset)); - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); this->eh_frame_->TestSetFdeCount(9); ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset)); - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); // Odd number of elements. for (size_t i = 0; i < 9; i++) { TypeParam pc = 0x1000 * (i + 1); @@ -337,7 +338,7 @@ TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) { EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i; ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset)) << "Failed at index " << i; - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); } // Even number of elements. @@ -358,7 +359,7 @@ TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) { EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i; ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset)) << "Failed at index " << i; - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); } } diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp index ef2fb32ab..a2ae5ebf7 100644 --- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp @@ -19,9 +19,10 @@ #include #include +#include + #include "DwarfEhFrameWithHdr.h" #include "DwarfEncoding.h" -#include "DwarfError.h" #include "LogFake.h" #include "MemoryFake.h" @@ -97,25 +98,29 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init) { // Verify a zero fde count fails to init. this->memory_.SetData32(0x1006, 0); ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100)); - ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->LastErrorCode()); // Verify an unexpected version will cause a fail. this->memory_.SetData32(0x1006, 126); this->memory_.SetData8(0x1000, 0); ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100)); - ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode()); this->memory_.SetData8(0x1000, 2); ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100)); - ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) { this->eh_frame_->TestSetTableEntrySize(0x10); this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4); + this->eh_frame_->TestSetEntriesOffset(0x1000); + ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr); - ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode()); + EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress()); ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr); - ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode()); + EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress()); } TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) { @@ -184,7 +189,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetBinary_verify) { uint64_t fde_offset; EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10)); // Not an error, just not found. - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); // Even number of elements. for (size_t i = 0; i < 10; i++) { TypeParam pc = 0x1000 * (i + 1); @@ -280,7 +285,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_end_check) { uint64_t fde_offset; ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset)); - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) { @@ -288,7 +293,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) { uint64_t fde_offset; ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset)); - ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode()); } TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) { diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp index 234d1c97d..3f09dd87e 100644 --- a/libunwindstack/tests/DwarfOpLogTest.cpp +++ b/libunwindstack/tests/DwarfOpLogTest.cpp @@ -21,11 +21,11 @@ #include +#include #include #include #include -#include "DwarfError.h" #include "DwarfOp.h" #include "MemoryFake.h" diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp index 2d5007b8f..036226d03 100644 --- a/libunwindstack/tests/DwarfOpTest.cpp +++ b/libunwindstack/tests/DwarfOpTest.cpp @@ -21,10 +21,10 @@ #include +#include #include #include -#include "DwarfError.h" #include "DwarfOp.h" #include "MemoryFake.h" @@ -53,13 +53,14 @@ TYPED_TEST_CASE_P(DwarfOpTest); TYPED_TEST_P(DwarfOpTest, decode) { // Memory error. ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode()); + EXPECT_EQ(0U, this->op_->LastErrorAddress()); // No error. this->op_memory_.SetMemory(0, std::vector{0x96}); this->mem_->set_cur_offset(0); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode()); ASSERT_EQ(0x96U, this->op_->cur_op()); ASSERT_EQ(1U, this->mem_->cur_offset()); } @@ -67,7 +68,8 @@ TYPED_TEST_P(DwarfOpTest, decode) { TYPED_TEST_P(DwarfOpTest, eval) { // Memory error. ASSERT_FALSE(this->op_->Eval(0, 2, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode()); + EXPECT_EQ(0U, this->op_->LastErrorAddress()); // Register set. // Do this first, to verify that subsequent calls reset the value. @@ -84,7 +86,7 @@ TYPED_TEST_P(DwarfOpTest, eval) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_TRUE(this->op_->Eval(0, 8, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode()); ASSERT_FALSE(this->op_->is_register()); ASSERT_EQ(8U, this->mem_->cur_offset()); ASSERT_EQ(4U, this->op_->StackSize()); @@ -96,7 +98,7 @@ TYPED_TEST_P(DwarfOpTest, eval) { // Infinite loop. this->op_memory_.SetMemory(0, std::vector{0x2f, 0xfd, 0xff}); ASSERT_FALSE(this->op_->Eval(0, 4, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->LastErrorCode()); ASSERT_FALSE(this->op_->is_register()); ASSERT_EQ(0U, this->op_->StackSize()); } @@ -111,7 +113,7 @@ TYPED_TEST_P(DwarfOpTest, illegal_opcode) { for (size_t i = 0; i < opcode_buffer.size(); i++) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); ASSERT_EQ(opcode_buffer[i], this->op_->cur_op()); } } @@ -122,7 +124,7 @@ TYPED_TEST_P(DwarfOpTest, illegal_in_version3) { for (size_t i = 0; i < opcode_buffer.size(); i++) { ASSERT_FALSE(this->op_->Decode(2)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); ASSERT_EQ(opcode_buffer[i], this->op_->cur_op()); } } @@ -133,7 +135,7 @@ TYPED_TEST_P(DwarfOpTest, illegal_in_version4) { for (size_t i = 0; i < opcode_buffer.size(); i++) { ASSERT_FALSE(this->op_->Decode(3)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); ASSERT_EQ(opcode_buffer[i], this->op_->cur_op()); } } @@ -178,7 +180,7 @@ TYPED_TEST_P(DwarfOpTest, not_implemented) { while (this->mem_->cur_offset() < opcode_buffer.size()) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->LastErrorCode()); } } @@ -216,7 +218,7 @@ TYPED_TEST_P(DwarfOpTest, op_deref) { this->regular_memory_.SetMemory(0x2010, &value, sizeof(value)); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); @@ -226,7 +228,8 @@ TYPED_TEST_P(DwarfOpTest, op_deref) { ASSERT_EQ(value, this->op_->StackAt(0)); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode()); + ASSERT_EQ(0x12345678U, this->op_->LastErrorAddress()); } TYPED_TEST_P(DwarfOpTest, op_deref_size) { @@ -235,7 +238,7 @@ TYPED_TEST_P(DwarfOpTest, op_deref_size) { this->regular_memory_.SetMemory(0x2010, &value, sizeof(value)); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); // Read all byte sizes up to the sizeof the type. for (size_t i = 1; i < sizeof(TypeParam); i++) { @@ -252,17 +255,18 @@ TYPED_TEST_P(DwarfOpTest, op_deref_size) { // Zero byte read. this->op_memory_.SetMemory(0, std::vector{0x0a, 0x10, 0x20, 0x94, 0x00}); ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); // Read too many bytes. this->op_memory_.SetMemory(0, std::vector{0x0a, 0x10, 0x20, 0x94, sizeof(TypeParam) + 1}); ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); // Force bad memory read. this->op_memory_.SetMemory(0, std::vector{0x0a, 0x10, 0x40, 0x94, 0x01}); ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode()); + EXPECT_EQ(0x4010U, this->op_->LastErrorAddress()); } TYPED_TEST_P(DwarfOpTest, const_unsigned) { @@ -529,7 +533,7 @@ TYPED_TEST_P(DwarfOpTest, op_dup) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(0x12, this->op_->cur_op()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); @@ -577,7 +581,7 @@ TYPED_TEST_P(DwarfOpTest, op_drop) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(0x13, this->op_->cur_op()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_over) { @@ -612,7 +616,7 @@ TYPED_TEST_P(DwarfOpTest, op_over) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(0x14, this->op_->cur_op()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_pick) { @@ -654,7 +658,7 @@ TYPED_TEST_P(DwarfOpTest, op_pick) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(0x15, this->op_->cur_op()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_swap) { @@ -686,7 +690,7 @@ TYPED_TEST_P(DwarfOpTest, op_swap) { ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(0x16, this->op_->cur_op()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_rot) { @@ -703,19 +707,19 @@ TYPED_TEST_P(DwarfOpTest, op_rot) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(3U, this->op_->StackSize()); @@ -753,7 +757,7 @@ TYPED_TEST_P(DwarfOpTest, op_abs) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); @@ -805,13 +809,13 @@ TYPED_TEST_P(DwarfOpTest, op_and) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); // Two positive values. ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); @@ -854,7 +858,7 @@ TYPED_TEST_P(DwarfOpTest, op_and) { ASSERT_EQ(5U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_div) { @@ -871,13 +875,13 @@ TYPED_TEST_P(DwarfOpTest, op_div) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -902,13 +906,13 @@ TYPED_TEST_P(DwarfOpTest, op_minus) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -935,13 +939,13 @@ TYPED_TEST_P(DwarfOpTest, op_mod) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -957,7 +961,7 @@ TYPED_TEST_P(DwarfOpTest, op_mod) { ASSERT_EQ(3U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_mul) { @@ -974,13 +978,13 @@ TYPED_TEST_P(DwarfOpTest, op_mul) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1003,7 +1007,7 @@ TYPED_TEST_P(DwarfOpTest, op_neg) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); @@ -1034,7 +1038,7 @@ TYPED_TEST_P(DwarfOpTest, op_not) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); @@ -1067,13 +1071,13 @@ TYPED_TEST_P(DwarfOpTest, op_or) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1098,13 +1102,13 @@ TYPED_TEST_P(DwarfOpTest, op_plus) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1125,7 +1129,7 @@ TYPED_TEST_P(DwarfOpTest, op_plus_uconst) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); @@ -1150,13 +1154,13 @@ TYPED_TEST_P(DwarfOpTest, op_shl) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1181,13 +1185,13 @@ TYPED_TEST_P(DwarfOpTest, op_shr) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1216,13 +1220,13 @@ TYPED_TEST_P(DwarfOpTest, op_shra) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1247,13 +1251,13 @@ TYPED_TEST_P(DwarfOpTest, op_xor) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(1U, this->op_->StackSize()); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); ASSERT_EQ(2U, this->op_->StackSize()); @@ -1280,7 +1284,7 @@ TYPED_TEST_P(DwarfOpTest, op_bra) { this->op_memory_.SetMemory(0, opcode_buffer); ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); // Push on a non-zero value with a positive branch. ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX)); @@ -1342,12 +1346,12 @@ TYPED_TEST_P(DwarfOpTest, compare_opcode_stack_error) { ASSERT_FALSE(this->op_->Eval(0, 1, DWARF_VERSION_MAX)); ASSERT_EQ(opcode, this->op_->cur_op()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); ASSERT_FALSE(this->op_->Eval(1, 4, DWARF_VERSION_MAX)); ASSERT_EQ(opcode, this->op_->cur_op()); ASSERT_EQ(1U, this->op_->StackSize()); - ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode()); } } @@ -1532,7 +1536,7 @@ TYPED_TEST_P(DwarfOpTest, op_breg_invalid_register) { // Should fail since this references a non-existent register. ASSERT_FALSE(this->op_->Eval(2, 4, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_bregx) { @@ -1560,7 +1564,7 @@ TYPED_TEST_P(DwarfOpTest, op_bregx) { ASSERT_EQ(0x90U, this->op_->StackAt(0)); ASSERT_FALSE(this->op_->Eval(7, 12, DWARF_VERSION_MAX)); - ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error()); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode()); } TYPED_TEST_P(DwarfOpTest, op_nop) { diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp index dfd2ce059..7e10935eb 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp @@ -19,10 +19,10 @@ #include #include +#include #include #include "DwarfEncoding.h" -#include "DwarfError.h" #include "LogFake.h" #include "MemoryFake.h" @@ -67,7 +67,7 @@ class MockDwarfSectionImpl : public DwarfSectionImpl { } void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); } - void TestClearError() { this->last_error_ = DWARF_ERROR_NONE; } + void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; } }; template @@ -102,7 +102,8 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) { loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode()); + EXPECT_EQ(0x5000U, this->section_->LastErrorAddress()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) { @@ -118,7 +119,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) { loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) { @@ -172,7 +173,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) { loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) { @@ -182,7 +183,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) { bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) { @@ -192,7 +193,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) { bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) { @@ -203,25 +204,25 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) { loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}}; bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); this->section_->TestClearError(); loc_regs.erase(CFA_REG); loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}}; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); this->section_->TestClearError(); loc_regs.erase(CFA_REG); loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}}; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); this->section_->TestClearError(); loc_regs.erase(CFA_REG); loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}}; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) { @@ -341,7 +342,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) { loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}}; bool finished; ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); - EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) { @@ -489,10 +490,12 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) { TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) { ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr); - EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode()); + EXPECT_EQ(0x4000U, this->section_->LastErrorAddress()); this->section_->TestClearError(); ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr); - EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode()); + EXPECT_EQ(0x4000U, this->section_->LastErrorAddress()); } TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) { @@ -518,24 +521,24 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) { EXPECT_EQ(4U, cie->code_alignment_factor); EXPECT_EQ(8, cie->data_alignment_factor); EXPECT_EQ(0x20U, cie->return_address_register); - EXPECT_EQ(DWARF_ERROR_NONE, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode()); this->section_->TestClearCachedCieEntry(); // Set version to 0, 2, 5 and verify we fail. this->memory_.SetData8(0x5008, 0x0); this->section_->TestClearError(); ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr); - EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode()); this->memory_.SetData8(0x5008, 0x2); this->section_->TestClearError(); ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr); - EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode()); this->memory_.SetData8(0x5008, 0x5); this->section_->TestClearError(); ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr); - EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode()); } TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) { @@ -681,10 +684,12 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_4) { TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) { ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr); - EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode()); + EXPECT_EQ(0x4000U, this->section_->LastErrorAddress()); this->section_->TestClearError(); ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr); - EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); + EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode()); + EXPECT_EQ(0x4000U, this->section_->LastErrorAddress()); } TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) { diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h index 099026ce0..e23298670 100644 --- a/libunwindstack/tests/ElfFake.h +++ b/libunwindstack/tests/ElfFake.h @@ -87,6 +87,10 @@ class ElfInterfaceFake : public ElfInterface { steps_.clear(); } + void FakeSetErrorCode(ErrorCode code) { last_error_.code = code; } + + void FakeSetErrorAddress(uint64_t address) { last_error_.address = address; } + private: std::unordered_map globals_; diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp index e6763ab01..31d6a6314 100644 --- a/libunwindstack/tests/ElfInterfaceArmTest.cpp +++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp @@ -303,6 +303,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx) { // FindEntry fails. bool finished; ASSERT_FALSE(interface.StepExidx(0x7000, 0, nullptr, nullptr, &finished)); + EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode()); // ExtractEntry should fail. interface.FakeSetStartOffset(0x1000); @@ -316,14 +317,18 @@ TEST_F(ElfInterfaceArmTest, StepExidx) { regs.set_sp(regs[ARM_REG_SP]); regs.set_pc(0x1234); ASSERT_FALSE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_MEMORY_INVALID, interface.LastErrorCode()); + EXPECT_EQ(0x1004U, interface.LastErrorAddress()); // Eval should fail. memory_.SetData32(0x1004, 0x81000000); ASSERT_FALSE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode()); // Everything should pass. memory_.SetData32(0x1004, 0x80b0b0b0); ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode()); ASSERT_FALSE(finished); ASSERT_EQ(0x1000U, regs.sp()); ASSERT_EQ(0x1000U, regs[ARM_REG_SP]); @@ -332,9 +337,11 @@ TEST_F(ElfInterfaceArmTest, StepExidx) { // Load bias is non-zero. ASSERT_TRUE(interface.StepExidx(0x8000, 0x1000, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode()); // Pc too small. ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode()); } TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) { @@ -356,6 +363,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) { // Everything should pass. bool finished; ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_NONE, interface.LastErrorCode()); ASSERT_FALSE(finished); ASSERT_EQ(0x10004U, regs.sp()); ASSERT_EQ(0x10004U, regs[ARM_REG_SP]); @@ -379,6 +387,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) { bool finished; ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_NONE, interface.LastErrorCode()); ASSERT_TRUE(finished); ASSERT_EQ(0x10000U, regs.sp()); ASSERT_EQ(0x10000U, regs[ARM_REG_SP]); @@ -401,6 +410,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) { bool finished; ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_NONE, interface.LastErrorCode()); ASSERT_TRUE(finished); ASSERT_EQ(0x10000U, regs.sp()); ASSERT_EQ(0x10000U, regs[ARM_REG_SP]); @@ -427,6 +437,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) { bool finished; ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_NONE, interface.LastErrorCode()); ASSERT_TRUE(finished); ASSERT_EQ(0U, regs.pc()); @@ -439,6 +450,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) { regs.set_pc(0x1234); ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished)); + EXPECT_EQ(ERROR_NONE, interface.LastErrorCode()); ASSERT_TRUE(finished); ASSERT_EQ(0U, regs.pc()); } diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 7e6a62a32..eb850336b 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -581,4 +581,30 @@ TEST_F(ElfTest, is_valid_pc_from_gnu_debugdata) { EXPECT_TRUE(elf.IsValidPc(0x1500)); } +TEST_F(ElfTest, error_code_not_valid) { + ElfFake elf(memory_); + elf.FakeSetValid(false); + + ErrorData error{ERROR_MEMORY_INVALID, 0x100}; + elf.GetLastError(&error); + EXPECT_EQ(ERROR_MEMORY_INVALID, error.code); + EXPECT_EQ(0x100U, error.address); +} + +TEST_F(ElfTest, error_code_valid) { + ElfFake elf(memory_); + elf.FakeSetValid(true); + ElfInterfaceFake* interface = new ElfInterfaceFake(memory_); + elf.FakeSetInterface(interface); + interface->FakeSetErrorCode(ERROR_MEMORY_INVALID); + interface->FakeSetErrorAddress(0x1000); + + ErrorData error{ERROR_NONE, 0}; + elf.GetLastError(&error); + EXPECT_EQ(ERROR_MEMORY_INVALID, error.code); + EXPECT_EQ(0x1000U, error.address); + EXPECT_EQ(ERROR_MEMORY_INVALID, elf.GetLastErrorCode()); + EXPECT_EQ(0x1000U, elf.GetLastErrorAddress()); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index cd468074e..bf2c1d892 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -129,6 +129,7 @@ TEST_F(UnwinderTest, multiple_frames) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -184,6 +185,7 @@ TEST_F(UnwinderTest, non_zero_map_offset) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -218,6 +220,7 @@ TEST_F(UnwinderTest, no_frames_after_finished) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -248,6 +251,7 @@ TEST_F(UnwinderTest, max_frames) { Unwinder unwinder(20, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode()); ASSERT_EQ(20U, unwinder.NumFrames()); @@ -288,6 +292,7 @@ TEST_F(UnwinderTest, verify_frames_skipped) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); std::vector skip_libs{"libunwind.so", "libanother.so"}; unwinder.Unwind(&skip_libs); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -346,6 +351,7 @@ TEST_F(UnwinderTest, sp_not_in_map) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(2U, unwinder.NumFrames()); @@ -392,6 +398,7 @@ TEST_F(UnwinderTest, pc_in_device_stops_unwind) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(1U, unwinder.NumFrames()); } @@ -410,6 +417,7 @@ TEST_F(UnwinderTest, sp_in_device_stops_unwind) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(1U, unwinder.NumFrames()); } @@ -423,6 +431,7 @@ TEST_F(UnwinderTest, pc_without_map) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -457,6 +466,7 @@ TEST_F(UnwinderTest, speculative_frame) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -517,6 +527,7 @@ TEST_F(UnwinderTest, speculative_frame_removed) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -552,6 +563,7 @@ TEST_F(UnwinderTest, map_ignore_suffixes) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); std::vector suffixes{"oat"}; unwinder.Unwind(nullptr, &suffixes); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(2U, unwinder.NumFrames()); // Make sure the elf was not initialized. @@ -607,6 +619,7 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { Unwinder unwinder(64, &maps_, ®s_, process_memory_); unwinder.Unwind(); + EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode()); ASSERT_EQ(3U, unwinder.NumFrames());