diff options
-rw-r--r-- | debuggerd/Android.bp | 6 | ||||
-rw-r--r-- | debuggerd/crash_dump.cpp | 31 | ||||
-rw-r--r-- | debuggerd/handler/debuggerd_fallback.cpp | 19 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/backtrace.cpp | 20 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/elf_utils.cpp | 121 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h | 10 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h | 29 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h | 19 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/BacktraceMock.h | 32 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/UnwinderMock.h | 40 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/tombstone_test.cpp | 722 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/tombstone.cpp | 221 |
12 files changed, 729 insertions, 541 deletions
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 10f52f45f..4a53a3305 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -114,7 +114,6 @@ cc_library_static { "libasync_safe", "libbase", "libdebuggerd", - "libbacktrace", "libunwindstack", "libdexfile", // libunwindstack dependency "libdexfile_external", // libunwindstack dependency @@ -124,7 +123,6 @@ cc_library_static { ], target: { recovery: { - cflags: ["-DNO_LIBDEXFILE_SUPPORT"], exclude_static_libs: [ "libartbase", "libdexfile", @@ -164,7 +162,6 @@ cc_library_static { srcs: [ "libdebuggerd/backtrace.cpp", - "libdebuggerd/elf_utils.cpp", "libdebuggerd/open_files_list.cpp", "libdebuggerd/tombstone.cpp", "libdebuggerd/utility.cpp", @@ -177,7 +174,6 @@ cc_library_static { include_dirs: ["bionic/libc"], static_libs: [ - "libbacktrace", "libdexfile_external", // libunwindstack dependency "libdexfile_support", // libunwindstack dependency "libunwindstack", @@ -223,7 +219,6 @@ cc_test { }, shared_libs: [ - "libbacktrace", "libbase", "libcutils", "libdebuggerd_client", @@ -291,7 +286,6 @@ cc_binary { ], shared_libs: [ - "libbacktrace", "libbase", "liblog", "libprocinfo", diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index d79d20b8a..82ba0a18e 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -48,7 +48,12 @@ #define ATRACE_TAG ATRACE_TAG_BIONIC #include <utils/Trace.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> #include "libdebuggerd/backtrace.h" #include "libdebuggerd/tombstone.h" @@ -63,8 +68,6 @@ using android::base::unique_fd; using android::base::StringPrintf; -using unwindstack::Regs; - static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { struct stat st; std::string task_path = StringPrintf("task/%d", tid); @@ -287,7 +290,8 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, case 1: *abort_msg_address = crash_info->data.v1.abort_msg_address; *siginfo = crash_info->data.v1.siginfo; - regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->data.v1.ucontext)); + regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), + &crash_info->data.v1.ucontext)); break; default: @@ -469,7 +473,7 @@ int main(int argc, char** argv) { info.siginfo = &siginfo; info.signo = info.siginfo->si_signo; } else { - info.registers.reset(Regs::RemoteGet(thread)); + info.registers.reset(unwindstack::Regs::RemoteGet(thread)); if (!info.registers) { PLOG(WARNING) << "failed to fetch registers for thread " << thread; ptrace(PTRACE_DETACH, thread, 0, 0); @@ -562,30 +566,25 @@ int main(int argc, char** argv) { } // TODO: Use seccomp to lock ourselves down. - std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(vm_pid, false)); - if (!map) { - LOG(FATAL) << "failed to create backtrace map"; - } - - std::shared_ptr<unwindstack::Memory> process_memory = map->GetProcessMemory(); - if (!process_memory) { - LOG(FATAL) << "failed to get unwindstack::Memory handle"; + unwindstack::UnwinderFromPid unwinder(256, vm_pid); + if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { + LOG(FATAL) << "Failed to init unwinder object."; } std::string amfd_data; if (backtrace) { ATRACE_NAME("dump_backtrace"); - dump_backtrace(std::move(g_output_fd), map.get(), thread_info, g_target_thread); + dump_backtrace(std::move(g_output_fd), &unwinder, thread_info, g_target_thread); } else { { ATRACE_NAME("fdsan table dump"); - populate_fdsan_table(&open_files, process_memory, fdsan_table_address); + populate_fdsan_table(&open_files, unwinder.GetProcessMemory(), fdsan_table_address); } { ATRACE_NAME("engrave_tombstone"); - engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info, - g_target_thread, abort_msg_address, &open_files, &amfd_data); + engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread, + abort_msg_address, &open_files, &amfd_data); } } diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp index 15c02651c..bbec612a8 100644 --- a/debuggerd/handler/debuggerd_fallback.cpp +++ b/debuggerd/handler/debuggerd_fallback.cpp @@ -42,9 +42,12 @@ #include <android-base/file.h> #include <android-base/unique_fd.h> #include <async_safe/log.h> -#include <backtrace/BacktraceMap.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> #include "debuggerd/handler.h" #include "handler/fallback.h" @@ -55,7 +58,6 @@ #include "libdebuggerd/tombstone.h" using android::base::unique_fd; -using unwindstack::Regs; extern "C" bool __linker_enable_fallback_allocator(); extern "C" void __linker_disable_fallback_allocator(); @@ -73,17 +75,22 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) { } { - std::unique_ptr<Regs> regs; + std::unique_ptr<unwindstack::Regs> regs; ThreadInfo thread; thread.pid = getpid(); thread.tid = gettid(); thread.thread_name = get_thread_name(gettid()); - thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext)); + unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch(); + thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext)); // TODO: Create this once and store it in a global? - std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid())); - dump_backtrace_thread(output_fd, map.get(), thread); + unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid()); + if (unwinder.Init(arch)) { + dump_backtrace_thread(output_fd, &unwinder, thread); + } else { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder."); + } } __linker_disable_fallback_allocator(); } diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp index f0a01f41c..753ebcb7c 100644 --- a/debuggerd/libdebuggerd/backtrace.cpp +++ b/debuggerd/libdebuggerd/backtrace.cpp @@ -35,8 +35,8 @@ #include <string> #include <android-base/unique_fd.h> -#include <backtrace/Backtrace.h> #include <log/log.h> +#include <unwindstack/Unwinder.h> #include "libdebuggerd/types.h" #include "libdebuggerd/utility.h" @@ -59,25 +59,27 @@ static void dump_process_footer(log_t* log, pid_t pid) { _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid); } -void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread) { +void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder, + const ThreadInfo& thread) { log_t log; log.tfd = output_fd; log.amfd_data = nullptr; _LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid); - std::vector<backtrace_frame_data_t> frames; - if (!Backtrace::Unwind(thread.registers.get(), map, &frames, 0, nullptr)) { + unwinder->SetRegs(thread.registers.get()); + unwinder->Unwind(); + if (unwinder->NumFrames() == 0) { _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid); return; } - for (auto& frame : frames) { - _LOG(&log, logtype::BACKTRACE, " %s\n", Backtrace::FormatFrameData(&frame).c_str()); + for (size_t i = 0; i < unwinder->NumFrames(); i++) { + _LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str()); } } -void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map, +void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder, const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) { log_t log; log.tfd = output_fd.get(); @@ -91,10 +93,10 @@ void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map, dump_process_header(&log, target->second.pid, target->second.process_name.c_str()); - dump_backtrace_thread(output_fd.get(), map, target->second); + dump_backtrace_thread(output_fd.get(), unwinder, target->second); for (const auto& [tid, info] : thread_info) { if (tid != target_thread) { - dump_backtrace_thread(output_fd.get(), map, info); + dump_backtrace_thread(output_fd.get(), unwinder, info); } } diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp deleted file mode 100644 index d7afc0b49..000000000 --- a/debuggerd/libdebuggerd/elf_utils.cpp +++ /dev/null @@ -1,121 +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. - */ - -#define LOG_TAG "DEBUG" - -#include "libdebuggerd/elf_utils.h" - -#include <elf.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include <string> - -#include <android-base/stringprintf.h> -#include <log/log.h> -#include <unwindstack/Memory.h> - -#define NOTE_ALIGN(size) (((size) + 3) & ~3) - -template <typename HdrType, typename PhdrType, typename NhdrType> -static bool get_build_id(unwindstack::Memory* memory, uintptr_t base_addr, uint8_t* e_ident, - std::string* build_id) { - HdrType hdr; - - memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT); - - // First read the rest of the header. - if (memory->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT, - sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) { - return false; - } - - for (size_t i = 0; i < hdr.e_phnum; i++) { - PhdrType phdr; - if (memory->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize, - reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) { - return false; - } - // Looking for the .note.gnu.build-id note. - if (phdr.p_type == PT_NOTE) { - size_t hdr_size = phdr.p_filesz; - uintptr_t addr = base_addr + phdr.p_offset; - while (hdr_size >= sizeof(NhdrType)) { - NhdrType nhdr; - if (memory->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) { - return false; - } - addr += sizeof(nhdr); - if (nhdr.n_type == NT_GNU_BUILD_ID) { - // Skip the name (which is the owner and should be "GNU"). - addr += NOTE_ALIGN(nhdr.n_namesz); - uint8_t build_id_data[160]; - if (nhdr.n_descsz > sizeof(build_id_data)) { - ALOGE("Possible corrupted note, desc size value is too large: %u", - nhdr.n_descsz); - return false; - } - if (memory->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) { - return false; - } - - build_id->clear(); - for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) { - *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]); - } - - return true; - } else { - // Move past the extra note data. - hdr_size -= sizeof(nhdr); - size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz); - addr += skip_bytes; - if (hdr_size < skip_bytes) { - break; - } - hdr_size -= skip_bytes; - } - } - } - } - return false; -} - -bool elf_get_build_id(unwindstack::Memory* memory, uintptr_t addr, std::string* build_id) { - // Read and verify the elf magic number first. - uint8_t e_ident[EI_NIDENT]; - if (memory->Read(addr, e_ident, SELFMAG) != SELFMAG) { - return false; - } - - if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { - return false; - } - - // Read the rest of EI_NIDENT. - if (memory->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) { - return false; - } - - if (e_ident[EI_CLASS] == ELFCLASS32) { - return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(memory, addr, e_ident, build_id); - } else if (e_ident[EI_CLASS] == ELFCLASS64) { - return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(memory, addr, e_ident, build_id); - } - - return false; -} diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h index 119e59b47..c20d09035 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h @@ -28,15 +28,19 @@ #include "types.h" #include "utility.h" -class BacktraceMap; +// Forward delcaration +namespace unwindstack { +class Unwinder; +} // Dumps a backtrace using a format similar to what Dalvik uses so that the result // can be intermixed in a bug report. -void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map, +void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder, const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread); void dump_backtrace_header(int output_fd); -void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread); +void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder, + const ThreadInfo& thread); void dump_backtrace_footer(int output_fd); #endif // _DEBUGGERD_BACKTRACE_H diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h deleted file mode 100644 index 5d0d92495..000000000 --- a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h +++ /dev/null @@ -1,29 +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 _DEBUGGERD_ELF_UTILS_H -#define _DEBUGGERD_ELF_UTILS_H - -#include <stdint.h> -#include <string> - -namespace unwindstack { -class Memory; -} - -bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string*); - -#endif // _DEBUGGERD_ELF_UTILS_H diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h index be90d0f0b..7133f778d 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h @@ -29,7 +29,13 @@ #include "open_files_list.h" #include "types.h" -class BacktraceMap; +// Forward declarations +namespace unwindstack { +class Unwinder; +} + +// The maximum number of frames to save when unwinding. +constexpr size_t kMaxFrames = 256; /* Create and open a tombstone file for writing. * Returns a writable file descriptor, or -1 with errno set appropriately. @@ -38,16 +44,15 @@ class BacktraceMap; int open_tombstone(std::string* path); /* Creates a tombstone file and writes the crash dump to it. */ -void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files, - pid_t pid, pid_t tid, const std::string& process_name, - const std::map<pid_t, std::string>& threads, uint64_t abort_msg_address, - std::string* amfd_data); +void engrave_tombstone(int tombstone_fd, unwindstack::Unwinder* unwinder, + const OpenFilesList* open_files, pid_t pid, pid_t tid, + const std::string& process_name, const std::map<pid_t, std::string>& threads, + uint64_t abort_msg_address, std::string* amfd_data); void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo, ucontext_t* ucontext); -void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map, - unwindstack::Memory* process_memory, +void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder, const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread, uint64_t abort_msg_address, OpenFilesList* open_files, std::string* amfd_data); diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h deleted file mode 100644 index e7dbed764..000000000 --- a/debuggerd/libdebuggerd/test/BacktraceMock.h +++ /dev/null @@ -1,32 +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 _DEBUGGERD_TEST_BACKTRACE_MOCK_H -#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H - -#include <backtrace/BacktraceMap.h> - -class BacktraceMapMock : public BacktraceMap { - public: - BacktraceMapMock() : BacktraceMap(0) {} - virtual ~BacktraceMapMock() {} - - void AddMap(backtrace_map_t& map) { - maps_.push_back(map); - } -}; - -#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H diff --git a/debuggerd/libdebuggerd/test/UnwinderMock.h b/debuggerd/libdebuggerd/test/UnwinderMock.h new file mode 100644 index 000000000..023a57807 --- /dev/null +++ b/debuggerd/libdebuggerd/test/UnwinderMock.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#pragma once + +#include <unwindstack/MapInfo.h> +#include <unwindstack/Maps.h> +#include <unwindstack/Unwinder.h> + +class UnwinderMock : public unwindstack::Unwinder { + public: + UnwinderMock() : Unwinder(128, new unwindstack::Maps, nullptr) {} + virtual ~UnwinderMock() { delete GetMaps(); } + + void MockAddMap(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, std::string name, + uint64_t load_bias) { + GetMaps()->Add(start, end, offset, flags, name, load_bias); + } + + void MockSetBuildID(uint64_t offset, const std::string& build_id) { + unwindstack::MapInfo* map_info = GetMaps()->Find(offset); + if (map_info != nullptr) { + std::string* new_build_id = new std::string(build_id); + map_info->build_id = reinterpret_cast<uintptr_t>(new_build_id); + } + } +}; diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp index d24c88731..eed5bd30f 100644 --- a/debuggerd/libdebuggerd/test/tombstone_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp @@ -26,26 +26,16 @@ #include "libdebuggerd/utility.h" -#include "BacktraceMock.h" -#include "elf_fake.h" +#include "UnwinderMock.h" #include "host_signal_fixup.h" #include "log_fake.h" #include "tombstone.cpp" -void dump_registers(log_t*, pid_t) { -} - -void dump_memory_and_code(log_t*, Backtrace*) { -} - -void dump_backtrace_to_log(Backtrace*, log_t*, char const*) { -} - class TombstoneTest : public ::testing::Test { protected: virtual void SetUp() { - map_mock_.reset(new BacktraceMapMock()); + unwinder_mock_.reset(new UnwinderMock()); char tmp_file[256]; const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX"; @@ -71,7 +61,6 @@ class TombstoneTest : public ::testing::Test { log_.should_retrieve_logcat = false; resetLogs(); - elf_set_fake_build_id(""); } virtual void TearDown() { @@ -80,24 +69,20 @@ class TombstoneTest : public ::testing::Test { } } - std::unique_ptr<BacktraceMapMock> map_mock_; + std::unique_ptr<UnwinderMock> unwinder_mock_; log_t log_; std::string amfd_data_; }; TEST_F(TombstoneTest, single_map) { - backtrace_map_t map; #if defined(__LP64__) - map.start = 0x123456789abcd000UL; - map.end = 0x123456789abdf000UL; + unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0); #else - map.start = 0x1234000; - map.end = 0x1235000; + unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0); #endif - map_mock_->AddMap(map); - dump_all_maps(&log_, map_mock_.get(), nullptr, 0); + dump_all_maps(&log_, unwinder_mock_.get(), 0); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -119,20 +104,25 @@ TEST_F(TombstoneTest, single_map) { } TEST_F(TombstoneTest, single_map_elf_build_id) { - backtrace_map_t map; + uint64_t build_id_offset; #if defined(__LP64__) - map.start = 0x123456789abcd000UL; - map.end = 0x123456789abdf000UL; + build_id_offset = 0x123456789abcd000UL; + unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ, + "/system/lib/libfake.so", 0); #else - map.start = 0x1234000; - map.end = 0x1235000; + build_id_offset = 0x1234000; + unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0); #endif - map.flags = PROT_READ; - map.name = "/system/lib/libfake.so"; - map_mock_->AddMap(map); - elf_set_fake_build_id("abcdef1234567890abcdef1234567890"); - dump_all_maps(&log_, map_mock_.get(), nullptr, 0); + unwinder_mock_->MockSetBuildID( + build_id_offset, + std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef), + static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56), + static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab), + static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12), + static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78), + static_cast<char>(0x90)}); + dump_all_maps(&log_, unwinder_mock_.get(), 0); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -153,83 +143,15 @@ TEST_F(TombstoneTest, single_map_elf_build_id) { ASSERT_STREQ("", getFakeLogPrint().c_str()); } -// Even though build id is present, it should not be printed in either of -// these cases. -TEST_F(TombstoneTest, single_map_no_build_id) { - backtrace_map_t map; -#if defined(__LP64__) - map.start = 0x123456789abcd000UL; - map.end = 0x123456789abdf000UL; -#else - map.start = 0x1234000; - map.end = 0x1235000; -#endif - map.flags = PROT_WRITE; - map_mock_->AddMap(map); - - map.name = "/system/lib/libfake.so"; - map_mock_->AddMap(map); - - elf_set_fake_build_id("abcdef1234567890abcdef1234567890"); - dump_all_maps(&log_, map_mock_.get(), nullptr, 0); - - std::string tombstone_contents; - ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); - ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory map (2 entries):\n" -#if defined(__LP64__) -" 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n" -" 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n"; -#else -" 01234000-01234fff -w- 0 1000\n" -" 01234000-01234fff -w- 0 1000 /system/lib/libfake.so\n"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); - - ASSERT_STREQ("", amfd_data_.c_str()); - - // Verify that the log buf is empty, and no error messages. - ASSERT_STREQ("", getFakeLogBuf().c_str()); - ASSERT_STREQ("", getFakeLogPrint().c_str()); -} - TEST_F(TombstoneTest, multiple_maps) { - backtrace_map_t map; - - map.start = 0xa234000; - map.end = 0xa235000; - map_mock_->AddMap(map); - - map.start = 0xa334000; - map.end = 0xa335000; - map.offset = 0xf000; - map.flags = PROT_READ; - map_mock_->AddMap(map); - - map.start = 0xa434000; - map.end = 0xa435000; - map.offset = 0x1000; - map.load_bias = 0xd000; - map.flags = PROT_WRITE; - map_mock_->AddMap(map); - - map.start = 0xa534000; - map.end = 0xa535000; - map.offset = 0x3000; - map.load_bias = 0x2000; - map.flags = PROT_EXEC; - map_mock_->AddMap(map); - - map.start = 0xa634000; - map.end = 0xa635000; - map.offset = 0; - map.load_bias = 0; - map.flags = PROT_READ | PROT_WRITE | PROT_EXEC; - map.name = "/system/lib/fake.so"; - map_mock_->AddMap(map); - - dump_all_maps(&log_, map_mock_.get(), nullptr, 0); + unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0); + unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0); + unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000); + unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000); + unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/system/lib/fake.so", 0); + + dump_all_maps(&log_, unwinder_mock_.get(), 0); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -259,31 +181,12 @@ TEST_F(TombstoneTest, multiple_maps) { } TEST_F(TombstoneTest, multiple_maps_fault_address_before) { - backtrace_map_t map; - - map.start = 0xa434000; - map.end = 0xa435000; - map.offset = 0x1000; - map.load_bias = 0xd000; - map.flags = PROT_WRITE; - map_mock_->AddMap(map); - - map.start = 0xa534000; - map.end = 0xa535000; - map.offset = 0x3000; - map.load_bias = 0x2000; - map.flags = PROT_EXEC; - map_mock_->AddMap(map); - - map.start = 0xa634000; - map.end = 0xa635000; - map.offset = 0; - map.load_bias = 0; - map.flags = PROT_READ | PROT_WRITE | PROT_EXEC; - map.name = "/system/lib/fake.so"; - map_mock_->AddMap(map); - - dump_all_maps(&log_, map_mock_.get(), nullptr, 0x1000); + unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000); + unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000); + unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/system/lib/fake.so", 0); + + dump_all_maps(&log_, unwinder_mock_.get(), 0x1000); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -311,31 +214,12 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_before) { } TEST_F(TombstoneTest, multiple_maps_fault_address_between) { - backtrace_map_t map; - - map.start = 0xa434000; - map.end = 0xa435000; - map.offset = 0x1000; - map.load_bias = 0xd000; - map.flags = PROT_WRITE; - map_mock_->AddMap(map); - - map.start = 0xa534000; - map.end = 0xa535000; - map.offset = 0x3000; - map.load_bias = 0x2000; - map.flags = PROT_EXEC; - map_mock_->AddMap(map); - - map.start = 0xa634000; - map.end = 0xa635000; - map.offset = 0; - map.load_bias = 0; - map.flags = PROT_READ | PROT_WRITE | PROT_EXEC; - map.name = "/system/lib/fake.so"; - map_mock_->AddMap(map); - - dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa533000); + unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000); + unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000); + unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/system/lib/fake.so", 0); + + dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -363,31 +247,12 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_between) { } TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) { - backtrace_map_t map; - - map.start = 0xa434000; - map.end = 0xa435000; - map.offset = 0x1000; - map.load_bias = 0xd000; - map.flags = PROT_WRITE; - map_mock_->AddMap(map); - - map.start = 0xa534000; - map.end = 0xa535000; - map.offset = 0x3000; - map.load_bias = 0x2000; - map.flags = PROT_EXEC; - map_mock_->AddMap(map); - - map.start = 0xa634000; - map.end = 0xa635000; - map.offset = 0; - map.load_bias = 0; - map.flags = PROT_READ | PROT_WRITE | PROT_EXEC; - map.name = "/system/lib/fake.so"; - map_mock_->AddMap(map); - - dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa534040); + unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000); + unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000); + unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/system/lib/fake.so", 0); + + dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -413,36 +278,17 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) { } TEST_F(TombstoneTest, multiple_maps_fault_address_after) { - backtrace_map_t map; - - map.start = 0xa434000; - map.end = 0xa435000; - map.offset = 0x1000; - map.load_bias = 0xd000; - map.flags = PROT_WRITE; - map_mock_->AddMap(map); - - map.start = 0xa534000; - map.end = 0xa535000; - map.offset = 0x3000; - map.load_bias = 0x2000; - map.flags = PROT_EXEC; - map_mock_->AddMap(map); - - map.start = 0xa634000; - map.end = 0xa635000; - map.offset = 0; - map.load_bias = 0; - map.flags = PROT_READ | PROT_WRITE | PROT_EXEC; - map.name = "/system/lib/fake.so"; - map_mock_->AddMap(map); + unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000); + unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000); + unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/system/lib/fake.so", 0); #if defined(__LP64__) uint64_t addr = 0x12345a534040UL; #else uint64_t addr = 0xf534040UL; #endif - dump_all_maps(&log_, map_mock_.get(), nullptr, addr); + dump_all_maps(&log_, unwinder_mock_.get(), addr); std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); @@ -502,3 +348,467 @@ TEST_F(TombstoneTest, dump_timestamp) { dump_timestamp(&log_, 0); ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str()); } + +class MemoryPattern : public unwindstack::Memory { + public: + MemoryPattern() = default; + virtual ~MemoryPattern() = default; + + size_t Read(uint64_t, void* dst, size_t size) override { + uint8_t* data = reinterpret_cast<uint8_t*>(dst); + for (size_t i = 0; i < size; i++) { + data[i] = (i % 0xff); + } + return size; + } +}; + +TEST_F(TombstoneTest, dump_stack_single_frame) { + std::vector<unwindstack::FrameData> frames; + unwindstack::Maps maps; + MemoryPattern memory; + + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000}); + dump_stack(&log_, frames, &maps, &memory); + + std::string contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents)); + + std::string expected = +#if defined(__LP64__) + " 0000000000001f80 0706050403020100\n" + " 0000000000001f88 0f0e0d0c0b0a0908\n" + " 0000000000001f90 1716151413121110\n" + " 0000000000001f98 1f1e1d1c1b1a1918\n" + " 0000000000001fa0 2726252423222120\n" + " 0000000000001fa8 2f2e2d2c2b2a2928\n" + " 0000000000001fb0 3736353433323130\n" + " 0000000000001fb8 3f3e3d3c3b3a3938\n" + " 0000000000001fc0 4746454443424140\n" + " 0000000000001fc8 4f4e4d4c4b4a4948\n" + " 0000000000001fd0 5756555453525150\n" + " 0000000000001fd8 5f5e5d5c5b5a5958\n" + " 0000000000001fe0 6766656463626160\n" + " 0000000000001fe8 6f6e6d6c6b6a6968\n" + " 0000000000001ff0 7776757473727170\n" + " 0000000000001ff8 7f7e7d7c7b7a7978\n" + " #00 0000000000002000 0706050403020100\n" + " 0000000000002008 0f0e0d0c0b0a0908\n" + " 0000000000002010 1716151413121110\n" + " 0000000000002018 1f1e1d1c1b1a1918\n" + " 0000000000002020 2726252423222120\n" + " 0000000000002028 2f2e2d2c2b2a2928\n" + " 0000000000002030 3736353433323130\n" + " 0000000000002038 3f3e3d3c3b3a3938\n" + " 0000000000002040 4746454443424140\n" + " 0000000000002048 4f4e4d4c4b4a4948\n" + " 0000000000002050 5756555453525150\n" + " 0000000000002058 5f5e5d5c5b5a5958\n" + " 0000000000002060 6766656463626160\n" + " 0000000000002068 6f6e6d6c6b6a6968\n" + " 0000000000002070 7776757473727170\n" + " 0000000000002078 7f7e7d7c7b7a7978\n"; +#else + " 00001fc0 03020100\n" + " 00001fc4 07060504\n" + " 00001fc8 0b0a0908\n" + " 00001fcc 0f0e0d0c\n" + " 00001fd0 13121110\n" + " 00001fd4 17161514\n" + " 00001fd8 1b1a1918\n" + " 00001fdc 1f1e1d1c\n" + " 00001fe0 23222120\n" + " 00001fe4 27262524\n" + " 00001fe8 2b2a2928\n" + " 00001fec 2f2e2d2c\n" + " 00001ff0 33323130\n" + " 00001ff4 37363534\n" + " 00001ff8 3b3a3938\n" + " 00001ffc 3f3e3d3c\n" + " #00 00002000 03020100\n" + " 00002004 07060504\n" + " 00002008 0b0a0908\n" + " 0000200c 0f0e0d0c\n" + " 00002010 13121110\n" + " 00002014 17161514\n" + " 00002018 1b1a1918\n" + " 0000201c 1f1e1d1c\n" + " 00002020 23222120\n" + " 00002024 27262524\n" + " 00002028 2b2a2928\n" + " 0000202c 2f2e2d2c\n" + " 00002030 33323130\n" + " 00002034 37363534\n" + " 00002038 3b3a3938\n" + " 0000203c 3f3e3d3c\n"; +#endif + EXPECT_EQ(expected, contents); +} + +TEST_F(TombstoneTest, dump_stack_multiple_frames_same_sp) { + std::vector<unwindstack::FrameData> frames; + unwindstack::Maps maps; + MemoryPattern memory; + + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000}); + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2000}); + dump_stack(&log_, frames, &maps, &memory); + + std::string contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents)); + + std::string expected = +#if defined(__LP64__) + " 0000000000001f80 0706050403020100\n" + " 0000000000001f88 0f0e0d0c0b0a0908\n" + " 0000000000001f90 1716151413121110\n" + " 0000000000001f98 1f1e1d1c1b1a1918\n" + " 0000000000001fa0 2726252423222120\n" + " 0000000000001fa8 2f2e2d2c2b2a2928\n" + " 0000000000001fb0 3736353433323130\n" + " 0000000000001fb8 3f3e3d3c3b3a3938\n" + " 0000000000001fc0 4746454443424140\n" + " 0000000000001fc8 4f4e4d4c4b4a4948\n" + " 0000000000001fd0 5756555453525150\n" + " 0000000000001fd8 5f5e5d5c5b5a5958\n" + " 0000000000001fe0 6766656463626160\n" + " 0000000000001fe8 6f6e6d6c6b6a6968\n" + " 0000000000001ff0 7776757473727170\n" + " 0000000000001ff8 7f7e7d7c7b7a7978\n" + " #00 0000000000002000 0706050403020100\n" + " ................ ................\n" + " #01 0000000000002000 0706050403020100\n" + " 0000000000002008 0f0e0d0c0b0a0908\n" + " 0000000000002010 1716151413121110\n" + " 0000000000002018 1f1e1d1c1b1a1918\n" + " 0000000000002020 2726252423222120\n" + " 0000000000002028 2f2e2d2c2b2a2928\n" + " 0000000000002030 3736353433323130\n" + " 0000000000002038 3f3e3d3c3b3a3938\n" + " 0000000000002040 4746454443424140\n" + " 0000000000002048 4f4e4d4c4b4a4948\n" + " 0000000000002050 5756555453525150\n" + " 0000000000002058 5f5e5d5c5b5a5958\n" + " 0000000000002060 6766656463626160\n" + " 0000000000002068 6f6e6d6c6b6a6968\n" + " 0000000000002070 7776757473727170\n" + " 0000000000002078 7f7e7d7c7b7a7978\n"; +#else + " 00001fc0 03020100\n" + " 00001fc4 07060504\n" + " 00001fc8 0b0a0908\n" + " 00001fcc 0f0e0d0c\n" + " 00001fd0 13121110\n" + " 00001fd4 17161514\n" + " 00001fd8 1b1a1918\n" + " 00001fdc 1f1e1d1c\n" + " 00001fe0 23222120\n" + " 00001fe4 27262524\n" + " 00001fe8 2b2a2928\n" + " 00001fec 2f2e2d2c\n" + " 00001ff0 33323130\n" + " 00001ff4 37363534\n" + " 00001ff8 3b3a3938\n" + " 00001ffc 3f3e3d3c\n" + " #00 00002000 03020100\n" + " ........ ........\n" + " #01 00002000 03020100\n" + " 00002004 07060504\n" + " 00002008 0b0a0908\n" + " 0000200c 0f0e0d0c\n" + " 00002010 13121110\n" + " 00002014 17161514\n" + " 00002018 1b1a1918\n" + " 0000201c 1f1e1d1c\n" + " 00002020 23222120\n" + " 00002024 27262524\n" + " 00002028 2b2a2928\n" + " 0000202c 2f2e2d2c\n" + " 00002030 33323130\n" + " 00002034 37363534\n" + " 00002038 3b3a3938\n" + " 0000203c 3f3e3d3c\n"; +#endif + EXPECT_EQ(expected, contents); +} + +TEST_F(TombstoneTest, dump_stack_multiple_frames) { + std::vector<unwindstack::FrameData> frames; + unwindstack::Maps maps; + MemoryPattern memory; + + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000}); + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010}); + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2100}); + dump_stack(&log_, frames, &maps, &memory); + + std::string contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents)); + + std::string expected = +#if defined(__LP64__) + " 0000000000001f80 0706050403020100\n" + " 0000000000001f88 0f0e0d0c0b0a0908\n" + " 0000000000001f90 1716151413121110\n" + " 0000000000001f98 1f1e1d1c1b1a1918\n" + " 0000000000001fa0 2726252423222120\n" + " 0000000000001fa8 2f2e2d2c2b2a2928\n" + " 0000000000001fb0 3736353433323130\n" + " 0000000000001fb8 3f3e3d3c3b3a3938\n" + " 0000000000001fc0 4746454443424140\n" + " 0000000000001fc8 4f4e4d4c4b4a4948\n" + " 0000000000001fd0 5756555453525150\n" + " 0000000000001fd8 5f5e5d5c5b5a5958\n" + " 0000000000001fe0 6766656463626160\n" + " 0000000000001fe8 6f6e6d6c6b6a6968\n" + " 0000000000001ff0 7776757473727170\n" + " 0000000000001ff8 7f7e7d7c7b7a7978\n" + " #00 0000000000002000 0706050403020100\n" + " 0000000000002008 0f0e0d0c0b0a0908\n" + " #01 0000000000002010 0706050403020100\n" + " 0000000000002018 0f0e0d0c0b0a0908\n" + " 0000000000002020 1716151413121110\n" + " 0000000000002028 1f1e1d1c1b1a1918\n" + " 0000000000002030 2726252423222120\n" + " 0000000000002038 2f2e2d2c2b2a2928\n" + " 0000000000002040 3736353433323130\n" + " 0000000000002048 3f3e3d3c3b3a3938\n" + " 0000000000002050 4746454443424140\n" + " 0000000000002058 4f4e4d4c4b4a4948\n" + " 0000000000002060 5756555453525150\n" + " 0000000000002068 5f5e5d5c5b5a5958\n" + " 0000000000002070 6766656463626160\n" + " 0000000000002078 6f6e6d6c6b6a6968\n" + " 0000000000002080 7776757473727170\n" + " 0000000000002088 7f7e7d7c7b7a7978\n" + " ................ ................\n" + " #02 0000000000002100 0706050403020100\n" + " 0000000000002108 0f0e0d0c0b0a0908\n" + " 0000000000002110 1716151413121110\n" + " 0000000000002118 1f1e1d1c1b1a1918\n" + " 0000000000002120 2726252423222120\n" + " 0000000000002128 2f2e2d2c2b2a2928\n" + " 0000000000002130 3736353433323130\n" + " 0000000000002138 3f3e3d3c3b3a3938\n" + " 0000000000002140 4746454443424140\n" + " 0000000000002148 4f4e4d4c4b4a4948\n" + " 0000000000002150 5756555453525150\n" + " 0000000000002158 5f5e5d5c5b5a5958\n" + " 0000000000002160 6766656463626160\n" + " 0000000000002168 6f6e6d6c6b6a6968\n" + " 0000000000002170 7776757473727170\n" + " 0000000000002178 7f7e7d7c7b7a7978\n"; +#else + " 00001fc0 03020100\n" + " 00001fc4 07060504\n" + " 00001fc8 0b0a0908\n" + " 00001fcc 0f0e0d0c\n" + " 00001fd0 13121110\n" + " 00001fd4 17161514\n" + " 00001fd8 1b1a1918\n" + " 00001fdc 1f1e1d1c\n" + " 00001fe0 23222120\n" + " 00001fe4 27262524\n" + " 00001fe8 2b2a2928\n" + " 00001fec 2f2e2d2c\n" + " 00001ff0 33323130\n" + " 00001ff4 37363534\n" + " 00001ff8 3b3a3938\n" + " 00001ffc 3f3e3d3c\n" + " #00 00002000 03020100\n" + " 00002004 07060504\n" + " 00002008 0b0a0908\n" + " 0000200c 0f0e0d0c\n" + " #01 00002010 03020100\n" + " 00002014 07060504\n" + " 00002018 0b0a0908\n" + " 0000201c 0f0e0d0c\n" + " 00002020 13121110\n" + " 00002024 17161514\n" + " 00002028 1b1a1918\n" + " 0000202c 1f1e1d1c\n" + " 00002030 23222120\n" + " 00002034 27262524\n" + " 00002038 2b2a2928\n" + " 0000203c 2f2e2d2c\n" + " 00002040 33323130\n" + " 00002044 37363534\n" + " 00002048 3b3a3938\n" + " 0000204c 3f3e3d3c\n" + " ........ ........\n" + " #02 00002100 03020100\n" + " 00002104 07060504\n" + " 00002108 0b0a0908\n" + " 0000210c 0f0e0d0c\n" + " 00002110 13121110\n" + " 00002114 17161514\n" + " 00002118 1b1a1918\n" + " 0000211c 1f1e1d1c\n" + " 00002120 23222120\n" + " 00002124 27262524\n" + " 00002128 2b2a2928\n" + " 0000212c 2f2e2d2c\n" + " 00002130 33323130\n" + " 00002134 37363534\n" + " 00002138 3b3a3938\n" + " 0000213c 3f3e3d3c\n"; +#endif + EXPECT_EQ(expected, contents); +} + +TEST_F(TombstoneTest, dump_stack_multiple_frames_disjoint_frames) { + std::vector<unwindstack::FrameData> frames; + unwindstack::Maps maps; + MemoryPattern memory; + + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000}); + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010}); + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1000}); + frames.push_back( + unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1030}); + dump_stack(&log_, frames, &maps, &memory); + + std::string contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents)); + + std::string expected = +#if defined(__LP64__) + " 0000000000001f80 0706050403020100\n" + " 0000000000001f88 0f0e0d0c0b0a0908\n" + " 0000000000001f90 1716151413121110\n" + " 0000000000001f98 1f1e1d1c1b1a1918\n" + " 0000000000001fa0 2726252423222120\n" + " 0000000000001fa8 2f2e2d2c2b2a2928\n" + " 0000000000001fb0 3736353433323130\n" + " 0000000000001fb8 3f3e3d3c3b3a3938\n" + " 0000000000001fc0 4746454443424140\n" + " 0000000000001fc8 4f4e4d4c4b4a4948\n" + " 0000000000001fd0 5756555453525150\n" + " 0000000000001fd8 5f5e5d5c5b5a5958\n" + " 0000000000001fe0 6766656463626160\n" + " 0000000000001fe8 6f6e6d6c6b6a6968\n" + " 0000000000001ff0 7776757473727170\n" + " 0000000000001ff8 7f7e7d7c7b7a7978\n" + " #00 0000000000002000 0706050403020100\n" + " 0000000000002008 0f0e0d0c0b0a0908\n" + " #01 0000000000002010 0706050403020100\n" + " 0000000000002018 0f0e0d0c0b0a0908\n" + " 0000000000002020 1716151413121110\n" + " 0000000000002028 1f1e1d1c1b1a1918\n" + " 0000000000002030 2726252423222120\n" + " 0000000000002038 2f2e2d2c2b2a2928\n" + " 0000000000002040 3736353433323130\n" + " 0000000000002048 3f3e3d3c3b3a3938\n" + " 0000000000002050 4746454443424140\n" + " 0000000000002058 4f4e4d4c4b4a4948\n" + " 0000000000002060 5756555453525150\n" + " 0000000000002068 5f5e5d5c5b5a5958\n" + " 0000000000002070 6766656463626160\n" + " 0000000000002078 6f6e6d6c6b6a6968\n" + " 0000000000002080 7776757473727170\n" + " 0000000000002088 7f7e7d7c7b7a7978\n" + " ................ ................\n" + " #02 0000000000001000 0706050403020100\n" + " 0000000000001008 0f0e0d0c0b0a0908\n" + " 0000000000001010 1716151413121110\n" + " 0000000000001018 1f1e1d1c1b1a1918\n" + " 0000000000001020 2726252423222120\n" + " 0000000000001028 2f2e2d2c2b2a2928\n" + " #03 0000000000001030 0706050403020100\n" + " 0000000000001038 0f0e0d0c0b0a0908\n" + " 0000000000001040 1716151413121110\n" + " 0000000000001048 1f1e1d1c1b1a1918\n" + " 0000000000001050 2726252423222120\n" + " 0000000000001058 2f2e2d2c2b2a2928\n" + " 0000000000001060 3736353433323130\n" + " 0000000000001068 3f3e3d3c3b3a3938\n" + " 0000000000001070 4746454443424140\n" + " 0000000000001078 4f4e4d4c4b4a4948\n" + " 0000000000001080 5756555453525150\n" + " 0000000000001088 5f5e5d5c5b5a5958\n" + " 0000000000001090 6766656463626160\n" + " 0000000000001098 6f6e6d6c6b6a6968\n" + " 00000000000010a0 7776757473727170\n" + " 00000000000010a8 7f7e7d7c7b7a7978\n"; +#else + " 00001fc0 03020100\n" + " 00001fc4 07060504\n" + " 00001fc8 0b0a0908\n" + " 00001fcc 0f0e0d0c\n" + " 00001fd0 13121110\n" + " 00001fd4 17161514\n" + " 00001fd8 1b1a1918\n" + " 00001fdc 1f1e1d1c\n" + " 00001fe0 23222120\n" + " 00001fe4 27262524\n" + " 00001fe8 2b2a2928\n" + " 00001fec 2f2e2d2c\n" + " 00001ff0 33323130\n" + " 00001ff4 37363534\n" + " 00001ff8 3b3a3938\n" + " 00001ffc 3f3e3d3c\n" + " #00 00002000 03020100\n" + " 00002004 07060504\n" + " 00002008 0b0a0908\n" + " 0000200c 0f0e0d0c\n" + " #01 00002010 03020100\n" + " 00002014 07060504\n" + " 00002018 0b0a0908\n" + " 0000201c 0f0e0d0c\n" + " 00002020 13121110\n" + " 00002024 17161514\n" + " 00002028 1b1a1918\n" + " 0000202c 1f1e1d1c\n" + " 00002030 23222120\n" + " 00002034 27262524\n" + " 00002038 2b2a2928\n" + " 0000203c 2f2e2d2c\n" + " 00002040 33323130\n" + " 00002044 37363534\n" + " 00002048 3b3a3938\n" + " 0000204c 3f3e3d3c\n" + " ........ ........\n" + " #02 00001000 03020100\n" + " 00001004 07060504\n" + " 00001008 0b0a0908\n" + " 0000100c 0f0e0d0c\n" + " 00001010 13121110\n" + " 00001014 17161514\n" + " 00001018 1b1a1918\n" + " 0000101c 1f1e1d1c\n" + " 00001020 23222120\n" + " 00001024 27262524\n" + " 00001028 2b2a2928\n" + " 0000102c 2f2e2d2c\n" + " #03 00001030 03020100\n" + " 00001034 07060504\n" + " 00001038 0b0a0908\n" + " 0000103c 0f0e0d0c\n" + " 00001040 13121110\n" + " 00001044 17161514\n" + " 00001048 1b1a1918\n" + " 0000104c 1f1e1d1c\n" + " 00001050 23222120\n" + " 00001054 27262524\n" + " 00001058 2b2a2928\n" + " 0000105c 2f2e2d2c\n" + " 00001060 33323130\n" + " 00001064 37363534\n" + " 00001068 3b3a3938\n" + " 0000106c 3f3e3d3c\n"; +#endif + EXPECT_EQ(expected, contents); +} 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) { |