From 6497234a597c9f681b8120a2599a11be71016f99 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 1 Oct 2021 11:37:52 -0700 Subject: Fix missing offset in display for apk backtrace. When an apk maps a shared library that only has a single read-executable map and the original apk files is unreadable, the offset data is not set properly. Specifically, this is the output before the bug: #01 pc 000000000222675c GoogleCamera.apk After the fix, the line now looks like so: #01 pc 000000000222675c GoogleCamera.apk (offset 0x269f000) There is no problem if the shared library creates a read-only, then read-executable map. Added a new unit test to cover this case. Bug: 201703079 Test: All unit tests pass. Test: Also, created an offline test to verify that with this change Test: the offset is displayed properly. The offline test will be Test: added in a follow-up cl. Change-Id: I3cc840beb6b3005afade06a4d0ae400e559a0046 Merged-In: I3cc840beb6b3005afade06a4d0ae400e559a0046 (cherry picked from commit e0b9c92e4294cb770af8a6ccf7c59b6829951ae7) --- libunwindstack/AndroidVersions.md | 16 ++++++++++++ libunwindstack/MapInfo.cpp | 2 ++ libunwindstack/tests/MapInfoCreateMemoryTest.cpp | 31 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/libunwindstack/AndroidVersions.md b/libunwindstack/AndroidVersions.md index b4e29ca..ff46829 100644 --- a/libunwindstack/AndroidVersions.md +++ b/libunwindstack/AndroidVersions.md @@ -114,3 +114,19 @@ included in linker arguments when using lld. and uses pc relative FDEs, the unwind will be incorrect. This tends to truncate unwinds since the unwinder could not find the correct unwind information for a given pc. + +## Android 12 ("S", API level 31) +* Fix bug where, if a shared library is dlopen'ed from within an apk file, + is not readable, and the shared library only produces a single read- + executable map for the elf data and executable data, the offset into the + apk will not be displayed. Previously the line would look like: + + #01 pc 000000000222675c GoogleCamera.apk + + to: + + #01 pc 000000000222675c GoogleCamera.apk (offset 0x269f000) + + If the apk file is readable, or dlopen'ing the shared library creates + a read-only map of the elf data, and a read-executable map of the + code, the offset will be displayed properly without this fix. diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index 8fb6f7e..1127cd9 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -166,6 +166,8 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr& process_memory) { // option is used. std::unique_ptr memory(new MemoryRange(process_memory, start(), end() - start(), 0)); if (Elf::IsValidElf(memory.get())) { + set_elf_start_offset(offset()); + // Might need to peek at the next map to create a memory object that // includes that map too. if (offset() != 0 || name().empty() || next_real_map() == nullptr || diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index d5e04a1..1f7f8bf 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -367,6 +367,37 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) { } } +TEST_F(MapInfoCreateMemoryTest, valid_single_rx_non_zero_offset) { + Maps maps; + maps.Add(0x3000, 0x5000, 0xa000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0); + + Elf32_Ehdr ehdr = {}; + TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM); + + // Setup an elf at offset 0x3000 in memory.. + memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr)); + memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x5000 - sizeof(ehdr), 0x34); + + MapInfo* map_info = maps.Find(0x3000); + ASSERT_TRUE(map_info != nullptr); + + std::unique_ptr mem(map_info->CreateMemory(process_memory_)); + ASSERT_TRUE(mem.get() != nullptr); + EXPECT_TRUE(map_info->memory_backed_elf()); + EXPECT_EQ(0UL, map_info->elf_offset()); + EXPECT_EQ(0xa000UL, map_info->offset()); + EXPECT_EQ(0xa000UL, map_info->elf_start_offset()); + + // Verify that reading values from this memory works properly. + std::vector buffer(0x3000); + size_t bytes = mem->Read(0, buffer.data(), buffer.size()); + ASSERT_EQ(0x2000UL, bytes); + ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr))); + for (size_t i = sizeof(ehdr); i < bytes; i++) { + ASSERT_EQ(0x34, buffer[i]) << "Failed at byte " << i; + } +} + TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { Maps maps; maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0); -- cgit v1.2.3