summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-10-02 03:09:44 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-10-02 03:09:44 +0000
commit6afd6d23f50026ddf3b6cfb440e779075e801316 (patch)
tree48e0b2403de19a1475a492a80459cc9a7b14edf8
parent9f9f7e2ba070ac5b6cea8dd8af272dadebe43a30 (diff)
parent6497234a597c9f681b8120a2599a11be71016f99 (diff)
downloadunwinding-6afd6d23f50026ddf3b6cfb440e779075e801316.tar.gz
Change-Id: I16abf222ed5e0886b4c2695b2b8c3efb00d54c67
-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);