diff options
Diffstat (limited to 'libunwindstack')
29 files changed, 260 insertions, 40 deletions
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 75a419c..7770b13 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -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/*", ], diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index bf86e6e..ad25e80 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -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); diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 286febc..e098a58 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -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) { diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 17470fd..0188def 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -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; } diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp index 76f2dc8..9352a5d 100644 --- a/libunwindstack/ElfInterfaceArm.cpp +++ b/libunwindstack/ElfInterfaceArm.cpp @@ -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); } diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h index 1d71cac..fd824f8 100644 --- a/libunwindstack/ElfInterfaceArm.h +++ b/libunwindstack/ElfInterfaceArm.h @@ -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); diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp index 05650fb..5f51a73 100644 --- a/libunwindstack/LocalUnwinder.cpp +++ b/libunwindstack/LocalUnwinder.cpp @@ -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; } diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index bcdbde8..9ffc0f7 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -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_); } } diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index af823da..f28cf25 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -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_; diff --git a/libunwindstack/include/unwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h index 4b481f0..3d8c2db 100644 --- a/libunwindstack/include/unwindstack/DwarfStructs.h +++ b/libunwindstack/include/unwindstack/DwarfStructs.h @@ -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 { diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index 97614b1..e15b221 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h @@ -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); diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 0c39b23..5df7ddf 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -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); diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp index febd6d3..e5a1aed 100644 --- a/libunwindstack/tests/DwarfSectionTest.cpp +++ b/libunwindstack/tests/DwarfSectionTest.cpp @@ -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 diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp index 3d5ddd6..b16cd53 100644 --- a/libunwindstack/tests/ElfFake.cpp +++ b/libunwindstack/tests/ElfFake.cpp @@ -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; } diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h index 3b6cb80..abda7b8 100644 --- a/libunwindstack/tests/ElfFake.h +++ b/libunwindstack/tests/ElfFake.h @@ -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; diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index f0852a4..d81edbf 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -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) { diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 0c6f9f8..ab427b5 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -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 diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/libc.so b/libunwindstack/tests/files/offline/signal_fde_x86/libc.so Binary files differnew file mode 100644 index 0000000..5c882e4 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86/libc.so diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test b/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test Binary files differnew file mode 100644 index 0000000..8dcff67 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/maps.txt b/libunwindstack/tests/files/offline/signal_fde_x86/maps.txt new file mode 100644 index 0000000..6166a9d --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86/maps.txt @@ -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 diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/regs.txt b/libunwindstack/tests/files/offline/signal_fde_x86/regs.txt new file mode 100644 index 0000000..456b212 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86/regs.txt @@ -0,0 +1,9 @@ +eax: 5aeec4ac +ebx: 5aeec4ac +ecx: 0 +edx: 6b +ebp: ecb37188 +edi: ebecda30 +esi: b +esp: ecb37188 +eip: 5ae0d4d9 diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/stack0.data b/libunwindstack/tests/files/offline/signal_fde_x86/stack0.data Binary files differnew file mode 100644 index 0000000..0bbbe22 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86/stack0.data diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data b/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data Binary files differnew file mode 100644 index 0000000..0873046 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so b/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so Binary files differnew file mode 100644 index 0000000..cea7336 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test b/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test Binary files differnew file mode 100644 index 0000000..c48e84e --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/maps.txt b/libunwindstack/tests/files/offline/signal_fde_x86_64/maps.txt new file mode 100644 index 0000000..514aa71 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/maps.txt @@ -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 diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/regs.txt b/libunwindstack/tests/files/offline/signal_fde_x86_64/regs.txt new file mode 100644 index 0000000..8da7b4e --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/regs.txt @@ -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 diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data Binary files differnew file mode 100644 index 0000000..e19a016 --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data Binary files differnew file mode 100644 index 0000000..3435f7c --- /dev/null +++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data |