Fix handling of load bias values.

It turns out that for the dwarf information, if a FDE indicates it's pc
relative, then pc has to be incremented by the load bias. If not, then
it should not be incremented.

Previously, the code always subtracted load bias values from pcs, and assumed
that all fdes were incremented by load bias values. The new code actually
reads the fdes and adjusted the pcs in the fde and in the eh frame hdr so
that load bias values are already handled properly.

In addition, add dumping of arm exidx values in unwind_reg_info. This allowed
verifying that the debug frame in those elf files was being handled properly.

Added a new unit test that only has a debug frame that has a non-zero load
bias and has fde entries that do not have pc relative encoding.

Fix a couple of other small bugs.

Bug: 109824792

Test: All libbacktrace/libunwindstack unit tests pass.
Test: Ran ART 137-cfi test and 004-ThreadStress.
Test: Verify that displaying the fde start and end pc actually match the
Test: real data for fde that have pc relative set, and that don't.
Test: Verified that the unwind information for arm exidx matches the
Test: debug frame data.

Change-Id: I707555286b5cb05df9f25489e8c5ede753cfe0fb
This commit is contained in:
Christopher Ferris 2018-06-06 14:47:31 -07:00
parent 3ee8926f5d
commit 4cc36d2b43
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;