diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h index 473d195ba..c94cad188 100644 --- a/libbacktrace/include/backtrace/BacktraceMap.h +++ b/libbacktrace/include/backtrace/BacktraceMap.h @@ -40,6 +40,10 @@ struct backtrace_stackinfo_t; // Special flag to indicate a map is in /dev/. However, a map in // /dev/ashmem/... does not set this flag. static constexpr int PROT_DEVICE_MAP = 0x8000; +// Special flag to indicate that this map represents an elf file +// created by ART for use with the gdb jit debug interface. +// This should only ever appear in offline maps data. +static constexpr int PROT_JIT_SYMFILE_MAP = 0x4000; struct backtrace_map_t { uint64_t start = 0; diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 08dcf7724..0d43f8724 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -194,6 +194,7 @@ cc_test { "tests/files/offline/eh_frame_hdr_begin_x86_64/*", "tests/files/offline/jit_debug_arm/*", "tests/files/offline/jit_debug_x86/*", + "tests/files/offline/jit_map_arm/*", "tests/files/offline/gnu_debugdata_arm/*", "tests/files/offline/straddle_arm/*", "tests/files/offline/straddle_arm64/*", diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp index 4c1621284..e1a1a7144 100644 --- a/libunwindstack/Maps.cpp +++ b/libunwindstack/Maps.cpp @@ -25,6 +25,7 @@ #include +#include #include #include #include @@ -209,6 +210,11 @@ void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, maps_.push_back(map_info); } +void Maps::Sort() { + std::sort(maps_.begin(), maps_.end(), + [](const MapInfo* a, const MapInfo* b) { return a->start < b->start; }); +} + Maps::~Maps() { for (auto& map : maps_) { delete map; diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 27262bd5b..9a6c6dfe2 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #if !defined(NO_LIBDEXFILE_SUPPORT) @@ -142,26 +143,31 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, uint64_t cur_sp = regs_->sp(); MapInfo* map_info = maps_->Find(regs_->pc()); - uint64_t rel_pc; uint64_t pc_adjustment = 0; uint64_t step_pc; + uint64_t rel_pc; Elf* elf; if (map_info == nullptr) { - rel_pc = regs_->pc(); - step_pc = rel_pc; + step_pc = regs_->pc(); + rel_pc = step_pc; last_error_.code = ERROR_INVALID_MAP; } else { if (ShouldStop(map_suffixes_to_ignore, map_info->name)) { break; } elf = map_info->GetElf(process_memory_, true); - rel_pc = elf->GetRelPc(regs_->pc(), map_info); + step_pc = regs_->pc(); + rel_pc = elf->GetRelPc(step_pc, map_info); + // Everyone except elf data in gdb jit debug maps uses the relative pc. + if (!(map_info->flags & MAPS_FLAGS_JIT_SYMFILE_MAP)) { + step_pc = rel_pc; + } if (adjust_pc) { pc_adjustment = regs_->GetPcAdjustment(rel_pc, elf); } else { pc_adjustment = 0; } - step_pc = rel_pc - pc_adjustment; + step_pc -= pc_adjustment; // If the pc is in an invalid elf file, try and get an Elf object // using the jit debug information. diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h index 17a2d28ae..74e5c4729 100644 --- a/libunwindstack/include/unwindstack/Maps.h +++ b/libunwindstack/include/unwindstack/Maps.h @@ -30,6 +30,10 @@ namespace unwindstack { // Special flag to indicate a map is in /dev/. However, a map in // /dev/ashmem/... does not set this flag. static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000; +// Special flag to indicate that this map represents an elf file +// created by ART for use with the gdb jit debug interface. +// This should only ever appear in offline maps data. +static constexpr int MAPS_FLAGS_JIT_SYMFILE_MAP = 0x4000; class Maps { public: @@ -45,6 +49,8 @@ class Maps { void Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name, uint64_t load_bias); + void Sort(); + typedef std::vector::iterator iterator; iterator begin() { return maps_.begin(); } iterator end() { return maps_.end(); } diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 532640f38..6c242a5ab 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1070,4 +1071,44 @@ TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) { EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp); } +TEST_F(UnwindOfflineTest, jit_map_arm) { + Init("jit_map_arm/", ARCH_ARM); + + maps_->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP, + "jit_map0.so", 0); + maps_->Add(0xd025cd98, 0xd025cff4, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP, + "jit_map1.so", 0); + maps_->Sort(); + + Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); + unwinder.Unwind(); + + std::string frame_info(DumpFrames(unwinder)); + ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; + EXPECT_EQ( + " #00 pc 00000000 jit_map0.so " + "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n" + " #01 pc 0000003d jit_map1.so " + "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n" + " #02 pc 004135bb libart.so (art_quick_osr_stub+42)\n" + + " #03 pc 003851dd libart.so (_ZN3art6Thread14CreateCallbackEPv+868)\n" + " #04 pc 00062925 libc.so (_ZL15__pthread_startPv+22)\n" + " #05 pc 0001de39 libc.so (__start_thread+24)\n", + frame_info); + + EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc); + EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp); + EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc); + EXPECT_EQ(0xcd4ff140U, unwinder.frames()[1].sp); + EXPECT_EQ(0xe4a755bbU, unwinder.frames()[2].pc); + EXPECT_EQ(0xcd4ff160U, unwinder.frames()[2].sp); + EXPECT_EQ(0xe49e71ddU, unwinder.frames()[3].pc); + EXPECT_EQ(0xcd4ff8e8U, unwinder.frames()[3].sp); + EXPECT_EQ(0xe7df3925U, unwinder.frames()[4].pc); + EXPECT_EQ(0xcd4ff958U, unwinder.frames()[4].sp); + EXPECT_EQ(0xe7daee39U, unwinder.frames()[5].pc); + EXPECT_EQ(0xcd4ff960U, unwinder.frames()[5].sp); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so new file mode 100644 index 000000000..e66788377 Binary files /dev/null and b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so differ diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so new file mode 100644 index 000000000..9a1d71483 Binary files /dev/null and b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so differ diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libart.so b/libunwindstack/tests/files/offline/jit_map_arm/libart.so new file mode 100644 index 000000000..09ba49532 Binary files /dev/null and b/libunwindstack/tests/files/offline/jit_map_arm/libart.so differ diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libc.so b/libunwindstack/tests/files/offline/jit_map_arm/libc.so new file mode 100644 index 000000000..39c9025db Binary files /dev/null and b/libunwindstack/tests/files/offline/jit_map_arm/libc.so differ diff --git a/libunwindstack/tests/files/offline/jit_map_arm/maps.txt b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt new file mode 100644 index 000000000..5aaec5420 --- /dev/null +++ b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt @@ -0,0 +1,2 @@ +e466e000-e4ae8000 r-xp 0 00:00 0 libart.so +e7d91000-e7e31000 r-xp 0 00:00 0 libc.so diff --git a/libunwindstack/tests/files/offline/jit_map_arm/regs.txt b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt new file mode 100644 index 000000000..0b518143a --- /dev/null +++ b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt @@ -0,0 +1,16 @@ +r0: e814103c +r1: 12dcf218 +r2: 1a90df75 +r3: ffffffbf +r4: 0 +r5: 12dc0800 +r6: 12dcf218 +r7: 1a90df75 +r8: 0 +r9: dd23cc00 +r10: 1c +r11: cd4ff16c +ip: 0 +sp: cd4ff140 +lr: d025cdd7 +pc: d025c788 diff --git a/libunwindstack/tests/files/offline/jit_map_arm/stack.data b/libunwindstack/tests/files/offline/jit_map_arm/stack.data new file mode 100644 index 000000000..fb8feebf1 Binary files /dev/null and b/libunwindstack/tests/files/offline/jit_map_arm/stack.data differ