Add error propagation into Unwinder/Elf objects.

The backtrace offline code uses these error codes to diagnose errors.
In addtion, I've had cases where seeing these errors would help diagnose
failures.

This also allows us to add a few features to indicate why an unwind
terminated (such as max frames exceeded).

Bug: 65682279

Test: Updated unit tests pass.
Change-Id: If82b5092698e8a194016d670efff1320f9b44d50
This commit is contained in:
Christopher Ferris 2018-01-23 17:52:23 -08:00
parent 335675c2fd
commit 2fcf4cf13e
31 changed files with 630 additions and 222 deletions

View file

@ -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;

View file

@ -61,6 +61,7 @@ class ArmExidx {
std::deque<uint8_t>* 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<uint8_t> data_;
ArmStatus status_ = ARM_STATUS_NONE;
uint64_t status_address_ = 0;
Memory* elf_memory_;
Memory* process_memory_;

View file

@ -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 <stdlib.h>
@ -31,4 +31,4 @@ namespace unwindstack {
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_ERROR_H
#endif // _LIBUNWINDSTACK_CHECK_H

View file

@ -23,12 +23,12 @@
#include <android-base/stringprintf.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/Log.h>
#include "DwarfCfa.h"
#include "DwarfEncoding.h"
#include "DwarfError.h"
#include "DwarfOp.h"
namespace unwindstack {
@ -44,7 +44,8 @@ bool DwarfCfa<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
case 0: {
const auto handle_func = DwarfCfa<AddressType>::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<AddressType>::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<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
}
uint64_t value;
if (!memory_->ReadEncodedValue<AddressType>(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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;

View file

@ -24,12 +24,11 @@
#include <type_traits>
#include <vector>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
#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_;

View file

@ -16,12 +16,12 @@
#include <stdint.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfStructs.h>
#include <unwindstack/Memory.h>
#include "Check.h"
#include "DwarfEhFrameWithHdr.h"
#include "DwarfError.h"
namespace unwindstack {
@ -36,14 +36,15 @@ bool DwarfEhFrameWithHdr<AddressType>::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<AddressType>::Init(uint64_t offset, uint64_t size) {
memory_.set_pc_offset(memory_.cur_offset());
if (!memory_.template ReadEncodedValue<AddressType>(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<AddressType>(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<AddressType>::GetFdeInfoFromIndex(size_t index) {
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
!memory_.template ReadEncodedValue<AddressType>(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<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t*
template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::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<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint6
memory_.set_pc_offset(memory_.cur_offset());
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(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<AddressType>(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;

View file

@ -22,12 +22,12 @@
#include <android-base/stringprintf.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/Log.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include "DwarfError.h"
#include "DwarfOp.h"
namespace unwindstack {
@ -48,7 +48,7 @@ bool DwarfOp<AddressType>::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<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_vers
template <typename AddressType>
bool DwarfOp<AddressType>::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<AddressType>::Decode(uint8_t dwarf_version) {
for (size_t i = 0; i < op->num_operands; i++) {
uint64_t value;
if (!memory_->ReadEncodedValue<AddressType>(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<AddressType>::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 <typename AddressType>
bool DwarfOp<AddressType>::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 <typename AddressType>
bool DwarfOp<AddressType>::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 <typename AddressType>
bool DwarfOp<AddressType>::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<SignedType>(top);
@ -263,7 +267,7 @@ template <typename AddressType>
bool DwarfOp<AddressType>::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 <typename AddressType>
bool DwarfOp<AddressType>::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 <typename AddressType>
bool DwarfOp<AddressType>::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<AddressType>::op_nop() {
template <typename AddressType>
bool DwarfOp<AddressType>::op_not_implemented() {
last_error_ = DWARF_ERROR_NOT_IMPLEMENTED;
last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
return false;
}

View file

@ -24,8 +24,9 @@
#include <type_traits>
#include <vector>
#include <unwindstack/DwarfError.h>
#include "DwarfEncoding.h"
#include "DwarfError.h"
namespace unwindstack {
@ -72,7 +73,9 @@ class DwarfOp {
void set_regs(RegsImpl<AddressType>* 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<AddressType>* regs_;
bool is_register_ = false;
DwarfError last_error_ = DWARF_ERROR_NONE;
DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
uint8_t cur_op_;
std::vector<AddressType> operands_;
std::deque<AddressType> stack_;

View file

@ -16,6 +16,7 @@
#include <stdint.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfSection.h>
@ -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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
bool* finished) {
RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(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<AddressType>::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<AddressType>::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<AddressType>::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 <typename AddressType>
bool DwarfSectionImpl<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>(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 <typename AddressType>
bool DwarfSectionImpl<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::FillInFde(DwarfFde* fde) {
memory_.set_cur_offset(cur_offset);
if (!memory_.ReadEncodedValue<AddressType>(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<AddressType>(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<AddressType>::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<AddressType>(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 <typename AddressType>
bool DwarfSectionImpl<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>::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<AddressType>(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<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t se
uint64_t start;
if (!memory_.template ReadEncodedValue<AddressType>(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<AddressType>(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<AddressType>::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<AddressType>::CreateSortedFdeList() {
if (value32 == static_cast<uint32_t>(-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<AddressType>::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<AddressType>::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<AddressType>::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;
}

View file

@ -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) {

View file

@ -24,6 +24,7 @@
#include <Xz.h>
#include <XzCrc64.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfSection.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Log.h>
@ -160,6 +161,8 @@ template <typename EhdrType, typename PhdrType, typename ShdrType>
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<uintptr_t>(&phdr.p_type) - reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_flags) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_vaddr) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_offset) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_memsz) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_offset) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_memsz) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_offset) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_vaddr) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&phdr.p_memsz) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&shdr.sh_type) - reinterpret_cast<uintptr_t>(&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<uintptr_t>(&str_shdr.sh_type) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&str_shdr.sh_offset) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&str_shdr.sh_size) -
reinterpret_cast<uintptr_t>(&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<uintptr_t>(&shdr.sh_name) -
reinterpret_cast<uintptr_t>(&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;
}

View file

@ -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;
}

View file

@ -78,6 +78,8 @@ static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
const std::vector<std::string>* 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<std::string>* 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<std::string>* 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<std::string>* 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;
}
}

View file

@ -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 <stdint.h>
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

View file

@ -22,6 +22,7 @@
#include <iterator>
#include <unordered_map>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
@ -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;

View file

@ -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_; }

View file

@ -26,6 +26,7 @@
#include <vector>
#include <unwindstack/DwarfSection.h>
#include <unwindstack/Error.h>
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 <typename EhdrType, typename PhdrType>
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<DwarfSection> eh_frame_;
std::unique_ptr<DwarfSection> debug_frame_;
// The Elf object owns the gnu_debugdata interface object.

View file

@ -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 <stdint.h>
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

View file

@ -24,6 +24,7 @@
#include <string>
#include <vector>
#include <unwindstack/Error.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@ -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<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
JitDebug* jit_debug_ = nullptr;
ErrorData last_error_;
};
} // namespace unwindstack

View file

@ -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) {

View file

@ -21,13 +21,13 @@
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
#include <unwindstack/Log.h>
#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());

View file

@ -19,9 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#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());
}
}

View file

@ -19,9 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#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());
}
}

View file

@ -19,9 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#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) {

View file

@ -21,11 +21,11 @@
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/Log.h>
#include <unwindstack/Regs.h>
#include "DwarfError.h"
#include "DwarfOp.h"
#include "MemoryFake.h"

View file

@ -21,10 +21,10 @@
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/Log.h>
#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<uint8_t>{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<uint8_t>{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<uint8_t>{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<uint8_t>{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<uint8_t>{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) {

View file

@ -19,10 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfSection.h>
#include "DwarfEncoding.h"
#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
@ -67,7 +67,7 @@ class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
}
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 <typename TypeParam>
@ -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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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) {

View file

@ -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<std::string, uint64_t> globals_;

View file

@ -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, &regs, &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, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// Everything should pass.
memory_.SetData32(0x1004, 0x80b0b0b0);
ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &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, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// Pc too small.
ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &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, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0U, regs.pc());
}

View file

@ -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

View file

@ -129,6 +129,7 @@ TEST_F(UnwinderTest, multiple_frames) {
Unwinder unwinder(64, &maps_, &regs_, 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_, &regs_, 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_, &regs_, 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_, &regs_, 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_, &regs_, process_memory_);
std::vector<std::string> 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_, &regs_, 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_, &regs_, 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_, &regs_, 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_, &regs_, 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_, &regs_, 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_, &regs_, 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_, &regs_, process_memory_);
std::vector<std::string> 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_, &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
ASSERT_EQ(3U, unwinder.NumFrames());