summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2023-02-09 18:24:31 -0800
committerChristopher Ferris <cferris@google.com>2023-02-14 00:30:52 +0000
commit54e8259b422e572a827333217cd2dbb6b32c5a7a (patch)
tree3684f9a8701b57a64330ccac08cdf6d3b3eb533d
parent6f4653d1cd327affb66145a444dfb60ce960d82b (diff)
downloadunwinding-android-13.0.0_r74.tar.gz
Some shared libraries seem to be putting a dynamic symbol table at the end of the shared library. Modify the GetMaxSize() function to read the PT_LOAD values and if that is larger than the computed elf size, use that value instead. Added new offline test to expose this problem. Bug: 268566992 Test: All unit tests pass. Change-Id: I9c240e83d6090417fc1f642f049175def908be32 (cherry picked from commit 55a088e31bbfb5ffa23e48cb25ff1b72a8f64207)
-rw-r--r--libunwindstack/Android.bp1
-rw-r--r--libunwindstack/ElfInterface.cpp27
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gzbin0 -> 453288 bytes
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt6
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt3
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt34
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/stack.databin0 -> 5240 bytes
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gzbin0 -> 1817 bytes
-rw-r--r--libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gzbin0 -> 1923 bytes
-rw-r--r--libunwindstack/tests/UnwindOfflineTest.cpp27
10 files changed, 95 insertions, 3 deletions
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index bed17e4..3c1eeb8 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -361,6 +361,7 @@ cc_defaults {
"offline_files/apk_rorx_unreadable_arm64/*",
"offline_files/apk_rx_arm64/*",
"offline_files/apk_rx_unreadable_arm64/*",
+ "offline_files/apk_soname_at_end_arm64/*",
"offline_files/art_quick_osr_stub_arm/*",
"offline_files/bad_eh_frame_hdr_arm64/*",
"offline_files/debug_frame_first_x86/*",
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 0389198..43f1218 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -520,12 +520,33 @@ template <typename ElfTypes>
void ElfInterfaceImpl<ElfTypes>::GetMaxSize(Memory* memory, uint64_t* size) {
EhdrType ehdr;
if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
+ *size = 0;
return;
}
- if (ehdr.e_shnum == 0) {
- return;
+
+ // If this winds up as zero, the PT_LOAD reading will get a better value.
+ uint64_t elf_size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
+
+ // Search through the PT_LOAD values and if any result in a larger elf
+ // size, use that.
+ uint64_t offset = ehdr.e_phoff;
+ for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
+ PhdrType phdr;
+ if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
+ break;
+ }
+ if (phdr.p_type == PT_LOAD) {
+ uint64_t end_offset;
+ if (__builtin_add_overflow(phdr.p_offset, phdr.p_memsz, &end_offset)) {
+ continue;
+ }
+ if (end_offset > elf_size) {
+ elf_size = end_offset;
+ }
+ }
}
- *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
+
+ *size = elf_size;
}
template <typename EhdrType, typename ShdrType>
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gz b/libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gz
new file mode 100644
index 0000000..7f8b791
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gz
Binary files differ
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt b/libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt
new file mode 100644
index 0000000..0f17200
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt
@@ -0,0 +1,6 @@
+580e17c000-580e17d000 r--p 0 00:00 0 unwinder
+580e17d000-580e17e000 r-xp 1000 00:00 0 unwinder
+7c0064a000-7c0064b000 r--p a000 00:00 0 unwinder.apk
+7c0064b000-7c0064c000 r-xp b000 00:00 0 unwinder.apk
+7e90877000-7e908ba000 r--p 0 00:00 0 libc.so
+7e908ba000-7e9094c000 r-xp 43000 00:00 0 libc.so
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt b/libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt
new file mode 100644
index 0000000..557dda7
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt
@@ -0,0 +1,3 @@
+ #00 pc 000000000000113c unwinder.apk!libunwindstack_local.so (offset 0xa000) (WaitForever+60)
+ #01 pc 00000000000010f0 unwinder (main+144)
+ #02 pc 0000000000052cc8 libc.so (__libc_init+104)
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt b/libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt
new file mode 100644
index 0000000..26dc38a
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt
@@ -0,0 +1,34 @@
+x0: 7ff9ec4b94
+x1: 0
+x2: 0
+x3: 0
+x4: 10
+x5: b400007d8087e0c9
+x6: a
+x7: 7f7f7f7f7f7f7f7f
+x8: 1
+x9: fbf40ad8e3dbed37
+x10: 10ec
+x11: 10ec
+x12: 163
+x13: 7ff9ec44c4
+x14: 0
+x15: 2
+x16: 7e9094ec00
+x17: 7e90941e30
+x18: 7e918d4000
+x19: 7c0064b100
+x20: 7e91416000
+x21: 1
+x22: 7ff9ec4c78
+x23: 0
+x24: 0
+x25: 0
+x26: 0
+x27: 0
+x28: 0
+x29: 7ff9ec4ba0
+lr: 7c0064b148
+sp: 7ff9ec4b90
+pc: 7c0064b13c
+pst: 60001000
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/stack.data b/libunwindstack/offline_files/apk_soname_at_end_arm64/stack.data
new file mode 100644
index 0000000..19079b1
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gz b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gz
new file mode 100644
index 0000000..f38d8f1
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gz
Binary files differ
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gz b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gz
new file mode 100644
index 0000000..90eb389
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gz
Binary files differ
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0d6fa1d..0306b29 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1658,5 +1658,32 @@ TEST_F(UnwindOfflineTest, apk_rx_unreadable_arm64) {
VerifyApkRX(unwinder);
}
+TEST_F(UnwindOfflineTest, apk_soname_at_end_arm64) {
+ std::string error_msg;
+ if (!offline_utils_.Init({.offline_files_dir = "apk_soname_at_end_arm64/", .arch = ARCH_ARM64},
+ &error_msg))
+ FAIL() << error_msg;
+
+ Regs* regs = offline_utils_.GetRegs();
+ std::unique_ptr<Regs> regs_copy(regs->Clone());
+ Unwinder unwinder(128, offline_utils_.GetMaps(), regs, offline_utils_.GetProcessMemory());
+ unwinder.Unwind();
+
+ size_t expected_num_frames;
+ if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
+ std::string expected_frame_info;
+ if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(expected_frame_info, frame_info);
+ EXPECT_EQ(0x7c0064b13cULL, unwinder.frames()[0].pc);
+ EXPECT_EQ(0x7ff9ec4b90ULL, unwinder.frames()[0].sp);
+ EXPECT_EQ(0x580e17d0f0ULL, unwinder.frames()[1].pc);
+ EXPECT_EQ(0x7ff9ec4bb0ULL, unwinder.frames()[1].sp);
+ EXPECT_EQ(0x7e908c9cc8ULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7ff9ec4c10ULL, unwinder.frames()[2].sp);
+}
+
} // namespace
} // namespace unwindstack