summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libunwindstack/AndroidVersions.md16
-rw-r--r--libunwindstack/MapInfo.cpp2
-rw-r--r--libunwindstack/tests/MapInfoCreateMemoryTest.cpp31
3 files changed, 49 insertions, 0 deletions
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<Memory>& process_memory) {
// option is used.
std::unique_ptr<MemoryRange> 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<Elf32_Ehdr>(&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<Memory> 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<uint8_t> 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);