Add ability to read jit gdb data.
Changes:
- New JitDebug class to handle all of the jit gdb interface.
- Add unit tests for all, along with new offline test using debug data.
- Add new Memory type called MemoryOfflineParts that has multiple
MemoryOffline objects to support the offline test.
- Update the tools to use the JitDebug object.
- Modify libbacktrace to use the JitDebug, but only looking in libart.so
and libartd.so.
- Change the Format32Bits to Is32Bit since it's more accurate and I use
it in a different context where original name didn't make sense.
- Add a new function to find global variables in an elf file
(GetGlobalVariable).
- Add a new function to determine if a pc is valid for this elf (IsValidPc).
Bug: 68396769
Test: Ran new unit tests. Added new offline test that uses jit debug data.
Test: Ran art test that generates jit data and verified a crash unwinds
Test: through the jit data.
Change-Id: I6e7ee2f5bab2242028a06feece156dff21c0a974
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index a83f85b..b0a1c0c 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -27,12 +27,13 @@
#include <android-base/stringprintf.h>
#include <unwindstack/Elf.h>
+#include <unwindstack/JitDebug.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Unwinder.h>
namespace unwindstack {
-void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc) {
+void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
FrameData* frame = &frames_.at(frame_num);
@@ -53,7 +54,7 @@
frame->map_flags = map_info->flags;
frame->map_load_bias = elf->GetLoadBias();
- if (!elf->GetFunctionName(frame->rel_pc, &frame->function_name, &frame->function_offset)) {
+ if (!elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) {
frame->function_name = "";
frame->function_offset = 0;
}
@@ -79,17 +80,20 @@
bool return_address_attempt = false;
bool adjust_pc = false;
+ std::unique_ptr<JitDebug> jit_debug;
for (; frames_.size() < max_frames_;) {
uint64_t cur_pc = regs_->pc();
uint64_t cur_sp = regs_->sp();
MapInfo* map_info = maps_->Find(regs_->pc());
uint64_t rel_pc;
+ uint64_t adjusted_pc;
uint64_t adjusted_rel_pc;
Elf* elf;
if (map_info == nullptr) {
rel_pc = regs_->pc();
adjusted_rel_pc = rel_pc;
+ adjusted_pc = rel_pc;
} else {
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
@@ -97,16 +101,30 @@
elf = map_info->GetElf(process_memory_, true);
rel_pc = elf->GetRelPc(regs_->pc(), map_info);
if (adjust_pc) {
- adjusted_rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
+ adjusted_pc = regs_->GetAdjustedPc(rel_pc, elf);
} else {
- adjusted_rel_pc = rel_pc;
+ adjusted_pc = rel_pc;
+ }
+ adjusted_rel_pc = adjusted_pc;
+
+ // If the pc is in an invalid elf file, try and get an Elf object
+ // using the jit debug information.
+ if (!elf->valid() && jit_debug_ != nullptr) {
+ uint64_t adjusted_jit_pc = regs_->pc() - (rel_pc - adjusted_pc);
+ Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc);
+ if (jit_elf != nullptr) {
+ // The jit debug information requires a non relative adjusted pc.
+ adjusted_pc = adjusted_jit_pc;
+ adjusted_rel_pc = adjusted_pc - map_info->start;
+ elf = jit_elf;
+ }
}
}
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
- FillInFrame(map_info, elf, adjusted_rel_pc);
+ FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
// Once a frame is added, stop skipping frames.
initial_map_names_to_skip = nullptr;
@@ -134,7 +152,7 @@
in_device_map = true;
} else {
bool finished;
- stepped = elf->Step(rel_pc, adjusted_rel_pc, map_info->elf_offset, regs_,
+ stepped = elf->Step(rel_pc, adjusted_pc, map_info->elf_offset, regs_,
process_memory_.get(), &finished);
if (stepped && finished) {
break;
@@ -174,13 +192,13 @@
if (frame_num >= frames_.size()) {
return "";
}
- return FormatFrame(frames_[frame_num], regs_->Format32Bit());
+ return FormatFrame(frames_[frame_num], regs_->Is32Bit());
}
-std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) {
+std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
std::string data;
- if (bits32) {
+ if (is32bit) {
data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
} else {
data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
@@ -208,4 +226,9 @@
return data;
}
+void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
+ jit_debug->SetArch(arch);
+ jit_debug_ = jit_debug;
+}
+
} // namespace unwindstack