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
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 @@
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 @@
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 @@
.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 @@
.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 @@
.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 @@
.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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