diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index b7650a178..5423de53a 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -241,6 +241,7 @@ cc_test { "tests/files/offline/debug_frame_first_x86/*", "tests/files/offline/debug_frame_load_bias_arm/*", "tests/files/offline/eh_frame_hdr_begin_x86_64/*", + "tests/files/offline/invalid_elf_offset_arm/*", "tests/files/offline/jit_debug_arm/*", "tests/files/offline/jit_debug_x86/*", "tests/files/offline/jit_map_arm/*", diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index 03658b445..d3cec069a 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -231,11 +231,13 @@ Elf* MapInfo::GetElf(const std::shared_ptr& process_memory, ArchEnum exp } } - // If there is a read-only map then a read-execute map that represents the - // same elf object, make sure the previous map is using the same elf - // object if it hasn't already been set. - if (prev_map != nullptr && elf_start_offset != offset && prev_map->offset == elf_start_offset && - prev_map->name == name) { + if (!elf->valid()) { + elf_start_offset = offset; + } else if (prev_map != nullptr && elf_start_offset != offset && + prev_map->offset == elf_start_offset && prev_map->name == name) { + // If there is a read-only map then a read-execute map that represents the + // same elf object, make sure the previous map is using the same elf + // object if it hasn't already been set. std::lock_guard guard(prev_map->mutex_); if (prev_map->elf.get() == nullptr) { prev_map->elf = elf; diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 6c64c4097..553b34406 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -62,7 +62,7 @@ class UnwindOfflineTest : public ::testing::Test { free(cwd_); } - void Init(const char* file_dir, ArchEnum arch) { + void Init(const char* file_dir, ArchEnum arch, bool add_stack = true) { dir_ = TestGetFileDirectory() + "offline/" + file_dir; std::string data; @@ -71,23 +71,25 @@ class UnwindOfflineTest : public ::testing::Test { maps_.reset(new BufferMaps(data.c_str())); ASSERT_TRUE(maps_->Parse()); - std::string stack_name(dir_ + "stack.data"); - struct stat st; - if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { - std::unique_ptr stack_memory(new MemoryOffline); - ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0)); - process_memory_.reset(stack_memory.release()); - } else { - std::unique_ptr stack_memory(new MemoryOfflineParts); - for (size_t i = 0;; i++) { - stack_name = dir_ + "stack" + std::to_string(i) + ".data"; - if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) { - ASSERT_TRUE(i != 0) << "No stack data files found."; - break; + if (add_stack) { + std::string stack_name(dir_ + "stack.data"); + struct stat st; + if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { + std::unique_ptr stack_memory(new MemoryOffline); + ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0)); + process_memory_.reset(stack_memory.release()); + } else { + std::unique_ptr stack_memory(new MemoryOfflineParts); + for (size_t i = 0;; i++) { + stack_name = dir_ + "stack" + std::to_string(i) + ".data"; + if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) { + ASSERT_TRUE(i != 0) << "No stack data files found."; + break; + } + AddMemory(stack_name, stack_memory.get()); } - AddMemory(stack_name, stack_memory.get()); + process_memory_.reset(stack_memory.release()); } - process_memory_.reset(stack_memory.release()); } switch (arch) { @@ -1442,4 +1444,17 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_single_map_arm64) { EXPECT_EQ(0x7be4f07d20ULL, unwinder.frames()[12].sp); } +TEST_F(UnwindOfflineTest, invalid_elf_offset_arm) { + ASSERT_NO_FATAL_FAILURE(Init("invalid_elf_offset_arm/", ARCH_ARM, false)); + + Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); + unwinder.Unwind(); + + std::string frame_info(DumpFrames(unwinder)); + ASSERT_EQ(1U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; + EXPECT_EQ(" #00 pc 00aa7508 invalid.apk (offset 0x12e4000)\n", frame_info); + EXPECT_EQ(0xc898f508, unwinder.frames()[0].pc); + EXPECT_EQ(0xc2044218, unwinder.frames()[0].sp); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt new file mode 100644 index 000000000..022404c77 --- /dev/null +++ b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt @@ -0,0 +1 @@ +c7ee8000-c8c52fff r-xp 12e4000 00:00 0 invalid.apk diff --git a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt new file mode 100644 index 000000000..b7f10efc1 --- /dev/null +++ b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt @@ -0,0 +1,16 @@ +r0: c0434c00 +r1: 2a4c9fbc +r2: 00000000 +r3: c83ef1f9 +r4: 00000004 +r5: c2044904 +r6: 00000000 +r7: c20443b8 +r8: 000b33ff +r9: c20444b0 +r10: cac90740 +r11: 00000000 +ip: ed891ca4 +sp: c2044218 +lr: ed807265 +pc: c898f508