Support a map that represents gdb jit elf data.
Changes: - Add a new flag to the libbacktrace and libunwindstack map data. - Modify the unwinder to handle this map to use the raw pc when stepping. - Add new unit tests for this case. Bug: http://b/73127105 Test: Run simpleperf to unwind through jit symfiles. Test: Run new unit tests. Test: Run 137-cfi test on host. Change-Id: I10bc0410680accc6d35fe51e9f1098911f667e01
This commit is contained in:
parent
5ea2c4baf1
commit
d5b22c5f04
|
@ -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;
|
||||
|
|
|
@ -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/*",
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -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;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/JitDebug.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Maps.h>
|
||||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
#if !defined(NO_LIBDEXFILE_SUPPORT)
|
||||
|
@ -142,26 +143,31 @@ void Unwinder::Unwind(const std::vector<std::string>* 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.
|
||||
|
|
|
@ -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<MapInfo*>::iterator iterator;
|
||||
iterator begin() { return maps_.begin(); }
|
||||
iterator end() { return maps_.end(); }
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -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
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
|
||||
e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
|
|
@ -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
|
Binary file not shown.
Loading…
Reference in New Issue