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/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index df1642e..0e3ab2c 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -43,6 +43,30 @@
}
}
+bool ElfInterface::IsValidPc(uint64_t pc) {
+ if (!pt_loads_.empty()) {
+ for (auto& entry : pt_loads_) {
+ uint64_t start = entry.second.table_offset;
+ uint64_t end = start + entry.second.table_size;
+ if (pc >= start && pc < end) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // No PT_LOAD data, look for a fde for this pc in the section data.
+ if (debug_frame_ != nullptr && debug_frame_->GetFdeFromPc(pc) != nullptr) {
+ return true;
+ }
+
+ if (eh_frame_ != nullptr && eh_frame_->GetFdeFromPc(pc) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
Memory* ElfInterface::CreateGnuDebugdataMemory() {
if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
return nullptr;
@@ -225,6 +249,10 @@
return false;
}
dynamic_offset_ = phdr.p_offset;
+ if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
+ return false;
+ }
+ dynamic_vaddr_ = phdr.p_vaddr;
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
return false;
}
@@ -386,6 +414,20 @@
return false;
}
+template <typename SymType>
+bool ElfInterface::GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address) {
+ if (symbols_.empty()) {
+ return false;
+ }
+
+ for (const auto symbol : symbols_) {
+ if (symbol->GetGlobal<SymType>(memory_, name, memory_address)) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished) {
// Adjust the load bias to get the real relative pc.
@@ -451,6 +493,9 @@
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
uint64_t*);
+template bool ElfInterface::GetGlobalVariableWithTemplate<Elf32_Sym>(const std::string&, uint64_t*);
+template bool ElfInterface::GetGlobalVariableWithTemplate<Elf64_Sym>(const std::string&, uint64_t*);
+
template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);