summaryrefslogtreecommitdiff
path: root/libunwindstack
diff options
context:
space:
mode:
Diffstat (limited to 'libunwindstack')
-rw-r--r--libunwindstack/Android.bp2
-rw-r--r--libunwindstack/DwarfSection.cpp14
-rw-r--r--libunwindstack/Elf.cpp5
-rw-r--r--libunwindstack/ElfInterface.cpp10
-rw-r--r--libunwindstack/ElfInterfaceArm.cpp5
-rw-r--r--libunwindstack/ElfInterfaceArm.h3
-rw-r--r--libunwindstack/LocalUnwinder.cpp4
-rw-r--r--libunwindstack/Unwinder.cpp19
-rw-r--r--libunwindstack/include/unwindstack/DwarfSection.h2
-rw-r--r--libunwindstack/include/unwindstack/DwarfStructs.h1
-rw-r--r--libunwindstack/include/unwindstack/Elf.h3
-rw-r--r--libunwindstack/include/unwindstack/ElfInterface.h3
-rw-r--r--libunwindstack/tests/DwarfSectionTest.cpp26
-rw-r--r--libunwindstack/tests/ElfFake.cpp3
-rw-r--r--libunwindstack/tests/ElfFake.h2
-rw-r--r--libunwindstack/tests/ElfTest.cpp10
-rw-r--r--libunwindstack/tests/UnwindOfflineTest.cpp154
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86/libc.sobin0 -> 1090809 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_testbin0 -> 9065208 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86/maps.txt4
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86/regs.txt9
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86/stack0.databin0 -> 3712 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86/stack1.databin0 -> 17308 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86_64/libc.sobin0 -> 979313 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_testbin0 -> 6756144 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86_64/maps.txt4
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86_64/regs.txt17
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.databin0 -> 3304 bytes
-rw-r--r--libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.databin0 -> 12176 bytes
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, &regs_, nullptr, &finished));
+ bool is_signal_frame;
+ ASSERT_FALSE(section_->Step(0x1000, &regs_, 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, &regs_, nullptr, &finished));
+ bool is_signal_frame;
+ ASSERT_FALSE(section_->Step(0x1000, &regs_, 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, &regs_, &process, &finished));
+ bool is_signal_frame;
+ ASSERT_TRUE(section_->Step(0x1000, &regs_, &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, &regs_, &process, &finished));
- ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished));
- ASSERT_TRUE(section_->Step(0x1500, &regs_, &process, &finished));
+ bool is_signal_frame;
+ ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished, &is_signal_frame));
+ ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished, &is_signal_frame));
+ ASSERT_TRUE(section_->Step(0x1500, &regs_, &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, &regs_, &process, &finished));
+ bool is_signal_frame;
+ ASSERT_TRUE(section_->Step(0x1000, &regs_, &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, &regs_, &process, &finished));
- ASSERT_TRUE(section_->Step(0x700, &regs_, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x600, &regs_, &process, &finished, &is_signal_frame));
+ ASSERT_TRUE(section_->Step(0x700, &regs_, &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, &regs, &process_memory, &finished))
+ bool is_signal_frame;
+ EXPECT_CALL(*interface, Step(0x1000, &regs, &process_memory, &finished, &is_signal_frame))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(elf.Step(0x1000, &regs, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x1000, &regs, &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
new file mode 100644
index 0000000..5c882e4
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test b/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test
new file mode 100644
index 0000000..8dcff67
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86/libunwindstack_test
Binary files differ
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
new file mode 100644
index 0000000..0bbbe22
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data b/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data
new file mode 100644
index 0000000..0873046
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so b/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so
new file mode 100644
index 0000000..cea7336
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test b/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test
new file mode 100644
index 0000000..c48e84e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/libunwindstack_test
Binary files differ
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
new file mode 100644
index 0000000..e19a016
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data
new file mode 100644
index 0000000..3435f7c
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_fde_x86_64/stack1.data
Binary files differ