summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-10-02 21:09:47 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-10-02 21:09:47 +0000
commitde49fbe6a24fa4c7170316cb630425dcdd8a8bb8 (patch)
tree48e0b2403de19a1475a492a80459cc9a7b14edf8
parente8bfc6942d73adaac9e62001a00888b5a17dacce (diff)
parentd639acc5af1b2094d29068b03cc9f2795b141395 (diff)
downloadunwinding-android-platform-12.1.0_r4.tar.gz
Change-Id: Id2709c92e33e997f82fc36f4abb7f49de7699064
-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);