crash_dump: fork a copy of the target's address space.
Reduce the amount of time that a process remains paused by pausing its
threads, fetching their registers, and then performing unwinding on a
copy of its address space. This also works around a kernel change
that's in 4.9 that prevents ptrace from reading memory of processes
that we don't have immediate permissions to ptrace (even if we
previously ptraced them).
Bug: http://b/62112103
Bug: http://b/63989615
Test: treehugger
Change-Id: I7b9cc5dd8f54a354bc61f1bda0d2b7a8a55733c4
diff --git a/debuggerd/libdebuggerd/arm/machine.cpp b/debuggerd/libdebuggerd/arm/machine.cpp
deleted file mode 100644
index bfb5ea4..0000000
--- a/debuggerd/libdebuggerd/arm/machine.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *
- * Copyright 2006, 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/machine.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-
-#include <backtrace/Backtrace.h>
-#include <log/log.h>
-
-#include "libdebuggerd/utility.h"
-
-void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
- pt_regs regs;
- if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, ®s)) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- static const char reg_names[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
-
- for (int reg = 0; reg < 14; reg++) {
- dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", ®_names[reg * 2]);
- }
-
- dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");
-
- if (regs.ARM_pc != regs.ARM_lr) {
- dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
- }
-}
-
-#define DUMP_GP_REGISTERS(log, reg_prefix) \
- _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n", \
- static_cast<uint32_t>(reg_prefix##r0), static_cast<uint32_t>(reg_prefix##r1), \
- static_cast<uint32_t>(reg_prefix##r2), static_cast<uint32_t>(reg_prefix##r3)); \
- _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n", \
- static_cast<uint32_t>(reg_prefix##r4), static_cast<uint32_t>(reg_prefix##r5), \
- static_cast<uint32_t>(reg_prefix##r6), static_cast<uint32_t>(reg_prefix##r7)); \
- _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n", \
- static_cast<uint32_t>(reg_prefix##r8), static_cast<uint32_t>(reg_prefix##r9), \
- static_cast<uint32_t>(reg_prefix##r10), static_cast<uint32_t>(reg_prefix##fp)); \
- _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", \
- static_cast<uint32_t>(reg_prefix##ip), static_cast<uint32_t>(reg_prefix##sp), \
- static_cast<uint32_t>(reg_prefix##lr), static_cast<uint32_t>(reg_prefix##pc), \
- static_cast<uint32_t>(reg_prefix##cpsr))
-
-void dump_registers(log_t* log, pid_t tid) {
- pt_regs r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- DUMP_GP_REGISTERS(log, r.ARM_);
-
- user_vfp vfp_regs;
- if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
- ALOGE("cannot get FP registers: %s\n", strerror(errno));
- return;
- }
-
- for (size_t i = 0; i < 32; i += 2) {
- _LOG(log, logtype::FP_REGISTERS, " d%-2d %016llx d%-2d %016llx\n",
- i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
- }
- _LOG(log, logtype::FP_REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
-}
-
-void dump_registers(log_t* log, const ucontext_t* uc) {
- DUMP_GP_REGISTERS(log, uc->uc_mcontext.arm_);
-}
diff --git a/debuggerd/libdebuggerd/arm64/machine.cpp b/debuggerd/libdebuggerd/arm64/machine.cpp
deleted file mode 100644
index ad1c951..0000000
--- a/debuggerd/libdebuggerd/arm64/machine.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *
- * Copyright 2014, 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/machine.h"
-
-#include <elf.h>
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/uio.h>
-
-#include <backtrace/Backtrace.h>
-#include <log/log.h>
-
-#include "libdebuggerd/utility.h"
-
-void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
- struct user_pt_regs regs;
- struct iovec io;
- io.iov_base = ®s;
- io.iov_len = sizeof(regs);
-
- if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
- ALOGE("ptrace failed to get registers: %s", strerror(errno));
- return;
- }
-
- for (int reg = 0; reg < 31; reg++) {
- dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
- }
-
- dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
-
- if (regs.pc != regs.sp) {
- dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
- }
-}
-
-#define DUMP_GP_REGISTERS(log) \
- for (int i = 0; i < 28; i += 4) { \
- const char* fmt = " x%-2d %016llx x%-2d %016llx x%-2d %016llx x%-2d %016llx\n"; \
- _LOG(log, logtype::REGISTERS, fmt, i, r.regs[i], i + 1, r.regs[i + 1], i + 2, r.regs[i + 2], \
- i + 3, r.regs[i + 3]); \
- } \
- _LOG(log, logtype::REGISTERS, " x28 %016llx x29 %016llx x30 %016llx\n", r.regs[28], \
- r.regs[29], r.regs[30]); \
- _LOG(log, logtype::REGISTERS, " sp %016llx pc %016llx pstate %016llx\n", r.sp, r.pc, \
- r.pstate)
-
-void dump_registers(log_t* log, pid_t tid) {
- struct user_pt_regs r;
- struct iovec io;
- io.iov_base = &r;
- io.iov_len = sizeof(r);
-
- if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
- ALOGE("ptrace error: %s\n", strerror(errno));
- return;
- }
-
- DUMP_GP_REGISTERS(log);
-
- struct user_fpsimd_state f;
- io.iov_base = &f;
- io.iov_len = sizeof(f);
-
- if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
- ALOGE("ptrace error: %s\n", strerror(errno));
- return;
- }
-
- for (int i = 0; i < 32; i += 2) {
- _LOG(log, logtype::FP_REGISTERS,
- " v%-2d %016" PRIx64 "%016" PRIx64 " v%-2d %016" PRIx64 "%016" PRIx64 "\n",
- i,
- static_cast<uint64_t>(f.vregs[i] >> 64),
- static_cast<uint64_t>(f.vregs[i]),
- i+1,
- static_cast<uint64_t>(f.vregs[i+1] >> 64),
- static_cast<uint64_t>(f.vregs[i+1]));
- }
- _LOG(log, logtype::FP_REGISTERS, " fpsr %08x fpcr %08x\n", f.fpsr, f.fpcr);
-}
-
-void dump_registers(log_t* log, const ucontext_t* ucontext) {
- const mcontext_t& r = ucontext->uc_mcontext;
- DUMP_GP_REGISTERS(log);
-}
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f616e1b..f0a01f4 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -30,12 +30,15 @@
#include <time.h>
#include <unistd.h>
+#include <map>
#include <memory>
#include <string>
+#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
+#include "libdebuggerd/types.h"
#include "libdebuggerd/utility.h"
static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
@@ -56,62 +59,46 @@
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
-static void log_thread_name(log_t* log, pid_t tid, const char* thread_name) {
- _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread_name, tid);
-}
-
-static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::string& thread_name) {
- log_thread_name(log, tid, thread_name.c_str());
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
- if (backtrace->Unwind(0)) {
- dump_backtrace_to_log(backtrace.get(), log, " ");
- } else {
- ALOGE("Unwind failed: tid = %d: %s", tid,
- backtrace->GetErrorString(backtrace->GetError()).c_str());
- }
-}
-
-void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
- const std::map<pid_t, std::string>& threads, std::string* amfd_data) {
- log_t log;
- log.tfd = fd;
- log.amfd_data = amfd_data;
-
- dump_process_header(&log, pid, process_name.c_str());
- dump_thread(&log, map, pid, tid, threads.find(tid)->second.c_str());
-
- for (const auto& it : threads) {
- pid_t thread_tid = it.first;
- const std::string& thread_name = it.second;
- if (thread_tid != tid) {
- dump_thread(&log, map, pid, thread_tid, thread_name.c_str());
- }
- }
-
- dump_process_footer(&log, pid);
-}
-
-void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext) {
- pid_t pid = getpid();
- pid_t tid = gettid();
-
+void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread) {
log_t log;
log.tfd = output_fd;
log.amfd_data = nullptr;
- char thread_name[16];
- read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
- log_thread_name(&log, tid, thread_name);
+ _LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid);
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
- if (backtrace->Unwind(0, ucontext)) {
- dump_backtrace_to_log(backtrace.get(), &log, " ");
- } else {
- ALOGE("Unwind failed: tid = %d: %s", tid,
- backtrace->GetErrorString(backtrace->GetError()).c_str());
+ std::vector<backtrace_frame_data_t> frames;
+ if (!Backtrace::Unwind(thread.registers.get(), map, &frames, 0, nullptr)) {
+ _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());
+ }
+}
+
+void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+ const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) {
+ log_t log;
+ log.tfd = output_fd.get();
+ log.amfd_data = nullptr;
+
+ auto target = thread_info.find(target_thread);
+ if (target == thread_info.end()) {
+ ALOGE("failed to find target thread in thread info");
+ return;
+ }
+
+ dump_process_header(&log, target->second.pid, target->second.process_name.c_str());
+
+ dump_backtrace_thread(output_fd.get(), map, target->second);
+ for (const auto& [tid, info] : thread_info) {
+ if (tid != target_thread) {
+ dump_backtrace_thread(output_fd.get(), map, info);
+ }
+ }
+
+ dump_process_footer(&log, target->second.pid);
}
void dump_backtrace_header(int output_fd) {
@@ -131,9 +118,3 @@
dump_process_footer(&log, getpid());
}
-
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
- }
-}
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
index a35102f..d7afc0b 100644
--- a/debuggerd/libdebuggerd/elf_utils.cpp
+++ b/debuggerd/libdebuggerd/elf_utils.cpp
@@ -26,28 +26,28 @@
#include <string>
#include <android-base/stringprintf.h>
-#include <backtrace/Backtrace.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(
- Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
+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 (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
- sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
+ 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 (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
- reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(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.
@@ -56,7 +56,7 @@
uintptr_t addr = base_addr + phdr.p_offset;
while (hdr_size >= sizeof(NhdrType)) {
NhdrType nhdr;
- if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
+ if (memory->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
return false;
}
addr += sizeof(nhdr);
@@ -69,7 +69,7 @@
nhdr.n_descsz);
return false;
}
- if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
+ if (memory->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
return false;
}
@@ -95,10 +95,10 @@
return false;
}
-bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) {
+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 (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) {
+ if (memory->Read(addr, e_ident, SELFMAG) != SELFMAG) {
return false;
}
@@ -107,14 +107,14 @@
}
// Read the rest of EI_NIDENT.
- if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
+ 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>(backtrace, addr, e_ident, build_id);
+ 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>(backtrace, addr, e_ident, build_id);
+ 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 fe738f1..119e59b 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
@@ -23,21 +23,20 @@
#include <map>
#include <string>
+#include <android-base/unique_fd.h>
+
+#include "types.h"
#include "utility.h"
-class Backtrace;
class BacktraceMap;
// 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(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
- const std::map<pid_t, std::string>& threads, std::string* amfd_data);
+void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+ const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread);
-/* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
-
-void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext);
void dump_backtrace_header(int output_fd);
+void dump_backtrace_thread(int output_fd, BacktraceMap* map, 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
index 11d0a43..5d0d924 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
@@ -20,8 +20,10 @@
#include <stdint.h>
#include <string>
-class Backtrace;
+namespace unwindstack {
+class Memory;
+}
-bool elf_get_build_id(Backtrace*, uintptr_t, std::string*);
+bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string*);
#endif // _DEBUGGERD_ELF_UTILS_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/machine.h b/debuggerd/libdebuggerd/include/libdebuggerd/machine.h
deleted file mode 100644
index 5e56682..0000000
--- a/debuggerd/libdebuggerd/include/libdebuggerd/machine.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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_MACHINE_H
-#define _DEBUGGERD_MACHINE_H
-
-#include <sys/types.h>
-
-#include <backtrace/Backtrace.h>
-
-#include "utility.h"
-
-void dump_memory_and_code(log_t* log, Backtrace* backtrace);
-void dump_registers(log_t* log, pid_t tid);
-void dump_registers(log_t* log, const ucontext_t* uc);
-
-#endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
index b37228d..4727ca4 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
@@ -31,6 +31,6 @@
void populate_open_files_list(pid_t pid, OpenFilesList* list);
/* Dumps the open files list to the log. */
-void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix);
+void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix);
#endif // _DEBUGGERD_OPEN_FILES_LIST_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 79743b6..198c48b 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -24,7 +24,10 @@
#include <map>
#include <string>
+#include <android-base/unique_fd.h>
+
#include "open_files_list.h"
+#include "types.h"
class BacktraceMap;
@@ -43,11 +46,10 @@
void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext);
-// Compatibility shim.
-__attribute__((__unused__))
-static void engrave_tombstone_ucontext(int tombstone_fd, pid_t, pid_t, uintptr_t abort_msg_address,
- siginfo_t* siginfo, ucontext_t* ucontext) {
- engrave_tombstone_ucontext(tombstone_fd, abort_msg_address, siginfo, ucontext);
-}
+void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
+ unwindstack::Memory* process_memory,
+ const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
+ uintptr_t abort_msg_address, OpenFilesList* open_files,
+ std::string* amfd_data);
-#endif // _DEBUGGERD_TOMBSTONE_H
+#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/test/ptrace_fake.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
similarity index 62%
rename from debuggerd/libdebuggerd/test/ptrace_fake.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/types.h
index fdbb663..70583af 100644
--- a/debuggerd/libdebuggerd/test/ptrace_fake.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -1,5 +1,7 @@
+#pragma once
+
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,11 +16,19 @@
* limitations under the License.
*/
-#ifndef _DEBUGGERD_TEST_PTRACE_FAKE_H
-#define _DEBUGGERD_TEST_PTRACE_FAKE_H
+#include <memory>
+#include <string>
-#include <signal.h>
+#include <unwindstack/Regs.h>
-void ptrace_set_fake_getsiginfo(const siginfo_t&);
+struct ThreadInfo {
+ std::unique_ptr<unwindstack::Regs> registers;
+ pid_t tid;
+ std::string thread_name;
-#endif // _DEBUGGERD_TEST_PTRACE_FAKE_H
+ pid_t pid;
+ std::string process_name;
+
+ int signo = 0;
+ siginfo_t* siginfo = nullptr;
+};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index f481b78..c5abfe2 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -27,21 +27,24 @@
#include <android-base/macros.h>
#include <backtrace/Backtrace.h>
-struct log_t{
- // Tombstone file descriptor.
- int tfd;
- // Data to be sent to the Activity Manager.
- std::string* amfd_data;
- // The tid of the thread that crashed.
- pid_t crashed_tid;
- // The tid of the thread we are currently working with.
- pid_t current_tid;
- // logd daemon crash, can block asking for logcat data, allow suppression.
- bool should_retrieve_logcat;
+struct log_t {
+ // Tombstone file descriptor.
+ int tfd;
+ // Data to be sent to the Activity Manager.
+ std::string* amfd_data;
+ // The tid of the thread that crashed.
+ pid_t crashed_tid;
+ // The tid of the thread we are currently working with.
+ pid_t current_tid;
+ // logd daemon crash, can block asking for logcat data, allow suppression.
+ bool should_retrieve_logcat;
- log_t()
- : tfd(-1), amfd_data(nullptr), crashed_tid(-1), current_tid(-1),
- should_retrieve_logcat(true) {}
+ log_t()
+ : tfd(-1),
+ amfd_data(nullptr),
+ crashed_tid(-1),
+ current_tid(-1),
+ should_retrieve_logcat(true) {}
};
// List of types of logs to simplify the logging decision in _LOG
@@ -59,13 +62,20 @@
};
// Log information onto the tombstone.
-void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
- __attribute__ ((format(printf, 3, 4)));
+void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
-bool wait_for_signal(pid_t tid, siginfo_t* siginfo);
+namespace unwindstack {
+class Memory;
+}
-void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
+void dump_memory(log_t* log, unwindstack::Memory* backtrace, uintptr_t addr, const char* fmt, ...);
void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
+void drop_capabilities();
+
+bool signal_has_si_addr(int si_signo, int si_code);
+const char* get_signame(int sig);
+const char* get_sigcode(int signo, int code);
+
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/mips/machine.cpp b/debuggerd/libdebuggerd/mips/machine.cpp
deleted file mode 100644
index 1fc690b..0000000
--- a/debuggerd/libdebuggerd/mips/machine.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2012, 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/machine.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-
-#include <backtrace/Backtrace.h>
-#include <log/log.h>
-
-#include "libdebuggerd/utility.h"
-
-#define R(x) (static_cast<uintptr_t>(x))
-
-// If configured to do so, dump memory around *all* registers
-// for the crashing thread.
-void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
- pt_regs r;
- if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- static const char reg_names[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
-
- for (int reg = 0; reg < 32; reg++) {
- // skip uninteresting registers
- if (reg == 0 // $0
- || reg == 26 // $k0
- || reg == 27 // $k1
- || reg == 31 // $ra (done below)
- )
- continue;
-
- dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", ®_names[reg * 2]);
- }
-
- uintptr_t pc = R(r.cp0_epc);
- uintptr_t ra = R(r.regs[31]);
- dump_memory(log, backtrace, pc, "code around pc:");
- if (pc != ra) {
- dump_memory(log, backtrace, ra, "code around ra:");
- }
-}
-
-void dump_registers(log_t* log, pid_t tid) {
- pt_regs r;
- if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- _LOG(log, logtype::REGISTERS, " zr %08" PRIxPTR " at %08" PRIxPTR
- " v0 %08" PRIxPTR " v1 %08" PRIxPTR "\n",
- R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, logtype::REGISTERS, " a0 %08" PRIxPTR " a1 %08" PRIxPTR
- " a2 %08" PRIxPTR " a3 %08" PRIxPTR "\n",
- R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, logtype::REGISTERS, " t0 %08" PRIxPTR " t1 %08" PRIxPTR
- " t2 %08" PRIxPTR " t3 %08" PRIxPTR "\n",
- R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, logtype::REGISTERS, " t4 %08" PRIxPTR " t5 %08" PRIxPTR
- " t6 %08" PRIxPTR " t7 %08" PRIxPTR "\n",
- R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, logtype::REGISTERS, " s0 %08" PRIxPTR " s1 %08" PRIxPTR
- " s2 %08" PRIxPTR " s3 %08" PRIxPTR "\n",
- R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, logtype::REGISTERS, " s4 %08" PRIxPTR " s5 %08" PRIxPTR
- " s6 %08" PRIxPTR " s7 %08" PRIxPTR "\n",
- R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, logtype::REGISTERS, " t8 %08" PRIxPTR " t9 %08" PRIxPTR
- " k0 %08" PRIxPTR " k1 %08" PRIxPTR "\n",
- R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, logtype::REGISTERS, " gp %08" PRIxPTR " sp %08" PRIxPTR
- " s8 %08" PRIxPTR " ra %08" PRIxPTR "\n",
- R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, logtype::REGISTERS, " hi %08" PRIxPTR " lo %08" PRIxPTR
- " bva %08" PRIxPTR " epc %08" PRIxPTR "\n",
- R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
-}
diff --git a/debuggerd/libdebuggerd/mips64/machine.cpp b/debuggerd/libdebuggerd/mips64/machine.cpp
deleted file mode 100644
index 955e507..0000000
--- a/debuggerd/libdebuggerd/mips64/machine.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2014, 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/machine.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-
-#include <backtrace/Backtrace.h>
-#include <log/log.h>
-
-#include "libdebuggerd/utility.h"
-
-#define R(x) (static_cast<uintptr_t>(x))
-
-// If configured to do so, dump memory around *all* registers
-// for the crashing thread.
-void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
- pt_regs r;
- if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- static const char reg_names[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
-
- for (int reg = 0; reg < 32; reg++) {
- // skip uninteresting registers
- if (reg == 0 // $0
- || reg == 26 // $k0
- || reg == 27 // $k1
- || reg == 31 // $ra (done below)
- )
- continue;
-
- dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", ®_names[reg * 2]);
- }
-
- uintptr_t pc = R(r.cp0_epc);
- uintptr_t ra = R(r.regs[31]);
- dump_memory(log, backtrace, pc, "code around pc:");
- if (pc != ra) {
- dump_memory(log, backtrace, ra, "code around ra:");
- }
-}
-
-void dump_registers(log_t* log, pid_t tid) {
- pt_regs r;
- if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- _LOG(log, logtype::REGISTERS, " zr %016" PRIxPTR " at %016" PRIxPTR
- " v0 %016" PRIxPTR " v1 %016" PRIxPTR "\n",
- R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, logtype::REGISTERS, " a0 %016" PRIxPTR " a1 %016" PRIxPTR
- " a2 %016" PRIxPTR " a3 %016" PRIxPTR "\n",
- R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, logtype::REGISTERS, " a4 %016" PRIxPTR " a5 %016" PRIxPTR
- " a6 %016" PRIxPTR " a7 %016" PRIxPTR "\n",
- R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, logtype::REGISTERS, " t0 %016" PRIxPTR " t1 %016" PRIxPTR
- " t2 %016" PRIxPTR " t3 %016" PRIxPTR "\n",
- R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, logtype::REGISTERS, " s0 %016" PRIxPTR " s1 %016" PRIxPTR
- " s2 %016" PRIxPTR " s3 %016" PRIxPTR "\n",
- R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, logtype::REGISTERS, " s4 %016" PRIxPTR " s5 %016" PRIxPTR
- " s6 %016" PRIxPTR " s7 %016" PRIxPTR "\n",
- R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, logtype::REGISTERS, " t8 %016" PRIxPTR " t9 %016" PRIxPTR
- " k0 %016" PRIxPTR " k1 %016" PRIxPTR "\n",
- R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, logtype::REGISTERS, " gp %016" PRIxPTR " sp %016" PRIxPTR
- " s8 %016" PRIxPTR " ra %016" PRIxPTR "\n",
- R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, logtype::REGISTERS, " hi %016" PRIxPTR " lo %016" PRIxPTR
- " bva %016" PRIxPTR " epc %016" PRIxPTR "\n",
- R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
-}
diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp
index e199db8..b12703e 100644
--- a/debuggerd/libdebuggerd/open_files_list.cpp
+++ b/debuggerd/libdebuggerd/open_files_list.cpp
@@ -61,7 +61,7 @@
}
}
-void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix) {
+void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix) {
for (auto& file : files) {
_LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str());
}
diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h
index 6104f7e..e7dbed7 100644
--- a/debuggerd/libdebuggerd/test/BacktraceMock.h
+++ b/debuggerd/libdebuggerd/test/BacktraceMock.h
@@ -17,15 +17,6 @@
#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H
#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ucontext.h>
-
-#include <string>
-#include <vector>
-
-#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
class BacktraceMapMock : public BacktraceMap {
@@ -38,69 +29,4 @@
}
};
-
-class BacktraceMock : public Backtrace {
- public:
- explicit BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
- if (map_ == nullptr) {
- abort();
- }
- }
- virtual ~BacktraceMock() {}
-
- virtual bool Unwind(size_t, ucontext_t*) { return false; }
- virtual bool ReadWord(uintptr_t, word_t*) { return false;}
-
- virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; }
-
- virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
- size_t offset = 0;
- if (last_read_addr_ > 0) {
- offset = addr - last_read_addr_;
- }
- size_t bytes_available = buffer_.size() - offset;
-
- if (do_partial_read_) {
- // Do a partial read.
- if (bytes > bytes_partial_read_) {
- bytes = bytes_partial_read_;
- }
- bytes_partial_read_ -= bytes;
- // Only support a single partial read.
- do_partial_read_ = false;
- } else if (bytes > bytes_available) {
- bytes = bytes_available;
- }
-
- if (bytes > 0) {
- memcpy(buffer, buffer_.data() + offset, bytes);
- }
-
- last_read_addr_ = addr;
- return bytes;
- }
-
- void SetReadData(uint8_t* buffer, size_t bytes) {
- buffer_.resize(bytes);
- memcpy(buffer_.data(), buffer, bytes);
- bytes_partial_read_ = 0;
- do_partial_read_ = false;
- last_read_addr_ = 0;
- }
-
- void SetPartialReadAmount(size_t bytes) {
- if (bytes > buffer_.size()) {
- abort();
- }
- bytes_partial_read_ = bytes;
- do_partial_read_ = true;
- }
-
- private:
- std::vector<uint8_t> buffer_;
- size_t bytes_partial_read_ = 0;
- uintptr_t last_read_addr_ = 0;
- bool do_partial_read_ = false;
-};
-
#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
index 0fad2cf..7c8a0ea 100644
--- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
@@ -19,12 +19,12 @@
#include <memory>
#include <string>
-#include <gtest/gtest.h>
#include <android-base/file.h>
+#include <gtest/gtest.h>
+#include <unwindstack/Memory.h>
#include "libdebuggerd/utility.h"
-#include "BacktraceMock.h"
#include "log_fake.h"
const char g_expected_full_dump[] =
@@ -103,11 +103,59 @@
" 123456d0 -------- -------- -------- -------- ................\n";
#endif
+class MemoryMock : public unwindstack::Memory {
+ public:
+ virtual ~MemoryMock() = default;
+
+ virtual size_t Read(uint64_t addr, void* buffer, size_t bytes) override {
+ size_t offset = 0;
+ if (last_read_addr_ > 0) {
+ offset = addr - last_read_addr_;
+ }
+ size_t bytes_available = buffer_.size() - offset;
+
+ if (partial_read_) {
+ bytes = std::min(bytes, bytes_partial_read_);
+ bytes_partial_read_ -= bytes;
+ partial_read_ = bytes_partial_read_;
+ } else if (bytes > bytes_available) {
+ bytes = bytes_available;
+ }
+
+ if (bytes > 0) {
+ memcpy(buffer, buffer_.data() + offset, bytes);
+ }
+
+ last_read_addr_ = addr;
+ return bytes;
+ }
+
+ void SetReadData(uint8_t* buffer, size_t bytes) {
+ buffer_.resize(bytes);
+ memcpy(buffer_.data(), buffer, bytes);
+ bytes_partial_read_ = 0;
+ last_read_addr_ = 0;
+ }
+
+ void SetPartialReadAmount(size_t bytes) {
+ if (bytes > buffer_.size()) {
+ abort();
+ }
+ partial_read_ = true;
+ bytes_partial_read_ = bytes;
+ }
+
+ private:
+ std::vector<uint8_t> buffer_;
+ bool partial_read_ = false;
+ size_t bytes_partial_read_ = 0;
+ uintptr_t last_read_addr_ = 0;
+};
+
class DumpMemoryTest : public ::testing::Test {
protected:
virtual void SetUp() {
- map_mock_.reset(new BacktraceMapMock());
- backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
+ memory_mock_ = std::make_unique<MemoryMock>();
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -138,10 +186,10 @@
if (log_.tfd >= 0) {
close(log_.tfd);
}
+ memory_mock_.reset();
}
- std::unique_ptr<BacktraceMapMock> map_mock_;
- std::unique_ptr<BacktraceMock> backtrace_mock_;
+ std::unique_ptr<MemoryMock> memory_mock_;
log_t log_;
};
@@ -151,9 +199,9 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
- dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -170,10 +218,10 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(96);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(96);
- dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -190,9 +238,9 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
- dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -205,7 +253,7 @@
}
TEST_F(DumpMemoryTest, memory_unreadable) {
- dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:");
+ dump_memory(&log_, memory_mock_.get(), 0xa2345678, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -259,9 +307,9 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
- dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+ dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -278,10 +326,10 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(102);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(102);
- dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+ dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -303,10 +351,10 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(45);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(45);
- dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+ dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -330,9 +378,9 @@
TEST_F(DumpMemoryTest, address_low_fence) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
- dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x1000, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -384,9 +432,9 @@
TEST_F(DumpMemoryTest, memory_address_too_low) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
- dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -401,16 +449,16 @@
TEST_F(DumpMemoryTest, memory_address_too_high) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
#if defined(__LP64__)
- dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
- dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
- dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
#else
- dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
- dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
- dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
#endif
std::string tombstone_contents;
@@ -426,12 +474,12 @@
TEST_F(DumpMemoryTest, memory_address_would_overflow) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
#if defined(__LP64__)
- dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
#else
- dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
+ dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
#endif
std::string tombstone_contents;
@@ -449,12 +497,12 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
#if defined(__LP64__)
- dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
+ dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
#else
- dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
+ dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
#endif
std::string tombstone_contents;
@@ -509,12 +557,12 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(0);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(0);
size_t page_size = sysconf(_SC_PAGE_SIZE);
uintptr_t addr = 0x10000020 + page_size - 120;
- dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+ dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -568,12 +616,12 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(0);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(0);
size_t page_size = sysconf(_SC_PAGE_SIZE);
uintptr_t addr = 0x10000020 + page_size - 192;
- dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+ dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -627,11 +675,11 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(0);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(0);
uintptr_t addr = 0x10000020;
- dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+ dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -685,13 +733,13 @@
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
- backtrace_mock_->SetReadData(buffer, sizeof(buffer));
- backtrace_mock_->SetPartialReadAmount(0);
+ memory_mock_->SetReadData(buffer, sizeof(buffer));
+ memory_mock_->SetPartialReadAmount(0);
size_t page_size = sysconf(_SC_PAGE_SIZE);
uintptr_t addr = 0x10000020 + page_size - 256;
- dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+ dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
diff --git a/debuggerd/libdebuggerd/test/elf_fake.cpp b/debuggerd/libdebuggerd/test/elf_fake.cpp
index f8cbca7..9b8281a 100644
--- a/debuggerd/libdebuggerd/test/elf_fake.cpp
+++ b/debuggerd/libdebuggerd/test/elf_fake.cpp
@@ -20,7 +20,9 @@
#include <string>
-class Backtrace;
+namespace unwindstack {
+class Memory;
+}
std::string g_build_id;
@@ -28,7 +30,7 @@
g_build_id = build_id;
}
-bool elf_get_build_id(Backtrace*, uintptr_t, std::string* build_id) {
+bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string* build_id) {
if (g_build_id != "") {
*build_id = g_build_id;
return true;
diff --git a/debuggerd/libdebuggerd/test/ptrace_fake.cpp b/debuggerd/libdebuggerd/test/ptrace_fake.cpp
deleted file mode 100644
index 0d4080e..0000000
--- a/debuggerd/libdebuggerd/test/ptrace_fake.cpp
+++ /dev/null
@@ -1,53 +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 "ptrace_fake.h"
-
-#include <errno.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <sys/ptrace.h>
-
-#include <string>
-
-siginfo_t g_fake_si = {.si_signo = 0};
-
-void ptrace_set_fake_getsiginfo(const siginfo_t& si) {
- g_fake_si = si;
-}
-
-#if !defined(__BIONIC__)
-extern "C" long ptrace_fake(enum __ptrace_request request, ...) {
-#else
-extern "C" long ptrace_fake(int request, ...) {
-#endif
- if (request == PTRACE_GETSIGINFO) {
- if (g_fake_si.si_signo == 0) {
- errno = EFAULT;
- return -1;
- }
-
- va_list ap;
- va_start(ap, request);
- va_arg(ap, int);
- va_arg(ap, int);
- siginfo_t* si = va_arg(ap, siginfo*);
- va_end(ap);
- *si = g_fake_si;
- return 0;
- }
- return -1;
-}
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 59a43b7..1e3a10f 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -29,11 +29,6 @@
#include "elf_fake.h"
#include "host_signal_fixup.h"
#include "log_fake.h"
-#include "ptrace_fake.h"
-
-// In order to test this code, we need to include the tombstone.cpp code.
-// Including it, also allows us to override the ptrace function.
-#define ptrace ptrace_fake
#include "tombstone.cpp"
@@ -50,7 +45,6 @@
protected:
virtual void SetUp() {
map_mock_.reset(new BacktraceMapMock());
- backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -77,11 +71,6 @@
resetLogs();
elf_set_fake_build_id("");
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- si.si_signo = SIGABRT;
- si.si_code = SI_KERNEL;
- ptrace_set_fake_getsiginfo(si);
}
virtual void TearDown() {
@@ -91,7 +80,6 @@
}
std::unique_ptr<BacktraceMapMock> map_mock_;
- std::unique_ptr<BacktraceMock> backtrace_mock_;
log_t log_;
std::string amfd_data_;
@@ -108,7 +96,7 @@
#endif
map_mock_->AddMap(map);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -143,7 +131,7 @@
map_mock_->AddMap(map);
elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -182,7 +170,7 @@
map_mock_->AddMap(map);
elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -240,7 +228,7 @@
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -294,13 +282,7 @@
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- si.si_signo = SIGBUS;
- si.si_code = SI_KERNEL;
- si.si_addr = reinterpret_cast<void*>(0x1000);
- ptrace_set_fake_getsiginfo(si);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0x1000);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -352,13 +334,7 @@
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- si.si_signo = SIGBUS;
- si.si_code = SI_KERNEL;
- si.si_addr = reinterpret_cast<void*>(0xa533000);
- ptrace_set_fake_getsiginfo(si);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa533000);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -410,13 +386,7 @@
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- si.si_signo = SIGBUS;
- si.si_code = SI_KERNEL;
- si.si_addr = reinterpret_cast<void*>(0xa534040);
- ptrace_set_fake_getsiginfo(si);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa534040);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -466,17 +436,12 @@
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- si.si_signo = SIGBUS;
- si.si_code = SI_KERNEL;
#if defined(__LP64__)
- si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
+ uintptr_t addr = 0x12345a534040UL;
#else
- si.si_addr = reinterpret_cast<void*>(0xf534040UL);
+ uintptr_t addr = 0xf534040UL;
#endif
- ptrace_set_fake_getsiginfo(si);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+ dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -503,124 +468,6 @@
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
-TEST_F(TombstoneTest, multiple_maps_getsiginfo_fail) {
- 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);
-
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- ptrace_set_fake_getsiginfo(si);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
-
- 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 (1 entry):\n"
-#if defined(__LP64__)
- " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n";
-#else
- " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\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("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
-}
-
-TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) {
- backtrace_map_t map;
-
- map.start = 0xa434000;
- map.end = 0xa435000;
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- for (int i = 1; i < 255; i++) {
- ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
- ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
-
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- si.si_signo = i;
- si.si_code = SI_KERNEL;
- si.si_addr = reinterpret_cast<void*>(0x1000);
- ptrace_set_fake_getsiginfo(si);
- dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
-
- std::string tombstone_contents;
- ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
- ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- bool has_addr = false;
- switch (si.si_signo) {
- case SIGBUS:
- case SIGFPE:
- case SIGILL:
- case SIGSEGV:
- case SIGTRAP:
- has_addr = true;
- break;
- }
-
- const char* expected_addr_dump = \
-"\nmemory map (1 entry):\n"
-#if defined(__LP64__)
-"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
-" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
-#else
-"--->Fault address falls at 00001000 before any mapped regions\n"
-" 0a434000-0a434fff -w- 0 1000\n";
-#endif
- const char* expected_dump = \
-"\nmemory map (1 entry):\n"
-#if defined(__LP64__)
-" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
-#else
-" 0a434000-0a434fff -w- 0 1000\n";
-#endif
- if (has_addr) {
- ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
- << "Signal " << si.si_signo << " expected to include an address.";
- } else {
- ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
- << "Signal " << si.si_signo << " is not expected to include an address.";
- }
-
- 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, dump_signal_info_error) {
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- ptrace_set_fake_getsiginfo(si);
-
- dump_signal_info(&log_, 123);
-
- std::string tombstone_contents;
- ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
- ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ("", tombstone_contents.c_str());
-
- ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
-
- ASSERT_STREQ("", amfd_data_.c_str());
-}
-
TEST_F(TombstoneTest, dump_log_file_error) {
log_.should_retrieve_logcat = true;
dump_log_file(&log_, 123, "/fake/filename", 10);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index a0ba81b..99da801 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -35,8 +35,10 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/log.h>
#include <backtrace/Backtrace.h>
@@ -44,169 +46,27 @@
#include <log/log.h>
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
// Needed to get DEBUGGER_SIGNAL.
#include "debuggerd/handler.h"
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/elf_utils.h"
-#include "libdebuggerd/machine.h"
#include "libdebuggerd/open_files_list.h"
+#include "libdebuggerd/utility.h"
using android::base::GetBoolProperty;
using android::base::GetProperty;
using android::base::StringPrintf;
+using android::base::unique_fd;
+
+using unwindstack::Memory;
+using unwindstack::Regs;
#define STACK_WORDS 16
-static bool signal_has_si_addr(int si_signo, int si_code) {
- // Manually sent signals won't have si_addr.
- if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
- return false;
- }
-
- switch (si_signo) {
- case SIGBUS:
- case SIGFPE:
- case SIGILL:
- case SIGSEGV:
- case SIGTRAP:
- return true;
- default:
- return false;
- }
-}
-
-static const char* get_signame(int sig) {
- switch (sig) {
- case SIGABRT: return "SIGABRT";
- case SIGBUS: return "SIGBUS";
- case SIGFPE: return "SIGFPE";
- case SIGILL: return "SIGILL";
- case SIGSEGV: return "SIGSEGV";
-#if defined(SIGSTKFLT)
- case SIGSTKFLT: return "SIGSTKFLT";
-#endif
- case SIGSTOP: return "SIGSTOP";
- case SIGSYS: return "SIGSYS";
- case SIGTRAP: return "SIGTRAP";
- case DEBUGGER_SIGNAL: return "<debuggerd signal>";
- default: return "?";
- }
-}
-
-static const char* get_sigcode(int signo, int code) {
- // Try the signal-specific codes...
- switch (signo) {
- case SIGILL:
- switch (code) {
- case ILL_ILLOPC: return "ILL_ILLOPC";
- case ILL_ILLOPN: return "ILL_ILLOPN";
- case ILL_ILLADR: return "ILL_ILLADR";
- case ILL_ILLTRP: return "ILL_ILLTRP";
- case ILL_PRVOPC: return "ILL_PRVOPC";
- case ILL_PRVREG: return "ILL_PRVREG";
- case ILL_COPROC: return "ILL_COPROC";
- case ILL_BADSTK: return "ILL_BADSTK";
- }
- static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
- break;
- case SIGBUS:
- switch (code) {
- case BUS_ADRALN: return "BUS_ADRALN";
- case BUS_ADRERR: return "BUS_ADRERR";
- case BUS_OBJERR: return "BUS_OBJERR";
- case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
- case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
- }
- static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
- break;
- case SIGFPE:
- switch (code) {
- case FPE_INTDIV: return "FPE_INTDIV";
- case FPE_INTOVF: return "FPE_INTOVF";
- case FPE_FLTDIV: return "FPE_FLTDIV";
- case FPE_FLTOVF: return "FPE_FLTOVF";
- case FPE_FLTUND: return "FPE_FLTUND";
- case FPE_FLTRES: return "FPE_FLTRES";
- case FPE_FLTINV: return "FPE_FLTINV";
- case FPE_FLTSUB: return "FPE_FLTSUB";
- }
- static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
- break;
- case SIGSEGV:
- switch (code) {
- case SEGV_MAPERR: return "SEGV_MAPERR";
- case SEGV_ACCERR: return "SEGV_ACCERR";
-#if defined(SEGV_BNDERR)
- case SEGV_BNDERR: return "SEGV_BNDERR";
-#endif
-#if defined(SEGV_PKUERR)
- case SEGV_PKUERR: return "SEGV_PKUERR";
-#endif
- }
-#if defined(SEGV_PKUERR)
- static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
-#elif defined(SEGV_BNDERR)
- static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
-#else
- static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
-#endif
- break;
-#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
- case SIGSYS:
- switch (code) {
- case SYS_SECCOMP: return "SYS_SECCOMP";
- }
- static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
- break;
-#endif
- case SIGTRAP:
- switch (code) {
- case TRAP_BRKPT: return "TRAP_BRKPT";
- case TRAP_TRACE: return "TRAP_TRACE";
- case TRAP_BRANCH: return "TRAP_BRANCH";
- case TRAP_HWBKPT: return "TRAP_HWBKPT";
- }
- if ((code & 0xff) == SIGTRAP) {
- switch ((code >> 8) & 0xff) {
- case PTRACE_EVENT_FORK:
- return "PTRACE_EVENT_FORK";
- case PTRACE_EVENT_VFORK:
- return "PTRACE_EVENT_VFORK";
- case PTRACE_EVENT_CLONE:
- return "PTRACE_EVENT_CLONE";
- case PTRACE_EVENT_EXEC:
- return "PTRACE_EVENT_EXEC";
- case PTRACE_EVENT_VFORK_DONE:
- return "PTRACE_EVENT_VFORK_DONE";
- case PTRACE_EVENT_EXIT:
- return "PTRACE_EVENT_EXIT";
- case PTRACE_EVENT_SECCOMP:
- return "PTRACE_EVENT_SECCOMP";
- case PTRACE_EVENT_STOP:
- return "PTRACE_EVENT_STOP";
- }
- }
- static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
- break;
- }
- // Then the other codes...
- switch (code) {
- case SI_USER: return "SI_USER";
- case SI_KERNEL: return "SI_KERNEL";
- case SI_QUEUE: return "SI_QUEUE";
- case SI_TIMER: return "SI_TIMER";
- case SI_MESGQ: return "SI_MESGQ";
- case SI_ASYNCIO: return "SI_ASYNCIO";
- case SI_SIGIO: return "SI_SIGIO";
- case SI_TKILL: return "SI_TKILL";
- case SI_DETHREAD: return "SI_DETHREAD";
- }
- // Then give up...
- return "?";
-}
-
static void dump_header_info(log_t* log) {
auto fingerprint = GetProperty("ro.build.fingerprint", "unknown");
auto revision = GetProperty("ro.revision", "unknown");
@@ -216,73 +76,64 @@
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
-static void dump_probable_cause(log_t* log, const siginfo_t& si) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si) {
std::string cause;
- if (si.si_signo == SIGSEGV && si.si_code == SEGV_MAPERR) {
- if (si.si_addr < reinterpret_cast<void*>(4096)) {
+ if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
+ if (si->si_addr < reinterpret_cast<void*>(4096)) {
cause = StringPrintf("null pointer dereference");
- } else if (si.si_addr == reinterpret_cast<void*>(0xffff0ffc)) {
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0ffc)) {
cause = "call to kuser_helper_version";
- } else if (si.si_addr == reinterpret_cast<void*>(0xffff0fe0)) {
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fe0)) {
cause = "call to kuser_get_tls";
- } else if (si.si_addr == reinterpret_cast<void*>(0xffff0fc0)) {
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fc0)) {
cause = "call to kuser_cmpxchg";
- } else if (si.si_addr == reinterpret_cast<void*>(0xffff0fa0)) {
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fa0)) {
cause = "call to kuser_memory_barrier";
- } else if (si.si_addr == reinterpret_cast<void*>(0xffff0f60)) {
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
cause = "call to kuser_cmpxchg64";
}
- } else if (si.si_signo == SIGSYS && si.si_code == SYS_SECCOMP) {
- cause = StringPrintf("seccomp prevented call to disallowed %s system call %d",
- ABI_STRING, si.si_syscall);
+ } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
+ cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
+ si->si_syscall);
}
if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
}
-static void dump_signal_info(log_t* log, const siginfo_t* siginfo) {
- const siginfo_t& si = *siginfo;
+static void dump_signal_info(log_t* log, const siginfo_t* si) {
char addr_desc[32]; // ", fault addr 0x1234"
- if (signal_has_si_addr(si.si_signo, si.si_code)) {
- snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
+ if (signal_has_si_addr(si->si_signo, si->si_code)) {
+ snprintf(addr_desc, sizeof(addr_desc), "%p", si->si_addr);
} else {
snprintf(addr_desc, sizeof(addr_desc), "--------");
}
- _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si.si_signo,
- get_signame(si.si_signo), si.si_code, get_sigcode(si.si_signo, si.si_code), addr_desc);
+ _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si->si_signo,
+ get_signame(si->si_signo), si->si_code, get_sigcode(si->si_signo, si->si_code), addr_desc);
dump_probable_cause(log, si);
}
-static void dump_signal_info(log_t* log, pid_t tid) {
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
- ALOGE("cannot get siginfo: %s\n", strerror(errno));
- return;
- }
-
- dump_signal_info(log, &si);
-}
-
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, const char* process_name,
- const char* thread_name) {
+static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
// Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
// TODO: Why is this controlled by thread name?
- if (strcmp(thread_name, "logd") == 0 || strncmp(thread_name, "logd.", 4) == 0) {
+ if (thread_info.thread_name == "logd" ||
+ android::base::StartsWith(thread_info.thread_name, "logd.")) {
log->should_retrieve_logcat = false;
}
- _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, thread_name,
- process_name);
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", thread_info.pid,
+ thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
}
-static void dump_stack_segment(
- Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
+static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
+ uintptr_t* sp, size_t words, int label) {
// Read the data all at once.
word_t stack_data[words];
- size_t bytes_read = backtrace->Read(*sp, reinterpret_cast<uint8_t*>(&stack_data[0]), sizeof(word_t) * 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);
words = bytes_read / sizeof(word_t);
std::string line;
for (size_t i = 0; i < words; i++) {
@@ -296,11 +147,11 @@
line += StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]);
backtrace_map_t map;
- backtrace->FillInMap(stack_data[i], &map);
+ backtrace_map->FillIn(stack_data[i], &map);
if (BacktraceMap::IsValid(map) && !map.name.empty()) {
line += " " + map.name;
uintptr_t offset = 0;
- std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset, &map));
+ std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
if (!func_name.empty()) {
line += " (" + func_name;
if (offset) {
@@ -315,36 +166,38 @@
}
}
-static void dump_stack(Backtrace* backtrace, log_t* log) {
+static void dump_stack(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
+ std::vector<backtrace_frame_data_t>& frames) {
size_t first = 0, last;
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
- if (frame->sp) {
+ for (size_t i = 0; i < frames.size(); i++) {
+ const backtrace_frame_data_t& frame = frames[i];
+ if (frame.sp) {
if (!first) {
first = i+1;
}
last = i;
}
}
+
if (!first) {
return;
}
first--;
// Dump a few words before the first frame.
- word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
- dump_stack_segment(backtrace, log, &sp, STACK_WORDS, -1);
+ word_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
+ dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1);
// 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 = backtrace->GetFrame(i);
+ const backtrace_frame_data_t* frame = &frames[i];
if (sp != frame->sp) {
_LOG(log, logtype::STACK, " ........ ........\n");
sp = frame->sp;
}
if (i == last) {
- dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
+ dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, i);
if (sp < frame->sp + frame->stack_size) {
_LOG(log, logtype::STACK, " ........ ........\n");
}
@@ -355,7 +208,7 @@
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
- dump_stack_segment(backtrace, log, &sp, words, i);
+ dump_stack_segment(log, backtrace_map, process_memory, &sp, words, i);
}
}
}
@@ -372,44 +225,34 @@
return addr_str;
}
-static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t address) {
+static void dump_abort_message(log_t* log, Memory* process_memory, uintptr_t address) {
if (address == 0) {
return;
}
- address += sizeof(size_t); // Skip the buffer length.
+ size_t length;
+ if (!process_memory->ReadFully(address, &length, sizeof(length))) {
+ _LOG(log, logtype::HEADER, "Failed to read abort message header: %s\n", strerror(errno));
+ return;
+ }
char msg[512];
- memset(msg, 0, sizeof(msg));
- char* p = &msg[0];
- while (p < &msg[sizeof(msg)]) {
- word_t data;
- size_t len = sizeof(word_t);
- if (!backtrace->ReadWord(address, &data)) {
- break;
- }
- address += sizeof(word_t);
-
- while (len > 0 && (*p++ = (data >> (sizeof(word_t) - len) * 8) & 0xff) != 0) {
- len--;
- }
+ if (length >= sizeof(msg)) {
+ _LOG(log, logtype::HEADER, "Abort message too long: claimed length = %zd\n", length);
+ return;
}
- msg[sizeof(msg) - 1] = '\0';
+ if (!process_memory->ReadFully(address + sizeof(length), msg, length)) {
+ _LOG(log, logtype::HEADER, "Failed to read abort message: %s\n", strerror(errno));
+ return;
+ }
+
+ msg[length] = '\0';
_LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
}
-static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) {
- bool print_fault_address_marker = false;
- uintptr_t addr = 0;
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) != -1) {
- print_fault_address_marker = signal_has_si_addr(si.si_signo, si.si_code);
- addr = reinterpret_cast<uintptr_t>(si.si_addr);
- } else {
- ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
- }
+static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uintptr_t addr) {
+ bool print_fault_address_marker = addr;
ScopedBacktraceMapIteratorLock lock(map);
_LOG(log, logtype::MAPS,
@@ -464,7 +307,7 @@
space_needed = false;
line += " " + entry->name;
std::string build_id;
- if ((entry->flags & PROT_READ) && elf_get_build_id(backtrace, entry->start, &build_id)) {
+ if ((entry->flags & PROT_READ) && elf_get_build_id(process_memory, entry->start, &build_id)) {
line += " (BuildId: " + build_id + ")";
}
}
@@ -482,50 +325,117 @@
}
}
-static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
- if (backtrace->NumFrames()) {
- _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
- dump_backtrace_to_log(backtrace, log, " ");
-
- _LOG(log, logtype::STACK, "\nstack:\n");
- dump_stack(backtrace, log);
+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());
}
}
-// Weak noop implementation, real implementations are in <arch>/machine.cpp.
-__attribute__((weak)) void dump_registers(log_t* log, const ucontext_t*) {
- _LOG(log, logtype::REGISTERS, " register dumping unimplemented on this architecture");
+static void print_register_row(log_t* log,
+ const std::vector<std::pair<std::string, uint64_t>>& registers) {
+ std::string output;
+ for (auto& [name, value] : registers) {
+ output += android::base::StringPrintf(" %-3s %0*" PRIxPTR, name.c_str(),
+ static_cast<int>(2 * sizeof(void*)),
+ static_cast<uintptr_t>(value));
+ }
+
+ _LOG(log, logtype::REGISTERS, " %s\n", output.c_str());
}
-static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
- const std::string& thread_name, BacktraceMap* map,
- uintptr_t abort_msg_address, bool primary_thread) {
- log->current_tid = tid;
+void dump_registers(log_t* log, 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;
+ std::vector<std::pair<std::string, uint64_t>> special_row;
+
+#if defined(__arm__) || defined(__aarch64__)
+ static constexpr const char* special_registers[] = {"ip", "lr", "sp", "pc"};
+#elif defined(__i386__)
+ static constexpr const char* special_registers[] = {"ebp", "esp", "eip"};
+#elif defined(__x86_64__)
+ static constexpr const char* special_registers[] = {"rbp", "rsp", "rip"};
+#else
+ static constexpr const char* special_registers[] = {};
+#endif
+
+ regs->IterateRegisters([log, ¤t_row, &special_row](const char* name, uint64_t value) {
+ auto row = ¤t_row;
+ for (const char* special_name : special_registers) {
+ if (strcmp(special_name, name) == 0) {
+ row = &special_row;
+ break;
+ }
+ }
+
+ row->emplace_back(name, value);
+ if (current_row.size() == column_count) {
+ print_register_row(log, current_row);
+ current_row.clear();
+ }
+ });
+
+ if (!current_row.empty()) {
+ print_register_row(log, current_row);
+ }
+
+ print_register_row(log, special_row);
+}
+
+void dump_memory_and_code(log_t* log, Memory* memory, Regs* regs) {
+ regs->IterateRegisters([log, memory](const char* name, uint64_t value) {
+ dump_memory(log, memory, value, "memory near %s:", name);
+ });
+}
+
+static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory,
+ const ThreadInfo& thread_info, uintptr_t abort_msg_address,
+ bool primary_thread) {
+ UNUSED(process_memory);
+ log->current_tid = thread_info.tid;
if (!primary_thread) {
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
}
- dump_thread_info(log, pid, tid, process_name.c_str(), thread_name.c_str());
- dump_signal_info(log, tid);
+ dump_thread_info(log, thread_info);
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
- if (primary_thread) {
- dump_abort_message(backtrace.get(), log, abort_msg_address);
+ if (thread_info.siginfo) {
+ dump_signal_info(log, thread_info.siginfo);
}
- dump_registers(log, tid);
- if (backtrace->Unwind(0)) {
- dump_backtrace_and_stack(backtrace.get(), log);
- } else {
- ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
+
+ dump_registers(log, thread_info.registers.get());
+
+ std::vector<backtrace_frame_data_t> frames;
+ if (!Backtrace::Unwind(thread_info.registers.get(), map, &frames, 0, nullptr)) {
+ _LOG(log, logtype::THREAD, "Failed to unwind");
+ return false;
+ }
+
+ if (!frames.empty()) {
+ _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
+ dump_backtrace(log, frames, " ");
+
+ _LOG(log, logtype::STACK, "\nstack:\n");
+ dump_stack(log, map, process_memory, frames);
}
if (primary_thread) {
- dump_memory_and_code(log, backtrace.get());
+ dump_abort_message(log, process_memory, abort_msg_address);
+ }
+
+ if (primary_thread) {
+ dump_memory_and_code(log, process_memory, thread_info.registers.get());
if (map) {
- dump_all_maps(backtrace.get(), map, log, tid);
+ uintptr_t addr = 0;
+ siginfo_t* si = thread_info.siginfo;
+ if (signal_has_si_addr(si->si_signo, si->si_code)) {
+ addr = reinterpret_cast<uintptr_t>(si->si_addr);
+ }
+ dump_all_maps(log, map, process_memory, addr);
}
}
log->current_tid = log->crashed_tid;
+ return true;
}
// Reads the contents of the specified log device, filters out the entries
@@ -534,8 +444,7 @@
// If "tail" is non-zero, log the last "tail" number of lines.
static EventTagMap* g_eventTagMap = NULL;
-static void dump_log_file(
- log_t* log, pid_t pid, const char* filename, unsigned int tail) {
+static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned int tail) {
bool first = true;
struct logger_list* logger_list;
@@ -654,56 +563,15 @@
// Dumps the logs generated by the specified pid to the tombstone, from both
// "system" and "main" log devices. Ideally we'd interleave the output.
static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
+ if (pid == getpid()) {
+ // Cowardly refuse to dump logs while we're running in-process.
+ return;
+ }
+
dump_log_file(log, pid, "system", tail);
dump_log_file(log, pid, "main", tail);
}
-// Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, 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, uintptr_t abort_msg_address) {
- // don't copy log messages to tombstone unless this is a dev device
- bool want_logs = GetBoolProperty("ro.debuggable", false);
-
- _LOG(log, logtype::HEADER,
- "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
- dump_header_info(log);
- dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true);
- if (want_logs) {
- dump_logs(log, pid, 5);
- }
-
- for (const auto& it : threads) {
- pid_t thread_tid = it.first;
- const std::string& thread_name = it.second;
-
- if (thread_tid != tid) {
- dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false);
- }
- }
-
- if (open_files) {
- _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
- dump_open_files_list_to_log(*open_files, log, " ");
- }
-
- if (want_logs) {
- dump_logs(log, pid, 0);
- }
-}
-
-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, uintptr_t abort_msg_address,
- std::string* amfd_data) {
- log_t log;
- log.current_tid = tid;
- log.crashed_tid = tid;
- log.tfd = tombstone_fd;
- log.amfd_data = amfd_data;
- dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address);
-}
-
void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext) {
pid_t pid = getpid();
@@ -721,31 +589,69 @@
read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
- _LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
- dump_header_info(&log);
- dump_thread_info(&log, pid, tid, thread_name, process_name);
- dump_signal_info(&log, siginfo);
+ std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
- dump_abort_message(backtrace.get(), &log, abort_msg_address);
- dump_registers(&log, ucontext);
+ std::map<pid_t, ThreadInfo> threads;
+ threads[gettid()] = ThreadInfo{
+ .registers = std::move(regs),
+ .tid = tid,
+ .thread_name = thread_name,
+ .pid = pid,
+ .process_name = process_name,
+ .siginfo = siginfo,
+ };
- if (backtrace->Unwind(0, ucontext)) {
- dump_backtrace_and_stack(backtrace.get(), &log);
- } else {
- ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid(), false));
+ if (!backtrace_map) {
+ ALOGE("failed to create backtrace map");
+ _exit(1);
}
- // TODO: Make this match the format of dump_all_maps above.
- _LOG(&log, logtype::MAPS, "memory map:\n");
- android::base::unique_fd maps_fd(open("/proc/self/maps", O_RDONLY | O_CLOEXEC));
- if (maps_fd == -1) {
- _LOG(&log, logtype::MAPS, " failed to open /proc/self/maps: %s", strerror(errno));
- } else {
- char buf[256];
- ssize_t rc;
- while ((rc = TEMP_FAILURE_RETRY(read(maps_fd.get(), buf, sizeof(buf)))) > 0) {
- android::base::WriteFully(tombstone_fd, buf, rc);
+ 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);
+}
+
+void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory,
+ const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
+ uintptr_t abort_msg_address, OpenFilesList* open_files,
+ std::string* amfd_data) {
+ // don't copy log messages to tombstone unless this is a dev device
+ bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
+
+ log_t log;
+ log.current_tid = target_thread;
+ log.crashed_tid = target_thread;
+ log.tfd = output_fd.get();
+ log.amfd_data = amfd_data;
+
+ _LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+ dump_header_info(&log);
+
+ auto it = threads.find(target_thread);
+ if (it == threads.end()) {
+ LOG(FATAL) << "failed to find target thread";
+ }
+ dump_thread(&log, map, process_memory, it->second, abort_msg_address, true);
+
+ if (want_logs) {
+ dump_logs(&log, it->second.pid, 5);
+ }
+
+ for (auto& [tid, thread_info] : threads) {
+ if (tid == target_thread) {
+ continue;
}
+
+ dump_thread(&log, map, process_memory, thread_info, 0, false);
+ }
+
+ if (open_files) {
+ _LOG(&log, logtype::OPEN_FILES, "\nopen files:\n");
+ dump_open_files_list(&log, *open_files, " ");
+ }
+
+ if (want_logs) {
+ dump_logs(&log, it->second.pid, 0);
}
}
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 1b74652..247d806 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -21,6 +21,8 @@
#include <errno.h>
#include <signal.h>
#include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/wait.h>
@@ -34,7 +36,9 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
+#include <debuggerd/handler.h>
#include <log/log.h>
+#include <unwindstack/Memory.h>
using android::base::unique_fd;
@@ -117,34 +121,10 @@
}
}
-bool wait_for_signal(pid_t tid, siginfo_t* siginfo) {
- while (true) {
- int status;
- pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL));
- if (n == -1) {
- ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
- return false;
- } else if (n == tid) {
- if (WIFSTOPPED(status)) {
- if (ptrace(PTRACE_GETSIGINFO, tid, nullptr, siginfo) != 0) {
- ALOGE("PTRACE_GETSIGINFO failed: %s", strerror(errno));
- return false;
- }
- return true;
- } else {
- ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
- // This is the only circumstance under which we can allow a detach
- // to fail with ESRCH, which indicates the tid has exited.
- return false;
- }
- }
- }
-}
-
#define MEMORY_BYTES_TO_DUMP 256
#define MEMORY_BYTES_PER_LINE 16
-void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
+void dump_memory(log_t* log, unwindstack::Memory* memory, uintptr_t addr, const char* fmt, ...) {
std::string log_msg;
va_list ap;
va_start(ap, fmt);
@@ -172,7 +152,7 @@
// Dump 256 bytes
uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
memset(data, 0, MEMORY_BYTES_TO_DUMP);
- size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
+ size_t bytes = memory->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
if (bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but just in case.
ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
@@ -199,8 +179,8 @@
// into a readable map. Only requires one extra read because a map has
// to contain at least one page, and the total number of bytes to dump
// is smaller than a page.
- size_t bytes2 = backtrace->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
- sizeof(data) - bytes - start);
+ size_t bytes2 = memory->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+ sizeof(data) - bytes - start);
bytes += bytes2;
if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but we'll try and continue any way.
@@ -264,3 +244,169 @@
}
strcpy(buf, default_value);
}
+
+void drop_capabilities() {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ memset(&capdata, 0, sizeof(capdata));
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ PLOG(FATAL) << "failed to drop capabilities";
+ }
+
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
+ PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS";
+ }
+}
+
+bool signal_has_si_addr(int si_signo, int si_code) {
+ // Manually sent signals won't have si_addr.
+ if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+ return false;
+ }
+
+ switch (si_signo) {
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ case SIGSEGV:
+ case SIGTRAP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const char* get_signame(int sig) {
+ switch (sig) {
+ case SIGABRT: return "SIGABRT";
+ case SIGBUS: return "SIGBUS";
+ case SIGFPE: return "SIGFPE";
+ case SIGILL: return "SIGILL";
+ case SIGSEGV: return "SIGSEGV";
+#if defined(SIGSTKFLT)
+ case SIGSTKFLT: return "SIGSTKFLT";
+#endif
+ case SIGSTOP: return "SIGSTOP";
+ case SIGSYS: return "SIGSYS";
+ case SIGTRAP: return "SIGTRAP";
+ case DEBUGGER_SIGNAL: return "<debuggerd signal>";
+ default: return "?";
+ }
+}
+
+const char* get_sigcode(int signo, int code) {
+ // Try the signal-specific codes...
+ switch (signo) {
+ case SIGILL:
+ switch (code) {
+ case ILL_ILLOPC: return "ILL_ILLOPC";
+ case ILL_ILLOPN: return "ILL_ILLOPN";
+ case ILL_ILLADR: return "ILL_ILLADR";
+ case ILL_ILLTRP: return "ILL_ILLTRP";
+ case ILL_PRVOPC: return "ILL_PRVOPC";
+ case ILL_PRVREG: return "ILL_PRVREG";
+ case ILL_COPROC: return "ILL_COPROC";
+ case ILL_BADSTK: return "ILL_BADSTK";
+ }
+ static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
+ break;
+ case SIGBUS:
+ switch (code) {
+ case BUS_ADRALN: return "BUS_ADRALN";
+ case BUS_ADRERR: return "BUS_ADRERR";
+ case BUS_OBJERR: return "BUS_OBJERR";
+ case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
+ case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
+ }
+ static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
+ break;
+ case SIGFPE:
+ switch (code) {
+ case FPE_INTDIV: return "FPE_INTDIV";
+ case FPE_INTOVF: return "FPE_INTOVF";
+ case FPE_FLTDIV: return "FPE_FLTDIV";
+ case FPE_FLTOVF: return "FPE_FLTOVF";
+ case FPE_FLTUND: return "FPE_FLTUND";
+ case FPE_FLTRES: return "FPE_FLTRES";
+ case FPE_FLTINV: return "FPE_FLTINV";
+ case FPE_FLTSUB: return "FPE_FLTSUB";
+ }
+ static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
+ break;
+ case SIGSEGV:
+ switch (code) {
+ case SEGV_MAPERR: return "SEGV_MAPERR";
+ case SEGV_ACCERR: return "SEGV_ACCERR";
+#if defined(SEGV_BNDERR)
+ case SEGV_BNDERR: return "SEGV_BNDERR";
+#endif
+#if defined(SEGV_PKUERR)
+ case SEGV_PKUERR: return "SEGV_PKUERR";
+#endif
+ }
+#if defined(SEGV_PKUERR)
+ static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
+#elif defined(SEGV_BNDERR)
+ static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
+#else
+ static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
+#endif
+ break;
+#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
+ case SIGSYS:
+ switch (code) {
+ case SYS_SECCOMP: return "SYS_SECCOMP";
+ }
+ static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
+ break;
+#endif
+ case SIGTRAP:
+ switch (code) {
+ case TRAP_BRKPT: return "TRAP_BRKPT";
+ case TRAP_TRACE: return "TRAP_TRACE";
+ case TRAP_BRANCH: return "TRAP_BRANCH";
+ case TRAP_HWBKPT: return "TRAP_HWBKPT";
+ }
+ if ((code & 0xff) == SIGTRAP) {
+ switch ((code >> 8) & 0xff) {
+ case PTRACE_EVENT_FORK:
+ return "PTRACE_EVENT_FORK";
+ case PTRACE_EVENT_VFORK:
+ return "PTRACE_EVENT_VFORK";
+ case PTRACE_EVENT_CLONE:
+ return "PTRACE_EVENT_CLONE";
+ case PTRACE_EVENT_EXEC:
+ return "PTRACE_EVENT_EXEC";
+ case PTRACE_EVENT_VFORK_DONE:
+ return "PTRACE_EVENT_VFORK_DONE";
+ case PTRACE_EVENT_EXIT:
+ return "PTRACE_EVENT_EXIT";
+ case PTRACE_EVENT_SECCOMP:
+ return "PTRACE_EVENT_SECCOMP";
+ case PTRACE_EVENT_STOP:
+ return "PTRACE_EVENT_STOP";
+ }
+ }
+ static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
+ break;
+ }
+ // Then the other codes...
+ switch (code) {
+ case SI_USER: return "SI_USER";
+ case SI_KERNEL: return "SI_KERNEL";
+ case SI_QUEUE: return "SI_QUEUE";
+ case SI_TIMER: return "SI_TIMER";
+ case SI_MESGQ: return "SI_MESGQ";
+ case SI_ASYNCIO: return "SI_ASYNCIO";
+ case SI_SIGIO: return "SI_SIGIO";
+ case SI_TKILL: return "SI_TKILL";
+ case SI_DETHREAD: return "SI_DETHREAD";
+ }
+ // Then give up...
+ return "?";
+}
diff --git a/debuggerd/libdebuggerd/x86/machine.cpp b/debuggerd/libdebuggerd/x86/machine.cpp
deleted file mode 100644
index 09a64cd..0000000
--- a/debuggerd/libdebuggerd/x86/machine.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2006, 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/machine.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-
-#include <backtrace/Backtrace.h>
-#include <log/log.h>
-
-#include "libdebuggerd/utility.h"
-
-void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
- struct pt_regs r;
- if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.eax), "memory near eax:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.ebx), "memory near ebx:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.ecx), "memory near ecx:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.edx), "memory near edx:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.esi), "memory near esi:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.edi), "memory near edi:");
-
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.eip), "code around eip:");
-}
-
-void dump_registers(log_t* log, pid_t tid) {
- struct pt_regs r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- _LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
- r.eax, r.ebx, r.ecx, r.edx);
- _LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
- r.esi, r.edi);
- _LOG(log, logtype::REGISTERS, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
- r.xcs, r.xds, r.xes, r.xfs, r.xss);
- _LOG(log, logtype::REGISTERS, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
- r.eip, r.ebp, r.esp, r.eflags);
-}
diff --git a/debuggerd/libdebuggerd/x86_64/machine.cpp b/debuggerd/libdebuggerd/x86_64/machine.cpp
deleted file mode 100644
index de1c268..0000000
--- a/debuggerd/libdebuggerd/x86_64/machine.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-** Copyright 2013, 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/machine.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/user.h>
-
-#include <backtrace/Backtrace.h>
-#include <log/log.h>
-
-#include "libdebuggerd/utility.h"
-
-void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
- struct user_regs_struct r;
- if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rax), "memory near rax:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rbx), "memory near rbx:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rcx), "memory near rcx:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdx), "memory near rdx:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rsi), "memory near rsi:");
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdi), "memory near rdi:");
-
- dump_memory(log, backtrace, static_cast<uintptr_t>(r.rip), "code around rip:");
-}
-
-void dump_registers(log_t* log, pid_t tid) {
- struct user_regs_struct r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- ALOGE("cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
- r.rax, r.rbx, r.rcx, r.rdx);
- _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
- r.rsi, r.rdi);
- _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
- r.r8, r.r9, r.r10, r.r11);
- _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
- r.r12, r.r13, r.r14, r.r15);
- _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
- r.cs, r.ss);
- _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
- r.rip, r.rbp, r.rsp, r.eflags);
-}