Merge "libunwindstack: Support signal frame CIEs." am: f30b12e6ad
Original change: https://android-review.googlesource.com/c/platform/system/core/+/1443619 Change-Id: I1377383ec5e926ec430711c6e06489d92affd66a
This commit is contained in:
commit
27dcf97048
29 changed files with 260 additions and 40 deletions
|
@ -296,6 +296,8 @@ cc_defaults {
|
|||
"tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
|
||||
"tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
|
||||
"tests/files/offline/signal_load_bias_arm/*",
|
||||
"tests/files/offline/signal_fde_x86/*",
|
||||
"tests/files/offline/signal_fde_x86_64/*",
|
||||
"tests/files/offline/straddle_arm/*",
|
||||
"tests/files/offline/straddle_arm64/*",
|
||||
],
|
||||
|
|
|
@ -37,7 +37,8 @@ namespace unwindstack {
|
|||
|
||||
DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
|
||||
|
||||
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
|
||||
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame) {
|
||||
// Lookup the pc in the cache.
|
||||
auto it = loc_regs_.upper_bound(pc);
|
||||
if (it == loc_regs_.end() || pc < it->second.pc_start) {
|
||||
|
@ -59,6 +60,8 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f
|
|||
it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first;
|
||||
}
|
||||
|
||||
*is_signal_frame = it->second.cie->is_signal_frame;
|
||||
|
||||
// Now eval the actual registers.
|
||||
return Eval(it->second.cie, process_memory, it->second, regs, finished);
|
||||
}
|
||||
|
@ -241,6 +244,9 @@ bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
cie->is_signal_frame = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -558,8 +564,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
|
|||
cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
|
||||
}
|
||||
|
||||
// If the pc was set to zero, consider this the final frame.
|
||||
*finished = (cur_regs->pc() == 0) ? true : false;
|
||||
// If the pc was set to zero, consider this the final frame. Exception: if
|
||||
// this is the sigreturn frame, then we want to try to recover the real PC
|
||||
// using the return address (from LR or the stack), so keep going.
|
||||
*finished = (cur_regs->pc() == 0 && !cie->is_signal_frame) ? true : false;
|
||||
|
||||
cur_regs->set_sp(eval_info.cfa);
|
||||
|
||||
|
|
|
@ -188,14 +188,15 @@ bool Elf::StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memor
|
|||
}
|
||||
|
||||
// The relative pc is always relative to the start of the map from which it comes.
|
||||
bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
|
||||
bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame) {
|
||||
if (!valid_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lock during the step which can update information in the object.
|
||||
std::lock_guard<std::mutex> guard(lock_);
|
||||
return interface_->Step(rel_pc, regs, process_memory, finished);
|
||||
return interface_->Step(rel_pc, regs, process_memory, finished, is_signal_frame);
|
||||
}
|
||||
|
||||
bool Elf::IsValidElf(Memory* memory) {
|
||||
|
|
|
@ -499,25 +499,27 @@ bool ElfInterface::GetGlobalVariableWithTemplate(const std::string& name, uint64
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
|
||||
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame) {
|
||||
last_error_.code = ERROR_NONE;
|
||||
last_error_.address = 0;
|
||||
|
||||
// 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(pc, regs, process_memory, finished)) {
|
||||
if (debug_frame != nullptr &&
|
||||
debug_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try the eh_frame next.
|
||||
DwarfSection* eh_frame = eh_frame_.get();
|
||||
if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
|
||||
if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gnu_debugdata_interface_ != nullptr &&
|
||||
gnu_debugdata_interface_->Step(pc, regs, process_memory, finished)) {
|
||||
gnu_debugdata_interface_->Step(pc, regs, process_memory, finished, is_signal_frame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,12 +100,13 @@ void ElfInterfaceArm::HandleUnknownType(uint32_t type, uint64_t ph_offset, uint6
|
|||
total_entries_ = ph_filesz / 8;
|
||||
}
|
||||
|
||||
bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
|
||||
bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame) {
|
||||
// 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, regs, process_memory, finished) ||
|
||||
return ElfInterface32::Step(pc, regs, process_memory, finished, is_signal_frame) ||
|
||||
StepExidx(pc, regs, process_memory, finished);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ class ElfInterfaceArm : public ElfInterface32 {
|
|||
|
||||
void HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) override;
|
||||
|
||||
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
|
||||
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame) override;
|
||||
|
||||
bool StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||
|
||||
|
|
|
@ -113,9 +113,11 @@ bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_f
|
|||
step_pc -= pc_adjustment;
|
||||
|
||||
bool finished = false;
|
||||
bool is_signal_frame = false;
|
||||
if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) {
|
||||
step_pc = rel_pc;
|
||||
} else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished)) {
|
||||
} else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished,
|
||||
&is_signal_frame)) {
|
||||
finished = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -242,18 +242,21 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
|||
// some of the speculative frames.
|
||||
in_device_map = true;
|
||||
} else {
|
||||
bool is_signal_frame = false;
|
||||
if (elf->StepIfSignalHandler(rel_pc, regs_, process_memory_.get())) {
|
||||
stepped = true;
|
||||
if (frame != nullptr) {
|
||||
// Need to adjust the relative pc because the signal handler
|
||||
// pc should not be adjusted.
|
||||
frame->rel_pc = rel_pc;
|
||||
frame->pc += pc_adjustment;
|
||||
step_pc = rel_pc;
|
||||
}
|
||||
} else if (elf->Step(step_pc, regs_, process_memory_.get(), &finished)) {
|
||||
is_signal_frame = true;
|
||||
} else if (elf->Step(step_pc, regs_, process_memory_.get(), &finished,
|
||||
&is_signal_frame)) {
|
||||
stepped = true;
|
||||
}
|
||||
if (is_signal_frame && frame != nullptr) {
|
||||
// Need to adjust the relative pc because the signal handler
|
||||
// pc should not be adjusted.
|
||||
frame->rel_pc = rel_pc;
|
||||
frame->pc += pc_adjustment;
|
||||
step_pc = rel_pc;
|
||||
}
|
||||
elf->GetLastError(&last_error_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ class DwarfSection {
|
|||
|
||||
virtual uint64_t AdjustPcFromFde(uint64_t pc) = 0;
|
||||
|
||||
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished, bool* is_signal_frame);
|
||||
|
||||
protected:
|
||||
DwarfMemory memory_;
|
||||
|
|
|
@ -35,6 +35,7 @@ struct DwarfCie {
|
|||
uint64_t code_alignment_factor = 0;
|
||||
int64_t data_alignment_factor = 0;
|
||||
uint64_t return_address_register = 0;
|
||||
bool is_signal_frame = false;
|
||||
};
|
||||
|
||||
struct DwarfFde {
|
||||
|
|
|
@ -60,7 +60,8 @@ class Elf {
|
|||
|
||||
bool StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory);
|
||||
|
||||
bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||
bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame);
|
||||
|
||||
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ class ElfInterface {
|
|||
|
||||
virtual std::string GetBuildID() = 0;
|
||||
|
||||
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished,
|
||||
bool* is_signal_frame);
|
||||
|
||||
virtual bool IsValidPc(uint64_t pc);
|
||||
|
||||
|
|
|
@ -68,7 +68,8 @@ TEST_F(DwarfSectionTest, Step_fail_fde) {
|
|||
EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
|
||||
|
||||
bool finished;
|
||||
ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
TEST_F(DwarfSectionTest, Step_fail_cie_null) {
|
||||
|
@ -79,7 +80,8 @@ TEST_F(DwarfSectionTest, Step_fail_cie_null) {
|
|||
EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
|
||||
|
||||
bool finished;
|
||||
ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
|
||||
|
@ -93,7 +95,8 @@ TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
|
|||
.WillOnce(::testing::Return(false));
|
||||
|
||||
bool finished;
|
||||
ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
TEST_F(DwarfSectionTest, Step_pass) {
|
||||
|
@ -111,7 +114,8 @@ TEST_F(DwarfSectionTest, Step_pass) {
|
|||
.WillOnce(::testing::Return(true));
|
||||
|
||||
bool finished;
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
|
||||
|
@ -137,9 +141,10 @@ TEST_F(DwarfSectionTest, Step_cache) {
|
|||
.WillRepeatedly(::testing::Return(true));
|
||||
|
||||
bool finished;
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
|
||||
ASSERT_TRUE(section_->Step(0x1500, ®s_, &process, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished, &is_signal_frame));
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished, &is_signal_frame));
|
||||
ASSERT_TRUE(section_->Step(0x1500, ®s_, &process, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
|
||||
|
@ -157,7 +162,8 @@ TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
|
|||
.WillRepeatedly(::testing::Return(true));
|
||||
|
||||
bool finished;
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished, &is_signal_frame));
|
||||
|
||||
DwarfFde fde1{};
|
||||
fde1.pc_start = 0x500;
|
||||
|
@ -167,8 +173,8 @@ TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
|
|||
EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_, ::testing::_))
|
||||
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
|
||||
|
||||
ASSERT_TRUE(section_->Step(0x600, ®s_, &process, &finished));
|
||||
ASSERT_TRUE(section_->Step(0x700, ®s_, &process, &finished));
|
||||
ASSERT_TRUE(section_->Step(0x600, ®s_, &process, &finished, &is_signal_frame));
|
||||
ASSERT_TRUE(section_->Step(0x700, ®s_, &process, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -52,7 +52,7 @@ bool ElfInterfaceFake::GetGlobalVariable(const std::string& global, uint64_t* of
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ElfInterfaceFake::Step(uint64_t, Regs* regs, Memory*, bool* finished) {
|
||||
bool ElfInterfaceFake::Step(uint64_t, Regs* regs, Memory*, bool* finished, bool* is_signal_frame) {
|
||||
if (steps_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ bool ElfInterfaceFake::Step(uint64_t, Regs* regs, Memory*, bool* finished) {
|
|||
fake_regs->set_pc(entry.pc);
|
||||
fake_regs->set_sp(entry.sp);
|
||||
*finished = entry.finished;
|
||||
*is_signal_frame = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ class ElfInterfaceFake : public ElfInterface {
|
|||
bool GetGlobalVariable(const std::string&, uint64_t*) override;
|
||||
std::string GetBuildID() override { return fake_build_id_; }
|
||||
|
||||
bool Step(uint64_t, Regs*, Memory*, bool*) override;
|
||||
bool Step(uint64_t, Regs*, Memory*, bool*, bool*) override;
|
||||
|
||||
void FakeSetGlobalVariable(const std::string& global, uint64_t offset) {
|
||||
globals_[global] = offset;
|
||||
|
|
|
@ -138,7 +138,8 @@ TEST_F(ElfTest, elf_invalid) {
|
|||
EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
|
||||
|
||||
bool finished;
|
||||
ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
|
||||
bool is_signal_frame;
|
||||
ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished, &is_signal_frame));
|
||||
EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
|
||||
}
|
||||
|
||||
|
@ -327,7 +328,7 @@ class ElfInterfaceMock : public ElfInterface {
|
|||
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
|
||||
std::string GetBuildID() override { return ""; }
|
||||
|
||||
MOCK_METHOD(bool, Step, (uint64_t, Regs*, Memory*, bool*), (override));
|
||||
MOCK_METHOD(bool, Step, (uint64_t, Regs*, Memory*, bool*, bool*), (override));
|
||||
MOCK_METHOD(bool, GetGlobalVariable, (const std::string&, uint64_t*), (override));
|
||||
MOCK_METHOD(bool, IsValidPc, (uint64_t), (override));
|
||||
|
||||
|
@ -351,10 +352,11 @@ TEST_F(ElfTest, step_in_interface) {
|
|||
MemoryFake process_memory;
|
||||
|
||||
bool finished;
|
||||
EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
|
||||
bool is_signal_frame;
|
||||
EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished, &is_signal_frame))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x1000, ®s, &process_memory, &finished));
|
||||
ASSERT_TRUE(elf.Step(0x1000, ®s, &process_memory, &finished, &is_signal_frame));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, get_global_invalid_elf) {
|
||||
|
|
|
@ -1736,4 +1736,158 @@ TEST_F(UnwindOfflineTest, empty_arm64) {
|
|||
EXPECT_EQ(0x7ffb6c0f30U, unwinder.frames()[6].sp);
|
||||
}
|
||||
|
||||
// This test has a libc.so where the __restore has been changed so
|
||||
// that the signal handler match does not occur and it uses the
|
||||
// fde to do the unwind.
|
||||
TEST_F(UnwindOfflineTest, signal_fde_x86) {
|
||||
ASSERT_NO_FATAL_FAILURE(Init("signal_fde_x86/", ARCH_X86));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
ASSERT_EQ(20U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
|
||||
EXPECT_EQ(
|
||||
" #00 pc 007914d9 libunwindstack_test (SignalInnerFunction+25)\n"
|
||||
" #01 pc 007914fc libunwindstack_test (SignalMiddleFunction+28)\n"
|
||||
" #02 pc 0079152c libunwindstack_test (SignalOuterFunction+28)\n"
|
||||
" #03 pc 0079af62 libunwindstack_test (unwindstack::SignalCallerHandler(int, siginfo*, "
|
||||
"void*)+50)\n"
|
||||
" #04 pc 00058fb0 libc.so (__restore)\n"
|
||||
" #05 pc 00000000 <unknown>\n"
|
||||
" #06 pc 0079161a libunwindstack_test (InnerFunction+218)\n"
|
||||
" #07 pc 007923aa libunwindstack_test (MiddleFunction+42)\n"
|
||||
" #08 pc 007923ea libunwindstack_test (OuterFunction+42)\n"
|
||||
" #09 pc 00797444 libunwindstack_test (unwindstack::RemoteThroughSignal(int, unsigned "
|
||||
"int)+868)\n"
|
||||
" #10 pc 007985b8 libunwindstack_test "
|
||||
"(unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+56)\n"
|
||||
" #11 pc 00817a19 libunwindstack_test\n"
|
||||
" #12 pc 008178c5 libunwindstack_test (testing::Test::Run()+277)\n"
|
||||
" #13 pc 00818d3e libunwindstack_test (testing::TestInfo::Run()+318)\n"
|
||||
" #14 pc 008198b4 libunwindstack_test (testing::TestSuite::Run()+436)\n"
|
||||
" #15 pc 00828cb0 libunwindstack_test "
|
||||
"(testing::internal::UnitTestImpl::RunAllTests()+1216)\n"
|
||||
" #16 pc 0082870f libunwindstack_test (testing::UnitTest::Run()+367)\n"
|
||||
" #17 pc 0084031e libunwindstack_test (IsolateMain+2334)\n"
|
||||
" #18 pc 0083f9e9 libunwindstack_test (main+41)\n"
|
||||
" #19 pc 00050646 libc.so (__libc_init+118)\n",
|
||||
frame_info);
|
||||
|
||||
EXPECT_EQ(0x5ae0d4d9U, unwinder.frames()[0].pc);
|
||||
EXPECT_EQ(0xecb37188U, unwinder.frames()[0].sp);
|
||||
EXPECT_EQ(0x5ae0d4fcU, unwinder.frames()[1].pc);
|
||||
EXPECT_EQ(0xecb37190U, unwinder.frames()[1].sp);
|
||||
EXPECT_EQ(0x5ae0d52cU, unwinder.frames()[2].pc);
|
||||
EXPECT_EQ(0xecb371b0U, unwinder.frames()[2].sp);
|
||||
EXPECT_EQ(0x5ae16f62U, unwinder.frames()[3].pc);
|
||||
EXPECT_EQ(0xecb371d0U, unwinder.frames()[3].sp);
|
||||
EXPECT_EQ(0xec169fb0U, unwinder.frames()[4].pc);
|
||||
EXPECT_EQ(0xecb371f0U, unwinder.frames()[4].sp);
|
||||
EXPECT_EQ(0x0U, unwinder.frames()[5].pc);
|
||||
EXPECT_EQ(0xffcfac6cU, unwinder.frames()[5].sp);
|
||||
EXPECT_EQ(0x5ae0d61aU, unwinder.frames()[6].pc);
|
||||
EXPECT_EQ(0xffcfac6cU, unwinder.frames()[6].sp);
|
||||
EXPECT_EQ(0x5ae0e3aaU, unwinder.frames()[7].pc);
|
||||
EXPECT_EQ(0xffcfad60U, unwinder.frames()[7].sp);
|
||||
EXPECT_EQ(0x5ae0e3eaU, unwinder.frames()[8].pc);
|
||||
EXPECT_EQ(0xffcfad90U, unwinder.frames()[8].sp);
|
||||
EXPECT_EQ(0x5ae13444U, unwinder.frames()[9].pc);
|
||||
EXPECT_EQ(0xffcfadc0U, unwinder.frames()[9].sp);
|
||||
EXPECT_EQ(0x5ae145b8U, unwinder.frames()[10].pc);
|
||||
EXPECT_EQ(0xffcfb020U, unwinder.frames()[10].sp);
|
||||
EXPECT_EQ(0x5ae93a19U, unwinder.frames()[11].pc);
|
||||
EXPECT_EQ(0xffcfb050U, unwinder.frames()[11].sp);
|
||||
EXPECT_EQ(0x5ae938c5U, unwinder.frames()[12].pc);
|
||||
EXPECT_EQ(0xffcfb090U, unwinder.frames()[12].sp);
|
||||
EXPECT_EQ(0x5ae94d3eU, unwinder.frames()[13].pc);
|
||||
EXPECT_EQ(0xffcfb0f0U, unwinder.frames()[13].sp);
|
||||
EXPECT_EQ(0x5ae958b4U, unwinder.frames()[14].pc);
|
||||
EXPECT_EQ(0xffcfb160U, unwinder.frames()[14].sp);
|
||||
EXPECT_EQ(0x5aea4cb0U, unwinder.frames()[15].pc);
|
||||
EXPECT_EQ(0xffcfb1d0U, unwinder.frames()[15].sp);
|
||||
EXPECT_EQ(0x5aea470fU, unwinder.frames()[16].pc);
|
||||
EXPECT_EQ(0xffcfb270U, unwinder.frames()[16].sp);
|
||||
EXPECT_EQ(0x5aebc31eU, unwinder.frames()[17].pc);
|
||||
EXPECT_EQ(0xffcfb2c0U, unwinder.frames()[17].sp);
|
||||
EXPECT_EQ(0x5aebb9e9U, unwinder.frames()[18].pc);
|
||||
EXPECT_EQ(0xffcfc3c0U, unwinder.frames()[18].sp);
|
||||
EXPECT_EQ(0xec161646U, unwinder.frames()[19].pc);
|
||||
EXPECT_EQ(0xffcfc3f0U, unwinder.frames()[19].sp);
|
||||
}
|
||||
|
||||
// This test has a libc.so where the __restore_rt has been changed so
|
||||
// that the signal handler match does not occur and it uses the
|
||||
// fde to do the unwind.
|
||||
TEST_F(UnwindOfflineTest, signal_fde_x86_64) {
|
||||
ASSERT_NO_FATAL_FAILURE(Init("signal_fde_x86_64/", ARCH_X86_64));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
ASSERT_EQ(18U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
|
||||
EXPECT_EQ(
|
||||
" #00 pc 000000000058415b libunwindstack_test (SignalInnerFunction+11)\n"
|
||||
" #01 pc 0000000000584168 libunwindstack_test (SignalMiddleFunction+8)\n"
|
||||
" #02 pc 0000000000584178 libunwindstack_test (SignalOuterFunction+8)\n"
|
||||
" #03 pc 000000000058ac77 libunwindstack_test (unwindstack::SignalCallerHandler(int, "
|
||||
"siginfo*, void*)+23)\n"
|
||||
" #04 pc 0000000000057d10 libc.so (__restore_rt)\n"
|
||||
" #05 pc 0000000000000000 <unknown>\n"
|
||||
" #06 pc 0000000000584244 libunwindstack_test (InnerFunction+196)\n"
|
||||
" #07 pc 0000000000584b44 libunwindstack_test (MiddleFunction+20)\n"
|
||||
" #08 pc 0000000000584b64 libunwindstack_test (OuterFunction+20)\n"
|
||||
" #09 pc 0000000000588457 libunwindstack_test (unwindstack::RemoteThroughSignal(int, "
|
||||
"unsigned int)+583)\n"
|
||||
" #10 pc 0000000000588f67 libunwindstack_test "
|
||||
"(unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+23)\n"
|
||||
" #11 pc 00000000005d9c38 libunwindstack_test (testing::Test::Run()+216)\n"
|
||||
" #12 pc 00000000005daf9a libunwindstack_test (testing::TestInfo::Run()+266)\n"
|
||||
" #13 pc 00000000005dba46 libunwindstack_test (testing::TestSuite::Run()+390)\n"
|
||||
" #14 pc 00000000005ea4c6 libunwindstack_test "
|
||||
"(testing::internal::UnitTestImpl::RunAllTests()+1190)\n"
|
||||
" #15 pc 00000000005e9f61 libunwindstack_test (testing::UnitTest::Run()+337)\n"
|
||||
" #16 pc 0000000000600155 libunwindstack_test (IsolateMain+2037)\n"
|
||||
" #17 pc 000000000004e405 libc.so (__libc_init+101)\n",
|
||||
frame_info);
|
||||
|
||||
EXPECT_EQ(0x5bb41271e15bU, unwinder.frames()[0].pc);
|
||||
EXPECT_EQ(0x707eb5aa8320U, unwinder.frames()[0].sp);
|
||||
EXPECT_EQ(0x5bb41271e168U, unwinder.frames()[1].pc);
|
||||
EXPECT_EQ(0x707eb5aa8330U, unwinder.frames()[1].sp);
|
||||
EXPECT_EQ(0x5bb41271e178U, unwinder.frames()[2].pc);
|
||||
EXPECT_EQ(0x707eb5aa8340U, unwinder.frames()[2].sp);
|
||||
EXPECT_EQ(0x5bb412724c77U, unwinder.frames()[3].pc);
|
||||
EXPECT_EQ(0x707eb5aa8350U, unwinder.frames()[3].sp);
|
||||
EXPECT_EQ(0x707eb2ca5d10U, unwinder.frames()[4].pc);
|
||||
EXPECT_EQ(0x707eb5aa8380U, unwinder.frames()[4].sp);
|
||||
EXPECT_EQ(0x0U, unwinder.frames()[5].pc);
|
||||
EXPECT_EQ(0x7ffcaadde078U, unwinder.frames()[5].sp);
|
||||
EXPECT_EQ(0x5bb41271e244U, unwinder.frames()[6].pc);
|
||||
EXPECT_EQ(0x7ffcaadde078U, unwinder.frames()[6].sp);
|
||||
EXPECT_EQ(0x5bb41271eb44U, unwinder.frames()[7].pc);
|
||||
EXPECT_EQ(0x7ffcaadde1a0U, unwinder.frames()[7].sp);
|
||||
EXPECT_EQ(0x5bb41271eb64U, unwinder.frames()[8].pc);
|
||||
EXPECT_EQ(0x7ffcaadde1c0U, unwinder.frames()[8].sp);
|
||||
EXPECT_EQ(0x5bb412722457U, unwinder.frames()[9].pc);
|
||||
EXPECT_EQ(0x7ffcaadde1e0U, unwinder.frames()[9].sp);
|
||||
EXPECT_EQ(0x5bb412722f67U, unwinder.frames()[10].pc);
|
||||
EXPECT_EQ(0x7ffcaadde510U, unwinder.frames()[10].sp);
|
||||
EXPECT_EQ(0x5bb412773c38U, unwinder.frames()[11].pc);
|
||||
EXPECT_EQ(0x7ffcaadde530U, unwinder.frames()[11].sp);
|
||||
EXPECT_EQ(0x5bb412774f9aU, unwinder.frames()[12].pc);
|
||||
EXPECT_EQ(0x7ffcaadde560U, unwinder.frames()[12].sp);
|
||||
EXPECT_EQ(0x5bb412775a46U, unwinder.frames()[13].pc);
|
||||
EXPECT_EQ(0x7ffcaadde5b0U, unwinder.frames()[13].sp);
|
||||
EXPECT_EQ(0x5bb4127844c6U, unwinder.frames()[14].pc);
|
||||
EXPECT_EQ(0x7ffcaadde5f0U, unwinder.frames()[14].sp);
|
||||
EXPECT_EQ(0x5bb412783f61U, unwinder.frames()[15].pc);
|
||||
EXPECT_EQ(0x7ffcaadde6c0U, unwinder.frames()[15].sp);
|
||||
EXPECT_EQ(0x5bb41279a155U, unwinder.frames()[16].pc);
|
||||
EXPECT_EQ(0x7ffcaadde720U, unwinder.frames()[16].sp);
|
||||
EXPECT_EQ(0x707eb2c9c405U, unwinder.frames()[17].pc);
|
||||
EXPECT_EQ(0x7ffcaaddf870U, unwinder.frames()[17].sp);
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
BIN
libunwindstack/tests/files/offline/signal_fde_x86/libc.so
Normal file
BIN
libunwindstack/tests/files/offline/signal_fde_x86/libc.so
Normal file
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
5a67c000-5a7ba000 r--p 0 00:00 0 libunwindstack_test
|
||||
5a7ba000-5aedd000 r-xp 13d000 00:00 0 libunwindstack_test
|
||||
ec111000-ec153000 r--p 0 00:00 0 libc.so
|
||||
ec153000-ec200000 r-xp 41000 00:00 0 libc.so
|
|
@ -0,0 +1,9 @@
|
|||
eax: 5aeec4ac
|
||||
ebx: 5aeec4ac
|
||||
ecx: 0
|
||||
edx: 6b
|
||||
ebp: ecb37188
|
||||
edi: ebecda30
|
||||
esi: b
|
||||
esp: ecb37188
|
||||
eip: 5ae0d4d9
|
BIN
libunwindstack/tests/files/offline/signal_fde_x86/stack0.data
Normal file
BIN
libunwindstack/tests/files/offline/signal_fde_x86/stack0.data
Normal file
Binary file not shown.
BIN
libunwindstack/tests/files/offline/signal_fde_x86/stack1.data
Normal file
BIN
libunwindstack/tests/files/offline/signal_fde_x86/stack1.data
Normal file
Binary file not shown.
BIN
libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so
Normal file
BIN
libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so
Normal file
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
5bb41219a000-5bb4122cd000 r--p 0 00:00 0 libunwindstack_test
|
||||
5bb4122cd000-5bb4127b9000 r-xp 132000 00:00 0 libunwindstack_test
|
||||
707eb2c4e000-707eb2c91000 r--p 0 00:00 0 libc.so
|
||||
707eb2c91000-707eb2d1b000 r-xp 42000 00:00 0 libc.so
|
|
@ -0,0 +1,17 @@
|
|||
rax: 0
|
||||
rbx: 707d82c59c60
|
||||
rcx: 4
|
||||
rdx: 707eb5aa8380
|
||||
r8: 7ffcaadde470
|
||||
r9: 7ffcaadde478
|
||||
r10: 8
|
||||
r11: 206
|
||||
r12: 707cb2c64330
|
||||
r13: 0
|
||||
r14: 174e9096a8f
|
||||
r15: 707d52c96cb0
|
||||
rdi: b
|
||||
rsi: 707eb5aa84b0
|
||||
rbp: 707eb5aa8320
|
||||
rsp: 707eb5aa8320
|
||||
rip: 5bb41271e15b
|
BIN
libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data
Normal file
BIN
libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data
Normal file
Binary file not shown.
BIN
libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data
Normal file
BIN
libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data
Normal file
Binary file not shown.
Loading…
Reference in a new issue