From 94ece83270deca76c69f5755f8c0ff5c859341fd Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Tue, 22 Sep 2015 01:38:17 +0000 Subject: [PATCH] Revert "Revert "Revert "Add BacktraceOffline for offline backtracing.""" This reverts commit 0a411c934a81e5c77a27ef5b69d391038f36e969. Change-Id: Ic1824afac6c32f1087b66de9d6368a561f235d13 --- debuggerd/Android.mk | 1 - include/backtrace/Backtrace.h | 14 - include/backtrace/BacktraceMap.h | 3 - libbacktrace/Android.build.mk | 4 - libbacktrace/Android.mk | 25 - libbacktrace/Backtrace.cpp | 6 - libbacktrace/BacktraceMap.cpp | 10 - libbacktrace/BacktraceOffline.cpp | 636 ------------------------ libbacktrace/BacktraceOffline.h | 105 ---- libbacktrace/backtrace_offline_test.cpp | 189 ------- 10 files changed, 993 deletions(-) delete mode 100644 libbacktrace/BacktraceOffline.cpp delete mode 100644 libbacktrace/BacktraceOffline.h delete mode 100644 libbacktrace/backtrace_offline_test.cpp diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index de0f94334..f7a5f8207 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -99,7 +99,6 @@ debuggerd_c_includes := \ debuggerd_cpp_flags := \ $(common_cppflags) \ -Wno-missing-field-initializers \ - -fno-rtti \ # Only build the host tests on linux. ifeq ($(HOST_OS),linux) diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h index f440bd283..290682a74 100644 --- a/include/backtrace/Backtrace.h +++ b/include/backtrace/Backtrace.h @@ -52,12 +52,6 @@ struct ucontext; typedef ucontext ucontext_t; #endif -struct backtrace_stackinfo_t { - uint64_t start; - uint64_t end; - const uint8_t* data; -}; - class Backtrace { public: // Create the correct Backtrace object based on what is to be unwound. @@ -72,14 +66,6 @@ public: // If map is not NULL, the map is still owned by the caller. static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL); - // Create an offline Backtrace object that can be used to do an unwind without a process - // that is still running. If cache_file is set to true, then elf information will be cached - // for this call. The cached information survives until the calling process ends. This means - // that subsequent calls to create offline Backtrace objects will continue to use the same - // cache. It also assumes that the elf files used for each offline unwind are the same. - static Backtrace* CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map, - const backtrace_stackinfo_t& stack, bool cache_file = false); - virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h index 2373c45e8..bb18aa2e2 100644 --- a/include/backtrace/BacktraceMap.h +++ b/include/backtrace/BacktraceMap.h @@ -31,7 +31,6 @@ #include #include -#include struct backtrace_map_t { uintptr_t start = 0; @@ -49,8 +48,6 @@ public: // is unsupported. static BacktraceMap* Create(pid_t pid, bool uncached = false); - static BacktraceMap* Create(pid_t pid, const std::vector& maps); - virtual ~BacktraceMap(); // Fill in the map data structure for the given address. diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk index 8e63dab57..4983b5530 100644 --- a/libbacktrace/Android.build.mk +++ b/libbacktrace/Android.build.mk @@ -69,10 +69,7 @@ LOCAL_LDLIBS := \ $($(module)_ldlibs) \ $($(module)_ldlibs_$(build_type)) \ -LOCAL_STRIP_MODULE := $($(module)_strip_module) - ifeq ($(build_type),target) - include $(LLVM_DEVICE_BUILD_MK) include $(BUILD_$(build_target)) endif @@ -80,7 +77,6 @@ ifeq ($(build_type),host) # Only build if host builds are supported. ifeq ($(build_host),true) LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer - include $(LLVM_HOST_BUILD_MK) include $(BUILD_HOST_$(build_target)) endif endif diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index 9c6742ecf..395d67700 100644 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -25,7 +25,6 @@ libbacktrace_common_conlyflags := \ libbacktrace_common_cppflags := \ -std=gnu++11 \ - -I external/libunwind/include/tdep \ # The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists. libbacktrace_common_clang_cflags += \ @@ -38,9 +37,6 @@ build_host := true endif endif -LLVM_ROOT_PATH := external/llvm -include $(LLVM_ROOT_PATH)/llvm.mk - #------------------------------------------------------------------------- # The libbacktrace library. #------------------------------------------------------------------------- @@ -48,7 +44,6 @@ libbacktrace_src_files := \ Backtrace.cpp \ BacktraceCurrent.cpp \ BacktraceMap.cpp \ - BacktraceOffline.cpp \ BacktracePtrace.cpp \ thread_utils.c \ ThreadEntry.cpp \ @@ -61,20 +56,6 @@ libbacktrace_shared_libraries := \ liblog \ libunwind \ -# Use shared llvm library on device to save space. -libbacktrace_shared_libraries_target := \ - libLLVM \ - -# Use static llvm libraries on host to remove dependency on 32-bit llvm shared library -# which is not included in the prebuilt. -libbacktrace_static_libraries_host := \ - libLLVMObject \ - libLLVMBitReader \ - libLLVMMC \ - libLLVMMCParser \ - libLLVMCore \ - libLLVMSupport \ - libbacktrace_ldlibs_host := \ -lpthread \ -lrt \ @@ -105,8 +86,6 @@ libbacktrace_test_cflags := \ libbacktrace_test_src_files := \ backtrace_testlib.c \ -libbacktrace_test_strip_module := false - module := libbacktrace_test module_tag := debug build_type := target @@ -128,7 +107,6 @@ backtrace_test_cflags_target := \ -DENABLE_PSS_TESTS \ backtrace_test_src_files := \ - backtrace_offline_test.cpp \ backtrace_test.cpp \ GetPss.cpp \ thread_utils.c \ @@ -142,7 +120,6 @@ backtrace_test_shared_libraries := \ libbacktrace \ libbase \ libcutils \ - libunwind \ backtrace_test_shared_libraries_target += \ libdl \ @@ -150,8 +127,6 @@ backtrace_test_shared_libraries_target += \ backtrace_test_ldlibs_host += \ -ldl \ -backtrace_test_strip_module := false - module := backtrace_test module_tag := debug build_type := target diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp index 9ead452cf..97f0ef445 100644 --- a/libbacktrace/Backtrace.cpp +++ b/libbacktrace/Backtrace.cpp @@ -30,7 +30,6 @@ #include #include "BacktraceLog.h" -#include "BacktraceOffline.h" #include "thread_utils.h" #include "UnwindCurrent.h" #include "UnwindPtrace.h" @@ -141,8 +140,3 @@ Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { return new UnwindPtrace(pid, tid, map); } } - -Backtrace* Backtrace::CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map, - const backtrace_stackinfo_t& stack, bool cache_file) { - return new BacktraceOffline(pid, tid, map, stack, cache_file); -} diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp index eac20fe29..ca47f6781 100644 --- a/libbacktrace/BacktraceMap.cpp +++ b/libbacktrace/BacktraceMap.cpp @@ -144,13 +144,3 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool /*uncached*/) { return map; } #endif - -BacktraceMap* BacktraceMap::Create(pid_t pid, const std::vector& maps) { - BacktraceMap* backtrace_map = new BacktraceMap(pid); - backtrace_map->maps_.insert(backtrace_map->maps_.begin(), maps.begin(), maps.end()); - std::sort(backtrace_map->maps_.begin(), backtrace_map->maps_.end(), - [](const backtrace_map_t& map1, const backtrace_map_t& map2) { - return map1.start < map2.start; - }); - return backtrace_map; -} diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp deleted file mode 100644 index 27dfb8313..000000000 --- a/libbacktrace/BacktraceOffline.cpp +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BacktraceOffline.h" - -extern "C" { -#define UNW_REMOTE_ONLY -#include -} - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-parameter" - -#include -#include -#include -#include - -#pragma clang diagnostic pop - -#include "BacktraceLog.h" - -void Space::Clear() { - start = 0; - end = 0; - data = nullptr; -} - -size_t Space::Read(uint64_t addr, uint8_t* buffer, size_t size) { - if (addr >= start && addr < end) { - size_t read_size = std::min(size, static_cast(end - addr)); - memcpy(buffer, data + (addr - start), read_size); - return read_size; - } - return 0; -} - -static int FindProcInfo(unw_addr_space_t addr_space, unw_word_t ip, unw_proc_info* proc_info, - int need_unwind_info, void* arg) { - BacktraceOffline* backtrace = reinterpret_cast(arg); - bool result = backtrace->FindProcInfo(addr_space, ip, proc_info, need_unwind_info); - return result ? 0 : -UNW_EINVAL; -} - -static void PutUnwindInfo(unw_addr_space_t, unw_proc_info_t*, void*) { -} - -static int GetDynInfoListAddr(unw_addr_space_t, unw_word_t*, void*) { - return -UNW_ENOINFO; -} - -static int AccessMem(unw_addr_space_t, unw_word_t addr, unw_word_t* value, int write, void* arg) { - if (write == 1) { - return -UNW_EINVAL; - } - BacktraceOffline* backtrace = reinterpret_cast(arg); - *value = 0; - size_t read_size = backtrace->Read(addr, reinterpret_cast(value), sizeof(unw_word_t)); - // Strictly we should check if read_size matches sizeof(unw_word_t), but it is possible in - // .eh_frame_hdr that the section can end at a position not aligned in sizeof(unw_word_t), and - // we should permit the read at the end of the section. - return (read_size > 0u ? 0 : -UNW_EINVAL); -} - -static int AccessReg(unw_addr_space_t, unw_regnum_t unwind_reg, unw_word_t* value, int write, - void* arg) { - if (write == 1) { - return -UNW_EINVAL; - } - BacktraceOffline* backtrace = reinterpret_cast(arg); - uint64_t reg_value; - bool result = backtrace->ReadReg(unwind_reg, ®_value); - if (result) { - *value = static_cast(reg_value); - } - return result ? 0 : -UNW_EINVAL; -} - -static int AccessFpReg(unw_addr_space_t, unw_regnum_t, unw_fpreg_t*, int, void*) { - return -UNW_EINVAL; -} - -static int Resume(unw_addr_space_t, unw_cursor_t*, void*) { - return -UNW_EINVAL; -} - -static int GetProcName(unw_addr_space_t, unw_word_t, char*, size_t, unw_word_t*, void*) { - return -UNW_EINVAL; -} - -static unw_accessors_t accessors = { - .find_proc_info = FindProcInfo, - .put_unwind_info = PutUnwindInfo, - .get_dyn_info_list_addr = GetDynInfoListAddr, - .access_mem = AccessMem, - .access_reg = AccessReg, - .access_fpreg = AccessFpReg, - .resume = Resume, - .get_proc_name = GetProcName, -}; - -bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { - if (context == nullptr) { - BACK_LOGW("The context is needed for offline backtracing."); - return false; - } - context_ = context; - - unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0); - unw_cursor_t cursor; - int ret = unw_init_remote(&cursor, addr_space, this); - if (ret != 0) { - BACK_LOGW("unw_init_remote failed %d", ret); - unw_destroy_addr_space(addr_space); - return false; - } - size_t num_frames = 0; - do { - unw_word_t pc; - ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); - if (ret < 0) { - BACK_LOGW("Failed to read IP %d", ret); - break; - } - unw_word_t sp; - ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); - if (ret < 0) { - BACK_LOGW("Failed to read SP %d", ret); - break; - } - - if (num_ignore_frames == 0) { - frames_.resize(num_frames + 1); - backtrace_frame_data_t* frame = &frames_[num_frames]; - frame->num = num_frames; - frame->pc = static_cast(pc); - frame->sp = static_cast(sp); - frame->stack_size = 0; - - if (num_frames > 0) { - backtrace_frame_data_t* prev = &frames_[num_frames - 1]; - prev->stack_size = frame->sp - prev->sp; - } - frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - FillInMap(frame->pc, &frame->map); - num_frames++; - } else { - num_ignore_frames--; - } - ret = unw_step(&cursor); - } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); - - unw_destroy_addr_space(addr_space); - context_ = nullptr; - return true; -} - -bool BacktraceOffline::ReadWord(uintptr_t ptr, word_t* out_value) { - size_t bytes_read = Read(ptr, reinterpret_cast(out_value), sizeof(word_t)); - return bytes_read == sizeof(word_t); -} - -size_t BacktraceOffline::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { - // Normally, libunwind needs stack information and call frame information to do remote unwinding. - // If call frame information is stored in .debug_frame, libunwind can read it from file - // by itself. If call frame information is stored in .eh_frame, we need to provide data in - // .eh_frame/.eh_frame_hdr sections. - // The order of readings below doesn't matter, as the spaces don't overlap with each other. - size_t read_size = eh_frame_hdr_space_.Read(addr, buffer, bytes); - if (read_size != 0) { - return read_size; - } - read_size = eh_frame_space_.Read(addr, buffer, bytes); - if (read_size != 0) { - return read_size; - } - read_size = stack_space_.Read(addr, buffer, bytes); - return read_size; -} - -static bool FileOffsetToVaddr( - const std::vector& program_headers, - uint64_t file_offset, uint64_t* vaddr) { - for (auto& header : program_headers) { - if (file_offset >= header.file_offset && file_offset < header.file_offset + header.file_size) { - // TODO: Consider load_bias? - *vaddr = file_offset - header.file_offset + header.vaddr; - return true; - } - } - return false; -} - -bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, - unw_proc_info_t* proc_info, int need_unwind_info) { - backtrace_map_t map; - FillInMap(ip, &map); - if (!BacktraceMap::IsValid(map)) { - return false; - } - const std::string& filename = map.name; - DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename); - if (debug_frame == nullptr) { - return false; - } - if (debug_frame->is_eh_frame) { - uint64_t ip_offset = ip - map.start + map.offset; - uint64_t ip_vaddr; // vaddr in the elf file. - bool result = FileOffsetToVaddr(debug_frame->eh_frame.program_headers, ip_offset, &ip_vaddr); - if (!result) { - return false; - } - // Calculate the addresses where .eh_frame_hdr and .eh_frame stay when the process was running. - eh_frame_hdr_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_hdr_vaddr; - eh_frame_hdr_space_.end = - eh_frame_hdr_space_.start + debug_frame->eh_frame.eh_frame_hdr_data.size(); - eh_frame_hdr_space_.data = debug_frame->eh_frame.eh_frame_hdr_data.data(); - - eh_frame_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_vaddr; - eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.eh_frame_data.size(); - eh_frame_space_.data = debug_frame->eh_frame.eh_frame_data.data(); - - unw_dyn_info di; - memset(&di, '\0', sizeof(di)); - di.start_ip = map.start; - di.end_ip = map.end; - di.format = UNW_INFO_FORMAT_REMOTE_TABLE; - di.u.rti.name_ptr = 0; - di.u.rti.segbase = eh_frame_hdr_space_.start; - di.u.rti.table_data = - eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr; - di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t); - int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this); - return ret == 0; - } - - eh_frame_hdr_space_.Clear(); - eh_frame_space_.Clear(); - unw_dyn_info_t di; - unw_word_t segbase = map.start - map.offset; - int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end); - if (found == 1) { - int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this); - return ret == 0; - } - return false; -} - -bool BacktraceOffline::ReadReg(size_t reg, uint64_t* value) { - bool result = true; -#if defined(__arm__) - switch (reg) { - case UNW_ARM_R0: - *value = context_->uc_mcontext.arm_r0; - break; - case UNW_ARM_R1: - *value = context_->uc_mcontext.arm_r1; - break; - case UNW_ARM_R2: - *value = context_->uc_mcontext.arm_r2; - break; - case UNW_ARM_R3: - *value = context_->uc_mcontext.arm_r3; - break; - case UNW_ARM_R4: - *value = context_->uc_mcontext.arm_r4; - break; - case UNW_ARM_R5: - *value = context_->uc_mcontext.arm_r5; - break; - case UNW_ARM_R6: - *value = context_->uc_mcontext.arm_r6; - break; - case UNW_ARM_R7: - *value = context_->uc_mcontext.arm_r7; - break; - case UNW_ARM_R8: - *value = context_->uc_mcontext.arm_r8; - break; - case UNW_ARM_R9: - *value = context_->uc_mcontext.arm_r9; - break; - case UNW_ARM_R10: - *value = context_->uc_mcontext.arm_r10; - break; - case UNW_ARM_R11: - *value = context_->uc_mcontext.arm_fp; - break; - case UNW_ARM_R12: - *value = context_->uc_mcontext.arm_ip; - break; - case UNW_ARM_R13: - *value = context_->uc_mcontext.arm_sp; - break; - case UNW_ARM_R14: - *value = context_->uc_mcontext.arm_lr; - break; - case UNW_ARM_R15: - *value = context_->uc_mcontext.arm_pc; - break; - default: - result = false; - } -#elif defined(__aarch64__) - if (reg <= UNW_AARCH64_PC) { - *value = context_->uc_mcontext.regs[reg]; - } else { - result = false; - } -#elif defined(__x86_64__) - switch (reg) { - case UNW_X86_64_R8: - *value = context_->uc_mcontext.gregs[REG_R8]; - break; - case UNW_X86_64_R9: - *value = context_->uc_mcontext.gregs[REG_R9]; - break; - case UNW_X86_64_R10: - *value = context_->uc_mcontext.gregs[REG_R10]; - break; - case UNW_X86_64_R11: - *value = context_->uc_mcontext.gregs[REG_R11]; - break; - case UNW_X86_64_R12: - *value = context_->uc_mcontext.gregs[REG_R12]; - break; - case UNW_X86_64_R13: - *value = context_->uc_mcontext.gregs[REG_R13]; - break; - case UNW_X86_64_R14: - *value = context_->uc_mcontext.gregs[REG_R14]; - break; - case UNW_X86_64_R15: - *value = context_->uc_mcontext.gregs[REG_R15]; - break; - case UNW_X86_64_RDI: - *value = context_->uc_mcontext.gregs[REG_RDI]; - break; - case UNW_X86_64_RSI: - *value = context_->uc_mcontext.gregs[REG_RSI]; - break; - case UNW_X86_64_RBP: - *value = context_->uc_mcontext.gregs[REG_RBP]; - break; - case UNW_X86_64_RBX: - *value = context_->uc_mcontext.gregs[REG_RBX]; - break; - case UNW_X86_64_RDX: - *value = context_->uc_mcontext.gregs[REG_RDX]; - break; - case UNW_X86_64_RAX: - *value = context_->uc_mcontext.gregs[REG_RAX]; - break; - case UNW_X86_64_RCX: - *value = context_->uc_mcontext.gregs[REG_RCX]; - break; - case UNW_X86_64_RSP: - *value = context_->uc_mcontext.gregs[REG_RSP]; - break; - case UNW_X86_64_RIP: - *value = context_->uc_mcontext.gregs[REG_RIP]; - break; - default: - result = false; - } -#elif defined(__i386__) - switch (reg) { - case UNW_X86_GS: - *value = context_->uc_mcontext.gregs[REG_GS]; - break; - case UNW_X86_FS: - *value = context_->uc_mcontext.gregs[REG_FS]; - break; - case UNW_X86_ES: - *value = context_->uc_mcontext.gregs[REG_ES]; - break; - case UNW_X86_DS: - *value = context_->uc_mcontext.gregs[REG_DS]; - break; - case UNW_X86_EAX: - *value = context_->uc_mcontext.gregs[REG_EAX]; - break; - case UNW_X86_EBX: - *value = context_->uc_mcontext.gregs[REG_EBX]; - break; - case UNW_X86_ECX: - *value = context_->uc_mcontext.gregs[REG_ECX]; - break; - case UNW_X86_EDX: - *value = context_->uc_mcontext.gregs[REG_EDX]; - break; - case UNW_X86_ESI: - *value = context_->uc_mcontext.gregs[REG_ESI]; - break; - case UNW_X86_EDI: - *value = context_->uc_mcontext.gregs[REG_EDI]; - break; - case UNW_X86_EBP: - *value = context_->uc_mcontext.gregs[REG_EBP]; - break; - case UNW_X86_EIP: - *value = context_->uc_mcontext.gregs[REG_EIP]; - break; - case UNW_X86_ESP: - *value = context_->uc_mcontext.gregs[REG_ESP]; - break; - case UNW_X86_TRAPNO: - *value = context_->uc_mcontext.gregs[REG_TRAPNO]; - break; - case UNW_X86_CS: - *value = context_->uc_mcontext.gregs[REG_CS]; - break; - case UNW_X86_EFLAGS: - *value = context_->uc_mcontext.gregs[REG_EFL]; - break; - case UNW_X86_SS: - *value = context_->uc_mcontext.gregs[REG_SS]; - break; - default: - result = false; - } -#endif - return result; -} - -std::string BacktraceOffline::GetFunctionNameRaw(uintptr_t, uintptr_t* offset) { - // We don't have enough information to support this. And it is expensive. - *offset = 0; - return ""; -} - -std::unordered_map> BacktraceOffline::debug_frames_; -std::unordered_set BacktraceOffline::debug_frame_missing_files_; - -static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename); - -DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) { - if (cache_file_) { - auto it = debug_frames_.find(filename); - if (it != debug_frames_.end()) { - return it->second.get(); - } - if (debug_frame_missing_files_.find(filename) != debug_frame_missing_files_.end()) { - return nullptr; - } - } - DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename); - if (cache_file_) { - if (debug_frame != nullptr) { - debug_frames_.emplace(filename, std::unique_ptr(debug_frame)); - } else { - debug_frame_missing_files_.insert(filename); - } - } else { - if (last_debug_frame_ != nullptr) { - delete last_debug_frame_; - } - last_debug_frame_ = debug_frame; - } - return debug_frame; -} - -static bool OmitEncodedValue(uint8_t encode, const uint8_t*& p) { - if (encode == DW_EH_PE_omit) { - return 0; - } - uint8_t format = encode & 0x0f; - switch (format) { - case DW_EH_PE_ptr: - p += sizeof(unw_word_t); - break; - case DW_EH_PE_uleb128: - case DW_EH_PE_sleb128: - while ((*p & 0x80) != 0) { - ++p; - } - ++p; - break; - case DW_EH_PE_udata2: - case DW_EH_PE_sdata2: - p += 2; - break; - case DW_EH_PE_udata4: - case DW_EH_PE_sdata4: - p += 4; - break; - case DW_EH_PE_udata8: - case DW_EH_PE_sdata8: - p += 8; - break; - default: - return false; - } - return true; -} - -static bool GetFdeTableOffsetInEhFrameHdr(const std::vector& data, - uint64_t* table_offset_in_eh_frame_hdr) { - const uint8_t* p = data.data(); - const uint8_t* end = p + data.size(); - if (p + 4 > end) { - return false; - } - uint8_t version = *p++; - if (version != 1) { - return false; - } - uint8_t eh_frame_ptr_encode = *p++; - uint8_t fde_count_encode = *p++; - uint8_t fde_table_encode = *p++; - - if (fde_table_encode != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { - return false; - } - - if (!OmitEncodedValue(eh_frame_ptr_encode, p) || !OmitEncodedValue(fde_count_encode, p)) { - return false; - } - if (p >= end) { - return false; - } - *table_offset_in_eh_frame_hdr = p - data.data(); - return true; -} - -using ProgramHeader = DebugFrameInfo::EhFrame::ProgramHeader; - -template -DebugFrameInfo* ReadDebugFrameFromELFFile(const llvm::object::ELFFile* elf) { - bool has_eh_frame_hdr = false; - uint64_t eh_frame_hdr_vaddr = 0; - std::vector eh_frame_hdr_data; - bool has_eh_frame = false; - uint64_t eh_frame_vaddr = 0; - std::vector eh_frame_data; - - for (auto it = elf->begin_sections(); it != elf->end_sections(); ++it) { - llvm::ErrorOr name = elf->getSectionName(&*it); - if (name) { - if (name.get() == ".debug_frame") { - DebugFrameInfo* debug_frame = new DebugFrameInfo; - debug_frame->is_eh_frame = false; - return debug_frame; - } - if (name.get() == ".eh_frame_hdr") { - has_eh_frame_hdr = true; - eh_frame_hdr_vaddr = it->sh_addr; - llvm::ErrorOr> data = elf->getSectionContents(&*it); - if (data) { - eh_frame_hdr_data.insert(eh_frame_hdr_data.begin(), data->data(), - data->data() + data->size()); - } else { - return nullptr; - } - } else if (name.get() == ".eh_frame") { - has_eh_frame = true; - eh_frame_vaddr = it->sh_addr; - llvm::ErrorOr> data = elf->getSectionContents(&*it); - if (data) { - eh_frame_data.insert(eh_frame_data.begin(), data->data(), data->data() + data->size()); - } else { - return nullptr; - } - } - } - } - if (!(has_eh_frame_hdr && has_eh_frame)) { - return nullptr; - } - uint64_t fde_table_offset; - if (!GetFdeTableOffsetInEhFrameHdr(eh_frame_hdr_data, &fde_table_offset)) { - return nullptr; - } - - std::vector program_headers; - for (auto it = elf->begin_program_headers(); it != elf->end_program_headers(); ++it) { - ProgramHeader header; - header.vaddr = it->p_vaddr; - header.file_offset = it->p_offset; - header.file_size = it->p_filesz; - program_headers.push_back(header); - } - DebugFrameInfo* debug_frame = new DebugFrameInfo; - debug_frame->is_eh_frame = true; - debug_frame->eh_frame.eh_frame_hdr_vaddr = eh_frame_hdr_vaddr; - debug_frame->eh_frame.eh_frame_vaddr = eh_frame_vaddr; - debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr = fde_table_offset; - debug_frame->eh_frame.eh_frame_hdr_data = std::move(eh_frame_hdr_data); - debug_frame->eh_frame.eh_frame_data = std::move(eh_frame_data); - debug_frame->eh_frame.program_headers = program_headers; - return debug_frame; -} - -static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) { - auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename)); - if (owning_binary.getError()) { - return nullptr; - } - llvm::object::Binary* binary = owning_binary.get().getBinary(); - auto obj = llvm::dyn_cast(binary); - if (obj == nullptr) { - return nullptr; - } - if (auto elf = llvm::dyn_cast(obj)) { - return ReadDebugFrameFromELFFile(elf->getELFFile()); - } - if (auto elf = llvm::dyn_cast(obj)) { - return ReadDebugFrameFromELFFile(elf->getELFFile()); - } - return nullptr; -} diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h deleted file mode 100644 index 42f826da9..000000000 --- a/libbacktrace/BacktraceOffline.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _LIBBACKTRACE_UNWIND_OFFLINE_H -#define _LIBBACKTRACE_UNWIND_OFFLINE_H - -#include -#include -#include -#include - -#include -#include - -#include - -struct Space { - uint64_t start; - uint64_t end; - const uint8_t* data; - - Space() { - Clear(); - } - - void Clear(); - size_t Read(uint64_t addr, uint8_t* buffer, size_t size); -}; - -struct DebugFrameInfo { - bool is_eh_frame; - struct EhFrame { - uint64_t eh_frame_hdr_vaddr; - uint64_t eh_frame_vaddr; - uint64_t fde_table_offset_in_eh_frame_hdr; - std::vector eh_frame_hdr_data; - std::vector eh_frame_data; - struct ProgramHeader { - uint64_t vaddr; - uint64_t file_offset; - uint64_t file_size; - }; - std::vector program_headers; - } eh_frame; -}; - -class BacktraceOffline : public Backtrace { - public: - BacktraceOffline(pid_t pid, pid_t tid, BacktraceMap* map, const backtrace_stackinfo_t& stack, - bool cache_file) - : Backtrace(pid, tid, map), - cache_file_(cache_file), - context_(nullptr), - last_debug_frame_(nullptr) { - stack_space_.start = stack.start; - stack_space_.end = stack.end; - stack_space_.data = stack.data; - } - - virtual ~BacktraceOffline() { - if (last_debug_frame_ != nullptr) { - delete last_debug_frame_; - } - } - - bool Unwind(size_t num_ignore_frames, ucontext_t* context) override; - - bool ReadWord(uintptr_t ptr, word_t* out_value) override; - - size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override; - - bool FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info, - int need_unwind_info); - - bool ReadReg(size_t reg_index, uint64_t* value); - - protected: - std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; - DebugFrameInfo* GetDebugFrameInFile(const std::string& filename); - - static std::unordered_map> debug_frames_; - static std::unordered_set debug_frame_missing_files_; - - bool cache_file_; - ucontext_t* context_; - Space eh_frame_hdr_space_; - Space eh_frame_space_; - Space stack_space_; - DebugFrameInfo* last_debug_frame_; -}; - -#endif // _LIBBACKTRACE_BACKTRACE_OFFLINE_H diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp deleted file mode 100644 index 88a3533a2..000000000 --- a/libbacktrace/backtrace_offline_test.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -extern "C" { -// Prototypes for functions in the test library. -int test_level_one(int, int, int, int, void (*)(void*), void*); -int test_level_two(int, int, int, int, void (*)(void*), void*); -int test_level_three(int, int, int, int, void (*)(void*), void*); -int test_level_four(int, int, int, int, void (*)(void*), void*); -int test_recursive_call(int, void (*)(void*), void*); -} - -static volatile bool g_exit_flag = false; - -static void GetContextAndExit(void* arg) { - unw_context_t* unw_context = reinterpret_cast(arg); - unw_getcontext(unw_context); - // Don't touch the stack anymore. - while (!g_exit_flag) { - } -} - -struct OfflineThreadArg { - unw_context_t unw_context; - pid_t tid; - std::function function; -}; - -static void* OfflineThreadFunc(void* arg) { - OfflineThreadArg* fn_arg = reinterpret_cast(arg); - fn_arg->tid = gettid(); - fn_arg->function(GetContextAndExit, &fn_arg->unw_context); - return nullptr; -} - -static ucontext_t GetUContextFromUnwContext(const unw_context_t& unw_context) { - ucontext_t ucontext; - memset(&ucontext, 0, sizeof(ucontext)); -#if defined(__arm__) - ucontext.uc_mcontext.arm_r0 = unw_context.regs[0]; - ucontext.uc_mcontext.arm_r1 = unw_context.regs[1]; - ucontext.uc_mcontext.arm_r2 = unw_context.regs[2]; - ucontext.uc_mcontext.arm_r3 = unw_context.regs[3]; - ucontext.uc_mcontext.arm_r4 = unw_context.regs[4]; - ucontext.uc_mcontext.arm_r5 = unw_context.regs[5]; - ucontext.uc_mcontext.arm_r6 = unw_context.regs[6]; - ucontext.uc_mcontext.arm_r7 = unw_context.regs[7]; - ucontext.uc_mcontext.arm_r8 = unw_context.regs[8]; - ucontext.uc_mcontext.arm_r9 = unw_context.regs[9]; - ucontext.uc_mcontext.arm_r10 = unw_context.regs[10]; - ucontext.uc_mcontext.arm_fp = unw_context.regs[11]; - ucontext.uc_mcontext.arm_ip = unw_context.regs[12]; - ucontext.uc_mcontext.arm_sp = unw_context.regs[13]; - ucontext.uc_mcontext.arm_lr = unw_context.regs[14]; - ucontext.uc_mcontext.arm_pc = unw_context.regs[15]; -#else - ucontext.uc_mcontext = unw_context.uc_mcontext; -#endif - return ucontext; -} - -static void OfflineBacktraceFunctionCall(std::function function, - std::vector* pc_values) { - // Create a thread to generate the needed stack and registers information. - g_exit_flag = false; - const size_t stack_size = 1024 * 1024; - void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - ASSERT_NE(MAP_FAILED, stack); - uintptr_t stack_addr = reinterpret_cast(stack); - pthread_attr_t attr; - ASSERT_EQ(0, pthread_attr_init(&attr)); - ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast(stack), stack_size)); - pthread_t thread; - OfflineThreadArg arg; - arg.function = function; - ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg)); - // Wait for the offline thread to generate the stack and unw_context information. - sleep(1); - // Copy the stack information. - std::vector stack_data(reinterpret_cast(stack), - reinterpret_cast(stack) + stack_size); - g_exit_flag = true; - ASSERT_EQ(0, pthread_join(thread, nullptr)); - ASSERT_EQ(0, munmap(stack, stack_size)); - - // Do offline backtrace. - std::unique_ptr map(BacktraceMap::Create(getpid())); - ASSERT_TRUE(map != nullptr); - - backtrace_stackinfo_t stack_info; - stack_info.start = stack_addr; - stack_info.end = stack_addr + stack_size; - stack_info.data = stack_data.data(); - - std::unique_ptr backtrace( - Backtrace::CreateOffline(getpid(), arg.tid, map.get(), stack_info)); - ASSERT_TRUE(backtrace != nullptr); - - ucontext_t ucontext = GetUContextFromUnwContext(arg.unw_context); - ASSERT_TRUE(backtrace->Unwind(0, &ucontext)); - - // Collect pc values of the call stack frames. - for (size_t i = 0; i < backtrace->NumFrames(); ++i) { - pc_values->push_back(backtrace->GetFrame(i)->pc); - } -} - -// Return the name of the function which matches the address. Although we don't know the -// exact end of each function, it is accurate enough for the tests. -static std::string FunctionNameForAddress(uintptr_t addr) { - struct FunctionSymbol { - std::string name; - uintptr_t start; - uintptr_t end; - }; - - static std::vector symbols; - if (symbols.empty()) { - symbols = std::vector{ - {"unknown_start", 0, 0}, - {"test_level_one", reinterpret_cast(&test_level_one), 0}, - {"test_level_two", reinterpret_cast(&test_level_two), 0}, - {"test_level_three", reinterpret_cast(&test_level_three), 0}, - {"test_level_four", reinterpret_cast(&test_level_four), 0}, - {"test_recursive_call", reinterpret_cast(&test_recursive_call), 0}, - {"GetContextAndExit", reinterpret_cast(&GetContextAndExit), 0}, - {"unknown_end", static_cast(-1), static_cast(-1)}, - }; - std::sort( - symbols.begin(), symbols.end(), - [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; }); - for (size_t i = 0; i + 1 < symbols.size(); ++i) { - symbols[i].end = symbols[i + 1].start; - } - } - for (auto& symbol : symbols) { - if (addr >= symbol.start && addr < symbol.end) { - return symbol.name; - } - } - return ""; -} - -TEST(libbacktrace, offline) { - std::function function = - std::bind(test_level_one, 1, 2, 3, 4, std::placeholders::_1, std::placeholders::_2); - std::vector pc_values; - OfflineBacktraceFunctionCall(function, &pc_values); - ASSERT_FALSE(pc_values.empty()); - ASSERT_LE(pc_values.size(), static_cast(MAX_BACKTRACE_FRAMES)); - - size_t test_one_index = 0; - for (size_t i = 0; i < pc_values.size(); ++i) { - if (FunctionNameForAddress(pc_values[i]) == "test_level_one") { - test_one_index = i; - break; - } - } - - ASSERT_GE(test_one_index, 3u); - ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index])); - ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1])); - ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2])); - ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3])); -} - -TEST(libbacktrace, offline_max_trace) { - std::function function = std::bind( - test_recursive_call, MAX_BACKTRACE_FRAMES + 10, std::placeholders::_1, std::placeholders::_2); - std::vector pc_values; - OfflineBacktraceFunctionCall(function, &pc_values); - ASSERT_FALSE(pc_values.empty()); - ASSERT_EQ(static_cast(MAX_BACKTRACE_FRAMES), pc_values.size()); - ASSERT_EQ("test_recursive_call", FunctionNameForAddress(pc_values.back())); -}