Merge "Fix handling of load bias values."

am: 9c1d75983a

Change-Id: I6cde23f871fa5e36b0b9333f5fba8bd86dc56f48
This commit is contained in:
Christopher Ferris 2018-06-12 18:00:25 -07:00 committed by android-build-merger
commit 8ad4f27932
40 changed files with 1741 additions and 887 deletions

View file

@ -223,6 +223,7 @@ cc_test {
"tests/files/offline/art_quick_osr_stub_arm/*",
"tests/files/offline/bad_eh_frame_hdr_arm64/*",
"tests/files/offline/debug_frame_first_x86/*",
"tests/files/offline/debug_frame_load_bias_arm/*",
"tests/files/offline/eh_frame_hdr_begin_x86_64/*",
"tests/files/offline/jit_debug_arm/*",
"tests/files/offline/jit_debug_x86/*",

View file

@ -31,6 +31,8 @@
namespace unwindstack {
static constexpr uint8_t LOG_CFA_REG = 64;
void ArmExidx::LogRawData() {
std::string log_str("Raw Data:");
for (const uint8_t data : data_) {
@ -63,8 +65,10 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
if (data == 1) {
// This is a CANT UNWIND entry.
status_ = ARM_STATUS_NO_UNWIND;
if (log_) {
log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
}
log(log_indent_, "[cantunwind]");
}
return false;
@ -86,7 +90,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
// If this didn't end with a finish op, add one.
data_.push_back(ARM_OP_FINISH);
}
if (log_) {
if (log_type_ == ARM_LOG_FULL) {
LogRawData();
}
return true;
@ -163,7 +167,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
data_.push_back(ARM_OP_FINISH);
}
if (log_) {
if (log_type_ == ARM_LOG_FULL) {
LogRawData();
}
return true;
@ -190,32 +194,45 @@ inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
registers |= byte;
if (registers == 0) {
// 10000000 00000000: Refuse to unwind
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Refuse to unwind");
}
status_ = ARM_STATUS_NO_UNWIND;
return false;
}
// 1000iiii iiiiiiii: Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
if (log_) {
bool add_comma = false;
std::string msg = "pop {";
for (size_t i = 0; i < 12; i++) {
if (registers & (1 << i)) {
if (add_comma) {
msg += ", ";
registers <<= 4;
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
bool add_comma = false;
std::string msg = "pop {";
for (size_t reg = 4; reg < 16; reg++) {
if (registers & (1 << reg)) {
if (add_comma) {
msg += ", ";
}
msg += android::base::StringPrintf("r%zu", reg);
add_comma = true;
}
}
log(log_indent_, "%s}", msg.c_str());
} else {
uint32_t cfa_offset = __builtin_popcount(registers) * 4;
log_cfa_offset_ += cfa_offset;
for (size_t reg = 4; reg < 16; reg++) {
if (registers & (1 << reg)) {
log_regs_[reg] = cfa_offset;
cfa_offset -= 4;
}
msg += android::base::StringPrintf("r%zu", i + 4);
add_comma = true;
}
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
}
registers <<= 4;
for (size_t reg = 4; reg < 16; reg++) {
if (registers & (1 << reg)) {
if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
@ -246,15 +263,20 @@ inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
if (bits == 13 || bits == 15) {
// 10011101: Reserved as prefix for ARM register to register moves
// 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "[Reserved]");
}
status_ = ARM_STATUS_RESERVED;
return false;
}
// 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
if (log_) {
log(log_indent_, "vsp = r%d", bits);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
log(log_indent_, "vsp = r%d", bits);
} else {
log_regs_[LOG_CFA_REG] = bits;
}
if (log_skip_execution_) {
return true;
}
@ -270,17 +292,36 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
// 10100nnn: Pop r4-r[4+nnn]
// 10101nnn: Pop r4-r[4+nnn], r14
if (log_) {
std::string msg = "pop {r4";
if (log_type_ != ARM_LOG_NONE) {
uint8_t end_reg = byte & 0x7;
if (end_reg) {
msg += android::base::StringPrintf("-r%d", 4 + end_reg);
}
if (byte & 0x8) {
log(log_indent_, "%s, r14}", msg.c_str());
if (log_type_ == ARM_LOG_FULL) {
std::string msg = "pop {r4";
if (end_reg) {
msg += android::base::StringPrintf("-r%d", 4 + end_reg);
}
if (byte & 0x8) {
log(log_indent_, "%s, r14}", msg.c_str());
} else {
log(log_indent_, "%s}", msg.c_str());
}
} else {
log(log_indent_, "%s}", msg.c_str());
end_reg += 4;
uint32_t cfa_offset = (end_reg - 3) * 4;
if (byte & 0x8) {
cfa_offset += 4;
}
log_cfa_offset_ += cfa_offset;
for (uint8_t reg = 4; reg <= end_reg; reg++) {
log_regs_[reg] = cfa_offset;
cfa_offset -= 4;
}
if (byte & 0x8) {
log_regs_[14] = cfa_offset;
}
}
if (log_skip_execution_) {
return true;
}
@ -307,8 +348,11 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
inline bool ArmExidx::DecodePrefix_10_11_0000() {
// 10110000: Finish
if (log_) {
log(log_indent_, "finish");
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
log(log_indent_, "finish");
}
if (log_skip_execution_) {
status_ = ARM_STATUS_FINISH;
return false;
@ -326,7 +370,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
if (byte == 0) {
// 10110001 00000000: Spare
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
@ -334,7 +378,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
}
if (byte >> 4) {
// 10110001 xxxxyyyy: Spare (xxxx != 0000)
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
@ -342,19 +386,32 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
}
// 10110001 0000iiii: Pop integer registers under mask {r3, r2, r1, r0}
if (log_) {
bool add_comma = false;
std::string msg = "pop {";
for (size_t i = 0; i < 4; i++) {
if (byte & (1 << i)) {
if (add_comma) {
msg += ", ";
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
bool add_comma = false;
std::string msg = "pop {";
for (size_t i = 0; i < 4; i++) {
if (byte & (1 << i)) {
if (add_comma) {
msg += ", ";
}
msg += android::base::StringPrintf("r%zu", i);
add_comma = true;
}
}
log(log_indent_, "%s}", msg.c_str());
} else {
byte &= 0xf;
uint32_t cfa_offset = __builtin_popcount(byte) * 4;
log_cfa_offset_ += cfa_offset;
for (size_t reg = 0; reg < 4; reg++) {
if (byte & (1 << reg)) {
log_regs_[reg] = cfa_offset;
cfa_offset -= 4;
}
msg += android::base::StringPrintf("r%zu", i);
add_comma = true;
}
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -373,6 +430,15 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
return true;
}
inline void ArmExidx::AdjustRegisters(int32_t offset) {
for (auto& entry : log_regs_) {
if (entry.first >= LOG_CFA_REG) {
break;
}
entry.second += offset;
}
}
inline bool ArmExidx::DecodePrefix_10_11_0010() {
// 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
uint32_t result = 0;
@ -387,8 +453,15 @@ inline bool ArmExidx::DecodePrefix_10_11_0010() {
shift += 7;
} while (byte & 0x80);
result <<= 2;
if (log_) {
log(log_indent_, "vsp = vsp + %d", 0x204 + result);
if (log_type_ != ARM_LOG_NONE) {
int32_t cfa_offset = 0x204 + result;
if (log_type_ == ARM_LOG_FULL) {
log(log_indent_, "vsp = vsp + %d", cfa_offset);
} else {
log_cfa_offset_ += cfa_offset;
}
AdjustRegisters(cfa_offset);
if (log_skip_execution_) {
return true;
}
@ -404,14 +477,20 @@ inline bool ArmExidx::DecodePrefix_10_11_0011() {
return false;
}
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
uint8_t end_reg = start_reg + (byte & 0xf);
if (end_reg) {
msg += android::base::StringPrintf("-d%d", end_reg);
if (log_type_ == ARM_LOG_FULL) {
std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
if (end_reg) {
msg += android::base::StringPrintf("-d%d", end_reg);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported DX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -422,7 +501,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0011() {
inline bool ArmExidx::DecodePrefix_10_11_01nn() {
// 101101nn: Spare
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
@ -433,13 +512,18 @@ inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
CHECK((byte & ~0x07) == 0xb8);
// 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
if (log_) {
std::string msg = "pop {d8";
uint8_t last_reg = (byte & 0x7);
if (last_reg) {
msg += android::base::StringPrintf("-d%d", last_reg + 8);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
uint8_t last_reg = (byte & 0x7);
std::string msg = "pop {d8";
if (last_reg) {
msg += android::base::StringPrintf("-d%d", last_reg + 8);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported DX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -489,14 +573,19 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
}
// 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
if (log_) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
uint8_t end_reg = byte & 0xf;
if (end_reg) {
msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
uint8_t end_reg = byte & 0xf;
if (end_reg) {
msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported wRX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -510,32 +599,40 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
if (byte == 0) {
// 11000111 00000000: Spare
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
return false;
} else if ((byte >> 4) == 0) {
// 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
if (log_) {
bool add_comma = false;
std::string msg = "pop {";
for (size_t i = 0; i < 4; i++) {
if (byte & (1 << i)) {
if (add_comma) {
msg += ", ";
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
bool add_comma = false;
std::string msg = "pop {";
for (size_t i = 0; i < 4; i++) {
if (byte & (1 << i)) {
if (add_comma) {
msg += ", ";
}
msg += android::base::StringPrintf("wCGR%zu", i);
add_comma = true;
}
msg += android::base::StringPrintf("wCGR%zu", i);
add_comma = true;
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported wCGR register display");
}
if (log_skip_execution_) {
return true;
}
log(log_indent_, "%s}", msg.c_str());
}
// Only update the cfa.
cfa_ += __builtin_popcount(byte) * 4;
} else {
// 11000111 xxxxyyyy: Spare (xxxx != 0000)
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
@ -543,13 +640,18 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
}
} else {
// 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
if (log_) {
std::string msg = "pop {wR10";
uint8_t nnn = byte & 0x7;
if (nnn) {
msg += android::base::StringPrintf("-wR%d", 10 + nnn);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
std::string msg = "pop {wR10";
uint8_t nnn = byte & 0x7;
if (nnn) {
msg += android::base::StringPrintf("-wR%d", 10 + nnn);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported wRX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -570,14 +672,19 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
return false;
}
if (log_) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
uint8_t end_reg = byte & 0xf;
if (end_reg) {
msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
uint8_t end_reg = byte & 0xf;
if (end_reg) {
msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported DX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -590,14 +697,19 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
return false;
}
if (log_) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
uint8_t end_reg = byte & 0xf;
if (end_reg) {
msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
uint8_t start_reg = byte >> 4;
std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
uint8_t end_reg = byte & 0xf;
if (end_reg) {
msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported DX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -606,7 +718,7 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
cfa_ += (byte & 0xf) * 8 + 8;
} else {
// 11001yyy: Spare (yyy != 000, 001)
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
@ -619,13 +731,18 @@ inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
CHECK((byte & ~0x07) == 0xd0);
// 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
if (log_) {
std::string msg = "pop {d8";
uint8_t end_reg = byte & 0x7;
if (end_reg) {
msg += android::base::StringPrintf("-d%d", 8 + end_reg);
if (log_type_ != ARM_LOG_NONE) {
if (log_type_ == ARM_LOG_FULL) {
std::string msg = "pop {d8";
uint8_t end_reg = byte & 0x7;
if (end_reg) {
msg += android::base::StringPrintf("-d%d", 8 + end_reg);
}
log(log_indent_, "%s}", msg.c_str());
} else {
log(log_indent_, "Unsupported DX register display");
}
log(log_indent_, "%s}", msg.c_str());
if (log_skip_execution_) {
return true;
}
@ -646,7 +763,7 @@ inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
return DecodePrefix_11_010(byte);
default:
// 11xxxyyy: Spare (xxx != 000, 001, 010)
if (log_) {
if (log_type_ != ARM_LOG_NONE) {
log(log_indent_, "Spare");
}
status_ = ARM_STATUS_SPARE;
@ -664,8 +781,15 @@ bool ArmExidx::Decode() {
switch (byte >> 6) {
case 0:
// 00xxxxxx: vsp = vsp + (xxxxxxx << 2) + 4
if (log_) {
log(log_indent_, "vsp = vsp + %d", ((byte & 0x3f) << 2) + 4);
if (log_type_ != ARM_LOG_NONE) {
int32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
if (log_type_ == ARM_LOG_FULL) {
log(log_indent_, "vsp = vsp + %d", cfa_offset);
} else {
log_cfa_offset_ += cfa_offset;
}
AdjustRegisters(cfa_offset);
if (log_skip_execution_) {
break;
}
@ -674,8 +798,15 @@ bool ArmExidx::Decode() {
break;
case 1:
// 01xxxxxx: vsp = vsp - (xxxxxxx << 2) + 4
if (log_) {
log(log_indent_, "vsp = vsp - %d", ((byte & 0x3f) << 2) + 4);
if (log_type_ != ARM_LOG_NONE) {
uint32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
if (log_type_ == ARM_LOG_FULL) {
log(log_indent_, "vsp = vsp - %d", cfa_offset);
} else {
log_cfa_offset_ -= cfa_offset;
}
AdjustRegisters(-cfa_offset);
if (log_skip_execution_) {
break;
}
@ -696,4 +827,36 @@ bool ArmExidx::Eval() {
return status_ == ARM_STATUS_FINISH;
}
void ArmExidx::LogByReg() {
if (log_type_ != ARM_LOG_BY_REG) {
return;
}
uint8_t cfa_reg;
if (log_regs_.count(LOG_CFA_REG) == 0) {
cfa_reg = 13;
} else {
cfa_reg = log_regs_[LOG_CFA_REG];
}
if (log_cfa_offset_ != 0) {
char sign = (log_cfa_offset_ > 0) ? '+' : '-';
log(log_indent_, "cfa = r%zu %c %d", cfa_reg, sign, abs(log_cfa_offset_));
} else {
log(log_indent_, "cfa = r%zu", cfa_reg);
}
for (const auto& entry : log_regs_) {
if (entry.first >= LOG_CFA_REG) {
break;
}
if (entry.second == 0) {
log(log_indent_, "r%zu = [cfa]", entry.first);
} else {
char sign = (entry.second > 0) ? '-' : '+';
log(log_indent_, "r%zu = [cfa %c %d]", entry.first, sign, abs(entry.second));
}
}
}
} // namespace unwindstack

View file

@ -20,6 +20,7 @@
#include <stdint.h>
#include <deque>
#include <map>
namespace unwindstack {
@ -44,6 +45,12 @@ enum ArmOp : uint8_t {
ARM_OP_FINISH = 0xb0,
};
enum ArmLogType : uint8_t {
ARM_LOG_NONE,
ARM_LOG_FULL,
ARM_LOG_BY_REG,
};
class ArmExidx {
public:
ArmExidx(RegsArm* regs, Memory* elf_memory, Memory* process_memory)
@ -52,6 +59,8 @@ class ArmExidx {
void LogRawData();
void LogByReg();
bool ExtractEntryData(uint32_t entry_offset);
bool Eval();
@ -71,12 +80,13 @@ class ArmExidx {
bool pc_set() { return pc_set_; }
void set_pc_set(bool pc_set) { pc_set_ = pc_set; }
void set_log(bool log) { log_ = log; }
void set_log(ArmLogType log_type) { log_type_ = log_type; }
void set_log_skip_execution(bool skip_execution) { log_skip_execution_ = skip_execution; }
void set_log_indent(uint8_t indent) { log_indent_ = indent; }
private:
bool GetByte(uint8_t* byte);
void AdjustRegisters(int32_t offset);
bool DecodePrefix_10_00(uint8_t byte);
bool DecodePrefix_10_01(uint8_t byte);
@ -103,10 +113,12 @@ class ArmExidx {
Memory* elf_memory_;
Memory* process_memory_;
bool log_ = false;
ArmLogType log_type_ = ARM_LOG_NONE;
uint8_t log_indent_ = 0;
bool log_skip_execution_ = false;
bool pc_set_ = false;
int32_t log_cfa_offset_ = 0;
std::map<uint8_t, int32_t> log_regs_;
};
} // namespace unwindstack

View file

@ -264,8 +264,8 @@ bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset,
}
template <typename AddressType>
bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t load_bias,
uint64_t start_offset, uint64_t end_offset) {
bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t start_offset,
uint64_t end_offset) {
memory_->set_cur_offset(start_offset);
uint64_t cfa_offset;
uint64_t cur_pc = fde_->pc_start;
@ -301,8 +301,8 @@ bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t load_bias
break;
}
if (cur_pc != old_pc) {
log(indent, "");
log(indent, "PC 0x%" PRIx64, cur_pc + load_bias);
log(0, "");
log(indent, "PC 0x%" PRIx64, cur_pc);
}
old_pc = cur_pc;
}

View file

@ -71,8 +71,7 @@ class DwarfCfa {
bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
dwarf_loc_regs_t* loc_regs);
bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset,
uint64_t end_offset);
bool Log(uint32_t indent, uint64_t pc, uint64_t start_offset, uint64_t end_offset);
const DwarfErrorData& last_error() { return last_error_; }
DwarfErrorCode LastErrorCode() { return last_error_.code; }

View file

@ -22,12 +22,18 @@
#include "Check.h"
#include "DwarfEhFrameWithHdr.h"
#include "DwarfEncoding.h"
namespace unwindstack {
static inline bool IsEncodingRelative(uint8_t encoding) {
encoding >>= 4;
return encoding > 0 && encoding <= DW_EH_PE_funcrel;
}
template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size) {
uint8_t data[4];
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
load_bias_ = load_bias;
memory_.clear_func_offset();
memory_.clear_text_offset();
@ -35,6 +41,7 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size) {
memory_.set_cur_offset(offset);
// Read the first four bytes all at once.
uint8_t data[4];
if (!memory_.ReadBytes(data, 4)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
@ -100,7 +107,7 @@ DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
memory_.set_data_offset(entries_data_offset_);
memory_.set_cur_offset(entries_offset_ + 2 * index * table_entry_size_);
memory_.set_pc_offset(memory_.cur_offset());
memory_.set_pc_offset(0);
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
@ -109,6 +116,11 @@ DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
fde_info_.erase(index);
return nullptr;
}
// Relative encodings require adding in the load bias.
if (IsEncodingRelative(table_encoding_)) {
value += load_bias_;
}
info->pc = value;
return info;
}
@ -174,27 +186,27 @@ bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint6
memory_.set_data_offset(entries_data_offset_);
memory_.set_cur_offset(cur_entries_offset_);
memory_.set_pc_offset(0);
cur_entries_offset_ = 0;
FdeInfo* prev_info = nullptr;
for (size_t current = fde_info_.size();
current < fde_count_ && memory_.cur_offset() < entries_end_; current++) {
memory_.set_pc_offset(memory_.cur_offset());
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value)) {
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)) {
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
fde_info_.erase(current);
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
}
info->pc = value + 4;
// Relative encodings require adding in the load bias.
if (IsEncodingRelative(table_encoding_)) {
value += load_bias_;
}
info->pc = value;
if (pc < info->pc) {
if (prev_info == nullptr) {

View file

@ -38,6 +38,7 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame<AddressType> {
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
using DwarfSectionImpl<AddressType>::load_bias_;
struct FdeInfo {
AddressType pc;
@ -47,7 +48,7 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame<AddressType> {
DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame<AddressType>(memory) {}
virtual ~DwarfEhFrameWithHdr() = default;
bool Init(uint64_t offset, uint64_t size) override;
bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;

View file

@ -420,6 +420,7 @@ bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
last_error_.address = memory_.cur_offset();
return false;
}
memory_.set_pc_offset(pc_offset_);
if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
@ -521,19 +522,19 @@ 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_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
}
// The load bias only applies to the start.
memory_.set_pc_offset(load_bias_);
bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
fde->pc_start = AdjustPcFromFde(fde->pc_start);
if (!memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding & 0xf, &fde->pc_end)) {
memory_.set_pc_offset(0);
if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
}
fde->pc_end += fde->pc_start;
if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
// Augmentation Size
uint64_t aug_length;
@ -544,6 +545,7 @@ bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
}
uint64_t cur_offset = memory_.cur_offset();
memory_.set_pc_offset(pc_offset_);
if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
@ -582,17 +584,16 @@ bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfF
}
template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, uint64_t load_bias,
const DwarfFde* fde) {
bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) {
DwarfCfa<AddressType> cfa(&memory_, fde);
// Always print the cie information.
const DwarfCie* cie = fde->cie;
if (!cfa.Log(indent, pc, load_bias, cie->cfa_instructions_offset, cie->cfa_instructions_end)) {
if (!cfa.Log(indent, pc, cie->cfa_instructions_offset, cie->cfa_instructions_end)) {
last_error_ = cfa.last_error();
return false;
}
if (!cfa.Log(indent, pc, load_bias, fde->cfa_instructions_offset, fde->cfa_instructions_end)) {
if (!cfa.Log(indent, pc, fde->cfa_instructions_offset, fde->cfa_instructions_end)) {
last_error_ = cfa.last_error();
return false;
}
@ -600,15 +601,16 @@ bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, uint64_t lo
}
template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size) {
bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
load_bias_ = load_bias;
entries_offset_ = offset;
entries_end_ = offset + size;
memory_.clear_func_offset();
memory_.clear_text_offset();
memory_.set_data_offset(offset);
memory_.set_cur_offset(offset);
memory_.set_pc_offset(offset);
memory_.set_data_offset(offset);
pc_offset_ = offset;
return CreateSortedFdeList();
}
@ -717,6 +719,7 @@ bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* e
return false;
}
uint64_t value;
memory_.set_pc_offset(pc_offset_);
if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
@ -737,15 +740,13 @@ bool DwarfSectionImpl<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t se
}
uint64_t start;
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &start)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
}
memory_.set_pc_offset(load_bias_);
bool valid = memory_.template ReadEncodedValue<AddressType>(encoding, &start);
start = AdjustPcFromFde(start);
uint64_t length;
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &length)) {
memory_.set_pc_offset(0);
if (!valid || !memory_.template ReadEncodedValue<AddressType>(encoding, &length)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
@ -877,7 +878,7 @@ bool DwarfSectionImpl<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fd
while (first < last) {
size_t current = (first + last) / 2;
const FdeInfo* info = &fdes_[current];
if (pc >= info->start && pc <= info->end) {
if (pc >= info->start && pc < info->end) {
*fde_offset = info->offset;
return true;
}

View file

@ -53,7 +53,7 @@ bool Elf::Init(bool init_gnu_debugdata) {
valid_ = interface_->Init(&load_bias_);
if (valid_) {
interface_->InitHeaders();
interface_->InitHeaders(load_bias_);
if (init_gnu_debugdata) {
InitGnuDebugdata();
} else {
@ -83,7 +83,7 @@ void Elf::InitGnuDebugdata() {
// is in the uncompressed data.
uint64_t load_bias;
if (gnu->Init(&load_bias)) {
gnu->InitHeaders();
gnu->InitHeaders(load_bias);
interface_->SetGnuDebugdataInterface(gnu);
} else {
// Free all of the memory associated with the gnu_debugdata section.
@ -103,9 +103,9 @@ uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
std::lock_guard<std::mutex> guard(lock_);
return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
(gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
addr, load_bias_, name, func_offset)));
return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
(gnu_debugdata_interface_ &&
gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
}
bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) {
@ -174,7 +174,7 @@ bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* pr
// Lock during the step which can update information in the object.
std::lock_guard<std::mutex> guard(lock_);
return interface_->Step(adjusted_rel_pc, load_bias_, regs, process_memory, finished);
return interface_->Step(adjusted_rel_pc, regs, process_memory, finished);
}
bool Elf::IsValidElf(Memory* memory) {
@ -220,7 +220,6 @@ bool Elf::IsValidPc(uint64_t pc) {
if (!valid_ || pc < load_bias_) {
return false;
}
pc -= load_bias_;
if (interface_->IsValidPc(pc)) {
return true;

View file

@ -124,10 +124,10 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() {
}
template <typename AddressType>
void ElfInterface::InitHeadersWithTemplate() {
void ElfInterface::InitHeadersWithTemplate(uint64_t load_bias) {
if (eh_frame_hdr_offset_ != 0) {
eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) {
if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, load_bias)) {
eh_frame_.reset(nullptr);
}
}
@ -136,7 +136,7 @@ void ElfInterface::InitHeadersWithTemplate() {
// If there is an eh_frame section without an eh_frame_hdr section,
// or using the frame hdr object failed to init.
eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_, load_bias)) {
eh_frame_.reset(nullptr);
}
}
@ -150,7 +150,7 @@ void ElfInterface::InitHeadersWithTemplate() {
if (debug_frame_offset_ != 0) {
debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_, load_bias)) {
debug_frame_.reset(nullptr);
debug_frame_offset_ = 0;
debug_frame_size_ = static_cast<uint64_t>(-1);
@ -441,14 +441,14 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
}
template <typename SymType>
bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
uint64_t* func_offset) {
if (symbols_.empty()) {
return false;
}
for (const auto symbol : symbols_) {
if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
if (symbol->GetName<SymType>(addr, memory_, name, func_offset)) {
return true;
}
}
@ -469,34 +469,25 @@ bool ElfInterface::GetGlobalVariableWithTemplate(const std::string& name, uint64
return false;
}
bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished) {
bool ElfInterface::Step(uint64_t pc, 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;
// Try the debug_frame first since it contains the most specific unwind
// information.
DwarfSection* debug_frame = debug_frame_.get();
if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory, finished)) {
return true;
}
// Try the eh_frame next.
DwarfSection* eh_frame = eh_frame_.get();
if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
return true;
}
// Finally try the gnu_debugdata interface, but always use a zero load bias.
if (gnu_debugdata_interface_ != nullptr &&
gnu_debugdata_interface_->Step(pc, 0, regs, process_memory, finished)) {
gnu_debugdata_interface_->Step(pc, regs, process_memory, finished)) {
return true;
}
@ -559,8 +550,8 @@ void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
}
// Instantiate all of the needed template functions.
template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
template void ElfInterface::InitHeadersWithTemplate<uint32_t>(uint64_t);
template void ElfInterface::InitHeadersWithTemplate<uint64_t>(uint64_t);
template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
@ -574,9 +565,9 @@ template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
uint64_t*);
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
uint64_t*);
template bool ElfInterface::GetGlobalVariableWithTemplate<Elf32_Sym>(const std::string&, uint64_t*);

View file

@ -26,6 +26,14 @@
namespace unwindstack {
bool ElfInterfaceArm::Init(uint64_t* load_bias) {
if (!ElfInterface32::Init(load_bias)) {
return false;
}
load_bias_ = *load_bias;
return true;
}
bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
if (start_offset_ == 0 || total_entries_ == 0) {
last_error_.code = ERROR_UNWIND_INFO;
@ -96,24 +104,22 @@ bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_b
return true;
}
bool ElfInterfaceArm::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished) {
bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
// Dwarf unwind information is precise about whether a pc is covered or not,
// but arm unwind information only has ranges of pc. In order to avoid
// incorrectly doing a bad unwind using arm unwind information for a
// different function, always try and unwind with the dwarf information first.
return ElfInterface32::Step(pc, load_bias, regs, process_memory, finished) ||
StepExidx(pc, load_bias, regs, process_memory, finished);
return ElfInterface32::Step(pc, regs, process_memory, finished) ||
StepExidx(pc, regs, process_memory, finished);
}
bool ElfInterfaceArm::StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished) {
bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
// Adjust the load bias to get the real relative pc.
if (pc < load_bias) {
if (pc < load_bias_) {
last_error_.code = ERROR_UNWIND_INFO;
return false;
}
pc -= load_bias;
pc -= load_bias_;
RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs);
uint64_t entry_offset;
@ -167,13 +173,12 @@ bool ElfInterfaceArm::StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Mem
return return_value;
}
bool ElfInterfaceArm::GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* offset) {
bool ElfInterfaceArm::GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) {
// For ARM, thumb function symbols have bit 0 set, but the address passed
// in here might not have this bit set and result in a failure to find
// the thumb function names. Adjust the address and offset to account
// for this possible case.
if (ElfInterface32::GetFunctionName(addr | 1, load_bias, name, offset)) {
if (ElfInterface32::GetFunctionName(addr | 1, name, offset)) {
*offset &= ~1;
return true;
}

View file

@ -64,28 +64,30 @@ class ElfInterfaceArm : public ElfInterface32 {
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, total_entries_); }
bool Init(uint64_t* load_bias) override;
bool GetPrel31Addr(uint32_t offset, uint32_t* addr);
bool FindEntry(uint32_t pc, uint64_t* entry_offset);
bool HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) override;
bool Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished) override;
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
bool StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished);
bool StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished);
bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* offset) override;
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) override;
uint64_t start_offset() { return start_offset_; }
size_t total_entries() { return total_entries_; }
void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; }
protected:
uint64_t start_offset_ = 0;
size_t total_entries_ = 0;
uint64_t load_bias_ = 0;
std::unordered_map<size_t, uint32_t> addrs_;
};

View file

@ -54,10 +54,7 @@ const Symbols::Info* Symbols::GetInfoFromCache(uint64_t addr) {
}
template <typename SymType>
bool Symbols::GetName(uint64_t addr, uint64_t load_bias, Memory* elf_memory, std::string* name,
uint64_t* func_offset) {
addr += load_bias;
bool Symbols::GetName(uint64_t addr, Memory* elf_memory, std::string* name, uint64_t* func_offset) {
if (symbols_.size() != 0) {
const Info* info = GetInfoFromCache(addr);
if (info) {
@ -81,9 +78,6 @@ bool Symbols::GetName(uint64_t addr, uint64_t load_bias, Memory* elf_memory, std
if (entry.st_shndx != SHN_UNDEF && ELF32_ST_TYPE(entry.st_info) == STT_FUNC) {
// Treat st_value as virtual address.
uint64_t start_offset = entry.st_value;
if (entry.st_shndx != SHN_ABS) {
start_offset += load_bias;
}
uint64_t end_offset = start_offset + entry.st_size;
// Cache the value.
@ -134,8 +128,8 @@ bool Symbols::GetGlobal(Memory* elf_memory, const std::string& name, uint64_t* m
}
// Instantiate all of the needed template functions.
template bool Symbols::GetName<Elf32_Sym>(uint64_t, uint64_t, Memory*, std::string*, uint64_t*);
template bool Symbols::GetName<Elf64_Sym>(uint64_t, uint64_t, Memory*, std::string*, uint64_t*);
template bool Symbols::GetName<Elf32_Sym>(uint64_t, Memory*, std::string*, uint64_t*);
template bool Symbols::GetName<Elf64_Sym>(uint64_t, Memory*, std::string*, uint64_t*);
template bool Symbols::GetGlobal<Elf32_Sym>(Memory*, const std::string&, uint64_t*);
template bool Symbols::GetGlobal<Elf64_Sym>(Memory*, const std::string&, uint64_t*);

View file

@ -44,8 +44,7 @@ class Symbols {
const Info* GetInfoFromCache(uint64_t addr);
template <typename SymType>
bool GetName(uint64_t addr, uint64_t load_bias, Memory* elf_memory, std::string* name,
uint64_t* func_offset);
bool GetName(uint64_t addr, Memory* elf_memory, std::string* name, uint64_t* func_offset);
template <typename SymType>
bool GetGlobal(Memory* elf_memory, const std::string& name, uint64_t* memory_address);

View file

@ -78,13 +78,13 @@ class DwarfSection {
DwarfErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
virtual bool Init(uint64_t offset, uint64_t size) = 0;
virtual bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) = 0;
virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0;
virtual bool Log(uint8_t indent, uint64_t pc, uint64_t load_bias, const DwarfFde* fde) = 0;
virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) = 0;
virtual const DwarfFde* GetFdeFromIndex(size_t index) = 0;
@ -131,7 +131,7 @@ class DwarfSectionImpl : public DwarfSection {
DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
virtual ~DwarfSectionImpl() = default;
bool Init(uint64_t offset, uint64_t size) override;
bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
@ -150,7 +150,7 @@ class DwarfSectionImpl : public DwarfSection {
bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override;
bool Log(uint8_t indent, uint64_t pc, uint64_t load_bias, const DwarfFde* fde) override;
bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
protected:
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
@ -162,6 +162,9 @@ class DwarfSectionImpl : public DwarfSection {
bool CreateSortedFdeList();
uint64_t load_bias_ = 0;
uint64_t pc_offset_ = 0;
std::vector<FdeInfo> fdes_;
uint64_t entries_offset_;
uint64_t entries_end_;

View file

@ -54,17 +54,15 @@ class ElfInterface {
virtual bool Init(uint64_t* load_bias) = 0;
virtual void InitHeaders() = 0;
virtual void InitHeaders(uint64_t load_bias) = 0;
virtual bool GetSoname(std::string* name) = 0;
virtual bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* offset) = 0;
virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
virtual bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) = 0;
virtual bool Step(uint64_t rel_pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished);
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
virtual bool IsValidPc(uint64_t pc);
@ -100,7 +98,7 @@ class ElfInterface {
protected:
template <typename AddressType>
void InitHeadersWithTemplate();
void InitHeadersWithTemplate(uint64_t load_bias);
template <typename EhdrType, typename PhdrType, typename ShdrType>
bool ReadAllHeaders(uint64_t* load_bias);
@ -115,8 +113,7 @@ class ElfInterface {
bool GetSonameWithTemplate(std::string* soname);
template <typename SymType>
bool GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* func_offset);
bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
template <typename SymType>
bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address);
@ -169,15 +166,16 @@ class ElfInterface32 : public ElfInterface {
return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
}
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
void InitHeaders(uint64_t load_bias) override {
ElfInterface::InitHeadersWithTemplate<uint32_t>(load_bias);
}
bool GetSoname(std::string* soname) override {
return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname);
}
bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* func_offset) override {
return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, load_bias, name, func_offset);
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
}
bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) override {
@ -198,15 +196,16 @@ class ElfInterface64 : public ElfInterface {
return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
}
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
void InitHeaders(uint64_t load_bias) override {
ElfInterface::InitHeadersWithTemplate<uint64_t>(load_bias);
}
bool GetSoname(std::string* soname) override {
return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname);
}
bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* func_offset) override {
return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, load_bias, name, func_offset);
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
}
bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) override {

File diff suppressed because it is too large Load diff

View file

@ -301,7 +301,7 @@ TEST_F(ArmExidxExtractTest, cant_unwind_log) {
elf_memory_.SetData32(0x1000, 0x7fff2340);
elf_memory_.SetData32(0x1004, 1);
exidx_->set_log(true);
exidx_->set_log(ARM_LOG_FULL);
exidx_->set_log_indent(0);
exidx_->set_log_skip_execution(false);
@ -316,7 +316,7 @@ TEST_F(ArmExidxExtractTest, raw_data_compact) {
elf_memory_.SetData32(0x4000, 0x7ffa3000);
elf_memory_.SetData32(0x4004, 0x80a8b0b0);
exidx_->set_log(true);
exidx_->set_log(ARM_LOG_FULL);
exidx_->set_log_indent(0);
exidx_->set_log_skip_execution(false);
@ -330,7 +330,7 @@ TEST_F(ArmExidxExtractTest, raw_data_non_compact) {
elf_memory_.SetData32(0x6234, 0x2);
elf_memory_.SetData32(0x6238, 0x00112233);
exidx_->set_log(true);
exidx_->set_log(ARM_LOG_FULL);
exidx_->set_log_indent(0);
exidx_->set_log_skip_execution(false);

View file

@ -79,7 +79,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) {
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2001));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
std::string expected = "4 unwind Illegal\n";
expected += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", i);
ASSERT_EQ(expected, GetFakeLogPrint());
@ -90,7 +90,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_nop) {
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x00});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2001));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
std::string expected =
"4 unwind DW_CFA_nop\n"
"4 unwind Raw Data: 0x00\n";
@ -101,7 +101,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_nop) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_offset) {
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x83, 0x04});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2002));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2002));
std::string expected =
"4 unwind DW_CFA_offset register(3) 4\n"
"4 unwind Raw Data: 0x83 0x04\n";
@ -111,7 +111,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_offset) {
ResetLogs();
this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x83, 0x84, 0x01});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2100, 0x2103));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2100, 0x2103));
expected =
"4 unwind DW_CFA_offset register(3) 132\n"
"4 unwind Raw Data: 0x83 0x84 0x01\n";
@ -122,7 +122,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_offset) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended) {
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x05, 0x03, 0x02});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x503));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x503));
std::string expected =
"4 unwind DW_CFA_offset_extended register(3) 2\n"
"4 unwind Raw Data: 0x05 0x03 0x02\n";
@ -132,7 +132,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended) {
ResetLogs();
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x05, 0x81, 0x01, 0x82, 0x12});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1500, 0x1505));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1500, 0x1505));
expected =
"4 unwind DW_CFA_offset_extended register(129) 2306\n"
"4 unwind Raw Data: 0x05 0x81 0x01 0x82 0x12\n";
@ -143,7 +143,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended_sf) {
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x11, 0x05, 0x10});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x503));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x503));
std::string expected =
"4 unwind DW_CFA_offset_extended_sf register(5) 16\n"
"4 unwind Raw Data: 0x11 0x05 0x10\n";
@ -154,7 +154,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended_sf) {
ResetLogs();
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x11, 0x86, 0x01, 0xff, 0x7f});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1500, 0x1505));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1500, 0x1505));
expected =
"4 unwind DW_CFA_offset_extended_sf register(134) -1\n"
"4 unwind Raw Data: 0x11 0x86 0x01 0xff 0x7f\n";
@ -165,7 +165,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended_sf) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_restore) {
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0xc2});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2001));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
std::string expected =
"4 unwind DW_CFA_restore register(2)\n"
"4 unwind Raw Data: 0xc2\n";
@ -175,7 +175,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_restore) {
ResetLogs();
this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x82, 0x04, 0xc2});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x3000, 0x3003));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x3000, 0x3003));
expected =
"4 unwind DW_CFA_offset register(2) 4\n"
"4 unwind Raw Data: 0x82 0x04\n"
@ -188,7 +188,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_restore) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_restore_extended) {
this->memory_.SetMemory(0x4000, std::vector<uint8_t>{0x06, 0x08});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x4000, 0x4002));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x4000, 0x4002));
std::string expected =
"4 unwind DW_CFA_restore_extended register(8)\n"
"4 unwind Raw Data: 0x06 0x08\n";
@ -198,7 +198,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_restore_extended) {
ResetLogs();
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x05, 0x82, 0x02, 0x04, 0x06, 0x82, 0x02});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x5000, 0x5007));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x5000, 0x5007));
expected =
"4 unwind DW_CFA_offset_extended register(258) 4\n"
"4 unwind Raw Data: 0x05 0x82 0x02 0x04\n"
@ -228,7 +228,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_set_loc) {
this->memory_.SetMemory(0x50, buffer, sizeof(buffer));
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x50, 0x51 + sizeof(TypeParam)));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam)));
std::string expected = "4 unwind DW_CFA_set_loc " + address_str + "\n";
expected += "4 unwind " + raw_data + "\n";
expected += "4 unwind \n";
@ -240,7 +240,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_set_loc) {
ResetLogs();
this->fde_.pc_start = address + 0x10;
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x50, 0x51 + sizeof(TypeParam)));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam)));
expected = "4 unwind DW_CFA_set_loc " + address_str + "\n";
expected += "4 unwind " + raw_data + "\n";
expected += "4 unwind \n";
@ -252,7 +252,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_set_loc) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc) {
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x44});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x201));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x201));
std::string expected =
"4 unwind DW_CFA_advance_loc 4\n"
"4 unwind Raw Data: 0x44\n"
@ -260,22 +260,12 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc) {
"4 unwind PC 0x2010\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x200, 0x201));
expected =
"4 unwind DW_CFA_advance_loc 4\n"
"4 unwind Raw Data: 0x44\n"
"4 unwind \n"
"4 unwind PC 0x2110\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
}
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc1) {
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x02, 0x04});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x202));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x202));
std::string expected =
"4 unwind DW_CFA_advance_loc1 4\n"
"4 unwind Raw Data: 0x02 0x04\n"
@ -283,22 +273,12 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc1) {
"4 unwind PC 0x2004\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x10, 0x200, 0x202));
expected =
"4 unwind DW_CFA_advance_loc1 4\n"
"4 unwind Raw Data: 0x02 0x04\n"
"4 unwind \n"
"4 unwind PC 0x2014\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
}
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc2) {
this->memory_.SetMemory(0x600, std::vector<uint8_t>{0x03, 0x04, 0x03});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x600, 0x603));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x600, 0x603));
std::string expected =
"4 unwind DW_CFA_advance_loc2 772\n"
"4 unwind Raw Data: 0x03 0x04 0x03\n"
@ -306,22 +286,12 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc2) {
"4 unwind PC 0x2304\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1000, 0x600, 0x603));
expected =
"4 unwind DW_CFA_advance_loc2 772\n"
"4 unwind Raw Data: 0x03 0x04 0x03\n"
"4 unwind \n"
"4 unwind PC 0x3304\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
}
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc4) {
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x04, 0x04, 0x03, 0x02, 0x01});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x505));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x505));
std::string expected =
"4 unwind DW_CFA_advance_loc4 16909060\n"
"4 unwind Raw Data: 0x04 0x04 0x03 0x02 0x01\n"
@ -329,22 +299,12 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc4) {
"4 unwind PC 0x1022304\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x500, 0x505));
expected =
"4 unwind DW_CFA_advance_loc4 16909060\n"
"4 unwind Raw Data: 0x04 0x04 0x03 0x02 0x01\n"
"4 unwind \n"
"4 unwind PC 0x1024304\n";
ASSERT_EQ(expected, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
}
TYPED_TEST_P(DwarfCfaLogTest, cfa_undefined) {
this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x07, 0x09});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0xa00, 0xa02));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0xa00, 0xa02));
std::string expected =
"4 unwind DW_CFA_undefined register(9)\n"
"4 unwind Raw Data: 0x07 0x09\n";
@ -355,7 +315,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_undefined) {
dwarf_loc_regs_t cie_loc_regs;
this->memory_.SetMemory(0x1a00, std::vector<uint8_t>{0x07, 0x81, 0x01});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1a00, 0x1a03));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1a00, 0x1a03));
expected =
"4 unwind DW_CFA_undefined register(129)\n"
"4 unwind Raw Data: 0x07 0x81 0x01\n";
@ -366,7 +326,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_undefined) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_same) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x08, 0x7f});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
std::string expected =
"4 unwind DW_CFA_same_value register(127)\n"
"4 unwind Raw Data: 0x08 0x7f\n";
@ -376,7 +336,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_same) {
ResetLogs();
this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x08, 0xff, 0x01});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2100, 0x2103));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2100, 0x2103));
expected =
"4 unwind DW_CFA_same_value register(255)\n"
"4 unwind Raw Data: 0x08 0xff 0x01\n";
@ -387,7 +347,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_same) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_register) {
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x300, 0x303));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x300, 0x303));
std::string expected =
"4 unwind DW_CFA_register register(2) register(1)\n"
"4 unwind Raw Data: 0x09 0x02 0x01\n";
@ -397,7 +357,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_register) {
ResetLogs();
this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x09, 0xff, 0x01, 0xff, 0x03});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x4300, 0x4305));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x4300, 0x4305));
expected =
"4 unwind DW_CFA_register register(255) register(511)\n"
"4 unwind Raw Data: 0x09 0xff 0x01 0xff 0x03\n";
@ -408,7 +368,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_register) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_state) {
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x0a});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x300, 0x301));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x300, 0x301));
std::string expected =
"4 unwind DW_CFA_remember_state\n"
@ -419,7 +379,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_state) {
ResetLogs();
this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x0b});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x4300, 0x4301));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x4300, 0x4301));
expected =
"4 unwind DW_CFA_restore_state\n"
@ -431,7 +391,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_state) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_state_cfa_offset_restore) {
this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x0a, 0x0e, 0x40, 0x0b});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x3000, 0x3004));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x3000, 0x3004));
std::string expected =
"4 unwind DW_CFA_remember_state\n"
@ -447,7 +407,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_state_cfa_offset_restore) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0c, 0x7f, 0x74});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
std::string expected =
"4 unwind DW_CFA_def_cfa register(127) 116\n"
@ -458,7 +418,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa) {
ResetLogs();
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0c, 0xff, 0x02, 0xf4, 0x04});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x205));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x205));
expected =
"4 unwind DW_CFA_def_cfa register(383) 628\n"
@ -470,7 +430,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_sf) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x12, 0x30, 0x25});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
std::string expected =
"4 unwind DW_CFA_def_cfa_sf register(48) 37\n"
@ -482,7 +442,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_sf) {
ResetLogs();
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x12, 0xa3, 0x01, 0xfa, 0x7f});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x205));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x205));
expected =
"4 unwind DW_CFA_def_cfa_sf register(163) -6\n"
@ -494,7 +454,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_sf) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_register) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0d, 0x72});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
std::string expected =
"4 unwind DW_CFA_def_cfa_register register(114)\n"
@ -505,7 +465,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_register) {
ResetLogs();
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0d, 0xf9, 0x20});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x203));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x203));
expected =
"4 unwind DW_CFA_def_cfa_register register(4217)\n"
@ -517,7 +477,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_register) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0e, 0x59});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
std::string expected =
"4 unwind DW_CFA_def_cfa_offset 89\n"
@ -526,7 +486,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset) {
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
expected =
"4 unwind DW_CFA_def_cfa_offset 89\n"
@ -537,7 +497,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset) {
ResetLogs();
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0e, 0xd4, 0x0a});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x203));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x203));
expected =
"4 unwind DW_CFA_def_cfa_offset 1364\n"
@ -549,7 +509,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset_sf) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x13, 0x23});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
std::string expected =
"4 unwind DW_CFA_def_cfa_offset_sf 35\n"
@ -558,7 +518,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset_sf) {
ASSERT_EQ("", GetFakeLogBuf());
ResetLogs();
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
expected =
"4 unwind DW_CFA_def_cfa_offset_sf 35\n"
@ -570,7 +530,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset_sf) {
ResetLogs();
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x13, 0xf6, 0x7f});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x203));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x203));
expected =
"4 unwind DW_CFA_def_cfa_offset_sf -10\n"
@ -582,7 +542,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset_sf) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_expression) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0f, 0x04, 0x01, 0x02, 0x04, 0x05});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x106));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x106));
std::string expected =
"4 unwind DW_CFA_def_cfa_expression 4\n"
@ -614,7 +574,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_expression) {
}
expected += '\n';
this->memory_.SetMemory(0x200, ops);
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x284));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x284));
expected = "4 unwind DW_CFA_def_cfa_expression 129\n" + expected;
ASSERT_EQ(expected + op_string, GetFakeLogPrint());
@ -624,7 +584,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_expression) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_expression) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x10, 0x04, 0x02, 0xc0, 0xc1});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x105));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x105));
std::string expected =
"4 unwind DW_CFA_expression register(4) 2\n"
@ -652,7 +612,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_expression) {
expected = "4 unwind DW_CFA_expression register(255) 130\n" + expected + "\n";
this->memory_.SetMemory(0x200, ops);
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x287));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x287));
ASSERT_EQ(expected + op_string, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
@ -661,7 +621,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_expression) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x14, 0x45, 0x54});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
std::string expected =
"4 unwind DW_CFA_val_offset register(69) 84\n"
@ -672,7 +632,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset) {
ResetLogs();
this->memory_.SetMemory(0x400, std::vector<uint8_t>{0x14, 0xa2, 0x02, 0xb4, 0x05});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x400, 0x405));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x400, 0x405));
expected =
"4 unwind DW_CFA_val_offset register(290) 692\n"
@ -684,7 +644,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset_sf) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x15, 0x56, 0x12});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
std::string expected =
"4 unwind DW_CFA_val_offset_sf register(86) 18\n"
@ -696,7 +656,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset_sf) {
ResetLogs();
this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x15, 0xff, 0x01, 0xc0, 0x7f});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0xa00, 0xa05));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0xa00, 0xa05));
expected =
"4 unwind DW_CFA_val_offset_sf register(255) -64\n"
@ -708,7 +668,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset_sf) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_val_expression) {
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x16, 0x05, 0x02, 0xb0, 0xb1});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x105));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x105));
std::string expected =
"4 unwind DW_CFA_val_expression register(5) 2\n"
@ -737,7 +697,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_val_expression) {
this->memory_.SetMemory(0xa00, ops);
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0xa00, 0xaad));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0xa00, 0xaad));
ASSERT_EQ(expected + op_string, GetFakeLogPrint());
ASSERT_EQ("", GetFakeLogBuf());
@ -746,7 +706,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_val_expression) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_args_size) {
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2e, 0x04});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2002));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2002));
std::string expected =
"4 unwind DW_CFA_GNU_args_size 4\n"
@ -757,7 +717,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_args_size) {
ResetLogs();
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x2e, 0xa4, 0x80, 0x04});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x5000, 0x5004));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x5000, 0x5004));
expected =
"4 unwind DW_CFA_GNU_args_size 65572\n"
@ -769,7 +729,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_args_size) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_negative_offset_extended) {
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x2f, 0x08, 0x10});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x503));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x503));
std::string expected =
"4 unwind DW_CFA_GNU_negative_offset_extended register(8) 16\n"
@ -780,7 +740,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_negative_offset_extended) {
ResetLogs();
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x2f, 0x81, 0x02, 0xff, 0x01});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1500, 0x1505));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1500, 0x1505));
expected =
"4 unwind DW_CFA_GNU_negative_offset_extended register(257) 255\n"
@ -792,7 +752,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_negative_offset_extended) {
TYPED_TEST_P(DwarfCfaLogTest, cfa_register_override) {
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01, 0x09, 0x02, 0x04});
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x300, 0x306));
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x300, 0x306));
std::string expected =
"4 unwind DW_CFA_register register(2) register(1)\n"

View file

@ -103,7 +103,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init32) {
this->memory_.SetData32(0x5508, 0x4500);
this->memory_.SetData32(0x550c, 0x500);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -142,7 +142,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init32_fde_not_following_cie) {
this->memory_.SetData32(0x5108, 0x1500);
this->memory_.SetData32(0x510c, 0x200);
ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
}
@ -181,7 +181,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
this->memory_.SetData32(0x5508, 0x4500);
this->memory_.SetData32(0x550c, 0x500);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
}
@ -226,7 +226,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init64) {
this->memory_.SetData64(0x5514, 0x4500);
this->memory_.SetData64(0x551c, 0x500);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -267,7 +267,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init64_fde_not_following_cie) {
this->memory_.SetData64(0x5114, 0x1500);
this->memory_.SetData64(0x511c, 0x200);
ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
}
@ -312,10 +312,48 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
this->memory_.SetData64(0x5514, 0x4500);
this->memory_.SetData64(0x551c, 0x500);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
}
TYPED_TEST_P(DwarfDebugFrameTest, Init_non_zero_load_bias) {
// CIE 32 information.
this->memory_.SetData32(0x5000, 0xfc);
this->memory_.SetData32(0x5004, 0xffffffff);
this->memory_.SetData8(0x5008, 1);
this->memory_.SetData8(0x5009, 'z');
this->memory_.SetData8(0x500a, 'R');
this->memory_.SetData8(0x500b, '\0');
this->memory_.SetData8(0x500c, 0);
this->memory_.SetData8(0x500d, 0);
this->memory_.SetData8(0x500e, 0);
this->memory_.SetData8(0x500f, 0);
this->memory_.SetData8(0x5010, 0x1b);
// FDE 32 information.
this->memory_.SetData32(0x5100, 0xfc);
this->memory_.SetData32(0x5104, 0);
this->memory_.SetData32(0x5108, 0x1500);
this->memory_.SetData32(0x510c, 0x200);
this->memory_.SetData8(0x5110, 0);
this->memory_.SetData8(0x5111, 0);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0x1000));
ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
this->debug_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
EXPECT_EQ(0x2500U, info.start);
EXPECT_EQ(0x2700U, info.end);
const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2504);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x2500U, fde->pc_start);
EXPECT_EQ(0x2700U, fde->pc_end);
}
TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
// CIE 32 information.
this->memory_.SetData32(0x5000, 0xfc);
@ -340,7 +378,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
this->memory_.SetData16(0x5108, 0x1500);
this->memory_.SetData16(0x510a, 0x200);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200));
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -383,7 +421,7 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init_version4) {
this->memory_.SetData16(0x5108, 0x1500);
this->memory_.SetData16(0x510a, 0x200);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200));
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -538,8 +576,8 @@ TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) {
REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie,
Init32_do_not_fail_on_bad_next_entry, Init64,
Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie,
Init_version1, Init_version4, GetFdeOffsetFromPc, GetCieFde32,
GetCieFde64);
Init_non_zero_load_bias, Init_version1, Init_version4,
GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);

View file

@ -103,7 +103,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init32) {
this->memory_.SetData32(0x5508, 0x4500);
this->memory_.SetData32(0x550c, 0x500);
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600));
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -142,7 +142,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
this->memory_.SetData32(0x5108, 0x1500);
this->memory_.SetData32(0x510c, 0x200);
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
}
@ -187,7 +187,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init64) {
this->memory_.SetData64(0x5514, 0x4500);
this->memory_.SetData64(0x551c, 0x500);
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600));
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -228,10 +228,48 @@ TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
this->memory_.SetData64(0x5114, 0x1500);
this->memory_.SetData64(0x511c, 0x200);
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameTest, Init_non_zero_load_bias) {
// CIE 32 information.
this->memory_.SetData32(0x5000, 0xfc);
this->memory_.SetData32(0x5004, 0);
this->memory_.SetData8(0x5008, 1);
this->memory_.SetData8(0x5009, 'z');
this->memory_.SetData8(0x500a, 'R');
this->memory_.SetData8(0x500b, '\0');
this->memory_.SetData8(0x500c, 0);
this->memory_.SetData8(0x500d, 0);
this->memory_.SetData8(0x500e, 0);
this->memory_.SetData8(0x500f, 0);
this->memory_.SetData8(0x5010, 0x1b);
// FDE 32 information.
this->memory_.SetData32(0x5100, 0xfc);
this->memory_.SetData32(0x5104, 0x104);
this->memory_.SetData32(0x5108, 0x1500);
this->memory_.SetData32(0x510c, 0x200);
this->memory_.SetData8(0x5110, 0);
this->memory_.SetData8(0x5111, 0);
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0x2000));
ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
EXPECT_EQ(0x8608U, info.start);
EXPECT_EQ(0x8808U, info.end);
const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x8700);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x8608U, fde->pc_start);
EXPECT_EQ(0x8808U, fde->pc_end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
// CIE 32 information.
this->memory_.SetData32(0x5000, 0xfc);
@ -256,7 +294,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
this->memory_.SetData16(0x5108, 0x1500);
this->memory_.SetData16(0x510a, 0x200);
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200));
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0));
ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -299,7 +337,7 @@ TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
this->memory_.SetData16(0x5108, 0x1500);
this->memory_.SetData16(0x510a, 0x200);
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200));
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0));
ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
@ -450,8 +488,8 @@ TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
}
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, Init32, Init32_fde_not_following_cie, Init64,
Init64_fde_not_following_cie, Init_version1, Init_version4,
GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
Init64_fde_not_following_cie, Init_non_zero_load_bias, Init_version1,
Init_version4, GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);

View file

@ -83,7 +83,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init) {
this->memory_.SetData16(0x1004, 0x500);
this->memory_.SetData32(0x1006, 126);
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100));
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
EXPECT_EQ(DW_EH_PE_sdata4, this->eh_frame_->TestGetTableEncoding());
@ -97,19 +97,66 @@ 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_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
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_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
this->memory_.SetData8(0x1000, 2);
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias) {
this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
DW_EH_PE_pcrel | DW_EH_PE_sdata4});
this->memory_.SetData16(0x1004, 0x500);
this->memory_.SetData32(0x1006, 1);
this->memory_.SetData32(0x100a, 0x2500);
this->memory_.SetData32(0x100e, 0x1400);
// CIE 32 information.
this->memory_.SetData32(0x1300, 0xfc);
this->memory_.SetData32(0x1304, 0);
this->memory_.SetData8(0x1308, 1);
this->memory_.SetData8(0x1309, 'z');
this->memory_.SetData8(0x130a, 'R');
this->memory_.SetData8(0x130b, '\0');
this->memory_.SetData8(0x130c, 0);
this->memory_.SetData8(0x130d, 0);
this->memory_.SetData8(0x130e, 0);
this->memory_.SetData8(0x130f, 0);
this->memory_.SetData8(0x1310, 0x1b);
// FDE 32 information.
this->memory_.SetData32(0x1400, 0xfc);
this->memory_.SetData32(0x1404, 0x104);
this->memory_.SetData32(0x1408, 0x10f8);
this->memory_.SetData32(0x140c, 0x200);
this->memory_.SetData8(0x1410, 0);
this->memory_.SetData8(0x1411, 0);
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
EXPECT_EQ(1U, this->eh_frame_->TestGetFdeCount());
EXPECT_EQ(0x500U, this->eh_frame_->TestGetPtrOffset());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetEntriesOffset());
EXPECT_EQ(0x1100U, this->eh_frame_->TestGetEntriesEnd());
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x4500U, fde->pc_start);
EXPECT_EQ(0x4700U, fde->pc_end);
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
@ -123,6 +170,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
}
// We are assuming that pc rel, is really relative to the load_bias.
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_pcrel | DW_EH_PE_udata4);
this->eh_frame_->TestSetEntriesOffset(0x1000);
@ -134,8 +182,8 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
EXPECT_EQ(0x1380U, info->pc);
EXPECT_EQ(0x1540U, info->offset);
EXPECT_EQ(0x340U, info->pc);
EXPECT_EQ(0x500U, info->offset);
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_datarel) {
@ -430,14 +478,14 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_fde_not_found) {
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
}
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, GetFdeInfoFromIndex_expect_cache_fail,
GetFdeInfoFromIndex_read_pcrel, GetFdeInfoFromIndex_read_datarel,
GetFdeInfoFromIndex_cached, GetFdeOffsetBinary_verify,
GetFdeOffsetBinary_index_fail, GetFdeOffsetSequential,
GetFdeOffsetSequential_last_element, GetFdeOffsetSequential_end_check,
GetFdeOffsetFromPc_fail_fde_count, GetFdeOffsetFromPc_binary_search,
GetFdeOffsetFromPc_sequential_search, GetCieFde32, GetCieFde64,
GetFdeFromPc_fde_not_found);
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
GetFdeOffsetBinary_verify, GetFdeOffsetBinary_index_fail,
GetFdeOffsetSequential, GetFdeOffsetSequential_last_element,
GetFdeOffsetSequential_end_check, GetFdeOffsetFromPc_fail_fde_count,
GetFdeOffsetFromPc_binary_search, GetFdeOffsetFromPc_sequential_search,
GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);

View file

@ -36,7 +36,7 @@ class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
MockDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
virtual ~MockDwarfSectionImpl() = default;
MOCK_METHOD2(Init, bool(uint64_t, uint64_t));
MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
@ -884,7 +884,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Log) {
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x00});
this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0xc2});
ASSERT_TRUE(this->section_->Log(2, 0x1000, 0x1000, &fde));
ASSERT_TRUE(this->section_->Log(2, 0x1000, &fde));
ASSERT_EQ(
"4 unwind DW_CFA_nop\n"

View file

@ -30,13 +30,13 @@ class MockDwarfSection : public DwarfSection {
MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
virtual ~MockDwarfSection() = default;
MOCK_METHOD4(Log, bool(uint8_t, uint64_t, uint64_t, const DwarfFde*));
MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*));
MOCK_METHOD2(Init, bool(uint64_t, uint64_t));
MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));

View file

@ -32,7 +32,7 @@ namespace unwindstack {
std::deque<FunctionData> ElfInterfaceFake::functions_;
std::deque<StepData> ElfInterfaceFake::steps_;
bool ElfInterfaceFake::GetFunctionName(uint64_t, uint64_t, std::string* name, uint64_t* offset) {
bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) {
if (functions_.empty()) {
return false;
}
@ -52,7 +52,7 @@ bool ElfInterfaceFake::GetGlobalVariable(const std::string& global, uint64_t* of
return true;
}
bool ElfInterfaceFake::Step(uint64_t, uint64_t, Regs* regs, Memory*, bool* finished) {
bool ElfInterfaceFake::Step(uint64_t, Regs* regs, Memory*, bool* finished) {
if (steps_.empty()) {
return false;
}

View file

@ -67,13 +67,13 @@ class ElfInterfaceFake : public ElfInterface {
virtual ~ElfInterfaceFake() = default;
bool Init(uint64_t*) override { return false; }
void InitHeaders() override {}
void InitHeaders(uint64_t) override {}
bool GetSoname(std::string*) override { return false; }
bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override;
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
bool GetGlobalVariable(const std::string&, uint64_t*) override;
bool Step(uint64_t, uint64_t, Regs*, Memory*, bool*) override;
bool Step(uint64_t, Regs*, Memory*, bool*) override;
void FakeSetGlobalVariable(const std::string& global, uint64_t offset) {
globals_[global] = offset;

View file

@ -302,7 +302,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx) {
// FindEntry fails.
bool finished;
ASSERT_FALSE(interface.StepExidx(0x7000, 0, nullptr, nullptr, &finished));
ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// ExtractEntry should fail.
@ -316,18 +316,18 @@ TEST_F(ElfInterfaceArmTest, StepExidx) {
regs[ARM_REG_LR] = 0x20000;
regs.set_sp(regs[ARM_REG_SP]);
regs.set_pc(0x1234);
ASSERT_FALSE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
ASSERT_FALSE(interface.StepExidx(0x7000, &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));
ASSERT_FALSE(interface.StepExidx(0x7000, &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));
ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
ASSERT_FALSE(finished);
ASSERT_EQ(0x1000U, regs.sp());
@ -336,11 +336,13 @@ TEST_F(ElfInterfaceArmTest, StepExidx) {
ASSERT_EQ(0x20000U, regs[ARM_REG_PC]);
// Load bias is non-zero.
ASSERT_TRUE(interface.StepExidx(0x8000, 0x1000, &regs, &process_memory_, &finished));
interface.set_load_bias(0x1000);
ASSERT_TRUE(interface.StepExidx(0x8000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// Pc too small.
ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, &regs, &process_memory_, &finished));
interface.set_load_bias(0x9000);
ASSERT_FALSE(interface.StepExidx(0x8000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
}
@ -362,7 +364,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
// Everything should pass.
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_FALSE(finished);
ASSERT_EQ(0x10004U, regs.sp());
@ -386,7 +388,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
regs.set_pc(0x1234);
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0x10000U, regs.sp());
@ -409,7 +411,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
regs.set_pc(0x1234);
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0x10000U, regs.sp());
@ -436,7 +438,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) {
regs.set_pc(0x1234);
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0U, regs.pc());
@ -449,7 +451,7 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) {
regs.set_sp(regs[ARM_REG_SP]);
regs.set_pc(0x1234);
ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0U, regs.pc());

View file

@ -647,7 +647,7 @@ void ElfInterfaceTest::InitHeadersEhFrameTest() {
memory_.SetData32(0x10004, 0x500);
memory_.SetData32(0x10008, 250);
elf.InitHeaders();
elf.InitHeaders(0);
EXPECT_FALSE(elf.eh_frame() == nullptr);
EXPECT_TRUE(elf.debug_frame() == nullptr);
@ -680,7 +680,7 @@ void ElfInterfaceTest::InitHeadersDebugFrame() {
memory_.SetData32(0x5108, 0x1500);
memory_.SetData32(0x510c, 0x200);
elf.InitHeaders();
elf.InitHeaders(0);
EXPECT_TRUE(elf.eh_frame() == nullptr);
EXPECT_FALSE(elf.debug_frame() == nullptr);
@ -703,7 +703,7 @@ void ElfInterfaceTest::InitHeadersEhFrameFail() {
elf.FakeSetDebugFrameOffset(0);
elf.FakeSetDebugFrameSize(0);
elf.InitHeaders();
elf.InitHeaders(0);
EXPECT_TRUE(elf.eh_frame() == nullptr);
EXPECT_EQ(0U, elf.eh_frame_offset());
@ -728,7 +728,7 @@ void ElfInterfaceTest::InitHeadersDebugFrameFail() {
elf.FakeSetDebugFrameOffset(0x1000);
elf.FakeSetDebugFrameSize(0x100);
elf.InitHeaders();
elf.InitHeaders(0);
EXPECT_TRUE(elf.eh_frame() == nullptr);
EXPECT_TRUE(elf.debug_frame() == nullptr);
@ -833,10 +833,10 @@ void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
// Look in the first symbol table.
std::string name;
uint64_t name_offset;
ASSERT_TRUE(elf->GetFunctionName(0x90010, 0, &name, &name_offset));
ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset));
EXPECT_EQ("function_one", name);
EXPECT_EQ(16U, name_offset);
ASSERT_TRUE(elf->GetFunctionName(0xd0020, 0, &name, &name_offset));
ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset));
EXPECT_EQ("function_two", name);
EXPECT_EQ(32U, name_offset);
}
@ -1065,7 +1065,7 @@ TEST_F(ElfInterfaceTest, is_valid_pc_from_debug_frame) {
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
elf->InitHeaders();
elf->InitHeaders(0);
EXPECT_EQ(0U, load_bias);
EXPECT_FALSE(elf->IsValidPc(0));
EXPECT_FALSE(elf->IsValidPc(0x20ff));
@ -1128,7 +1128,7 @@ TEST_F(ElfInterfaceTest, is_valid_pc_from_eh_frame) {
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
elf->InitHeaders();
elf->InitHeaders(0);
EXPECT_EQ(0U, load_bias);
EXPECT_FALSE(elf->IsValidPc(0));
EXPECT_FALSE(elf->IsValidPc(0x27ff));

View file

@ -297,16 +297,11 @@ TEST_F(ElfTest, rel_pc) {
elf.FakeSetInterface(interface);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
MapInfo map_info(0x1000, 0x2000);
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
elf.FakeSetLoadBias(0x3000);
ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
elf.FakeSetValid(false);
elf.FakeSetLoadBias(0);
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
}
@ -328,7 +323,6 @@ TEST_F(ElfTest, step_in_signal_map) {
}
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
bool finished;
ASSERT_TRUE(elf.Step(0x3000, 0x1000, &regs, &process_memory, &finished));
EXPECT_FALSE(finished);
@ -342,11 +336,11 @@ class ElfInterfaceMock : public ElfInterface {
virtual ~ElfInterfaceMock() = default;
bool Init(uint64_t*) override { return false; }
void InitHeaders() override {}
void InitHeaders(uint64_t) override {}
bool GetSoname(std::string*) override { return false; }
bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override { return false; }
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
MOCK_METHOD5(Step, bool(uint64_t, uint64_t, Regs*, Memory*, bool*));
MOCK_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
MOCK_METHOD2(GetGlobalVariable, bool(const std::string&, uint64_t*));
MOCK_METHOD1(IsValidPc, bool(uint64_t));
@ -358,7 +352,6 @@ class ElfInterfaceMock : public ElfInterface {
TEST_F(ElfTest, step_in_interface) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
RegsArm regs;
@ -367,30 +360,12 @@ TEST_F(ElfTest, step_in_interface) {
MemoryFake process_memory;
bool finished;
EXPECT_CALL(*interface, Step(0x1000, 0, &regs, &process_memory, &finished))
EXPECT_CALL(*interface, Step(0x1000, &regs, &process_memory, &finished))
.WillOnce(::testing::Return(true));
ASSERT_TRUE(elf.Step(0x1004, 0x1000, &regs, &process_memory, &finished));
}
TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0x4000);
RegsArm regs;
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
MemoryFake process_memory;
bool finished;
EXPECT_CALL(*interface, Step(0x7300, 0x4000, &regs, &process_memory, &finished))
.WillOnce(::testing::Return(true));
ASSERT_TRUE(elf.Step(0x7304, 0x7300, &regs, &process_memory, &finished));
}
TEST_F(ElfTest, get_global_invalid_elf) {
ElfFake elf(memory_);
elf.FakeSetValid(false);
@ -403,7 +378,6 @@ TEST_F(ElfTest, get_global_invalid_elf) {
TEST_F(ElfTest, get_global_valid_not_in_interface) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
@ -431,10 +405,26 @@ TEST_F(ElfTest, get_global_valid_below_load_bias) {
ASSERT_FALSE(elf.GetGlobalVariable(global, &offset));
}
TEST_F(ElfTest, get_global_valid_dynamic_zero_non_zero_load_bias) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0x100);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
uint64_t offset;
std::string global("something");
EXPECT_CALL(*interface, GetGlobalVariable(global, &offset))
.WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x300), ::testing::Return(true)));
ASSERT_TRUE(elf.GetGlobalVariable(global, &offset));
EXPECT_EQ(0x200U, offset);
}
TEST_F(ElfTest, get_global_valid_dynamic_zero) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
@ -456,7 +446,6 @@ TEST_F(ElfTest, get_global_valid_dynamic_zero) {
TEST_F(ElfTest, get_global_valid_in_gnu_debugdata_dynamic_zero) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
@ -470,27 +459,9 @@ TEST_F(ElfTest, get_global_valid_in_gnu_debugdata_dynamic_zero) {
EXPECT_EQ(0x300U, offset);
}
TEST_F(ElfTest, get_global_valid_dynamic_zero_non_zero_load_bias) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0x100);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
uint64_t offset;
std::string global("something");
EXPECT_CALL(*interface, GetGlobalVariable(global, &offset))
.WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x300), ::testing::Return(true)));
ASSERT_TRUE(elf.GetGlobalVariable(global, &offset));
EXPECT_EQ(0x200U, offset);
}
TEST_F(ElfTest, get_global_valid_dynamic_adjust_negative) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
interface->MockSetDynamicOffset(0x400);
@ -510,7 +481,6 @@ TEST_F(ElfTest, get_global_valid_dynamic_adjust_negative) {
TEST_F(ElfTest, get_global_valid_dynamic_adjust_positive) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
interface->MockSetDynamicOffset(0x1000);
@ -530,7 +500,6 @@ TEST_F(ElfTest, get_global_valid_dynamic_adjust_positive) {
TEST_F(ElfTest, is_valid_pc_elf_invalid) {
ElfFake elf(memory_);
elf.FakeSetValid(false);
elf.FakeSetLoadBias(0);
EXPECT_FALSE(elf.IsValidPc(0x100));
EXPECT_FALSE(elf.IsValidPc(0x200));
@ -539,7 +508,6 @@ TEST_F(ElfTest, is_valid_pc_elf_invalid) {
TEST_F(ElfTest, is_valid_pc_interface) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
@ -549,25 +517,9 @@ TEST_F(ElfTest, is_valid_pc_interface) {
EXPECT_TRUE(elf.IsValidPc(0x1500));
}
TEST_F(ElfTest, is_valid_pc_non_zero_load_bias) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0x1000);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);
EXPECT_CALL(*interface, IsValidPc(0x500)).WillOnce(::testing::Return(true));
EXPECT_FALSE(elf.IsValidPc(0x100));
EXPECT_FALSE(elf.IsValidPc(0x200));
EXPECT_TRUE(elf.IsValidPc(0x1500));
}
TEST_F(ElfTest, is_valid_pc_from_gnu_debugdata) {
ElfFake elf(memory_);
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
elf.FakeSetInterface(interface);

View file

@ -70,18 +70,18 @@ TYPED_TEST_P(SymbolsTest, function_bounds_check) {
std::string name;
uint64_t func_offset;
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
ASSERT_EQ("fake_function", name);
ASSERT_EQ(0U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0x500f, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x500f, &this->memory_, &name, &func_offset));
ASSERT_EQ("fake_function", name);
ASSERT_EQ(0xfU, func_offset);
// Check one before and one after the function.
ASSERT_FALSE(symbols.GetName<TypeParam>(0x4fff, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5010, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x4fff, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5010, &this->memory_, &name, &func_offset));
}
TYPED_TEST_P(SymbolsTest, no_symbol) {
@ -98,7 +98,7 @@ TYPED_TEST_P(SymbolsTest, no_symbol) {
// First verify that we can get the name.
std::string name;
uint64_t func_offset;
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
ASSERT_EQ("fake_function", name);
ASSERT_EQ(0U, func_offset);
@ -107,7 +107,7 @@ TYPED_TEST_P(SymbolsTest, no_symbol) {
this->memory_.SetMemory(offset, &sym, sizeof(sym));
// Clear the cache to force the symbol data to be re-read.
symbols.ClearCache();
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
// Set the function back, and set the shndx to UNDEF.
sym.st_info = STT_FUNC;
@ -115,7 +115,7 @@ TYPED_TEST_P(SymbolsTest, no_symbol) {
this->memory_.SetMemory(offset, &sym, sizeof(sym));
// Clear the cache to force the symbol data to be re-read.
symbols.ClearCache();
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
}
TYPED_TEST_P(SymbolsTest, multiple_entries) {
@ -144,34 +144,34 @@ TYPED_TEST_P(SymbolsTest, multiple_entries) {
std::string name;
uint64_t func_offset;
ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_two", name);
ASSERT_EQ(1U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_one", name);
ASSERT_EQ(4U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_three", name);
ASSERT_EQ(1U, func_offset);
// Reget some of the others to verify getting one function name doesn't
// affect any of the next calls.
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5008, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5008, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_one", name);
ASSERT_EQ(8U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0x3008, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x3008, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_two", name);
ASSERT_EQ(4U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0xa01a, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0xa01a, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_three", name);
ASSERT_EQ(0xaU, func_offset);
}
@ -203,47 +203,21 @@ TYPED_TEST_P(SymbolsTest, multiple_entries_nonstandard_size) {
std::string name;
uint64_t func_offset;
ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_two", name);
ASSERT_EQ(1U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_one", name);
ASSERT_EQ(4U, func_offset);
name.clear();
ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, &this->memory_, &name, &func_offset));
ASSERT_EQ("function_three", name);
ASSERT_EQ(1U, func_offset);
}
TYPED_TEST_P(SymbolsTest, load_bias) {
Symbols symbols(0x1000, sizeof(TypeParam), sizeof(TypeParam), 0x2000, 0x100);
TypeParam sym;
this->InitSym(&sym, 0x5000, 0x10, 0x40);
uint64_t offset = 0x1000;
this->memory_.SetMemory(offset, &sym, sizeof(sym));
std::string fake_name("fake_function");
this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1);
// Set a non-zero load_bias that should be a valid function offset.
std::string name;
uint64_t func_offset;
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, 0x1000, &this->memory_, &name, &func_offset));
ASSERT_EQ("fake_function", name);
ASSERT_EQ(4U, func_offset);
// Set a flag that should cause the load_bias to be ignored.
sym.st_shndx = SHN_ABS;
this->memory_.SetMemory(offset, &sym, sizeof(sym));
// Clear the cache to force the symbol data to be re-read.
symbols.ClearCache();
ASSERT_FALSE(symbols.GetName<TypeParam>(0x5004, 0x1000, &this->memory_, &name, &func_offset));
}
TYPED_TEST_P(SymbolsTest, symtab_value_out_of_bounds) {
Symbols symbols_end_at_100(0x1000, sizeof(TypeParam) * 2, sizeof(TypeParam), 0x2000, 0x100);
Symbols symbols_end_at_200(0x1000, sizeof(TypeParam) * 2, sizeof(TypeParam), 0x2000, 0x200);
@ -265,18 +239,16 @@ TYPED_TEST_P(SymbolsTest, symtab_value_out_of_bounds) {
std::string name;
uint64_t func_offset;
// Verify that we can get the function name properly for both entries.
ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
ASSERT_EQ("fake_function", name);
ASSERT_EQ(0U, func_offset);
ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x3000, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x3000, &this->memory_, &name, &func_offset));
ASSERT_EQ("function", name);
ASSERT_EQ(0U, func_offset);
// Now use the symbol table that ends at 0x100.
ASSERT_FALSE(
symbols_end_at_100.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(
symbols_end_at_100.GetName<TypeParam>(0x3000, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols_end_at_100.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols_end_at_100.GetName<TypeParam>(0x3000, &this->memory_, &name, &func_offset));
}
// Verify the entire func table is cached.
@ -302,9 +274,9 @@ TYPED_TEST_P(SymbolsTest, symtab_read_cached) {
// Do call that should cache all of the entries (except the string data).
std::string name;
uint64_t func_offset;
ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, &this->memory_, &name, &func_offset));
this->memory_.Clear();
ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, 0, &this->memory_, &name, &func_offset));
ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, &this->memory_, &name, &func_offset));
// Clear the memory and only put the symbol data string data in memory.
this->memory_.Clear();
@ -317,15 +289,15 @@ TYPED_TEST_P(SymbolsTest, symtab_read_cached) {
fake_name = "third_entry";
this->memory_.SetMemory(0xa300, fake_name.c_str(), fake_name.size() + 1);
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5001, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x5001, &this->memory_, &name, &func_offset));
ASSERT_EQ("first_entry", name);
ASSERT_EQ(1U, func_offset);
ASSERT_TRUE(symbols.GetName<TypeParam>(0x2002, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x2002, &this->memory_, &name, &func_offset));
ASSERT_EQ("second_entry", name);
ASSERT_EQ(2U, func_offset);
ASSERT_TRUE(symbols.GetName<TypeParam>(0x1003, 0, &this->memory_, &name, &func_offset));
ASSERT_TRUE(symbols.GetName<TypeParam>(0x1003, &this->memory_, &name, &func_offset));
ASSERT_EQ("third_entry", name);
ASSERT_EQ(3U, func_offset);
}
@ -381,17 +353,17 @@ TYPED_TEST_P(SymbolsTest, get_global) {
EXPECT_FALSE(symbols.GetGlobal<TypeParam>(&this->memory_, "function_1", &offset));
std::string name;
EXPECT_TRUE(symbols.GetName<TypeParam>(0x10002, 0, &this->memory_, &name, &offset));
EXPECT_TRUE(symbols.GetName<TypeParam>(0x10002, &this->memory_, &name, &offset));
EXPECT_EQ("function_0", name);
EXPECT_EQ(2U, offset);
EXPECT_TRUE(symbols.GetName<TypeParam>(0x12004, 0, &this->memory_, &name, &offset));
EXPECT_TRUE(symbols.GetName<TypeParam>(0x12004, &this->memory_, &name, &offset));
EXPECT_EQ("function_1", name);
EXPECT_EQ(4U, offset);
}
REGISTER_TYPED_TEST_CASE_P(SymbolsTest, function_bounds_check, no_symbol, multiple_entries,
multiple_entries_nonstandard_size, load_bias, symtab_value_out_of_bounds,
multiple_entries_nonstandard_size, symtab_value_out_of_bounds,
symtab_read_cached, get_global);
typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes;

View file

@ -1200,4 +1200,43 @@ TEST_F(UnwindOfflineTest, offset_arm) {
EXPECT_EQ(0xffcc1558U, unwinder.frames()[18].sp);
}
// Test using a non-zero load bias library that has the fde entries
// encoded as 0xb, which is not set as pc relative.
TEST_F(UnwindOfflineTest, debug_frame_load_bias_arm) {
ASSERT_NO_FATAL_FAILURE(Init("debug_frame_load_bias_arm/", ARCH_ARM));
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(8U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 0005138c libc.so (__ioctl+8)\n"
" #01 pc 0002140f libc.so (ioctl+30)\n"
" #02 pc 00039535 libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+204)\n"
" #03 pc 00039633 libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+10)\n"
" #04 pc 00039b57 libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+38)\n"
" #05 pc 00000c21 mediaserver (main+104)\n"
" #06 pc 00084b89 libc.so (__libc_init+48)\n"
" #07 pc 00000b77 mediaserver (_start_main+38)\n",
frame_info);
EXPECT_EQ(0xf0be238cU, unwinder.frames()[0].pc);
EXPECT_EQ(0xffd4a638U, unwinder.frames()[0].sp);
EXPECT_EQ(0xf0bb240fU, unwinder.frames()[1].pc);
EXPECT_EQ(0xffd4a638U, unwinder.frames()[1].sp);
EXPECT_EQ(0xf1a75535U, unwinder.frames()[2].pc);
EXPECT_EQ(0xffd4a650U, unwinder.frames()[2].sp);
EXPECT_EQ(0xf1a75633U, unwinder.frames()[3].pc);
EXPECT_EQ(0xffd4a6b0U, unwinder.frames()[3].sp);
EXPECT_EQ(0xf1a75b57U, unwinder.frames()[4].pc);
EXPECT_EQ(0xffd4a6d0U, unwinder.frames()[4].sp);
EXPECT_EQ(0x8d1cc21U, unwinder.frames()[5].pc);
EXPECT_EQ(0xffd4a6e8U, unwinder.frames()[5].sp);
EXPECT_EQ(0xf0c15b89U, unwinder.frames()[6].pc);
EXPECT_EQ(0xffd4a700U, unwinder.frames()[6].sp);
EXPECT_EQ(0x8d1cb77U, unwinder.frames()[7].pc);
EXPECT_EQ(0xffd4a718U, unwinder.frames()[7].sp);
}
} // namespace unwindstack

View file

@ -0,0 +1,3 @@
8d1c000-8d1f000 r-xp 0 00:00 0 mediaserver
f0b91000-f0c2c000 r-xp 0 00:00 0 libc.so
f1a41000-f1a97000 r-xp 0 00:00 0 libbinder.so

View file

@ -0,0 +1,16 @@
r0: 3
r1: c0306201
r2: ffd4a658
r3: 0
r4: f0c36d8c
r5: ffd4a658
r6: f0168000
r7: 36
r8: ffd4a678
r9: f016802c
r10: ffd4a660
r11: 0
ip: 0
sp: ffd4a638
lr: f0bb2413
pc: f0be238c

View file

@ -37,7 +37,7 @@
namespace unwindstack {
void DumpArm(ElfInterfaceArm* interface) {
void DumpArm(Elf* elf, ElfInterfaceArm* interface) {
if (interface == nullptr) {
printf("No ARM Unwind Information.\n\n");
return;
@ -48,12 +48,11 @@ void DumpArm(ElfInterfaceArm* interface) {
uint64_t load_bias = entry.second.table_offset;
printf(" PC Range 0x%" PRIx64 " - 0x%" PRIx64 "\n", entry.second.offset + load_bias,
entry.second.table_size + load_bias);
for (auto addr : *interface) {
for (auto pc : *interface) {
std::string name;
printf(" PC 0x%" PRIx64, addr + load_bias);
printf(" PC 0x%" PRIx64, pc + load_bias);
uint64_t func_offset;
uint64_t pc = addr + load_bias;
if (interface->GetFunctionName(pc, load_bias, &name, &func_offset) && !name.empty()) {
if (elf->GetFunctionName(pc + load_bias, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
@ -63,7 +62,7 @@ void DumpArm(ElfInterfaceArm* interface) {
continue;
}
ArmExidx arm(nullptr, interface->memory(), nullptr);
arm.set_log(true);
arm.set_log(ARM_LOG_FULL);
arm.set_log_skip_execution(true);
arm.set_log_indent(2);
if (!arm.ExtractEntryData(entry)) {
@ -82,21 +81,21 @@ void DumpArm(ElfInterfaceArm* interface) {
printf("\n");
}
void DumpDwarfSection(ElfInterface* interface, DwarfSection* section, uint64_t load_bias) {
void DumpDwarfSection(Elf* elf, DwarfSection* section, uint64_t) {
for (const DwarfFde* fde : *section) {
// Sometimes there are entries that have empty length, skip those since
// they don't contain any interesting information.
if (fde == nullptr || fde->pc_start == fde->pc_end) {
continue;
}
printf("\n PC 0x%" PRIx64, fde->pc_start + load_bias);
printf("\n PC 0x%" PRIx64 "-0x%" PRIx64, fde->pc_start, fde->pc_end);
std::string name;
uint64_t func_offset;
if (interface->GetFunctionName(fde->pc_start, load_bias, &name, &func_offset) && !name.empty()) {
if (elf->GetFunctionName(fde->pc_start, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
if (!section->Log(2, UINT64_MAX, load_bias, fde)) {
if (!section->Log(2, UINT64_MAX, fde)) {
printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start);
}
}
@ -126,13 +125,13 @@ int GetElfInfo(const char* file, uint64_t offset) {
ElfInterface* interface = elf.interface();
if (elf.machine_type() == EM_ARM) {
DumpArm(reinterpret_cast<ElfInterfaceArm*>(interface));
DumpArm(&elf, reinterpret_cast<ElfInterfaceArm*>(interface));
printf("\n");
}
if (interface->eh_frame() != nullptr) {
printf("eh_frame information:\n");
DumpDwarfSection(interface, interface->eh_frame(), elf.GetLoadBias());
DumpDwarfSection(&elf, interface->eh_frame(), elf.GetLoadBias());
printf("\n");
} else {
printf("\nno eh_frame information\n");
@ -140,7 +139,7 @@ int GetElfInfo(const char* file, uint64_t offset) {
if (interface->debug_frame() != nullptr) {
printf("\ndebug_frame information:\n");
DumpDwarfSection(interface, interface->debug_frame(), elf.GetLoadBias());
DumpDwarfSection(&elf, interface->debug_frame(), elf.GetLoadBias());
printf("\n");
} else {
printf("\nno debug_frame information\n");
@ -151,12 +150,12 @@ int GetElfInfo(const char* file, uint64_t offset) {
if (gnu_debugdata_interface != nullptr) {
if (gnu_debugdata_interface->eh_frame() != nullptr) {
printf("\ngnu_debugdata (eh_frame):\n");
DumpDwarfSection(gnu_debugdata_interface, gnu_debugdata_interface->eh_frame(), 0);
DumpDwarfSection(&elf, gnu_debugdata_interface->eh_frame(), 0);
printf("\n");
}
if (gnu_debugdata_interface->debug_frame() != nullptr) {
printf("\ngnu_debugdata (debug_frame):\n");
DumpDwarfSection(gnu_debugdata_interface, gnu_debugdata_interface->debug_frame(), 0);
DumpDwarfSection(&elf, gnu_debugdata_interface->debug_frame(), 0);
printf("\n");
}
} else {

View file

@ -34,7 +34,9 @@
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Log.h>
#include "ArmExidx.h"
#include "DwarfOp.h"
#include "ElfInterfaceArm.h"
namespace unwindstack {
@ -136,6 +138,32 @@ void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uin
}
}
void PrintArmRegInformation(ElfInterfaceArm* interface, uint64_t pc) {
printf("\nArm exidx:\n");
uint64_t entry_offset;
if (!interface->FindEntry(pc, &entry_offset)) {
return;
}
ArmExidx arm(nullptr, interface->memory(), nullptr);
log_to_stdout(true);
arm.set_log(ARM_LOG_BY_REG);
arm.set_log_skip_execution(true);
arm.set_log_indent(1);
if (!arm.ExtractEntryData(entry_offset)) {
if (arm.status() != ARM_STATUS_NO_UNWIND) {
printf(" Error trying to extract data.\n");
}
return;
}
if (arm.data()->size() != 0 && arm.Eval()) {
arm.LogByReg();
} else {
printf(" Error tring to evaluate exidx data.\n");
}
}
int GetInfo(const char* file, uint64_t pc) {
MemoryFileAtOffset* memory = new MemoryFileAtOffset;
if (!memory->Init(file, 0)) {
@ -162,12 +190,22 @@ int GetInfo(const char* file, uint64_t pc) {
printf("Soname: %s\n\n", soname.c_str());
}
printf("PC 0x%" PRIx64 ":\n", pc);
printf("PC 0x%" PRIx64, pc);
std::string function_name;
uint64_t function_offset;
if (elf.GetFunctionName(pc, &function_name, &function_offset)) {
printf(" (%s)", function_name.c_str());
}
printf(":\n");
if (elf.machine_type() == EM_ARM) {
PrintArmRegInformation(reinterpret_cast<ElfInterfaceArm*>(interface), pc - load_bias);
}
DwarfSection* section = interface->eh_frame();
if (section != nullptr) {
printf("\neh_frame:\n");
PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
PrintRegInformation(section, memory, pc, elf.class_type());
} else {
printf("\nno eh_frame information\n");
}
@ -175,7 +213,7 @@ int GetInfo(const char* file, uint64_t pc) {
section = interface->debug_frame();
if (section != nullptr) {
printf("\ndebug_frame:\n");
PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
PrintRegInformation(section, memory, pc, elf.class_type());
printf("\n");
} else {
printf("\nno debug_frame information\n");

View file

@ -95,7 +95,6 @@ int main(int argc, char** argv) {
}
std::string name;
uint64_t load_bias = elf.GetLoadBias();
if (argc == 3) {
std::string cur_name;
uint64_t func_offset;
@ -113,8 +112,8 @@ int main(int argc, char** argv) {
// This is a crude way to get the symbols in order.
for (const auto& entry : elf.interface()->pt_loads()) {
uint64_t start = entry.second.offset + load_bias;
uint64_t end = entry.second.table_size + load_bias;
uint64_t start = entry.second.offset;
uint64_t end = entry.second.table_size;
for (uint64_t addr = start; addr < end; addr += 4) {
std::string cur_name;
uint64_t func_offset;