diff options
author | Christopher Ferris <cferris@google.com> | 2019-01-15 15:18:43 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2019-01-29 17:57:14 -0800 |
commit | 60eb19795bbcdeba162de104af1bcd14478ef230 (patch) | |
tree | 1b80fd0f80e32cda479f538279de6a34c7ed4262 /debuggerd/libdebuggerd/tombstone.cpp | |
parent | 9f5e9978c2b58ebdcc3d253c6e04e31e5b90a0e4 (diff) | |
download | system_core-60eb19795bbcdeba162de104af1bcd14478ef230.tar.gz system_core-60eb19795bbcdeba162de104af1bcd14478ef230.tar.bz2 system_core-60eb19795bbcdeba162de104af1bcd14478ef230.zip |
Replace libbacktrace with libunwindstack directly.
Small modifications to the dump_stack method and added unit tests to
verify the output.
Bug: 120606663
Test: Unit tests pass, debuggerd run on processes on target.
Change-Id: Id385a915b751abda3dd6baebed6c3ce498c3bf6e
Diffstat (limited to 'debuggerd/libdebuggerd/tombstone.cpp')
-rw-r--r-- | debuggerd/libdebuggerd/tombstone.cpp | 221 |
1 files changed, 115 insertions, 106 deletions
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index b20014f59..8798ad3d3 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -41,19 +41,20 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <android/log.h> -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> #include <log/log.h> #include <log/logprint.h> #include <private/android_filesystem_config.h> +#include <unwindstack/DexFiles.h> +#include <unwindstack/JitDebug.h> +#include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> +#include <unwindstack/Unwinder.h> // Needed to get DEBUGGER_SIGNAL. #include "debuggerd/handler.h" #include "libdebuggerd/backtrace.h" -#include "libdebuggerd/elf_utils.h" #include "libdebuggerd/open_files_list.h" #include "libdebuggerd/utility.h" @@ -62,9 +63,6 @@ using android::base::GetProperty; using android::base::StringPrintf; using android::base::unique_fd; -using unwindstack::Memory; -using unwindstack::Regs; - using namespace std::literals::string_literals; #define STACK_WORDS 16 @@ -87,7 +85,7 @@ static void dump_timestamp(log_t* log, time_t time) { _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf); } -static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) { +static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps) { std::string cause; if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) { if (si->si_addr < reinterpret_cast<void*>(4096)) { @@ -104,12 +102,9 @@ static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* m cause = "call to kuser_cmpxchg64"; } } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) { - for (auto it = map->begin(); it != map->end(); ++it) { - const backtrace_map_t* entry = *it; - if (si->si_addr >= reinterpret_cast<void*>(entry->start) && - si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) { - cause = "execute-only (no-read) memory access error; likely due to data in .text."; - } + unwindstack::MapInfo* map_info = maps->Find(reinterpret_cast<uint64_t>(si->si_addr)); + if (map_info != nullptr && map_info->flags == PROT_EXEC) { + cause = "execute-only (no-read) memory access error; likely due to data in .text."; } } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) { cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING, @@ -119,7 +114,8 @@ static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* m if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str()); } -static void dump_signal_info(log_t* log, const ThreadInfo& thread_info, Memory* process_memory) { +static void dump_signal_info(log_t* log, const ThreadInfo& thread_info, + unwindstack::Memory* process_memory) { char addr_desc[64]; // ", fault addr 0x1234" if (signal_has_si_addr(thread_info.siginfo)) { void* addr = thread_info.siginfo->si_addr; @@ -156,14 +152,14 @@ static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) { thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str()); } -static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory, +static void dump_stack_segment(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory, uint64_t* sp, size_t words, int label) { // Read the data all at once. word_t stack_data[words]; // TODO: Do we need to word align this for crashes caused by a misaligned sp? // The process_vm_readv implementation of Memory should handle this appropriately? - size_t bytes_read = process_memory->Read(*sp, stack_data, sizeof(word_t) * words); + size_t bytes_read = memory->Read(*sp, stack_data, sizeof(word_t) * words); words = bytes_read / sizeof(word_t); std::string line; for (size_t i = 0; i < words; i++) { @@ -176,17 +172,15 @@ static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* } line += StringPrintf("%" PRIPTR " %" PRIPTR, *sp, static_cast<uint64_t>(stack_data[i])); - backtrace_map_t map; - backtrace_map->FillIn(stack_data[i], &map); - std::string map_name{map.Name()}; - if (BacktraceMap::IsValid(map) && !map_name.empty()) { - line += " " + map_name; - uint64_t offset = 0; - std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset); - if (!func_name.empty()) { + unwindstack::MapInfo* map_info = maps->Find(stack_data[i]); + if (map_info != nullptr && !map_info->name.empty()) { + line += " " + map_info->name; + std::string func_name; + uint64_t func_offset = 0; + if (map_info->GetFunctionName(stack_data[i], &func_name, &func_offset)) { line += " (" + func_name; - if (offset) { - line += StringPrintf("+%" PRIu64, offset); + if (func_offset) { + line += StringPrintf("+%" PRIu64, func_offset); } line += ')'; } @@ -197,12 +191,11 @@ static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* } } -static void dump_stack(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory, - std::vector<backtrace_frame_data_t>& frames) { +static void dump_stack(log_t* log, const std::vector<unwindstack::FrameData>& frames, + unwindstack::Maps* maps, unwindstack::Memory* memory) { size_t first = 0, last; for (size_t i = 0; i < frames.size(); i++) { - const backtrace_frame_data_t& frame = frames[i]; - if (frame.sp) { + if (frames[i].sp) { if (!first) { first = i+1; } @@ -217,29 +210,44 @@ static void dump_stack(log_t* log, BacktraceMap* backtrace_map, Memory* process_ // Dump a few words before the first frame. uint64_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t); - dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1); + dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, -1); + +#if defined(__LP64__) + static constexpr const char delimiter[] = " ................ ................\n"; +#else + static constexpr const char delimiter[] = " ........ ........\n"; +#endif // Dump a few words from all successive frames. - // Only log the first 3 frames, put the rest in the tombstone. for (size_t i = first; i <= last; i++) { - const backtrace_frame_data_t* frame = &frames[i]; + auto* frame = &frames[i]; if (sp != frame->sp) { - _LOG(log, logtype::STACK, " ........ ........\n"); + _LOG(log, logtype::STACK, delimiter); sp = frame->sp; } - if (i == last) { - dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, i); - if (sp < frame->sp + frame->stack_size) { - _LOG(log, logtype::STACK, " ........ ........\n"); - } - } else { - size_t words = frame->stack_size / sizeof(word_t); - if (words == 0) { - words = 1; - } else if (words > STACK_WORDS) { + if (i != last) { + // Print stack data up to the stack from the next frame. + size_t words; + uint64_t next_sp = frames[i + 1].sp; + if (next_sp < sp) { + // The next frame is probably using a completely different stack, + // so dump the max from this stack. words = STACK_WORDS; + } else { + words = (next_sp - sp) / sizeof(word_t); + if (words == 0) { + // The sp is the same as the next frame, print at least + // one line for this frame. + words = 1; + } else if (words > STACK_WORDS) { + words = STACK_WORDS; + } } - dump_stack_segment(log, backtrace_map, process_memory, &sp, words, i); + dump_stack_segment(log, maps, memory, &sp, words, i); + } else { + // Print some number of words past the last stack frame since we + // don't know how large the stack is. + dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, i); } } } @@ -256,7 +264,7 @@ static std::string get_addr_string(uint64_t addr) { return addr_str; } -static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t address) { +static void dump_abort_message(log_t* log, unwindstack::Memory* process_memory, uint64_t address) { if (address == 0) { return; } @@ -285,16 +293,16 @@ static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t addr _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]); } -static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) { +static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t addr) { bool print_fault_address_marker = addr; - ScopedBacktraceMapIteratorLock lock(map); + unwindstack::Maps* maps = unwinder->GetMaps(); _LOG(log, logtype::MAPS, "\n" "memory map (%zu entr%s):", - map->size(), map->size() == 1 ? "y" : "ies"); + maps->Total(), maps->Total() == 1 ? "y" : "ies"); if (print_fault_address_marker) { - if (map->begin() != map->end() && addr < (*map->begin())->start) { + if (maps->Total() != 0 && addr < maps->Get(0)->start) { _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n", get_addr_string(addr).c_str()); print_fault_address_marker = false; @@ -305,51 +313,54 @@ static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, _LOG(log, logtype::MAPS, "\n"); } + std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory(); + std::string line; - for (auto it = map->begin(); it != map->end(); ++it) { - const backtrace_map_t* entry = *it; + for (unwindstack::MapInfo* map_info : *maps) { line = " "; if (print_fault_address_marker) { - if (addr < entry->start) { + if (addr < map_info->start) { _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n", get_addr_string(addr).c_str()); print_fault_address_marker = false; - } else if (addr >= entry->start && addr < entry->end) { + } else if (addr >= map_info->start && addr < map_info->end) { line = "--->"; print_fault_address_marker = false; } } - line += get_addr_string(entry->start) + '-' + get_addr_string(entry->end - 1) + ' '; - if (entry->flags & PROT_READ) { + line += get_addr_string(map_info->start) + '-' + get_addr_string(map_info->end - 1) + ' '; + if (map_info->flags & PROT_READ) { line += 'r'; } else { line += '-'; } - if (entry->flags & PROT_WRITE) { + if (map_info->flags & PROT_WRITE) { line += 'w'; } else { line += '-'; } - if (entry->flags & PROT_EXEC) { + if (map_info->flags & PROT_EXEC) { line += 'x'; } else { line += '-'; } - line += StringPrintf(" %8" PRIx64 " %8" PRIx64, entry->offset, entry->end - entry->start); + line += StringPrintf(" %8" PRIx64 " %8" PRIx64, map_info->offset, + map_info->end - map_info->start); bool space_needed = true; - if (entry->name.length() > 0) { + if (!map_info->name.empty()) { space_needed = false; - line += " " + entry->name; - std::string build_id; - if ((entry->flags & PROT_READ) && elf_get_build_id(process_memory, entry->start, &build_id)) { + line += " " + map_info->name; + std::string build_id = map_info->GetPrintableBuildID(); + if (!build_id.empty()) { line += " (BuildId: " + build_id + ")"; } } - if (entry->load_bias != 0) { + uint64_t load_bias = map_info->GetLoadBias(process_memory); + if (load_bias != 0) { if (space_needed) { line += ' '; } - line += StringPrintf(" (load bias 0x%" PRIx64 ")", entry->load_bias); + line += StringPrintf(" (load bias 0x%" PRIx64 ")", load_bias); } _LOG(log, logtype::MAPS, "%s\n", line.c_str()); } @@ -359,9 +370,9 @@ static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, } } -void dump_backtrace(log_t* log, std::vector<backtrace_frame_data_t>& frames, const char* prefix) { - for (auto& frame : frames) { - _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, Backtrace::FormatFrameData(&frame).c_str()); +void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) { + for (size_t i = 0; i < unwinder->NumFrames(); i++) { + _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str()); } } @@ -377,7 +388,7 @@ static void print_register_row(log_t* log, _LOG(log, logtype::REGISTERS, " %s\n", output.c_str()); } -void dump_registers(log_t* log, Regs* regs) { +void dump_registers(log_t* log, unwindstack::Regs* regs) { // Split lr/sp/pc into their own special row. static constexpr size_t column_count = 4; std::vector<std::pair<std::string, uint64_t>> current_row; @@ -416,23 +427,22 @@ void dump_registers(log_t* log, Regs* regs) { print_register_row(log, special_row); } -void dump_memory_and_code(log_t* log, BacktraceMap* map, Memory* memory, Regs* regs) { - regs->IterateRegisters([log, map, memory](const char* reg_name, uint64_t reg_value) { +void dump_memory_and_code(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory, + unwindstack::Regs* regs) { + regs->IterateRegisters([log, maps, memory](const char* reg_name, uint64_t reg_value) { std::string label{"memory near "s + reg_name}; - if (map) { - backtrace_map_t map_info; - map->FillIn(reg_value, &map_info); - std::string map_name{map_info.Name()}; - if (!map_name.empty()) label += " (" + map_info.Name() + ")"; + if (maps) { + unwindstack::MapInfo* map_info = maps->Find(reg_value); + if (map_info != nullptr && !map_info->name.empty()) { + label += " (" + map_info->name + ")"; + } } dump_memory(log, memory, reg_value, label); }); } -static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory, - const ThreadInfo& thread_info, uint64_t abort_msg_address, - bool primary_thread) { - UNUSED(process_memory); +static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info, + uint64_t abort_msg_address, bool primary_thread) { log->current_tid = thread_info.tid; if (!primary_thread) { _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); @@ -440,41 +450,41 @@ static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory, dump_thread_info(log, thread_info); if (thread_info.siginfo) { - dump_signal_info(log, thread_info, process_memory); - dump_probable_cause(log, thread_info.siginfo, map); + dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get()); + dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps()); } if (primary_thread) { - dump_abort_message(log, process_memory, abort_msg_address); + dump_abort_message(log, unwinder->GetProcessMemory().get(), abort_msg_address); } dump_registers(log, thread_info.registers.get()); // Unwind will mutate the registers, so make a copy first. - std::unique_ptr<Regs> regs_copy(thread_info.registers->Clone()); - std::vector<backtrace_frame_data_t> frames; - if (!Backtrace::Unwind(regs_copy.get(), map, &frames, 0, nullptr)) { + std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone()); + unwinder->SetRegs(regs_copy.get()); + unwinder->Unwind(); + if (unwinder->NumFrames() == 0) { _LOG(log, logtype::THREAD, "Failed to unwind"); - return false; - } - - if (!frames.empty()) { + } else { _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n"); - dump_backtrace(log, frames, " "); + dump_backtrace(log, unwinder, " "); _LOG(log, logtype::STACK, "\nstack:\n"); - dump_stack(log, map, process_memory, frames); + dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get()); } if (primary_thread) { - dump_memory_and_code(log, map, process_memory, thread_info.registers.get()); - if (map) { + unwindstack::Maps* maps = unwinder->GetMaps(); + dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(), + thread_info.registers.get()); + if (maps != nullptr) { uint64_t addr = 0; siginfo_t* si = thread_info.siginfo; if (signal_has_si_addr(si)) { addr = reinterpret_cast<uint64_t>(si->si_addr); } - dump_all_maps(log, map, process_memory, addr); + dump_all_maps(log, unwinder, addr); } } @@ -625,7 +635,8 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>"); read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>"); - std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext)); + std::unique_ptr<unwindstack::Regs> regs( + unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); std::map<pid_t, ThreadInfo> threads; threads[gettid()] = ThreadInfo{ @@ -637,18 +648,16 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si .siginfo = siginfo, }; - std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid(), false)); - if (!backtrace_map) { - ALOGE("failed to create backtrace map"); - _exit(1); + unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid); + if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { + LOG(FATAL) << "Failed to init unwinder object."; } - std::shared_ptr<Memory> process_memory = backtrace_map->GetProcessMemory(); - engrave_tombstone(unique_fd(dup(tombstone_fd)), backtrace_map.get(), process_memory.get(), - threads, tid, abort_msg_address, nullptr, nullptr); + engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address, + nullptr, nullptr); } -void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory, +void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder, const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread, uint64_t abort_msg_address, OpenFilesList* open_files, std::string* amfd_data) { @@ -669,7 +678,7 @@ void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_m if (it == threads.end()) { LOG(FATAL) << "failed to find target thread"; } - dump_thread(&log, map, process_memory, it->second, abort_msg_address, true); + dump_thread(&log, unwinder, it->second, abort_msg_address, true); if (want_logs) { dump_logs(&log, it->second.pid, 50); @@ -680,7 +689,7 @@ void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_m continue; } - dump_thread(&log, map, process_memory, thread_info, 0, false); + dump_thread(&log, unwinder, thread_info, 0, false); } if (open_files) { |