Merge "Fix handling of load bias values."
This commit is contained in:
commit
9c1d75983a
40 changed files with 1741 additions and 887 deletions
|
|
@ -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/*",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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*));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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, ®s, &process_memory_, &finished));
|
||||
ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
|
||||
EXPECT_EQ(ERROR_MEMORY_INVALID, interface.LastErrorCode());
|
||||
EXPECT_EQ(0x1004U, interface.LastErrorAddress());
|
||||
|
||||
// Eval should fail.
|
||||
memory_.SetData32(0x1004, 0x81000000);
|
||||
ASSERT_FALSE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
|
||||
ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
|
||||
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
|
||||
|
||||
// Everything should pass.
|
||||
memory_.SetData32(0x1004, 0x80b0b0b0);
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &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, ®s, &process_memory_, &finished));
|
||||
interface.set_load_bias(0x1000);
|
||||
ASSERT_TRUE(interface.StepExidx(0x8000, ®s, &process_memory_, &finished));
|
||||
EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
|
||||
|
||||
// Pc too small.
|
||||
ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, ®s, &process_memory_, &finished));
|
||||
interface.set_load_bias(0x9000);
|
||||
ASSERT_FALSE(interface.StepExidx(0x8000, ®s, &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, ®s, &process_memory_, &finished));
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &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, ®s, &process_memory_, &finished));
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &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, ®s, &process_memory_, &finished));
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &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, ®s, &process_memory_, &finished));
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &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, ®s, &process_memory_, &finished));
|
||||
ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
|
||||
EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
|
||||
ASSERT_TRUE(finished);
|
||||
ASSERT_EQ(0U, regs.pc());
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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, ®s, &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, ®s, &process_memory, &finished))
|
||||
EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x1004, 0x1000, ®s, &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, ®s, &process_memory, &finished))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x7304, 0x7300, ®s, &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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue