diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index d4cef7cde..df5da650c 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -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/*", diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp index 6e397e31f..818f5d16a 100644 --- a/libunwindstack/ArmExidx.cpp +++ b/libunwindstack/ArmExidx.cpp @@ -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 diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h index 96756a017..d9fc371c3 100644 --- a/libunwindstack/ArmExidx.h +++ b/libunwindstack/ArmExidx.h @@ -20,6 +20,7 @@ #include #include +#include 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 log_regs_; }; } // namespace unwindstack diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp index 6ecedce38..cd9ef6141 100644 --- a/libunwindstack/DwarfCfa.cpp +++ b/libunwindstack/DwarfCfa.cpp @@ -264,8 +264,8 @@ bool DwarfCfa::LogInstruction(uint32_t indent, uint64_t cfa_offset, } template -bool DwarfCfa::Log(uint32_t indent, uint64_t pc, uint64_t load_bias, - uint64_t start_offset, uint64_t end_offset) { +bool DwarfCfa::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::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; } diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h index 16c66e296..c5ffb8e89 100644 --- a/libunwindstack/DwarfCfa.h +++ b/libunwindstack/DwarfCfa.h @@ -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; } diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp index 9a4901344..fd6a457ef 100644 --- a/libunwindstack/DwarfEhFrameWithHdr.cpp +++ b/libunwindstack/DwarfEhFrameWithHdr.cpp @@ -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 -bool DwarfEhFrameWithHdr::Init(uint64_t offset, uint64_t size) { - uint8_t data[4]; +bool DwarfEhFrameWithHdr::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::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::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(table_encoding_, &value) || !memory_.template ReadEncodedValue(table_encoding_, &info->offset)) { @@ -109,6 +116,11 @@ DwarfEhFrameWithHdr::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::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(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(table_encoding_, &info->offset)) { + uint64_t value; + if (!memory_.template ReadEncodedValue(table_encoding_, &value) || + !memory_.template ReadEncodedValue(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) { diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h index 357116620..d16dd1006 100644 --- a/libunwindstack/DwarfEhFrameWithHdr.h +++ b/libunwindstack/DwarfEhFrameWithHdr.h @@ -38,6 +38,7 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame { using DwarfSectionImpl::entries_offset_; using DwarfSectionImpl::entries_end_; using DwarfSectionImpl::last_error_; + using DwarfSectionImpl::load_bias_; struct FdeInfo { AddressType pc; @@ -47,7 +48,7 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame { DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame(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; diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 65eec65b8..eb8394989 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -420,6 +420,7 @@ bool DwarfSectionImpl::FillInCie(DwarfCie* cie) { last_error_.address = memory_.cur_offset(); return false; } + memory_.set_pc_offset(pc_offset_); if (!memory_.ReadEncodedValue(encoding, &cie->personality_handler)) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = memory_.cur_offset(); @@ -521,19 +522,19 @@ bool DwarfSectionImpl::FillInFde(DwarfFde* fde) { } memory_.set_cur_offset(cur_offset); - if (!memory_.ReadEncodedValue(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(cie->fde_address_encoding, &fde->pc_start); fde->pc_start = AdjustPcFromFde(fde->pc_start); - if (!memory_.ReadEncodedValue(cie->fde_address_encoding & 0xf, &fde->pc_end)) { + memory_.set_pc_offset(0); + if (!valid || !memory_.ReadEncodedValue(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::FillInFde(DwarfFde* fde) { } uint64_t cur_offset = memory_.cur_offset(); + memory_.set_pc_offset(pc_offset_); if (!memory_.ReadEncodedValue(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::GetCfaLocationInfo(uint64_t pc, const DwarfF } template -bool DwarfSectionImpl::Log(uint8_t indent, uint64_t pc, uint64_t load_bias, - const DwarfFde* fde) { +bool DwarfSectionImpl::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) { DwarfCfa 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::Log(uint8_t indent, uint64_t pc, uint64_t lo } template -bool DwarfSectionImpl::Init(uint64_t offset, uint64_t size) { +bool DwarfSectionImpl::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::GetCieInfo(uint8_t* segment_size, uint8_t* e return false; } uint64_t value; + memory_.set_pc_offset(pc_offset_); if (!memory_.template ReadEncodedValue(encoding, &value)) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = memory_.cur_offset(); @@ -737,15 +740,13 @@ bool DwarfSectionImpl::AddFdeInfo(uint64_t entry_offset, uint8_t se } uint64_t start; - if (!memory_.template ReadEncodedValue(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(encoding, &start); start = AdjustPcFromFde(start); uint64_t length; - if (!memory_.template ReadEncodedValue(encoding & 0xf, &length)) { + memory_.set_pc_offset(0); + if (!valid || !memory_.template ReadEncodedValue(encoding, &length)) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = memory_.cur_offset(); return false; @@ -877,7 +878,7 @@ bool DwarfSectionImpl::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; } diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 3762107d6..472360698 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -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 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 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; diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 4c05a1bcc..954a82104 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -124,10 +124,10 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { } template -void ElfInterface::InitHeadersWithTemplate() { +void ElfInterface::InitHeadersWithTemplate(uint64_t load_bias) { if (eh_frame_hdr_offset_ != 0) { eh_frame_.reset(new DwarfEhFrameWithHdr(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(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(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(-1); @@ -441,14 +441,14 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) { } template -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(addr, load_bias, memory_, name, func_offset)) { + if (symbol->GetName(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(); -template void ElfInterface::InitHeadersWithTemplate(); +template void ElfInterface::InitHeadersWithTemplate(uint64_t); +template void ElfInterface::InitHeadersWithTemplate(uint64_t); template bool ElfInterface::ReadAllHeaders(uint64_t*); template bool ElfInterface::ReadAllHeaders(uint64_t*); @@ -574,9 +565,9 @@ template bool ElfInterface::ReadSectionHeaders(const Elf template bool ElfInterface::GetSonameWithTemplate(std::string*); template bool ElfInterface::GetSonameWithTemplate(std::string*); -template bool ElfInterface::GetFunctionNameWithTemplate(uint64_t, uint64_t, std::string*, +template bool ElfInterface::GetFunctionNameWithTemplate(uint64_t, std::string*, uint64_t*); -template bool ElfInterface::GetFunctionNameWithTemplate(uint64_t, uint64_t, std::string*, +template bool ElfInterface::GetFunctionNameWithTemplate(uint64_t, std::string*, uint64_t*); template bool ElfInterface::GetGlobalVariableWithTemplate(const std::string&, uint64_t*); diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp index f93baeb27..9b61599ce 100644 --- a/libunwindstack/ElfInterfaceArm.cpp +++ b/libunwindstack/ElfInterfaceArm.cpp @@ -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(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; } diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h index c1597ce3a..18efb6cc4 100644 --- a/libunwindstack/ElfInterfaceArm.h +++ b/libunwindstack/ElfInterfaceArm.h @@ -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 addrs_; }; diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp index 25def40c4..14ebdbbc5 100644 --- a/libunwindstack/Symbols.cpp +++ b/libunwindstack/Symbols.cpp @@ -54,10 +54,7 @@ const Symbols::Info* Symbols::GetInfoFromCache(uint64_t addr) { } template -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(uint64_t, uint64_t, Memory*, std::string*, uint64_t*); -template bool Symbols::GetName(uint64_t, uint64_t, Memory*, std::string*, uint64_t*); +template bool Symbols::GetName(uint64_t, Memory*, std::string*, uint64_t*); +template bool Symbols::GetName(uint64_t, Memory*, std::string*, uint64_t*); template bool Symbols::GetGlobal(Memory*, const std::string&, uint64_t*); template bool Symbols::GetGlobal(Memory*, const std::string&, uint64_t*); diff --git a/libunwindstack/Symbols.h b/libunwindstack/Symbols.h index 7d239c16b..7fcd067d3 100644 --- a/libunwindstack/Symbols.h +++ b/libunwindstack/Symbols.h @@ -44,8 +44,7 @@ class Symbols { const Info* GetInfoFromCache(uint64_t addr); template - 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 bool GetGlobal(Memory* elf_memory, const std::string& name, uint64_t* memory_address); diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index 209c54abc..847f382ed 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -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 fdes_; uint64_t entries_offset_; uint64_t entries_end_; diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 3a221bc2e..4d25c4027 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -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 - void InitHeadersWithTemplate(); + void InitHeadersWithTemplate(uint64_t load_bias); template bool ReadAllHeaders(uint64_t* load_bias); @@ -115,8 +113,7 @@ class ElfInterface { bool GetSonameWithTemplate(std::string* soname); template - 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 bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address); @@ -169,15 +166,16 @@ class ElfInterface32 : public ElfInterface { return ElfInterface::ReadAllHeaders(load_bias); } - void InitHeaders() override { ElfInterface::InitHeadersWithTemplate(); } + void InitHeaders(uint64_t load_bias) override { + ElfInterface::InitHeadersWithTemplate(load_bias); + } bool GetSoname(std::string* soname) override { return ElfInterface::GetSonameWithTemplate(soname); } - bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name, - uint64_t* func_offset) override { - return ElfInterface::GetFunctionNameWithTemplate(addr, load_bias, name, func_offset); + bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { + return ElfInterface::GetFunctionNameWithTemplate(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(load_bias); } - void InitHeaders() override { ElfInterface::InitHeadersWithTemplate(); } + void InitHeaders(uint64_t load_bias) override { + ElfInterface::InitHeadersWithTemplate(load_bias); + } bool GetSoname(std::string* soname) override { return ElfInterface::GetSonameWithTemplate(soname); } - bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name, - uint64_t* func_offset) override { - return ElfInterface::GetFunctionNameWithTemplate(addr, load_bias, name, func_offset); + bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { + return ElfInterface::GetFunctionNameWithTemplate(addr, name, func_offset); } bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) override { diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp index 8d6d00de9..5f3d1ea08 100644 --- a/libunwindstack/tests/ArmExidxDecodeTest.cpp +++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp @@ -36,8 +36,6 @@ namespace unwindstack { class ArmExidxDecodeTest : public ::testing::TestWithParam { protected: void Init(Memory* process_memory = nullptr) { - TearDown(); - if (process_memory == nullptr) { process_memory = &process_memory_; } @@ -50,8 +48,8 @@ class ArmExidxDecodeTest : public ::testing::TestWithParam { regs_arm_->set_sp(0); exidx_.reset(new ArmExidx(regs_arm_.get(), &elf_memory_, process_memory)); - if (log_) { - exidx_->set_log(true); + if (log_ != ARM_LOG_NONE) { + exidx_->set_log(log_); exidx_->set_log_indent(0); exidx_->set_log_skip_execution(false); } @@ -60,14 +58,20 @@ class ArmExidxDecodeTest : public ::testing::TestWithParam { } void SetUp() override { - if (GetParam() != "no_logging") { - log_ = false; + if (GetParam() == "no_logging") { + log_ = ARM_LOG_NONE; + } else if (GetParam() == "register_logging") { + log_ = ARM_LOG_BY_REG; } else { - log_ = true; + log_ = ARM_LOG_FULL; } - ResetLogs(); elf_memory_.Clear(); process_memory_.Clear(); + ResetExidx(); + } + + void ResetExidx() { + ResetLogs(); Init(); } @@ -77,7 +81,7 @@ class ArmExidxDecodeTest : public ::testing::TestWithParam { MemoryFake elf_memory_; MemoryFake process_memory_; - bool log_; + ArmLogType log_; }; TEST_P(ArmExidxDecodeTest, vsp_incr) { @@ -86,38 +90,59 @@ TEST_P(ArmExidxDecodeTest, vsp_incr) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 4\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp + 4\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 4\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10004U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->clear(); data_->push_back(0x01); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 8\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp + 8\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 8\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1000cU, exidx_->cfa()); + ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->clear(); data_->push_back(0x3f); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 256\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp + 256\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 256\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1010cU, exidx_->cfa()); + ASSERT_EQ(0x10100U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, vsp_decr) { @@ -126,38 +151,59 @@ TEST_P(ArmExidxDecodeTest, vsp_decr) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp - 4\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp - 4\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 - 4\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0xfffcU, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->clear(); data_->push_back(0x41); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp - 8\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp - 8\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 - 8\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0xfff4U, exidx_->cfa()); + ASSERT_EQ(0xfff8U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->clear(); data_->push_back(0x7f); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp - 256\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp - 256\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 - 256\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0xfef4U, exidx_->cfa()); + ASSERT_EQ(0xff00U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, refuse_unwind) { @@ -166,10 +212,14 @@ TEST_P(ArmExidxDecodeTest, refuse_unwind) { data_->push_back(0x00); ASSERT_FALSE(exidx_->Decode()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind Refuse to unwind\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Refuse to unwind\n", GetFakeLogPrint()); + break; } ASSERT_EQ(ARM_STATUS_NO_UNWIND, exidx_->status()); } @@ -182,29 +232,60 @@ TEST_P(ArmExidxDecodeTest, pop_up_to_12) { ASSERT_TRUE(exidx_->Decode()); ASSERT_TRUE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r15}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r15}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 4\n" + "4 unwind r15 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } ASSERT_EQ(0x10004U, exidx_->cfa()); ASSERT_EQ(0x10U, (*exidx_->regs())[15]); - ResetLogs(); + ResetExidx(); data_->push_back(0x8f); data_->push_back(0xff); for (size_t i = 0; i < 12; i++) { - process_memory_.SetData32(0x10004 + i * 4, i + 0x20); + process_memory_.SetData32(0x10000 + i * 4, i + 0x20); } exidx_->set_pc_set(false); ASSERT_TRUE(exidx_->Decode()); ASSERT_TRUE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15}\n", - GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15}\n", + GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 48\n" + "4 unwind r4 = [cfa - 48]\n" + "4 unwind r5 = [cfa - 44]\n" + "4 unwind r6 = [cfa - 40]\n" + "4 unwind r7 = [cfa - 36]\n" + "4 unwind r8 = [cfa - 32]\n" + "4 unwind r9 = [cfa - 28]\n" + "4 unwind r10 = [cfa - 24]\n" + "4 unwind r11 = [cfa - 20]\n" + "4 unwind r12 = [cfa - 16]\n" + "4 unwind r13 = [cfa - 12]\n" + "4 unwind r14 = [cfa - 8]\n" + "4 unwind r15 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } // Popping r13 results in a modified cfa. ASSERT_EQ(0x29U, exidx_->cfa()); @@ -222,7 +303,7 @@ TEST_P(ArmExidxDecodeTest, pop_up_to_12) { ASSERT_EQ(0x2aU, (*exidx_->regs())[14]); ASSERT_EQ(0x2bU, (*exidx_->regs())[15]); - ResetLogs(); + ResetExidx(); exidx_->set_cfa(0x10034); data_->push_back(0x81); data_->push_back(0x28); @@ -233,10 +314,22 @@ TEST_P(ArmExidxDecodeTest, pop_up_to_12) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r7, r9, r12}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r7, r9, r12}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 12\n" + "4 unwind r7 = [cfa - 12]\n" + "4 unwind r9 = [cfa - 8]\n" + "4 unwind r12 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } ASSERT_EQ(0x10040U, exidx_->cfa()); ASSERT_EQ(0x11U, (*exidx_->regs())[7]); @@ -255,34 +348,63 @@ TEST_P(ArmExidxDecodeTest, set_vsp_from_register) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = r0\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = r0\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r0\n", GetFakeLogPrint()); + break; } ASSERT_EQ(1U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); + exidx_->set_cfa(0x100); + for (size_t i = 0; i < 15; i++) { + (*regs_arm_)[i] = i + 1; + } data_->push_back(0x93); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = r3\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = r3\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r3\n", GetFakeLogPrint()); + break; } ASSERT_EQ(4U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); + exidx_->set_cfa(0x100); + for (size_t i = 0; i < 15; i++) { + (*regs_arm_)[i] = i + 1; + } data_->push_back(0x9e); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = r14\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = r14\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r14\n", GetFakeLogPrint()); + break; } ASSERT_EQ(15U, exidx_->cfa()); } @@ -292,22 +414,30 @@ TEST_P(ArmExidxDecodeTest, reserved_prefix) { data_->push_back(0x9d); ASSERT_FALSE(exidx_->Decode()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind [Reserved]\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind [Reserved]\n", GetFakeLogPrint()); + break; } ASSERT_EQ(ARM_STATUS_RESERVED, exidx_->status()); // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves - ResetLogs(); + ResetExidx(); data_->push_back(0x9f); ASSERT_FALSE(exidx_->Decode()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind [Reserved]\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind [Reserved]\n", GetFakeLogPrint()); + break; } ASSERT_EQ(ARM_STATUS_RESERVED, exidx_->status()); } @@ -319,53 +449,93 @@ TEST_P(ArmExidxDecodeTest, pop_registers) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 4\n" + "4 unwind r4 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } ASSERT_EQ(0x10004U, exidx_->cfa()); ASSERT_EQ(0x14U, (*exidx_->regs())[4]); - ResetLogs(); + ResetExidx(); data_->push_back(0xa3); - process_memory_.SetData32(0x10004, 0x20); - process_memory_.SetData32(0x10008, 0x30); - process_memory_.SetData32(0x1000c, 0x40); - process_memory_.SetData32(0x10010, 0x50); + process_memory_.SetData32(0x10000, 0x20); + process_memory_.SetData32(0x10004, 0x30); + process_memory_.SetData32(0x10008, 0x40); + process_memory_.SetData32(0x1000c, 0x50); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4-r7}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4-r7}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 16\n" + "4 unwind r4 = [cfa - 16]\n" + "4 unwind r5 = [cfa - 12]\n" + "4 unwind r6 = [cfa - 8]\n" + "4 unwind r7 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10014U, exidx_->cfa()); + ASSERT_EQ(0x10010U, exidx_->cfa()); ASSERT_EQ(0x20U, (*exidx_->regs())[4]); ASSERT_EQ(0x30U, (*exidx_->regs())[5]); ASSERT_EQ(0x40U, (*exidx_->regs())[6]); ASSERT_EQ(0x50U, (*exidx_->regs())[7]); - ResetLogs(); + ResetExidx(); data_->push_back(0xa7); - process_memory_.SetData32(0x10014, 0x41); - process_memory_.SetData32(0x10018, 0x51); - process_memory_.SetData32(0x1001c, 0x61); - process_memory_.SetData32(0x10020, 0x71); - process_memory_.SetData32(0x10024, 0x81); - process_memory_.SetData32(0x10028, 0x91); - process_memory_.SetData32(0x1002c, 0xa1); - process_memory_.SetData32(0x10030, 0xb1); + process_memory_.SetData32(0x10000, 0x41); + process_memory_.SetData32(0x10004, 0x51); + process_memory_.SetData32(0x10008, 0x61); + process_memory_.SetData32(0x1000c, 0x71); + process_memory_.SetData32(0x10010, 0x81); + process_memory_.SetData32(0x10014, 0x91); + process_memory_.SetData32(0x10018, 0xa1); + process_memory_.SetData32(0x1001c, 0xb1); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4-r11}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4-r11}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 32\n" + "4 unwind r4 = [cfa - 32]\n" + "4 unwind r5 = [cfa - 28]\n" + "4 unwind r6 = [cfa - 24]\n" + "4 unwind r7 = [cfa - 20]\n" + "4 unwind r8 = [cfa - 16]\n" + "4 unwind r9 = [cfa - 12]\n" + "4 unwind r10 = [cfa - 8]\n" + "4 unwind r11 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10034U, exidx_->cfa()); + ASSERT_EQ(0x10020U, exidx_->cfa()); ASSERT_EQ(0x41U, (*exidx_->regs())[4]); ASSERT_EQ(0x51U, (*exidx_->regs())[5]); ASSERT_EQ(0x61U, (*exidx_->regs())[6]); @@ -384,57 +554,100 @@ TEST_P(ArmExidxDecodeTest, pop_registers_with_r14) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4, r14}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4, r14}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 8\n" + "4 unwind r4 = [cfa - 8]\n" + "4 unwind r14 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } ASSERT_EQ(0x10008U, exidx_->cfa()); ASSERT_EQ(0x12U, (*exidx_->regs())[4]); ASSERT_EQ(0x22U, (*exidx_->regs())[14]); - ResetLogs(); + ResetExidx(); data_->push_back(0xab); - process_memory_.SetData32(0x10008, 0x1); - process_memory_.SetData32(0x1000c, 0x2); - process_memory_.SetData32(0x10010, 0x3); - process_memory_.SetData32(0x10014, 0x4); - process_memory_.SetData32(0x10018, 0x5); + process_memory_.SetData32(0x10000, 0x1); + process_memory_.SetData32(0x10004, 0x2); + process_memory_.SetData32(0x10008, 0x3); + process_memory_.SetData32(0x1000c, 0x4); + process_memory_.SetData32(0x10010, 0x5); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4-r7, r14}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4-r7, r14}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 20\n" + "4 unwind r4 = [cfa - 20]\n" + "4 unwind r5 = [cfa - 16]\n" + "4 unwind r6 = [cfa - 12]\n" + "4 unwind r7 = [cfa - 8]\n" + "4 unwind r14 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1001cU, exidx_->cfa()); + ASSERT_EQ(0x10014U, exidx_->cfa()); ASSERT_EQ(0x1U, (*exidx_->regs())[4]); ASSERT_EQ(0x2U, (*exidx_->regs())[5]); ASSERT_EQ(0x3U, (*exidx_->regs())[6]); ASSERT_EQ(0x4U, (*exidx_->regs())[7]); ASSERT_EQ(0x5U, (*exidx_->regs())[14]); - ResetLogs(); + ResetExidx(); data_->push_back(0xaf); - process_memory_.SetData32(0x1001c, 0x1a); - process_memory_.SetData32(0x10020, 0x2a); - process_memory_.SetData32(0x10024, 0x3a); - process_memory_.SetData32(0x10028, 0x4a); - process_memory_.SetData32(0x1002c, 0x5a); - process_memory_.SetData32(0x10030, 0x6a); - process_memory_.SetData32(0x10034, 0x7a); - process_memory_.SetData32(0x10038, 0x8a); - process_memory_.SetData32(0x1003c, 0x9a); + process_memory_.SetData32(0x10000, 0x1a); + process_memory_.SetData32(0x10004, 0x2a); + process_memory_.SetData32(0x10008, 0x3a); + process_memory_.SetData32(0x1000c, 0x4a); + process_memory_.SetData32(0x10010, 0x5a); + process_memory_.SetData32(0x10014, 0x6a); + process_memory_.SetData32(0x10018, 0x7a); + process_memory_.SetData32(0x1001c, 0x8a); + process_memory_.SetData32(0x10020, 0x9a); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r4-r11, r14}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r4-r11, r14}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 36\n" + "4 unwind r4 = [cfa - 36]\n" + "4 unwind r5 = [cfa - 32]\n" + "4 unwind r6 = [cfa - 28]\n" + "4 unwind r7 = [cfa - 24]\n" + "4 unwind r8 = [cfa - 20]\n" + "4 unwind r9 = [cfa - 16]\n" + "4 unwind r10 = [cfa - 12]\n" + "4 unwind r11 = [cfa - 8]\n" + "4 unwind r14 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10040U, exidx_->cfa()); + ASSERT_EQ(0x10024U, exidx_->cfa()); ASSERT_EQ(0x1aU, (*exidx_->regs())[4]); ASSERT_EQ(0x2aU, (*exidx_->regs())[5]); ASSERT_EQ(0x3aU, (*exidx_->regs())[6]); @@ -451,10 +664,17 @@ TEST_P(ArmExidxDecodeTest, finish) { data_->push_back(0xb0); ASSERT_FALSE(exidx_->Decode()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind finish\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind finish\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10000U, exidx_->cfa()); ASSERT_EQ(ARM_STATUS_FINISH, exidx_->status()); @@ -466,10 +686,14 @@ TEST_P(ArmExidxDecodeTest, spare) { data_->push_back(0x00); ASSERT_FALSE(exidx_->Decode()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10000U, exidx_->cfa()); ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); @@ -477,15 +701,19 @@ TEST_P(ArmExidxDecodeTest, spare) { // 10110001 xxxxyyyy: Spare (xxxx != 0000) for (size_t x = 1; x < 16; x++) { for (size_t y = 0; y < 16; y++) { - ResetLogs(); + ResetExidx(); data_->push_back(0xb1); data_->push_back((x << 4) | y); ASSERT_FALSE(exidx_->Decode()) << "x, y = " << x << ", " << y; ASSERT_EQ("", GetFakeLogBuf()) << "x, y = " << x << ", " << y; - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y; - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y; + break; } ASSERT_EQ(0x10000U, exidx_->cfa()) << "x, y = " << x << ", " << y; ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); @@ -494,29 +722,37 @@ TEST_P(ArmExidxDecodeTest, spare) { // 101101nn: Spare for (size_t n = 0; n < 4; n++) { - ResetLogs(); + ResetExidx(); data_->push_back(0xb4 | n); ASSERT_FALSE(exidx_->Decode()) << "n = " << n; ASSERT_EQ("", GetFakeLogBuf()) << "n = " << n; - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "n = " << n; - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "n = " << n; + break; } ASSERT_EQ(0x10000U, exidx_->cfa()) << "n = " << n; ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); } // 11000111 00000000: Spare - ResetLogs(); + ResetExidx(); data_->push_back(0xc7); data_->push_back(0x00); ASSERT_FALSE(exidx_->Decode()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10000U, exidx_->cfa()); ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); @@ -524,15 +760,19 @@ TEST_P(ArmExidxDecodeTest, spare) { // 11000111 xxxxyyyy: Spare (xxxx != 0000) for (size_t x = 1; x < 16; x++) { for (size_t y = 0; y < 16; y++) { - ResetLogs(); + ResetExidx(); data_->push_back(0xc7); data_->push_back(0x10); ASSERT_FALSE(exidx_->Decode()) << "x, y = " << x << ", " << y; ASSERT_EQ("", GetFakeLogBuf()) << "x, y = " << x << ", " << y; - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y; - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y; + break; } ASSERT_EQ(0x10000U, exidx_->cfa()) << "x, y = " << x << ", " << y; ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); @@ -541,14 +781,18 @@ TEST_P(ArmExidxDecodeTest, spare) { // 11001yyy: Spare (yyy != 000, 001) for (size_t y = 2; y < 8; y++) { - ResetLogs(); + ResetExidx(); data_->push_back(0xc8 | y); ASSERT_FALSE(exidx_->Decode()) << "y = " << y; ASSERT_EQ("", GetFakeLogBuf()) << "y = " << y; - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "y = " << y; - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "y = " << y; + break; } ASSERT_EQ(0x10000U, exidx_->cfa()) << "y = " << y; ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); @@ -557,14 +801,18 @@ TEST_P(ArmExidxDecodeTest, spare) { // 11xxxyyy: Spare (xxx != 000, 001, 010) for (size_t x = 3; x < 8; x++) { for (size_t y = 0; y < 8; y++) { - ResetLogs(); + ResetExidx(); data_->push_back(0xc0 | (x << 3) | y); ASSERT_FALSE(exidx_->Decode()) << "x, y = " << x << ", " << y; ASSERT_EQ("", GetFakeLogBuf()) << "x, y = " << x << ", " << y; - if (log_) { - ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y; - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y; + break; } ASSERT_EQ(0x10000U, exidx_->cfa()) << "x, y = " << x << ", " << y; ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status()); @@ -580,47 +828,81 @@ TEST_P(ArmExidxDecodeTest, pop_registers_under_mask) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r0}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r0}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 4\n" + "4 unwind r0 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } ASSERT_EQ(0x10004U, exidx_->cfa()); ASSERT_EQ(0x45U, (*exidx_->regs())[0]); - ResetLogs(); + ResetExidx(); data_->push_back(0xb1); data_->push_back(0x0a); - process_memory_.SetData32(0x10004, 0x23); - process_memory_.SetData32(0x10008, 0x24); + process_memory_.SetData32(0x10000, 0x23); + process_memory_.SetData32(0x10004, 0x24); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r1, r3}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r1, r3}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 8\n" + "4 unwind r1 = [cfa - 8]\n" + "4 unwind r3 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1000cU, exidx_->cfa()); + ASSERT_EQ(0x10008U, exidx_->cfa()); ASSERT_EQ(0x23U, (*exidx_->regs())[1]); ASSERT_EQ(0x24U, (*exidx_->regs())[3]); - ResetLogs(); + ResetExidx(); data_->push_back(0xb1); data_->push_back(0x0f); - process_memory_.SetData32(0x1000c, 0x65); - process_memory_.SetData32(0x10010, 0x54); - process_memory_.SetData32(0x10014, 0x43); - process_memory_.SetData32(0x10018, 0x32); + process_memory_.SetData32(0x10000, 0x65); + process_memory_.SetData32(0x10004, 0x54); + process_memory_.SetData32(0x10008, 0x43); + process_memory_.SetData32(0x1000c, 0x32); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {r0, r1, r2, r3}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {r0, r1, r2, r3}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 16\n" + "4 unwind r0 = [cfa - 16]\n" + "4 unwind r1 = [cfa - 12]\n" + "4 unwind r2 = [cfa - 8]\n" + "4 unwind r3 = [cfa - 4]\n", + GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1001cU, exidx_->cfa()); + ASSERT_EQ(0x10010U, exidx_->cfa()); ASSERT_EQ(0x65U, (*exidx_->regs())[0]); ASSERT_EQ(0x54U, (*exidx_->regs())[1]); ASSERT_EQ(0x43U, (*exidx_->regs())[2]); @@ -634,28 +916,42 @@ TEST_P(ArmExidxDecodeTest, vsp_large_incr) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 1024\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp + 1024\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 1024\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10400U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xb2); data_->push_back(0xff); data_->push_back(0x02); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 2048\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp + 2048\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 2048\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10c00U, exidx_->cfa()); + ASSERT_EQ(0x10800U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xb2); data_->push_back(0xff); data_->push_back(0x82); @@ -663,12 +959,19 @@ TEST_P(ArmExidxDecodeTest, vsp_large_incr) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 3147776\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind vsp = vsp + 3147776\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 3147776\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x311400U, exidx_->cfa()); + ASSERT_EQ(0x310800U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_vfp_fstmfdx) { @@ -678,25 +981,37 @@ TEST_P(ArmExidxDecodeTest, pop_vfp_fstmfdx) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d0}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d0}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x1000cU, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xb3); data_->push_back(0x48); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d4-d12}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d4-d12}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10058U, exidx_->cfa()); + ASSERT_EQ(0x1004cU, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_vfp8_fstmfdx) { @@ -705,36 +1020,54 @@ TEST_P(ArmExidxDecodeTest, pop_vfp8_fstmfdx) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d8}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d8}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x1000cU, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xbb); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d8-d11}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d8-d11}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10030U, exidx_->cfa()); + ASSERT_EQ(0x10024U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xbf); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d8-d15}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d8-d15}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10074U, exidx_->cfa()); + ASSERT_EQ(0x10044U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_mmx_wr10) { @@ -743,36 +1076,54 @@ TEST_P(ArmExidxDecodeTest, pop_mmx_wr10) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wR10}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wR10}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc2); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wR10-wR12}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wR10-wR12}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10020U, exidx_->cfa()); + ASSERT_EQ(0x10018U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc5); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wR10-wR15}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wR10-wR15}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10050U, exidx_->cfa()); + ASSERT_EQ(0x10030U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_mmx_wr) { @@ -782,38 +1133,56 @@ TEST_P(ArmExidxDecodeTest, pop_mmx_wr) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wR0}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wR0}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc6); data_->push_back(0x25); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wR2-wR7}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wR2-wR7}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10038U, exidx_->cfa()); + ASSERT_EQ(0x10030U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc6); data_->push_back(0xff); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wR15-wR30}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wR15-wR30}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x100b8U, exidx_->cfa()); + ASSERT_EQ(0x10080U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_mmx_wcgr) { @@ -823,38 +1192,56 @@ TEST_P(ArmExidxDecodeTest, pop_mmx_wcgr) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wCGR0}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wCGR0}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wCGR register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10004U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc7); data_->push_back(0x0a); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wCGR1, wCGR3}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wCGR1, wCGR3}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wCGR register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1000cU, exidx_->cfa()); + ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc7); data_->push_back(0x0f); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {wCGR0, wCGR1, wCGR2, wCGR3}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {wCGR0, wCGR1, wCGR2, wCGR3}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported wCGR register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x1001cU, exidx_->cfa()); + ASSERT_EQ(0x10010U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_vfp16_vpush) { @@ -864,38 +1251,56 @@ TEST_P(ArmExidxDecodeTest, pop_vfp16_vpush) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d16}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d16}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc8); data_->push_back(0x14); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d17-d21}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d17-d21}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10030U, exidx_->cfa()); + ASSERT_EQ(0x10028U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc8); data_->push_back(0xff); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d31-d46}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d31-d46}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x100b0U, exidx_->cfa()); + ASSERT_EQ(0x10080U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_vfp_vpush) { @@ -905,38 +1310,56 @@ TEST_P(ArmExidxDecodeTest, pop_vfp_vpush) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d0}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d0}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc9); data_->push_back(0x23); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d2-d5}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d2-d5}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10028U, exidx_->cfa()); + ASSERT_EQ(0x10020U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xc9); data_->push_back(0xff); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d15-d30}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d15-d30}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x100a8U, exidx_->cfa()); + ASSERT_EQ(0x10080U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, pop_vfp8_vpush) { @@ -945,36 +1368,54 @@ TEST_P(ArmExidxDecodeTest, pop_vfp8_vpush) { ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d8}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d8}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10008U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xd2); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d8-d10}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d8-d10}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10020U, exidx_->cfa()); + ASSERT_EQ(0x10018U, exidx_->cfa()); - ResetLogs(); + ResetExidx(); data_->push_back(0xd7); ASSERT_TRUE(exidx_->Decode()); ASSERT_FALSE(exidx_->pc_set()); ASSERT_EQ("", GetFakeLogBuf()); - if (log_) { - ASSERT_EQ("4 unwind pop {d8-d15}\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ("4 unwind pop {d8-d15}\n", GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint()); + break; } - ASSERT_EQ(0x10060U, exidx_->cfa()); + ASSERT_EQ(0x10040U, exidx_->cfa()); } TEST_P(ArmExidxDecodeTest, expect_truncated) { @@ -1047,32 +1488,147 @@ TEST_P(ArmExidxDecodeTest, verify_no_truncated) { TEST_P(ArmExidxDecodeTest, eval_multiple_decodes) { // vsp = vsp + 4 data_->push_back(0x00); - // vsp = vsp + 8 + // vsp = vsp + 12 data_->push_back(0x02); // Finish data_->push_back(0xb0); ASSERT_TRUE(exidx_->Eval()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 4\n" - "4 unwind vsp = vsp + 12\n" - "4 unwind finish\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ( + "4 unwind vsp = vsp + 4\n" + "4 unwind vsp = vsp + 12\n" + "4 unwind finish\n", + GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ("4 unwind cfa = r13 + 16\n", GetFakeLogPrint()); + break; } ASSERT_EQ(0x10010U, exidx_->cfa()); ASSERT_FALSE(exidx_->pc_set()); } +TEST_P(ArmExidxDecodeTest, eval_vsp_add_after_pop) { + // Pop {r15} + data_->push_back(0x88); + data_->push_back(0x00); + // vsp = vsp + 12 + data_->push_back(0x02); + // Finish + data_->push_back(0xb0); + process_memory_.SetData32(0x10000, 0x10); + + ASSERT_TRUE(exidx_->Eval()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ( + "4 unwind pop {r15}\n" + "4 unwind vsp = vsp + 12\n" + "4 unwind finish\n", + GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 16\n" + "4 unwind r15 = [cfa - 16]\n", + GetFakeLogPrint()); + break; + } + ASSERT_EQ(0x10010U, exidx_->cfa()); + ASSERT_TRUE(exidx_->pc_set()); + ASSERT_EQ(0x10U, (*exidx_->regs())[15]); +} + +TEST_P(ArmExidxDecodeTest, eval_vsp_add_large_after_pop) { + // Pop {r15} + data_->push_back(0x88); + data_->push_back(0x00); + // vsp = vsp + 1024 + data_->push_back(0xb2); + data_->push_back(0x7f); + // Finish + data_->push_back(0xb0); + process_memory_.SetData32(0x10000, 0x10); + + ASSERT_TRUE(exidx_->Eval()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ( + "4 unwind pop {r15}\n" + "4 unwind vsp = vsp + 1024\n" + "4 unwind finish\n", + GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 1028\n" + "4 unwind r15 = [cfa - 1028]\n", + GetFakeLogPrint()); + break; + } + ASSERT_EQ(0x10404U, exidx_->cfa()); + ASSERT_TRUE(exidx_->pc_set()); + ASSERT_EQ(0x10U, (*exidx_->regs())[15]); +} + +TEST_P(ArmExidxDecodeTest, eval_vsp_sub_after_pop) { + // Pop {r15} + data_->push_back(0x88); + data_->push_back(0x00); + // vsp = vsp - 4 + data_->push_back(0x41); + // Finish + data_->push_back(0xb0); + process_memory_.SetData32(0x10000, 0x10); + + ASSERT_TRUE(exidx_->Eval()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ( + "4 unwind pop {r15}\n" + "4 unwind vsp = vsp - 8\n" + "4 unwind finish\n", + GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 - 4\n" + "4 unwind r15 = [cfa + 4]\n", + GetFakeLogPrint()); + break; + } + ASSERT_EQ(0xfffcU, exidx_->cfa()); + ASSERT_TRUE(exidx_->pc_set()); + ASSERT_EQ(0x10U, (*exidx_->regs())[15]); +} + TEST_P(ArmExidxDecodeTest, eval_pc_set) { // vsp = vsp + 4 data_->push_back(0x00); - // vsp = vsp + 8 + // vsp = vsp + 12 data_->push_back(0x02); // Pop {r15} data_->push_back(0x88); data_->push_back(0x00); - // vsp = vsp + 8 + // vsp = vsp + 12 data_->push_back(0x02); // Finish data_->push_back(0xb0); @@ -1080,20 +1636,33 @@ TEST_P(ArmExidxDecodeTest, eval_pc_set) { process_memory_.SetData32(0x10010, 0x10); ASSERT_TRUE(exidx_->Eval()); - if (log_) { - ASSERT_EQ("4 unwind vsp = vsp + 4\n" - "4 unwind vsp = vsp + 12\n" - "4 unwind pop {r15}\n" - "4 unwind vsp = vsp + 12\n" - "4 unwind finish\n", GetFakeLogPrint()); - } else { - ASSERT_EQ("", GetFakeLogPrint()); + switch (log_) { + case ARM_LOG_NONE: + ASSERT_EQ("", GetFakeLogPrint()); + break; + case ARM_LOG_FULL: + ASSERT_EQ( + "4 unwind vsp = vsp + 4\n" + "4 unwind vsp = vsp + 12\n" + "4 unwind pop {r15}\n" + "4 unwind vsp = vsp + 12\n" + "4 unwind finish\n", + GetFakeLogPrint()); + break; + case ARM_LOG_BY_REG: + exidx_->LogByReg(); + ASSERT_EQ( + "4 unwind cfa = r13 + 32\n" + "4 unwind r15 = [cfa - 16]\n", + GetFakeLogPrint()); + break; } ASSERT_EQ(0x10020U, exidx_->cfa()); ASSERT_TRUE(exidx_->pc_set()); ASSERT_EQ(0x10U, (*exidx_->regs())[15]); } -INSTANTIATE_TEST_CASE_P(, ArmExidxDecodeTest, ::testing::Values("logging", "no_logging")); +INSTANTIATE_TEST_CASE_P(, ArmExidxDecodeTest, + ::testing::Values("logging", "register_logging", "no_logging")); } // namespace unwindstack diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp index 8d0f0e599..79c799c3a 100644 --- a/libunwindstack/tests/ArmExidxExtractTest.cpp +++ b/libunwindstack/tests/ArmExidxExtractTest.cpp @@ -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); diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp index b17ca33a8..bb2e8f039 100644 --- a/libunwindstack/tests/DwarfCfaLogTest.cpp +++ b/libunwindstack/tests/DwarfCfaLogTest.cpp @@ -79,7 +79,7 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) { this->memory_.SetMemory(0x2000, std::vector{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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{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" diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp index c28a41edb..3a5204463 100644 --- a/libunwindstack/tests/DwarfDebugFrameTest.cpp +++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp @@ -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::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::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::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::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::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 DwarfDebugFrameTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes); diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp index a73db6580..e8d53e647 100644 --- a/libunwindstack/tests/DwarfEhFrameTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameTest.cpp @@ -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::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::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::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::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::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 DwarfEhFrameTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes); diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp index 4240419a5..19c7b98a2 100644 --- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp @@ -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{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 DwarfEhFrameWithHdrTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes); diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp index c34029130..414f2f248 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp @@ -36,7 +36,7 @@ class MockDwarfSectionImpl : public DwarfSectionImpl { MockDwarfSectionImpl(Memory* memory) : DwarfSectionImpl(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{0x00}); this->memory_.SetMemory(0x6000, std::vector{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" diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp index 071d2dfa3..2c6c8790a 100644 --- a/libunwindstack/tests/DwarfSectionTest.cpp +++ b/libunwindstack/tests/DwarfSectionTest.cpp @@ -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*)); diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp index 66207dbd1..3d5ddd6b6 100644 --- a/libunwindstack/tests/ElfFake.cpp +++ b/libunwindstack/tests/ElfFake.cpp @@ -32,7 +32,7 @@ namespace unwindstack { std::deque ElfInterfaceFake::functions_; std::deque 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; } diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h index e23298670..a3bf5ce76 100644 --- a/libunwindstack/tests/ElfFake.h +++ b/libunwindstack/tests/ElfFake.h @@ -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; diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp index 70a52ad1e..5f1c2ac64 100644 --- a/libunwindstack/tests/ElfInterfaceArmTest.cpp +++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp @@ -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()); diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp index bf97e30bf..4008e9ba6 100644 --- a/libunwindstack/tests/ElfInterfaceTest.cpp +++ b/libunwindstack/tests/ElfInterfaceTest.cpp @@ -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)); diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index aecbf6dcb..55fe16f14 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -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); diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp index 45a7b58a0..b40a2531c 100644 --- a/libunwindstack/tests/SymbolsTest.cpp +++ b/libunwindstack/tests/SymbolsTest.cpp @@ -70,18 +70,18 @@ TYPED_TEST_P(SymbolsTest, function_bounds_check) { std::string name; uint64_t func_offset; - ASSERT_TRUE(symbols.GetName(0x5000, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x5000, &this->memory_, &name, &func_offset)); ASSERT_EQ("fake_function", name); ASSERT_EQ(0U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0x500f, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(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(0x4fff, 0, &this->memory_, &name, &func_offset)); - ASSERT_FALSE(symbols.GetName(0x5010, 0, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols.GetName(0x4fff, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols.GetName(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(0x5000, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(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(0x5000, 0, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols.GetName(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(0x5000, 0, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols.GetName(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(0x3005, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x3005, &this->memory_, &name, &func_offset)); ASSERT_EQ("function_two", name); ASSERT_EQ(1U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0x5004, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x5004, &this->memory_, &name, &func_offset)); ASSERT_EQ("function_one", name); ASSERT_EQ(4U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0xa011, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(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(0x5008, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x5008, &this->memory_, &name, &func_offset)); ASSERT_EQ("function_one", name); ASSERT_EQ(8U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0x3008, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x3008, &this->memory_, &name, &func_offset)); ASSERT_EQ("function_two", name); ASSERT_EQ(4U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0xa01a, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(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(0x3005, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x3005, &this->memory_, &name, &func_offset)); ASSERT_EQ("function_two", name); ASSERT_EQ(1U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0x5004, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x5004, &this->memory_, &name, &func_offset)); ASSERT_EQ("function_one", name); ASSERT_EQ(4U, func_offset); name.clear(); - ASSERT_TRUE(symbols.GetName(0xa011, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(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(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(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(0x5000, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols_end_at_200.GetName(0x5000, &this->memory_, &name, &func_offset)); ASSERT_EQ("fake_function", name); ASSERT_EQ(0U, func_offset); - ASSERT_TRUE(symbols_end_at_200.GetName(0x3000, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols_end_at_200.GetName(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(0x5000, 0, &this->memory_, &name, &func_offset)); - ASSERT_FALSE( - symbols_end_at_100.GetName(0x3000, 0, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols_end_at_100.GetName(0x5000, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols_end_at_100.GetName(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(0x6000, 0, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols.GetName(0x6000, &this->memory_, &name, &func_offset)); this->memory_.Clear(); - ASSERT_FALSE(symbols.GetName(0x6000, 0, &this->memory_, &name, &func_offset)); + ASSERT_FALSE(symbols.GetName(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(0x5001, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x5001, &this->memory_, &name, &func_offset)); ASSERT_EQ("first_entry", name); ASSERT_EQ(1U, func_offset); - ASSERT_TRUE(symbols.GetName(0x2002, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(0x2002, &this->memory_, &name, &func_offset)); ASSERT_EQ("second_entry", name); ASSERT_EQ(2U, func_offset); - ASSERT_TRUE(symbols.GetName(0x1003, 0, &this->memory_, &name, &func_offset)); + ASSERT_TRUE(symbols.GetName(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(&this->memory_, "function_1", &offset)); std::string name; - EXPECT_TRUE(symbols.GetName(0x10002, 0, &this->memory_, &name, &offset)); + EXPECT_TRUE(symbols.GetName(0x10002, &this->memory_, &name, &offset)); EXPECT_EQ("function_0", name); EXPECT_EQ(2U, offset); - EXPECT_TRUE(symbols.GetName(0x12004, 0, &this->memory_, &name, &offset)); + EXPECT_TRUE(symbols.GetName(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 SymbolsTestTypes; diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 285fc9e27..a65c077d7 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -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 diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so new file mode 100644 index 000000000..4b7bf44c4 Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so differ diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so new file mode 100644 index 000000000..013858ef5 Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so differ diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt new file mode 100644 index 000000000..10f13254b --- /dev/null +++ b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt @@ -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 diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver new file mode 100644 index 000000000..9e4a83f01 Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver differ diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt new file mode 100644 index 000000000..f147247e5 --- /dev/null +++ b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt @@ -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 diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data new file mode 100644 index 000000000..847c8192a Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data differ diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp index 5a8edfdf3..266a6db8e 100644 --- a/libunwindstack/tools/unwind_info.cpp +++ b/libunwindstack/tools/unwind_info.cpp @@ -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(interface)); + DumpArm(&elf, reinterpret_cast(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 { diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp index 47a4f912d..0f0156623 100644 --- a/libunwindstack/tools/unwind_reg_info.cpp +++ b/libunwindstack/tools/unwind_reg_info.cpp @@ -34,7 +34,9 @@ #include #include +#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(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"); diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp index 086dffef3..f8e3e9249 100644 --- a/libunwindstack/tools/unwind_symbols.cpp +++ b/libunwindstack/tools/unwind_symbols.cpp @@ -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;