From 2e8c6e26e6a66186b3350a99d394a9deebd57fe9 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 24 Jan 2018 08:52:47 -0800 Subject: Small behavioral changes to the unwinder. - Be a little more lenient when reading the cies/fdes. If next entry data winds up incorrect, don't fail, simply stop processing the entries. This only applies when reading all of the cies/fdes at once. - Fail to init an eh_frame with no entries and fallback to assuming the eh_frame has no header instead. - Change the step to always try debug_frame first which has the most accurate information. - Add small unit tests and a couple of offline unit tests to verify this behavior. These changes are needed to support offline unwinding since it depends on this new behavior. Bug: 65682279 Test: Ran new unit tests. Change-Id: I3529f1b0c8e14cd7409494e5de2f3c9e78d0855e --- libunwindstack/Android.bp | 2 + libunwindstack/DwarfEhFrameWithHdr.cpp | 5 + libunwindstack/DwarfError.h | 1 + libunwindstack/DwarfSection.cpp | 5 +- libunwindstack/ElfInterface.cpp | 33 +++--- libunwindstack/tests/DwarfDebugFrameTest.cpp | 92 ++++++++++++++- libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp | 6 + libunwindstack/tests/UnwindOfflineTest.cpp | 123 +++++++++++++++++++++ .../files/offline/bad_eh_frame_hdr_arm64/libc.so | Bin 0 -> 1139592 bytes .../files/offline/bad_eh_frame_hdr_arm64/maps.txt | 2 + .../files/offline/bad_eh_frame_hdr_arm64/regs.txt | 4 + .../offline/bad_eh_frame_hdr_arm64/stack.data | Bin 0 -> 72 bytes .../files/offline/bad_eh_frame_hdr_arm64/waiter64 | Bin 0 -> 67352 bytes .../files/offline/debug_frame_first_x86/libc.so | Bin 0 -> 52 bytes .../files/offline/debug_frame_first_x86/maps.txt | 2 + .../files/offline/debug_frame_first_x86/regs.txt | 9 ++ .../files/offline/debug_frame_first_x86/stack.data | Bin 0 -> 192 bytes .../files/offline/debug_frame_first_x86/waiter | Bin 0 -> 9816 bytes 18 files changed, 264 insertions(+), 20 deletions(-) create mode 100644 libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so create mode 100644 libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt create mode 100644 libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt create mode 100644 libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data create mode 100644 libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 create mode 100644 libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so create mode 100644 libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt create mode 100644 libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt create mode 100644 libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data create mode 100644 libunwindstack/tests/files/offline/debug_frame_first_x86/waiter diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 9389b40..8dae956 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -170,6 +170,8 @@ cc_test { data: [ "tests/files/elf32.xz", "tests/files/elf64.xz", + "tests/files/offline/bad_eh_frame_hdr_arm64/*", + "tests/files/offline/debug_frame_first_x86/*", "tests/files/offline/jit_debug_arm32/*", "tests/files/offline/jit_debug_x86_32/*", "tests/files/offline/gnu_debugdata_arm32/*", diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp index 0337dba..e0f1eed 100644 --- a/libunwindstack/DwarfEhFrameWithHdr.cpp +++ b/libunwindstack/DwarfEhFrameWithHdr.cpp @@ -64,6 +64,11 @@ bool DwarfEhFrameWithHdr::Init(uint64_t offset, uint64_t size) { return false; } + if (fde_count_ == 0) { + last_error_ = DWARF_ERROR_NO_FDES; + return false; + } + entries_offset_ = memory_.cur_offset(); entries_end_ = offset + size; entries_data_offset_ = offset; diff --git a/libunwindstack/DwarfError.h b/libunwindstack/DwarfError.h index 54199b8..d3cdd4d 100644 --- a/libunwindstack/DwarfError.h +++ b/libunwindstack/DwarfError.h @@ -31,6 +31,7 @@ enum DwarfError : uint8_t { DWARF_ERROR_TOO_MANY_ITERATIONS, DWARF_ERROR_CFA_NOT_DEFINED, DWARF_ERROR_UNSUPPORTED_VERSION, + DWARF_ERROR_NO_FDES, }; } // namespace unwindstack diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 91d855b..04a1fae 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -835,9 +835,8 @@ bool DwarfSectionImpl::CreateSortedFdeList() { } if (next_entry_offset < memory_.cur_offset()) { - // This indicates some kind of corruption, or malformed section data. - last_error_ = DWARF_ERROR_ILLEGAL_VALUE; - return false; + // Simply consider the processing done in this case. + break; } memory_.set_cur_offset(next_entry_offset); } diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 0e3ab2c..17cc16a 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -126,22 +126,26 @@ void ElfInterface::InitHeadersWithTemplate() { if (eh_frame_hdr_offset_ != 0) { eh_frame_.reset(new DwarfEhFrameWithHdr(memory_)); if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) { - // Even if the eh_frame_offset_ is non-zero, do not bother - // trying to read that since something has gone wrong. eh_frame_.reset(nullptr); - eh_frame_hdr_offset_ = 0; - eh_frame_hdr_size_ = static_cast(-1); } - } else if (eh_frame_offset_ != 0) { - // If there is a eh_frame section without a eh_frame_hdr section. + } + + if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) { + // If there is an eh_frame section without an eh_frame_hdr section, + // or using the frame hdr object failed to init. eh_frame_.reset(new DwarfEhFrame(memory_)); if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) { eh_frame_.reset(nullptr); - eh_frame_offset_ = 0; - eh_frame_size_ = static_cast(-1); } } + if (eh_frame_.get() == nullptr) { + eh_frame_hdr_offset_ = 0; + eh_frame_hdr_size_ = static_cast(-1); + eh_frame_offset_ = 0; + eh_frame_size_ = static_cast(-1); + } + if (debug_frame_offset_ != 0) { debug_frame_.reset(new DwarfDebugFrame(memory_)); if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) { @@ -436,15 +440,16 @@ bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* pro } uint64_t adjusted_pc = pc - load_bias; - // Try the eh_frame first. - DwarfSection* eh_frame = eh_frame_.get(); - if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) { + // 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(adjusted_pc, regs, process_memory, finished)) { return true; } - // Try the debug_frame next. - DwarfSection* debug_frame = debug_frame_.get(); - if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) { + // Try the eh_frame next. + DwarfSection* eh_frame = eh_frame_.get(); + if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) { return true; } diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp index 07204bc..243198e 100644 --- a/libunwindstack/tests/DwarfDebugFrameTest.cpp +++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp @@ -145,6 +145,45 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init32_fde_not_following_cie) { ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error()); } +TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) { + // CIE 32 information. + this->memory_.SetData32(0x5000, 0xfc); + this->memory_.SetData32(0x5004, 0xffffffff); + this->memory_.SetData8(0x5008, 1); + this->memory_.SetData8(0x5009, '\0'); + + // FDE 32 information. + this->memory_.SetData32(0x5100, 0xfc); + this->memory_.SetData32(0x5104, 0); + this->memory_.SetData32(0x5108, 0x1500); + this->memory_.SetData32(0x510c, 0x200); + + this->memory_.SetData32(0x5200, 0xfc); + this->memory_.SetData32(0x5204, 0); + this->memory_.SetData32(0x5208, 0x2500); + this->memory_.SetData32(0x520c, 0x300); + + // CIE 32 information. + this->memory_.SetData32(0x5300, 0); + this->memory_.SetData32(0x5304, 0xffffffff); + this->memory_.SetData8(0x5308, 1); + this->memory_.SetData8(0x5309, '\0'); + + // FDE 32 information. + this->memory_.SetData32(0x5400, 0xfc); + this->memory_.SetData32(0x5404, 0x300); + this->memory_.SetData32(0x5408, 0x3500); + this->memory_.SetData32(0x540c, 0x400); + + this->memory_.SetData32(0x5500, 0xfc); + this->memory_.SetData32(0x5504, 0x300); + this->memory_.SetData32(0x5508, 0x4500); + this->memory_.SetData32(0x550c, 0x500); + + ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600)); + ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount()); +} + TYPED_TEST_P(DwarfDebugFrameTest, Init64) { // CIE 64 information. this->memory_.SetData32(0x5000, 0xffffffff); @@ -231,6 +270,51 @@ TYPED_TEST_P(DwarfDebugFrameTest, Init64_fde_not_following_cie) { ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error()); } +TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) { + // CIE 64 information. + this->memory_.SetData32(0x5000, 0xffffffff); + this->memory_.SetData64(0x5004, 0xf4); + this->memory_.SetData64(0x500c, 0xffffffffffffffffULL); + this->memory_.SetData8(0x5014, 1); + this->memory_.SetData8(0x5015, '\0'); + + // FDE 64 information. + this->memory_.SetData32(0x5100, 0xffffffff); + this->memory_.SetData64(0x5104, 0xf4); + this->memory_.SetData64(0x510c, 0); + this->memory_.SetData64(0x5114, 0x1500); + this->memory_.SetData64(0x511c, 0x200); + + this->memory_.SetData32(0x5200, 0xffffffff); + this->memory_.SetData64(0x5204, 0xf4); + this->memory_.SetData64(0x520c, 0); + this->memory_.SetData64(0x5214, 0x2500); + this->memory_.SetData64(0x521c, 0x300); + + // CIE 64 information. + this->memory_.SetData32(0x5300, 0xffffffff); + this->memory_.SetData64(0x5304, 0); + this->memory_.SetData64(0x530c, 0xffffffffffffffffULL); + this->memory_.SetData8(0x5314, 1); + this->memory_.SetData8(0x5315, '\0'); + + // FDE 64 information. + this->memory_.SetData32(0x5400, 0xffffffff); + this->memory_.SetData64(0x5404, 0xf4); + this->memory_.SetData64(0x540c, 0x300); + this->memory_.SetData64(0x5414, 0x3500); + this->memory_.SetData64(0x541c, 0x400); + + this->memory_.SetData32(0x5500, 0xffffffff); + this->memory_.SetData64(0x5504, 0xf4); + this->memory_.SetData64(0x550c, 0x300); + this->memory_.SetData64(0x5514, 0x4500); + this->memory_.SetData64(0x551c, 0x500); + + ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600)); + ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount()); +} + TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) { // CIE 32 information. this->memory_.SetData32(0x5000, 0xfc); @@ -450,9 +534,11 @@ TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) { EXPECT_EQ(0x20U, fde->cie->return_address_register); } -REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie, Init64, - Init64_fde_not_following_cie, Init_version1, Init_version4, - GetFdeOffsetFromPc, GetCieFde32, GetCieFde64); +REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie, + Init32_do_not_fail_on_bad_next_entry, Init64, + Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie, + Init_version1, Init_version4, GetFdeOffsetFromPc, GetCieFde32, + GetCieFde64); typedef ::testing::Types DwarfDebugFrameTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes); diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp index 64b325b..ef2fb32 100644 --- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp @@ -94,7 +94,13 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init) { EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset()); EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset()); + // Verify a zero fde count fails to init. + this->memory_.SetData32(0x1006, 0); + ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100)); + ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->last_error()); + // Verify an unexpected version will cause a fail. + this->memory_.SetData32(0x1006, 126); this->memory_.SetData8(0x1000, 0); ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100)); ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error()); diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 582ac18..09376ab 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -625,4 +625,127 @@ TEST(UnwindOfflineTest, jit_debug_arm32) { frame_info); } +// The eh_frame_hdr data is present but set to zero fdes. This should +// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr. +// No .gnu_debugdata section in the elf file, so no symbols. +TEST(UnwindOfflineTest, bad_eh_frame_hdr_arm64) { + std::string dir(TestGetFileDirectory() + "offline/bad_eh_frame_hdr_arm64/"); + + MemoryOffline* memory = new MemoryOffline; + ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0)); + + FILE* fp = fopen((dir + "regs.txt").c_str(), "r"); + ASSERT_TRUE(fp != nullptr); + RegsArm64 regs; + uint64_t reg_value; + ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value)); + regs[ARM64_REG_PC] = reg_value; + ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value)); + regs[ARM64_REG_SP] = reg_value; + ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value)); + regs[ARM64_REG_LR] = reg_value; + ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", ®_value)); + regs[ARM64_REG_R29] = reg_value; + regs.SetFromRaw(); + fclose(fp); + + fp = fopen((dir + "maps.txt").c_str(), "r"); + ASSERT_TRUE(fp != nullptr); + // The file is guaranteed to be less than 4096 bytes. + std::vector buffer(4096); + ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp)); + fclose(fp); + + BufferMaps maps(buffer.data()); + ASSERT_TRUE(maps.Parse()); + + ASSERT_EQ(ARCH_ARM64, regs.Arch()); + + std::shared_ptr process_memory(memory); + + char* cwd = getcwd(nullptr, 0); + ASSERT_EQ(0, chdir(dir.c_str())); + Unwinder unwinder(128, &maps, ®s, process_memory); + unwinder.Unwind(); + ASSERT_EQ(0, chdir(cwd)); + free(cwd); + + std::string frame_info(DumpFrames(unwinder)); + ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; + EXPECT_EQ( + " #00 pc 0000000000000550 waiter64\n" + " #01 pc 0000000000000568 waiter64\n" + " #02 pc 000000000000057c waiter64\n" + " #03 pc 0000000000000590 waiter64\n" + " #04 pc 00000000000a8e98 libc.so (__libc_init+88)\n", + frame_info); +} + +// The elf has bad eh_frame unwind information for the pcs. If eh_frame +// is used first, the unwind will not match the expected output. +TEST(UnwindOfflineTest, debug_frame_first_x86) { + std::string dir(TestGetFileDirectory() + "offline/debug_frame_first_x86/"); + + MemoryOffline* memory = new MemoryOffline; + ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0)); + + FILE* fp = fopen((dir + "regs.txt").c_str(), "r"); + ASSERT_TRUE(fp != nullptr); + RegsX86 regs; + uint64_t reg_value; + ASSERT_EQ(1, fscanf(fp, "eax: %" SCNx64 "\n", ®_value)); + regs[X86_REG_EAX] = reg_value; + ASSERT_EQ(1, fscanf(fp, "ebx: %" SCNx64 "\n", ®_value)); + regs[X86_REG_EBX] = reg_value; + ASSERT_EQ(1, fscanf(fp, "ecx: %" SCNx64 "\n", ®_value)); + regs[X86_REG_ECX] = reg_value; + ASSERT_EQ(1, fscanf(fp, "edx: %" SCNx64 "\n", ®_value)); + regs[X86_REG_EDX] = reg_value; + ASSERT_EQ(1, fscanf(fp, "ebp: %" SCNx64 "\n", ®_value)); + regs[X86_REG_EBP] = reg_value; + ASSERT_EQ(1, fscanf(fp, "edi: %" SCNx64 "\n", ®_value)); + regs[X86_REG_EDI] = reg_value; + ASSERT_EQ(1, fscanf(fp, "esi: %" SCNx64 "\n", ®_value)); + regs[X86_REG_ESI] = reg_value; + ASSERT_EQ(1, fscanf(fp, "esp: %" SCNx64 "\n", ®_value)); + regs[X86_REG_ESP] = reg_value; + ASSERT_EQ(1, fscanf(fp, "eip: %" SCNx64 "\n", ®_value)); + regs[X86_REG_EIP] = reg_value; + regs.SetFromRaw(); + fclose(fp); + + fp = fopen((dir + "maps.txt").c_str(), "r"); + ASSERT_TRUE(fp != nullptr); + // The file is guaranteed to be less than 4096 bytes. + std::vector buffer(4096); + ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp)); + fclose(fp); + + BufferMaps maps(buffer.data()); + ASSERT_TRUE(maps.Parse()); + + ASSERT_EQ(ARCH_X86, regs.Arch()); + + std::shared_ptr process_memory(memory); + + char* cwd = getcwd(nullptr, 0); + ASSERT_EQ(0, chdir(dir.c_str())); + JitDebug jit_debug(process_memory); + Unwinder unwinder(128, &maps, ®s, process_memory); + unwinder.SetJitDebug(&jit_debug, regs.Arch()); + unwinder.Unwind(); + ASSERT_EQ(0, chdir(cwd)); + free(cwd); + + std::string frame_info(DumpFrames(unwinder)); + ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; + EXPECT_EQ( + " #00 pc 00000685 waiter (call_level3+53)\n" + " #01 pc 000006b7 waiter (call_level2+23)\n" + " #02 pc 000006d7 waiter (call_level1+23)\n" + " #03 pc 000006f7 waiter (main+23)\n" + " #04 pc 00018275 libc.so\n", + frame_info); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so new file mode 100644 index 0000000..78449bf Binary files /dev/null and b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so differ diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt new file mode 100644 index 0000000..7cada15 --- /dev/null +++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt @@ -0,0 +1,2 @@ +60a9fdf000-60a9fe0000 r-xp 0 00:00 0 waiter64 +7542cc0000-7542d8e000 r-xp 0 00:00 0 libc.so diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt new file mode 100644 index 0000000..c24adbe --- /dev/null +++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt @@ -0,0 +1,4 @@ +pc: 60a9fdf550 +sp: 7fdd141990 +lr: 60a9fdf56c +x29: 7fdd1419a0 diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data new file mode 100644 index 0000000..b56d420 Binary files /dev/null and b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data differ diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 new file mode 100644 index 0000000..81bda1d Binary files /dev/null and b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 differ diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so new file mode 100644 index 0000000..9c78790 Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so differ diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt new file mode 100644 index 0000000..74fc89f --- /dev/null +++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt @@ -0,0 +1,2 @@ +56598000-56599000 r-xp 0 00:00 0 waiter +f7432000-f75e3000 r-xp 0 00:00 0 libc.so diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt new file mode 100644 index 0000000..48f4440 --- /dev/null +++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt @@ -0,0 +1,9 @@ +eax: 1d88ef8c +ebx: 56599fe8 +ecx: 3 +edx: ffcf9ea4 +ebp: ffcf9e48 +edi: f75e5000 +esi: 1 +esp: ffcf9e38 +eip: 56598685 diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data new file mode 100644 index 0000000..0cf7d55 Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data differ diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter new file mode 100644 index 0000000..b1fc024 Binary files /dev/null and b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter differ -- cgit v1.2.3