libunwindstack: Support signal frame CIEs.
Mark a CIE with a S in its augmentation string as signal frame. This allows the code to properly handle signal frame data if none of the signal frame pattern matchers work. For a signal frame, DwarfSectionImpl<AddressType>::Eval needs to continue the unwinding even if PC is zero. A zero PC means that the program has crashed, and we should try to recover the real PC using the return address on the stack or LR. This behavior is tested by UnwindOffline.signal_{x86,x86_64}, which modify the libc.so files so that the signal frame pattern matcher fails and the CIE/FDE data is used instead. Test: libunwindstack_test Change-Id: I4655b070028fd984345311a5e743796f8c30ed36
This commit is contained in:
parent
483364a7ec
commit
9b8f545920
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