summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Gao2017-08-21 16:31:17 -0500
committerJosh Gao2017-12-15 16:11:12 -0600
commit2b2ae0c88ef83c4c53297ff54fa601b18c014fa4 (patch)
tree832d3ab764da9a63d4e22001f18045fa13078dd5 /debuggerd
parent385ea22741ed5bad794fb6b1dff2b46481f241c4 (diff)
downloadplatform-system-core-2b2ae0c88ef83c4c53297ff54fa601b18c014fa4.tar.gz
platform-system-core-2b2ae0c88ef83c4c53297ff54fa601b18c014fa4.tar.xz
platform-system-core-2b2ae0c88ef83c4c53297ff54fa601b18c014fa4.zip
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
Diffstat (limited to 'debuggerd')
-rw-r--r--debuggerd/Android.bp28
-rw-r--r--debuggerd/crash_dump.cpp505
-rw-r--r--debuggerd/debuggerd_test.cpp34
-rw-r--r--debuggerd/handler/debuggerd_fallback.cpp96
-rw-r--r--debuggerd/handler/debuggerd_handler.cpp284
-rw-r--r--debuggerd/libdebuggerd/arm/machine.cpp91
-rw-r--r--debuggerd/libdebuggerd/arm64/machine.cpp105
-rw-r--r--debuggerd/libdebuggerd/backtrace.cpp81
-rw-r--r--debuggerd/libdebuggerd/elf_utils.cpp28
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h13
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h6
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/machine.h30
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h2
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h16
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/types.h (renamed from debuggerd/libdebuggerd/test/ptrace_fake.h)22
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/utility.h46
-rw-r--r--debuggerd/libdebuggerd/mips/machine.cpp99
-rw-r--r--debuggerd/libdebuggerd/mips64/machine.cpp99
-rw-r--r--debuggerd/libdebuggerd/open_files_list.cpp2
-rw-r--r--debuggerd/libdebuggerd/test/BacktraceMock.h74
-rw-r--r--debuggerd/libdebuggerd/test/dump_memory_test.cpp150
-rw-r--r--debuggerd/libdebuggerd/test/elf_fake.cpp6
-rw-r--r--debuggerd/libdebuggerd/test/ptrace_fake.cpp53
-rw-r--r--debuggerd/libdebuggerd/test/tombstone_test.cpp173
-rw-r--r--debuggerd/libdebuggerd/tombstone.cpp536
-rw-r--r--debuggerd/libdebuggerd/utility.cpp202
-rw-r--r--debuggerd/libdebuggerd/x86/machine.cpp63
-rw-r--r--debuggerd/libdebuggerd/x86_64/machine.cpp68
-rw-r--r--debuggerd/protocol.h11
-rw-r--r--debuggerd/util.cpp16
-rw-r--r--debuggerd/util.h5
31 files changed, 1173 insertions, 1771 deletions
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 17a9f3a7c..c473e3395 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -4,9 +4,12 @@ cc_defaults {
4 "-Wall", 4 "-Wall",
5 "-Wextra", 5 "-Wextra",
6 "-Werror", 6 "-Werror",
7 "-Wno-unused-argument",
8 "-Wno-unused-function",
7 "-Wno-nullability-completeness", 9 "-Wno-nullability-completeness",
8 "-Os", 10 "-Os",
9 ], 11 ],
12 cpp_std: "gnu++17",
10 13
11 local_include_dirs: ["include"], 14 local_include_dirs: ["include"],
12} 15}
@@ -73,6 +76,7 @@ cc_library_static {
73 76
74 whole_static_libs: [ 77 whole_static_libs: [
75 "libasync_safe", 78 "libasync_safe",
79 "libcutils",
76 "libdebuggerd", 80 "libdebuggerd",
77 ], 81 ],
78 82
@@ -148,27 +152,6 @@ cc_library_static {
148 "libdebuggerd/utility.cpp", 152 "libdebuggerd/utility.cpp",
149 ], 153 ],
150 154
151 target: {
152 android_arm: {
153 srcs: ["libdebuggerd/arm/machine.cpp"],
154 },
155 android_arm64: {
156 srcs: ["libdebuggerd/arm64/machine.cpp"],
157 },
158 android_mips: {
159 srcs: ["libdebuggerd/mips/machine.cpp"],
160 },
161 android_mips64: {
162 srcs: ["libdebuggerd/mips64/machine.cpp"],
163 },
164 android_x86: {
165 srcs: ["libdebuggerd/x86/machine.cpp"],
166 },
167 android_x86_64: {
168 srcs: ["libdebuggerd/x86_64/machine.cpp"],
169 },
170 },
171
172 local_include_dirs: ["libdebuggerd/include"], 155 local_include_dirs: ["libdebuggerd/include"],
173 export_include_dirs: ["libdebuggerd/include"], 156 export_include_dirs: ["libdebuggerd/include"],
174 157
@@ -193,7 +176,6 @@ cc_test {
193 "libdebuggerd/test/elf_fake.cpp", 176 "libdebuggerd/test/elf_fake.cpp",
194 "libdebuggerd/test/log_fake.cpp", 177 "libdebuggerd/test/log_fake.cpp",
195 "libdebuggerd/test/open_files_list_test.cpp", 178 "libdebuggerd/test/open_files_list_test.cpp",
196 "libdebuggerd/test/ptrace_fake.cpp",
197 "libdebuggerd/test/tombstone_test.cpp", 179 "libdebuggerd/test/tombstone_test.cpp",
198 ], 180 ],
199 181
@@ -218,6 +200,7 @@ cc_test {
218 200
219 static_libs: [ 201 static_libs: [
220 "libdebuggerd", 202 "libdebuggerd",
203 "libunwindstack",
221 ], 204 ],
222 205
223 local_include_dirs: [ 206 local_include_dirs: [
@@ -264,6 +247,7 @@ cc_binary {
264 "libbase", 247 "libbase",
265 "liblog", 248 "liblog",
266 "libprocinfo", 249 "libprocinfo",
250 "libunwindstack",
267 ], 251 ],
268} 252}
269 253
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 827420e1b..a1f021184 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -18,11 +18,11 @@
18#include <dirent.h> 18#include <dirent.h>
19#include <fcntl.h> 19#include <fcntl.h>
20#include <stdlib.h> 20#include <stdlib.h>
21#include <sys/capability.h>
22#include <sys/prctl.h> 21#include <sys/prctl.h>
23#include <sys/ptrace.h> 22#include <sys/ptrace.h>
24#include <sys/types.h> 23#include <sys/types.h>
25#include <sys/un.h> 24#include <sys/un.h>
25#include <sys/wait.h>
26#include <syscall.h> 26#include <syscall.h>
27#include <unistd.h> 27#include <unistd.h>
28 28
@@ -47,6 +47,8 @@
47#define ATRACE_TAG ATRACE_TAG_BIONIC 47#define ATRACE_TAG ATRACE_TAG_BIONIC
48#include <utils/Trace.h> 48#include <utils/Trace.h>
49 49
50#include <unwindstack/Regs.h>
51
50#include "libdebuggerd/backtrace.h" 52#include "libdebuggerd/backtrace.h"
51#include "libdebuggerd/tombstone.h" 53#include "libdebuggerd/tombstone.h"
52#include "libdebuggerd/utility.h" 54#include "libdebuggerd/utility.h"
@@ -58,21 +60,9 @@
58#include "util.h" 60#include "util.h"
59 61
60using android::base::unique_fd; 62using android::base::unique_fd;
61using android::base::ReadFileToString;
62using android::base::StringPrintf; 63using android::base::StringPrintf;
63using android::base::Trim;
64 64
65static std::string get_process_name(pid_t pid) { 65using unwindstack::Regs;
66 std::string result = "<unknown>";
67 ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &result);
68 return result;
69}
70
71static std::string get_thread_name(pid_t tid) {
72 std::string result = "<unknown>";
73 ReadFileToString(StringPrintf("/proc/%d/comm", tid), &result);
74 return Trim(result);
75}
76 66
77static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { 67static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
78 struct stat st; 68 struct stat st;
@@ -90,8 +80,8 @@ static pid_t get_tracer(pid_t tracee) {
90} 80}
91 81
92// Attach to a thread, and verify that it's still a member of the given process 82// Attach to a thread, and verify that it's still a member of the given process
93static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) { 83static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error, int flags = 0) {
94 if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) { 84 if (ptrace(PTRACE_SEIZE, tid, 0, flags) != 0) {
95 if (errno == EPERM) { 85 if (errno == EPERM) {
96 pid_t tracer = get_tracer(tid); 86 pid_t tracer = get_tracer(tid);
97 if (tracer != -1) { 87 if (tracer != -1) {
@@ -108,18 +98,43 @@ static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error)
108 // Make sure that the task we attached to is actually part of the pid we're dumping. 98 // Make sure that the task we attached to is actually part of the pid we're dumping.
109 if (!pid_contains_tid(pid_proc_fd, tid)) { 99 if (!pid_contains_tid(pid_proc_fd, tid)) {
110 if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { 100 if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
111 PLOG(FATAL) << "failed to detach from thread " << tid; 101 PLOG(WARNING) << "failed to detach from thread " << tid;
112 } 102 }
113 *error = StringPrintf("thread %d is not in process", tid); 103 *error = StringPrintf("thread %d is not in process", tid);
114 return false; 104 return false;
115 } 105 }
116 106
117 // Put the task into ptrace-stop state. 107 return true;
118 if (ptrace(PTRACE_INTERRUPT, tid, 0, 0) != 0) { 108}
119 PLOG(FATAL) << "failed to interrupt thread " << tid; 109
110static bool wait_for_stop(pid_t tid, int* received_signal) {
111 while (true) {
112 int status;
113 pid_t result = waitpid(tid, &status, __WALL);
114 if (result != tid) {
115 PLOG(ERROR) << "waitpid failed on " << tid << " while detaching";
116 return false;
117 }
118
119 if (WIFSTOPPED(status)) {
120 if (status >> 16 == PTRACE_EVENT_STOP) {
121 *received_signal = 0;
122 } else {
123 *received_signal = WSTOPSIG(status);
124 }
125 return true;
126 }
120 } 127 }
128}
121 129
122 return true; 130// Interrupt a process and wait for it to be interrupted.
131static bool ptrace_interrupt(pid_t tid, int* received_signal) {
132 if (ptrace(PTRACE_INTERRUPT, tid, 0, 0) == 0) {
133 return wait_for_stop(tid, received_signal);
134 }
135
136 PLOG(ERROR) << "failed to interrupt " << tid << " to detach";
137 return false;
123} 138}
124 139
125static bool activity_manager_notify(pid_t pid, int signal, const std::string& amfd_data) { 140static bool activity_manager_notify(pid_t pid, int signal, const std::string& amfd_data) {
@@ -169,70 +184,39 @@ static bool activity_manager_notify(pid_t pid, int signal, const std::string& am
169 return true; 184 return true;
170} 185}
171 186
172static void signal_handler(int) { 187// Globals used by the abort handler.
173 // We can't log easily, because the heap might be corrupt. 188static pid_t g_target_thread = -1;
174 // Just die and let the surrounding log context explain things. 189static bool g_tombstoned_connected = false;
175 _exit(1); 190static unique_fd g_tombstoned_socket;
176} 191static unique_fd g_output_fd;
177 192
178static void abort_handler(pid_t target, const bool tombstoned_connected, 193static void Initialize(char** argv) {
179 unique_fd& tombstoned_socket, unique_fd& output_fd, 194 android::base::InitLogging(argv);
180 const char* abort_msg) { 195 android::base::SetAborter([](const char* abort_msg) {
181 // If we abort before we get an output fd, contact tombstoned to let any 196 // If we abort before we get an output fd, contact tombstoned to let any
182 // potential listeners know that we failed. 197 // potential listeners know that we failed.
183 if (!tombstoned_connected) { 198 if (!g_tombstoned_connected) {
184 if (!tombstoned_connect(target, &tombstoned_socket, &output_fd, kDebuggerdAnyIntercept)) { 199 if (!tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd,
185 // We failed to connect, not much we can do. 200 kDebuggerdAnyIntercept)) {
186 LOG(ERROR) << "failed to connected to tombstoned to report failure"; 201 // We failed to connect, not much we can do.
187 _exit(1); 202 LOG(ERROR) << "failed to connected to tombstoned to report failure";
203 _exit(1);
204 }
188 } 205 }
189 }
190
191 dprintf(output_fd.get(), "crash_dump failed to dump process");
192 if (target != 1) {
193 dprintf(output_fd.get(), " %d: %s\n", target, abort_msg);
194 } else {
195 dprintf(output_fd.get(), ": %s\n", abort_msg);
196 }
197
198 _exit(1);
199}
200
201static void drop_capabilities() {
202 ATRACE_CALL();
203 __user_cap_header_struct capheader;
204 memset(&capheader, 0, sizeof(capheader));
205 capheader.version = _LINUX_CAPABILITY_VERSION_3;
206 capheader.pid = 0;
207
208 __user_cap_data_struct capdata[2];
209 memset(&capdata, 0, sizeof(capdata));
210
211 if (capset(&capheader, &capdata[0]) == -1) {
212 PLOG(FATAL) << "failed to drop capabilities";
213 }
214 206
215 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { 207 dprintf(g_output_fd.get(), "crash_dump failed to dump process");
216 PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS"; 208 if (g_target_thread != 1) {
217 } 209 dprintf(g_output_fd.get(), " %d: %s\n", g_target_thread, abort_msg);
218} 210 } else {
219 211 dprintf(g_output_fd.get(), ": %s\n", abort_msg);
220int main(int argc, char** argv) { 212 }
221 atrace_begin(ATRACE_TAG, "before reparent");
222
223 pid_t target = getppid();
224 bool tombstoned_connected = false;
225 unique_fd tombstoned_socket;
226 unique_fd output_fd;
227 213
228 android::base::InitLogging(argv); 214 _exit(1);
229 android::base::SetAborter([&](const char* abort_msg) {
230 abort_handler(target, tombstoned_connected, tombstoned_socket, output_fd, abort_msg);
231 }); 215 });
232 216
233 // Don't try to dump ourselves. 217 // Don't try to dump ourselves.
234 struct sigaction action = {}; 218 struct sigaction action = {};
235 action.sa_handler = signal_handler; 219 action.sa_handler = SIG_DFL;
236 debuggerd_register_handlers(&action); 220 debuggerd_register_handlers(&action);
237 221
238 sigset_t mask; 222 sigset_t mask;
@@ -240,216 +224,328 @@ int main(int argc, char** argv) {
240 if (sigprocmask(SIG_SETMASK, &mask, nullptr) != 0) { 224 if (sigprocmask(SIG_SETMASK, &mask, nullptr) != 0) {
241 PLOG(FATAL) << "failed to set signal mask"; 225 PLOG(FATAL) << "failed to set signal mask";
242 } 226 }
227}
243 228
229static void ParseArgs(int argc, char** argv, pid_t* pseudothread_tid, DebuggerdDumpType* dump_type) {
244 if (argc != 4) { 230 if (argc != 4) {
245 LOG(FATAL) << "Wrong number of args: " << argc << " (expected 4)"; 231 LOG(FATAL) << "wrong number of args: " << argc << " (expected 4)";
246 } 232 }
247 233
248 pid_t main_tid; 234 if (!android::base::ParseInt(argv[1], &g_target_thread, 1, std::numeric_limits<pid_t>::max())) {
249 pid_t pseudothread_tid; 235 LOG(FATAL) << "invalid target tid: " << argv[1];
250 int dump_type;
251
252 if (!android::base::ParseInt(argv[1], &main_tid, 1, std::numeric_limits<pid_t>::max())) {
253 LOG(FATAL) << "invalid main tid: " << argv[1];
254 } 236 }
255 237
256 if (!android::base::ParseInt(argv[2], &pseudothread_tid, 1, std::numeric_limits<pid_t>::max())) { 238 if (!android::base::ParseInt(argv[2], pseudothread_tid, 1, std::numeric_limits<pid_t>::max())) {
257 LOG(FATAL) << "invalid pseudothread tid: " << argv[2]; 239 LOG(FATAL) << "invalid pseudothread tid: " << argv[2];
258 } 240 }
259 241
260 if (!android::base::ParseInt(argv[3], &dump_type, 0, 1)) { 242 int dump_type_int;
243 if (!android::base::ParseInt(argv[3], &dump_type_int, 0, 1)) {
261 LOG(FATAL) << "invalid requested dump type: " << argv[3]; 244 LOG(FATAL) << "invalid requested dump type: " << argv[3];
262 } 245 }
246 *dump_type = static_cast<DebuggerdDumpType>(dump_type_int);
247}
248
249static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
250 std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_address) {
251 std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf;
252 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf)));
253 if (rc == -1) {
254 PLOG(FATAL) << "failed to read target ucontext";
255 } else if (rc != sizeof(CrashInfo)) {
256 LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
257 << sizeof(CrashInfo);
258 }
259
260 CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
261 if (crash_info->version != 1) {
262 LOG(FATAL) << "version mismatch, expected 1, received " << crash_info->version;
263 }
264
265 *siginfo = crash_info->siginfo;
266 regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->ucontext));
267 *abort_address = crash_info->abort_msg_address;
268}
269
270// Wait for a process to clone and return the child's pid.
271// Note: this leaves the parent in PTRACE_EVENT_STOP.
272static pid_t wait_for_clone(pid_t pid, bool resume_child) {
273 int status;
274 pid_t result = TEMP_FAILURE_RETRY(waitpid(pid, &status, __WALL));
275 if (result == -1) {
276 PLOG(FATAL) << "failed to waitpid";
277 }
263 278
264 if (target == 1) { 279 if (WIFEXITED(status)) {
265 LOG(FATAL) << "target died before we could attach (received main tid = " << main_tid << ")"; 280 LOG(FATAL) << "traced process exited with status " << WEXITSTATUS(status);
281 } else if (WIFSIGNALED(status)) {
282 LOG(FATAL) << "traced process exited with signal " << WTERMSIG(status);
283 } else if (!WIFSTOPPED(status)) {
284 LOG(FATAL) << "process didn't stop? (status = " << status << ")";
266 } 285 }
267 286
268 android::procinfo::ProcessInfo target_info; 287 if (status >> 8 != (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
269 if (!android::procinfo::GetProcessInfo(main_tid, &target_info)) { 288 LOG(FATAL) << "process didn't stop due to PTRACE_O_TRACECLONE (status = " << status << ")";
270 LOG(FATAL) << "failed to fetch process info for target " << main_tid;
271 } 289 }
272 290
273 if (main_tid != target_info.tid || target != target_info.pid) { 291 pid_t child;
274 LOG(FATAL) << "target info mismatch, expected pid " << target << ", tid " << main_tid 292 if (ptrace(PTRACE_GETEVENTMSG, pid, 0, &child) != 0) {
275 << ", received pid " << target_info.pid << ", tid " << target_info.tid; 293 PLOG(FATAL) << "failed to get child pid via PTRACE_GETEVENTMSG";
276 } 294 }
277 295
278 // Open /proc/`getppid()` in the original process, and pass it down to the forked child. 296 int stop_signal;
279 std::string target_proc_path = "/proc/" + std::to_string(target); 297 if (!wait_for_stop(child, &stop_signal)) {
298 PLOG(FATAL) << "failed to waitpid on child";
299 }
300
301 CHECK_EQ(0, stop_signal);
302
303 if (resume_child) {
304 if (ptrace(PTRACE_CONT, child, 0, 0) != 0) {
305 PLOG(FATAL) << "failed to resume child (pid = " << child << ")";
306 }
307 }
308
309 return child;
310}
311
312static pid_t wait_for_vm_process(pid_t pseudothread_tid) {
313 // The pseudothread will double-fork, we want its grandchild.
314 pid_t intermediate = wait_for_clone(pseudothread_tid, true);
315 pid_t vm_pid = wait_for_clone(intermediate, false);
316 if (ptrace(PTRACE_DETACH, intermediate, 0, 0) != 0) {
317 PLOG(FATAL) << "failed to detach from intermediate vm process";
318 }
319
320 return vm_pid;
321}
322
323int main(int argc, char** argv) {
324 atrace_begin(ATRACE_TAG, "before reparent");
325 pid_t target_process = getppid();
326
327 // Open /proc/`getppid()` before we daemonize.
328 std::string target_proc_path = "/proc/" + std::to_string(target_process);
280 int target_proc_fd = open(target_proc_path.c_str(), O_DIRECTORY | O_RDONLY); 329 int target_proc_fd = open(target_proc_path.c_str(), O_DIRECTORY | O_RDONLY);
281 if (target_proc_fd == -1) { 330 if (target_proc_fd == -1) {
282 PLOG(FATAL) << "failed to open " << target_proc_path; 331 PLOG(FATAL) << "failed to open " << target_proc_path;
283 } 332 }
284 333
285 // Make sure our parent didn't die. 334 // Make sure getppid() hasn't changed.
286 if (getppid() != target) { 335 if (getppid() != target_process) {
287 PLOG(FATAL) << "parent died"; 336 LOG(FATAL) << "parent died";
288 } 337 }
289
290 atrace_end(ATRACE_TAG); 338 atrace_end(ATRACE_TAG);
291 339
292 // Reparent ourselves to init, so that the signal handler can waitpid on the 340 // Reparent ourselves to init, so that the signal handler can waitpid on the
293 // original process to avoid leaving a zombie for non-fatal dumps. 341 // original process to avoid leaving a zombie for non-fatal dumps.
342 // Move the input/output pipes off of stdout/stderr, out of paranoia.
343 unique_fd output_pipe(dup(STDOUT_FILENO));
344 unique_fd input_pipe(dup(STDIN_FILENO));
345
346 unique_fd fork_exit_read, fork_exit_write;
347 if (!Pipe(&fork_exit_read, &fork_exit_write)) {
348 PLOG(FATAL) << "failed to create pipe";
349 }
350
294 pid_t forkpid = fork(); 351 pid_t forkpid = fork();
295 if (forkpid == -1) { 352 if (forkpid == -1) {
296 PLOG(FATAL) << "fork failed"; 353 PLOG(FATAL) << "fork failed";
297 } else if (forkpid != 0) { 354 } else if (forkpid == 0) {
298 exit(0); 355 fork_exit_read.reset();
356 } else {
357 // We need the pseudothread to live until we get around to verifying the vm pid against it.
358 // The last thing it does is block on a waitpid on us, so wait until our child tells us to die.
359 fork_exit_write.reset();
360 char buf;
361 TEMP_FAILURE_RETRY(read(fork_exit_read.get(), &buf, sizeof(buf)));
362 _exit(0);
299 } 363 }
300 364
301 ATRACE_NAME("after reparent"); 365 ATRACE_NAME("after reparent");
366 pid_t pseudothread_tid;
367 DebuggerdDumpType dump_type;
368 uintptr_t abort_address = 0;
369
370 Initialize(argv);
371 ParseArgs(argc, argv, &pseudothread_tid, &dump_type);
302 372
303 // Die if we take too long. 373 // Die if we take too long.
304 // 374 //
305 // Note: processes with many threads and minidebug-info can take a bit to 375 // Note: processes with many threads and minidebug-info can take a bit to
306 // unwind, do not make this too small. b/62828735 376 // unwind, do not make this too small. b/62828735
307 alarm(5); 377 alarm(30);
308 378
309 std::string attach_error; 379 // Get the process name (aka cmdline).
380 std::string process_name = get_process_name(g_target_thread);
310 381
311 std::map<pid_t, std::string> threads; 382 // Collect the list of open files.
383 OpenFilesList open_files;
384 {
385 ATRACE_NAME("open files");
386 populate_open_files_list(g_target_thread, &open_files);
387 }
388
389 // In order to reduce the duration that we pause the process for, we ptrace
390 // the threads, fetch their registers and associated information, and then
391 // fork a separate process as a snapshot of the process's address space.
392 std::set<pid_t> threads;
393 if (!android::procinfo::GetProcessTids(g_target_thread, &threads)) {
394 PLOG(FATAL) << "failed to get process threads";
395 }
396
397 std::map<pid_t, ThreadInfo> thread_info;
398 siginfo_t siginfo;
399 std::string error;
312 400
313 { 401 {
314 ATRACE_NAME("ptrace"); 402 ATRACE_NAME("ptrace");
315 // Seize the main thread. 403 for (pid_t thread : threads) {
316 if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) { 404 // Trace the pseudothread separately, so we can use different options.
317 LOG(FATAL) << attach_error; 405 if (thread == pseudothread_tid) {
318 } 406 continue;
407 }
319 408
320 // Seize the siblings. 409 if (!ptrace_seize_thread(target_proc_fd, thread, &error)) {
321 { 410 bool fatal = thread == g_target_thread;
322 std::set<pid_t> siblings; 411 LOG(fatal ? FATAL : WARNING) << error;
323 if (!android::procinfo::GetProcessTids(target, &siblings)) {
324 PLOG(FATAL) << "failed to get process siblings";
325 } 412 }
326 413
327 // but not the already attached main thread. 414 ThreadInfo info;
328 siblings.erase(main_tid); 415 info.pid = target_process;
329 // or the handler pseudothread. 416 info.tid = thread;
330 siblings.erase(pseudothread_tid); 417 info.process_name = process_name;
418 info.thread_name = get_thread_name(thread);
331 419
332 for (pid_t sibling_tid : siblings) { 420 if (!ptrace_interrupt(thread, &info.signo)) {
333 if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { 421 PLOG(WARNING) << "failed to ptrace interrupt thread " << thread;
334 LOG(WARNING) << attach_error; 422 ptrace(PTRACE_DETACH, thread, 0, 0);
335 } else { 423 continue;
336 threads.emplace(sibling_tid, get_thread_name(sibling_tid)); 424 }
425
426 if (thread == g_target_thread) {
427 // Read the thread's registers along with the rest of the crash info out of the pipe.
428 ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_address);
429 info.siginfo = &siginfo;
430 info.signo = info.siginfo->si_signo;
431 } else {
432 info.registers.reset(Regs::RemoteGet(thread));
433 if (!info.registers) {
434 PLOG(WARNING) << "failed to fetch registers for thread " << thread;
435 ptrace(PTRACE_DETACH, thread, 0, 0);
436 continue;
337 } 437 }
338 } 438 }
439
440 thread_info[thread] = std::move(info);
339 } 441 }
340 } 442 }
341 443
342 // Collect the backtrace map, open files, and process/thread names, while we still have caps. 444 // Trace the pseudothread with PTRACE_O_TRACECLONE and tell it to fork.
343 std::unique_ptr<BacktraceMap> backtrace_map; 445 if (!ptrace_seize_thread(target_proc_fd, pseudothread_tid, &error, PTRACE_O_TRACECLONE)) {
344 { 446 LOG(FATAL) << "failed to seize pseudothread: " << error;
345 ATRACE_NAME("backtrace map");
346 backtrace_map.reset(BacktraceMap::Create(main_tid));
347 if (!backtrace_map) {
348 LOG(FATAL) << "failed to create backtrace map";
349 }
350 } 447 }
351 448
352 // Collect the list of open files. 449 if (TEMP_FAILURE_RETRY(write(output_pipe.get(), "\1", 1)) != 1) {
353 OpenFilesList open_files; 450 PLOG(FATAL) << "failed to write to pseudothread";
354 {
355 ATRACE_NAME("open files");
356 populate_open_files_list(target, &open_files);
357 } 451 }
358 452
359 std::string process_name = get_process_name(main_tid); 453 pid_t vm_pid = wait_for_vm_process(pseudothread_tid);
360 threads.emplace(main_tid, get_thread_name(main_tid)); 454 if (ptrace(PTRACE_DETACH, pseudothread_tid, 0, 0) != 0) {
455 PLOG(FATAL) << "failed to detach from pseudothread";
456 }
361 457
362 // Drop our capabilities now that we've attached to the threads we care about. 458 // The pseudothread can die now.
363 drop_capabilities(); 459 fork_exit_write.reset();
364 460
365 { 461 // Defer the message until later, for readability.
366 ATRACE_NAME("tombstoned_connect"); 462 bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
367 const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type); 463 if (siginfo.si_signo == DEBUGGER_SIGNAL) {
368 LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum; 464 wait_for_gdb = false;
369 tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
370 } 465 }
371 466
372 // Write a '\1' to stdout to tell the crashing process to resume. 467 // Detach from all of our attached threads before resuming.
373 // It also restores the value of PR_SET_DUMPABLE at this point. 468 for (const auto& [tid, thread] : thread_info) {
374 if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) { 469 int resume_signal = thread.signo == DEBUGGER_SIGNAL ? 0 : thread.signo;
375 PLOG(ERROR) << "failed to communicate to target process"; 470 if (wait_for_gdb) {
376 } 471 resume_signal = 0;
472 if (tgkill(target_process, tid, SIGSTOP) != 0) {
473 PLOG(WARNING) << "failed to send SIGSTOP to " << tid;
474 }
475 }
377 476
378 if (tombstoned_connected) { 477 LOG(DEBUG) << "detaching from thread " << tid;
379 if (TEMP_FAILURE_RETRY(dup2(output_fd.get(), STDOUT_FILENO)) == -1) { 478 if (ptrace(PTRACE_DETACH, tid, 0, resume_signal) != 0) {
380 PLOG(ERROR) << "failed to dup2 output fd (" << output_fd.get() << ") to STDOUT_FILENO"; 479 PLOG(ERROR) << "failed to detach from thread " << tid;
381 } 480 }
382 } else {
383 unique_fd devnull(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
384 TEMP_FAILURE_RETRY(dup2(devnull.get(), STDOUT_FILENO));
385 output_fd = std::move(devnull);
386 } 481 }
387 482
388 LOG(INFO) << "performing dump of process " << target << " (target tid = " << main_tid << ")"; 483 // Drop our capabilities now that we've fetched all of the information we need.
484 drop_capabilities();
389 485
390 // At this point, the thread that made the request has been attached and is 486 {
391 // in ptrace-stopped state. After resumption, the triggering signal that has 487 ATRACE_NAME("tombstoned_connect");
392 // been queued will be delivered. 488 LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type;
393 if (ptrace(PTRACE_CONT, main_tid, 0, 0) != 0) { 489 g_tombstoned_connected =
394 PLOG(ERROR) << "PTRACE_CONT(" << main_tid << ") failed"; 490 tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd, dump_type);
395 exit(1);
396 } 491 }
397 492
398 siginfo_t siginfo = {}; 493 if (g_tombstoned_connected) {
399 { 494 if (TEMP_FAILURE_RETRY(dup2(g_output_fd.get(), STDOUT_FILENO)) == -1) {
400 ATRACE_NAME("wait_for_signal"); 495 PLOG(ERROR) << "failed to dup2 output fd (" << g_output_fd.get() << ") to STDOUT_FILENO";
401 if (!wait_for_signal(main_tid, &siginfo)) {
402 printf("failed to wait for signal in tid %d: %s\n", main_tid, strerror(errno));
403 exit(1);
404 } 496 }
497 } else {
498 unique_fd devnull(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
499 TEMP_FAILURE_RETRY(dup2(devnull.get(), STDOUT_FILENO));
500 g_output_fd = std::move(devnull);
405 } 501 }
406 502
503 LOG(INFO) << "performing dump of process " << target_process << " (target tid = " << g_target_thread
504 << ")";
505
407 int signo = siginfo.si_signo; 506 int signo = siginfo.si_signo;
408 bool fatal_signal = signo != DEBUGGER_SIGNAL; 507 bool fatal_signal = signo != DEBUGGER_SIGNAL;
409 bool backtrace = false; 508 bool backtrace = false;
410 uintptr_t abort_address = 0;
411 509
412 // si_value can represent three things: 510 // si_value is special when used with DEBUGGER_SIGNAL.
413 // 0: dump tombstone 511 // 0: dump tombstone
414 // 1: dump backtrace 512 // 1: dump backtrace
415 // everything else: abort message address (implies dump tombstone) 513 if (!fatal_signal) {
416 if (siginfo.si_value.sival_int == 1) { 514 int si_val = siginfo.si_value.sival_int;
417 backtrace = true; 515 if (si_val == 0) {
418 } else if (siginfo.si_value.sival_ptr != nullptr) { 516 backtrace = false;
419 abort_address = reinterpret_cast<uintptr_t>(siginfo.si_value.sival_ptr); 517 } else if (si_val == 1) {
518 backtrace = true;
519 } else {
520 LOG(WARNING) << "unknown si_value value " << si_val;
521 }
420 } 522 }
421 523
422 // TODO: Use seccomp to lock ourselves down. 524 // TODO: Use seccomp to lock ourselves down.
525 std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(vm_pid, false));
526 if (!map) {
527 LOG(FATAL) << "failed to create backtrace map";
528 }
529
530 std::shared_ptr<unwindstack::Memory> process_memory = map->GetProcessMemory();
531 if (!process_memory) {
532 LOG(FATAL) << "failed to get unwindstack::Memory handle";
533 }
423 534
424 std::string amfd_data; 535 std::string amfd_data;
425 if (backtrace) { 536 if (backtrace) {
426 ATRACE_NAME("dump_backtrace"); 537 ATRACE_NAME("dump_backtrace");
427 dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0); 538 dump_backtrace(std::move(g_output_fd), map.get(), thread_info, g_target_thread);
428 } else { 539 } else {
429 ATRACE_NAME("engrave_tombstone"); 540 ATRACE_NAME("engrave_tombstone");
430 engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid, 541 engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info,
431 process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr); 542 g_target_thread, abort_address, &open_files, &amfd_data);
432 }
433
434 // We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
435 // group-stop state, which is true as long as no stopping signals are sent.
436
437 bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
438 if (!fatal_signal || siginfo.si_code == SI_USER) {
439 // Don't wait_for_gdb when the process didn't actually crash.
440 wait_for_gdb = false;
441 } 543 }
442 544
443 // If the process crashed or we need to send it SIGSTOP for wait_for_gdb, 545 if (fatal_signal) {
444 // get it in a state where it can receive signals, and then send the relevant 546 // Don't try to notify ActivityManager if it just crashed, or we might hang until timeout.
445 // signal. 547 if (thread_info[target_process].thread_name != "system_server") {
446 if (wait_for_gdb || fatal_signal) { 548 activity_manager_notify(target_process, signo, amfd_data);
447 if (ptrace(PTRACE_INTERRUPT, main_tid, 0, 0) != 0) {
448 PLOG(ERROR) << "failed to use PTRACE_INTERRUPT on " << main_tid;
449 }
450
451 if (tgkill(target, main_tid, wait_for_gdb ? SIGSTOP : signo) != 0) {
452 PLOG(ERROR) << "failed to resend signal " << signo << " to " << main_tid;
453 } 549 }
454 } 550 }
455 551
@@ -463,19 +559,12 @@ int main(int argc, char** argv) {
463 "* gdbclient.py -p %d\n" 559 "* gdbclient.py -p %d\n"
464 "*\n" 560 "*\n"
465 "***********************************************************", 561 "***********************************************************",
466 target, target); 562 target_process, target_process);
467 }
468
469 if (fatal_signal) {
470 // Don't try to notify ActivityManager if it just crashed, or we might hang until timeout.
471 if (target_info.name != "system_server" || target_info.uid != AID_SYSTEM) {
472 activity_manager_notify(target, signo, amfd_data);
473 }
474 } 563 }
475 564
476 // Close stdout before we notify tombstoned of completion. 565 // Close stdout before we notify tombstoned of completion.
477 close(STDOUT_FILENO); 566 close(STDOUT_FILENO);
478 if (tombstoned_connected && !tombstoned_notify_completion(tombstoned_socket.get())) { 567 if (g_tombstoned_connected && !tombstoned_notify_completion(g_tombstoned_socket.get())) {
479 LOG(ERROR) << "failed to notify tombstoned of completion"; 568 LOG(ERROR) << "failed to notify tombstoned of completion";
480 } 569 }
481 570
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 8d0c98bb0..0d17a3b5c 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -245,6 +245,8 @@ void CrasherTest::AssertDeath(int signo) {
245 int status; 245 int status;
246 pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0)); 246 pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0));
247 if (pid != crasher_pid) { 247 if (pid != crasher_pid) {
248 printf("failed to wait for crasher (pid %d)\n", crasher_pid);
249 sleep(100);
248 FAIL() << "failed to wait for crasher: " << strerror(errno); 250 FAIL() << "failed to wait for crasher: " << strerror(errno);
249 } 251 }
250 252
@@ -341,13 +343,12 @@ TEST_F(CrasherTest, signal) {
341 int intercept_result; 343 int intercept_result;
342 unique_fd output_fd; 344 unique_fd output_fd;
343 StartProcess([]() { 345 StartProcess([]() {
344 abort(); 346 while (true) {
347 sleep(1);
348 }
345 }); 349 });
346 StartIntercept(&output_fd); 350 StartIntercept(&output_fd);
347 351 FinishCrasher();
348 // Wait for a bit, or we might end up killing the process before the signal
349 // handler even gets a chance to be registered.
350 std::this_thread::sleep_for(100ms);
351 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)); 352 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
352 353
353 AssertDeath(SIGSEGV); 354 AssertDeath(SIGSEGV);
@@ -439,19 +440,6 @@ TEST_F(CrasherTest, wait_for_gdb) {
439 AssertDeath(SIGABRT); 440 AssertDeath(SIGABRT);
440} 441}
441 442
442// wait_for_gdb shouldn't trigger on manually sent signals.
443TEST_F(CrasherTest, wait_for_gdb_signal) {
444 if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
445 FAIL() << "failed to enable wait_for_gdb";
446 }
447
448 StartProcess([]() {
449 abort();
450 });
451 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
452 AssertDeath(SIGSEGV);
453}
454
455TEST_F(CrasherTest, backtrace) { 443TEST_F(CrasherTest, backtrace) {
456 std::string result; 444 std::string result;
457 int intercept_result; 445 int intercept_result;
@@ -596,15 +584,13 @@ TEST_F(CrasherTest, competing_tracer) {
596 int intercept_result; 584 int intercept_result;
597 unique_fd output_fd; 585 unique_fd output_fd;
598 StartProcess([]() { 586 StartProcess([]() {
599 while (true) { 587 raise(SIGABRT);
600 }
601 }); 588 });
602 589
603 StartIntercept(&output_fd); 590 StartIntercept(&output_fd);
604 FinishCrasher();
605 591
606 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0)); 592 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
607 ASSERT_EQ(0, kill(crasher_pid, SIGABRT)); 593 FinishCrasher();
608 594
609 int status; 595 int status;
610 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0)); 596 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
@@ -622,6 +608,10 @@ TEST_F(CrasherTest, competing_tracer) {
622 regex += R"( \(.+debuggerd_test)"; 608 regex += R"( \(.+debuggerd_test)";
623 ASSERT_MATCH(result, regex.c_str()); 609 ASSERT_MATCH(result, regex.c_str());
624 610
611 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
612 ASSERT_TRUE(WIFSTOPPED(status));
613 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
614
625 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT)); 615 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
626 AssertDeath(SIGABRT); 616 AssertDeath(SIGABRT);
627} 617}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 06d4a9b72..5fddddcf2 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -36,10 +36,14 @@
36#include <unistd.h> 36#include <unistd.h>
37 37
38#include <atomic> 38#include <atomic>
39#include <memory>
39 40
40#include <android-base/file.h> 41#include <android-base/file.h>
41#include <android-base/unique_fd.h> 42#include <android-base/unique_fd.h>
42#include <async_safe/log.h> 43#include <async_safe/log.h>
44#include <backtrace/BacktraceMap.h>
45#include <unwindstack/Memory.h>
46#include <unwindstack/Regs.h>
43 47
44#include "debuggerd/handler.h" 48#include "debuggerd/handler.h"
45#include "tombstoned/tombstoned.h" 49#include "tombstoned/tombstoned.h"
@@ -49,6 +53,7 @@
49#include "libdebuggerd/tombstone.h" 53#include "libdebuggerd/tombstone.h"
50 54
51using android::base::unique_fd; 55using android::base::unique_fd;
56using unwindstack::Regs;
52 57
53extern "C" void __linker_enable_fallback_allocator(); 58extern "C" void __linker_enable_fallback_allocator();
54extern "C" void __linker_disable_fallback_allocator(); 59extern "C" void __linker_disable_fallback_allocator();
@@ -61,7 +66,19 @@ extern "C" void __linker_disable_fallback_allocator();
61// exhaustion. 66// exhaustion.
62static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) { 67static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
63 __linker_enable_fallback_allocator(); 68 __linker_enable_fallback_allocator();
64 dump_backtrace_ucontext(output_fd, ucontext); 69 {
70 std::unique_ptr<Regs> regs;
71
72 ThreadInfo thread;
73 thread.pid = getpid();
74 thread.tid = gettid();
75 thread.thread_name = get_thread_name(gettid());
76 thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
77
78 // TODO: Create this once and store it in a global?
79 std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
80 dump_backtrace_thread(output_fd, map.get(), thread);
81 }
65 __linker_disable_fallback_allocator(); 82 __linker_disable_fallback_allocator();
66} 83}
67 84
@@ -162,41 +179,41 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
162 179
163 // Send a signal to all of our siblings, asking them to dump their stack. 180 // Send a signal to all of our siblings, asking them to dump their stack.
164 iterate_siblings( 181 iterate_siblings(
165 [](pid_t tid, int output_fd) { 182 [](pid_t tid, int output_fd) {
166 // Use a pipe, to be able to detect situations where the thread gracefully exits before 183 // Use a pipe, to be able to detect situations where the thread gracefully exits before
167 // receiving our signal. 184 // receiving our signal.
168 unique_fd pipe_read, pipe_write; 185 unique_fd pipe_read, pipe_write;
169 if (!Pipe(&pipe_read, &pipe_write)) { 186 if (!Pipe(&pipe_read, &pipe_write)) {
170 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s", 187 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s",
171 strerror(errno)); 188 strerror(errno));
172 return false; 189 return false;
173 } 190 }
174 191
175 trace_output_fd.store(pipe_write.get()); 192 trace_output_fd.store(pipe_write.get());
176 193
177 siginfo_t siginfo = {}; 194 siginfo_t siginfo = {};
178 siginfo.si_code = SI_QUEUE; 195 siginfo.si_code = SI_QUEUE;
179 siginfo.si_value.sival_int = ~0; 196 siginfo.si_value.sival_int = ~0;
180 siginfo.si_pid = getpid(); 197 siginfo.si_pid = getpid();
181 siginfo.si_uid = getuid(); 198 siginfo.si_uid = getuid();
182 199
183 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) { 200 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
184 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s", 201 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
185 tid, strerror(errno)); 202 tid, strerror(errno));
186 return false; 203 return false;
187 } 204 }
188 205
189 bool success = forward_output(pipe_read.get(), output_fd); 206 bool success = forward_output(pipe_read.get(), output_fd);
190 if (success) { 207 if (success) {
191 // The signaled thread has closed trace_output_fd already. 208 // The signaled thread has closed trace_output_fd already.
192 (void)pipe_write.release(); 209 (void)pipe_write.release();
193 } else { 210 } else {
194 trace_output_fd.store(-1); 211 trace_output_fd.store(-1);
195 } 212 }
196 213
197 return true; 214 return true;
198 }, 215 },
199 output_fd.get()); 216 output_fd.get());
200 217
201 dump_backtrace_footer(output_fd.get()); 218 dump_backtrace_footer(output_fd.get());
202 tombstoned_notify_completion(tombstone_socket.get()); 219 tombstoned_notify_completion(tombstone_socket.get());
@@ -206,7 +223,8 @@ exit:
206} 223}
207 224
208static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) { 225static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
209 // Only allow one thread to handle a crash. 226 // Only allow one thread to handle a crash at a time (this can happen multiple times without
227 // exit, since tombstones can be requested without a real crash happening.)
210 static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER; 228 static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
211 int ret = pthread_mutex_lock(&crash_mutex); 229 int ret = pthread_mutex_lock(&crash_mutex);
212 if (ret != 0) { 230 if (ret != 0) {
@@ -221,11 +239,13 @@ static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_mes
221 if (tombstoned_connected) { 239 if (tombstoned_connected) {
222 tombstoned_notify_completion(tombstone_socket.get()); 240 tombstoned_notify_completion(tombstone_socket.get());
223 } 241 }
242
243 pthread_mutex_unlock(&crash_mutex);
224} 244}
225 245
226extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext, 246extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
227 void* abort_message) { 247 void* abort_message) {
228 if (info->si_signo == DEBUGGER_SIGNAL) { 248 if (info->si_signo == DEBUGGER_SIGNAL && info->si_value.sival_int != 0) {
229 return trace_handler(info, ucontext); 249 return trace_handler(info, ucontext);
230 } else { 250 } else {
231 return crash_handler(info, ucontext, abort_message); 251 return crash_handler(info, ucontext, abort_message);
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index bd202ff14..02bc4b84f 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -44,15 +44,21 @@
44#include <sys/prctl.h> 44#include <sys/prctl.h>
45#include <sys/socket.h> 45#include <sys/socket.h>
46#include <sys/syscall.h> 46#include <sys/syscall.h>
47#include <sys/uio.h>
47#include <sys/un.h> 48#include <sys/un.h>
48#include <sys/wait.h> 49#include <sys/wait.h>
49#include <unistd.h> 50#include <unistd.h>
50 51
51#include <android-base/unique_fd.h> 52#include <android-base/unique_fd.h>
52#include <async_safe/log.h> 53#include <async_safe/log.h>
54#include <cutils/properties.h>
55
56#include <libdebuggerd/utility.h>
53 57
54#include "dump_type.h" 58#include "dump_type.h"
59#include "protocol.h"
55 60
61using android::base::Pipe;
56using android::base::unique_fd; 62using android::base::unique_fd;
57 63
58// see man(2) prctl, specifically the section about PR_GET_NAME 64// see man(2) prctl, specifically the section about PR_GET_NAME
@@ -114,7 +120,7 @@ static void __noreturn __printflike(1, 2) fatal_errno(const char* fmt, ...) {
114 va_list args; 120 va_list args;
115 va_start(args, fmt); 121 va_start(args, fmt);
116 122
117 char buf[4096]; 123 char buf[256];
118 async_safe_format_buffer_va_list(buf, sizeof(buf), fmt, args); 124 async_safe_format_buffer_va_list(buf, sizeof(buf), fmt, args);
119 fatal("%s: %s", buf, strerror(err)); 125 fatal("%s: %s", buf, strerror(err));
120} 126}
@@ -147,7 +153,7 @@ static bool get_main_thread_name(char* buf, size_t len) {
147 * mutex is being held, so we don't want to use any libc functions that 153 * mutex is being held, so we don't want to use any libc functions that
148 * could allocate memory or hold a lock. 154 * could allocate memory or hold a lock.
149 */ 155 */
150static void log_signal_summary(int signum, const siginfo_t* info) { 156static void log_signal_summary(const siginfo_t* info) {
151 char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination 157 char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
152 if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { 158 if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
153 strcpy(thread_name, "<name unknown>"); 159 strcpy(thread_name, "<name unknown>");
@@ -157,57 +163,19 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
157 thread_name[MAX_TASK_NAME_LEN] = 0; 163 thread_name[MAX_TASK_NAME_LEN] = 0;
158 } 164 }
159 165
160 if (signum == DEBUGGER_SIGNAL) { 166 if (info->si_signo == DEBUGGER_SIGNAL) {
161 async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(), 167 async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
162 thread_name); 168 thread_name);
163 return; 169 return;
164 } 170 }
165 171
166 const char* signal_name = "???"; 172 const char* signal_name = get_signame(info->si_signo);
167 bool has_address = false; 173 bool has_address = signal_has_si_addr(info->si_signo, info->si_code);
168 switch (signum) { 174
169 case SIGABRT: 175 // Many signals don't have an address.
170 signal_name = "SIGABRT"; 176 char addr_desc[32] = ""; // ", fault addr 0x1234"
171 break; 177 if (has_address) {
172 case SIGBUS: 178 async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
173 signal_name = "SIGBUS";
174 has_address = true;
175 break;
176 case SIGFPE:
177 signal_name = "SIGFPE";
178 has_address = true;
179 break;
180 case SIGILL:
181 signal_name = "SIGILL";
182 has_address = true;
183 break;
184 case SIGSEGV:
185 signal_name = "SIGSEGV";
186 has_address = true;
187 break;
188#if defined(SIGSTKFLT)
189 case SIGSTKFLT:
190 signal_name = "SIGSTKFLT";
191 break;
192#endif
193 case SIGSYS:
194 signal_name = "SIGSYS";
195 break;
196 case SIGTRAP:
197 signal_name = "SIGTRAP";
198 break;
199 }
200
201 // "info" will be null if the siginfo_t information was not available.
202 // Many signals don't have an address or a code.
203 char code_desc[32]; // ", code -6"
204 char addr_desc[32]; // ", fault addr 0x1234"
205 addr_desc[0] = code_desc[0] = 0;
206 if (info != nullptr) {
207 async_safe_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
208 if (has_address) {
209 async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
210 }
211 } 179 }
212 180
213 char main_thread_name[MAX_TASK_NAME_LEN + 1]; 181 char main_thread_name[MAX_TASK_NAME_LEN + 1];
@@ -216,8 +184,9 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
216 } 184 }
217 185
218 async_safe_format_log( 186 async_safe_format_log(
219 ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s), pid %d (%s)", signum, 187 ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s), code %d (%s)%s in tid %d (%s), pid %d (%s)",
220 signal_name, code_desc, addr_desc, __gettid(), thread_name, __getpid(), main_thread_name); 188 info->si_signo, signal_name, info->si_code, get_sigcode(info->si_signo, info->si_code),
189 addr_desc, __gettid(), thread_name, __getpid(), main_thread_name);
221} 190}
222 191
223/* 192/*
@@ -268,12 +237,44 @@ static void raise_caps() {
268 } 237 }
269} 238}
270 239
240static pid_t __fork() {
241 return clone(nullptr, nullptr, 0, nullptr);
242}
243
244// Double-clone, with CLONE_FILES to share the file descriptor table for kcmp validation.
245// Returns 0 in the orphaned child, the pid of the orphan in the original process, or -1 on failure.
246static void create_vm_process() {
247 pid_t first = clone(nullptr, nullptr, CLONE_FILES, nullptr);
248 if (first == -1) {
249 fatal_errno("failed to clone vm process");
250 } else if (first == 0) {
251 drop_capabilities();
252
253 if (clone(nullptr, nullptr, CLONE_FILES, nullptr) == -1) {
254 _exit(errno);
255 }
256
257 // Exit immediately on both sides of the fork.
258 // crash_dump is ptracing us, so it'll get to do whatever it wants in between.
259 _exit(0);
260 }
261
262 int status;
263 if (TEMP_FAILURE_RETRY(waitpid(first, &status, __WCLONE)) != first) {
264 fatal_errno("failed to waitpid in double fork");
265 } else if (!WIFEXITED(status)) {
266 fatal("intermediate process didn't exit cleanly in double fork (status = %d)", status);
267 } else if (WEXITSTATUS(status)) {
268 fatal("second clone failed: %s", strerror(WEXITSTATUS(status)));
269 }
270}
271
271struct debugger_thread_info { 272struct debugger_thread_info {
272 bool crash_dump_started;
273 pid_t crashing_tid; 273 pid_t crashing_tid;
274 pid_t pseudothread_tid; 274 pid_t pseudothread_tid;
275 int signal_number; 275 siginfo_t* siginfo;
276 siginfo_t* info; 276 void* ucontext;
277 uintptr_t abort_msg;
277}; 278};
278 279
279// Logging and contacting debuggerd requires free file descriptors, which we might not have. 280// Logging and contacting debuggerd requires free file descriptors, which we might not have.
@@ -284,7 +285,8 @@ struct debugger_thread_info {
284static void* pseudothread_stack; 285static void* pseudothread_stack;
285 286
286static DebuggerdDumpType get_dump_type(const debugger_thread_info* thread_info) { 287static DebuggerdDumpType get_dump_type(const debugger_thread_info* thread_info) {
287 if (thread_info->signal_number == DEBUGGER_SIGNAL && thread_info->info->si_value.sival_int) { 288 if (thread_info->siginfo->si_signo == DEBUGGER_SIGNAL &&
289 thread_info->siginfo->si_value.sival_int) {
288 return kDebuggerdNativeBacktrace; 290 return kDebuggerdNativeBacktrace;
289 } 291 }
290 292
@@ -299,25 +301,58 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
299 } 301 }
300 302
301 int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); 303 int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
304 if (devnull == -1) {
305 fatal_errno("failed to open /dev/null");
306 } else if (devnull != 0) {
307 fatal_errno("expected /dev/null fd to be 0, actually %d", devnull);
308 }
302 309
303 // devnull will be 0. 310 // devnull will be 0.
304 TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO)); 311 TEMP_FAILURE_RETRY(dup2(devnull, 1));
305 TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO)); 312 TEMP_FAILURE_RETRY(dup2(devnull, 2));
306 313
307 unique_fd pipe_read, pipe_write; 314 unique_fd input_read, input_write;
308 if (!android::base::Pipe(&pipe_read, &pipe_write)) { 315 unique_fd output_read, output_write;
316 if (!Pipe(&input_read, &input_write) != 0 || !Pipe(&output_read, &output_write)) {
309 fatal_errno("failed to create pipe"); 317 fatal_errno("failed to create pipe");
310 } 318 }
311 319
320 // ucontext_t is absurdly large on AArch64, so piece it together manually with writev.
321 uint32_t version = 1;
322 constexpr size_t expected =
323 sizeof(version) + sizeof(siginfo_t) + sizeof(ucontext_t) + sizeof(uintptr_t);
324
325 errno = 0;
326 if (fcntl(output_write.get(), F_SETPIPE_SZ, expected) < static_cast<int>(expected)) {
327 fatal_errno("failed to set pipe bufer size");
328 }
329
330 struct iovec iovs[4] = {
331 {.iov_base = &version, .iov_len = sizeof(version)},
332 {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)},
333 {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)},
334 {.iov_base = &thread_info->abort_msg, .iov_len = sizeof(uintptr_t)},
335 };
336
337 ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, 4));
338 if (rc == -1) {
339 fatal_errno("failed to write crash info");
340 } else if (rc != expected) {
341 fatal("failed to write crash info, wrote %zd bytes, expected %zd", rc, expected);
342 }
343
312 // Don't use fork(2) to avoid calling pthread_atfork handlers. 344 // Don't use fork(2) to avoid calling pthread_atfork handlers.
313 int forkpid = clone(nullptr, nullptr, 0, nullptr); 345 pid_t crash_dump_pid = __fork();
314 if (forkpid == -1) { 346 if (crash_dump_pid == -1) {
315 async_safe_format_log(ANDROID_LOG_FATAL, "libc", 347 async_safe_format_log(ANDROID_LOG_FATAL, "libc",
316 "failed to fork in debuggerd signal handler: %s", strerror(errno)); 348 "failed to fork in debuggerd signal handler: %s", strerror(errno));
317 } else if (forkpid == 0) { 349 } else if (crash_dump_pid == 0) {
318 TEMP_FAILURE_RETRY(dup2(pipe_write.get(), STDOUT_FILENO)); 350 TEMP_FAILURE_RETRY(dup2(input_write.get(), STDOUT_FILENO));
319 pipe_write.reset(); 351 TEMP_FAILURE_RETRY(dup2(output_read.get(), STDIN_FILENO));
320 pipe_read.reset(); 352 input_read.reset();
353 input_write.reset();
354 output_read.reset();
355 output_write.reset();
321 356
322 raise_caps(); 357 raise_caps();
323 358
@@ -332,45 +367,49 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
332 367
333 execle(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type, 368 execle(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type,
334 nullptr, nullptr); 369 nullptr, nullptr);
335
336 fatal_errno("exec failed"); 370 fatal_errno("exec failed");
337 } else {
338 pipe_write.reset();
339 char buf[4];
340 ssize_t rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), &buf, sizeof(buf)));
341 if (rc == -1) {
342 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s",
343 strerror(errno));
344 } else if (rc == 0) {
345 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec");
346 } else if (rc != 1) {
347 async_safe_format_log(ANDROID_LOG_FATAL, "libc",
348 "read of IPC pipe returned unexpected value: %zd", rc);
349 } else {
350 if (buf[0] != '\1') {
351 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure");
352 } else {
353 thread_info->crash_dump_started = true;
354 }
355 }
356 pipe_read.reset();
357
358 // Don't leave a zombie child.
359 int status;
360 if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) {
361 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
362 strerror(errno));
363 } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
364 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
365 thread_info->crash_dump_started = false;
366 }
367 } 371 }
368 372
369 syscall(__NR_exit, 0); 373 input_write.reset();
374 output_read.reset();
375
376 // crash_dump will ptrace and pause all of our threads, and then write to the pipe to tell
377 // us to fork off a process to read memory from.
378 char buf[4];
379 rc = TEMP_FAILURE_RETRY(read(input_read.get(), &buf, sizeof(buf)));
380 if (rc == -1) {
381 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno));
382 return 1;
383 } else if (rc == 0) {
384 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec");
385 return 1;
386 } else if (rc != 1) {
387 async_safe_format_log(ANDROID_LOG_FATAL, "libc",
388 "read of IPC pipe returned unexpected value: %zd", rc);
389 return 1;
390 } else if (buf[0] != '\1') {
391 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure");
392 return 1;
393 }
394
395 // crash_dump is ptracing us, fork off a copy of our address space for it to use.
396 create_vm_process();
397
398 input_read.reset();
399 input_write.reset();
400
401 // Don't leave a zombie child.
402 int status;
403 if (TEMP_FAILURE_RETRY(waitpid(crash_dump_pid, &status, 0)) == -1) {
404 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
405 strerror(errno));
406 } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
407 async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
408 }
370 return 0; 409 return 0;
371} 410}
372 411
373static void resend_signal(siginfo_t* info, bool crash_dump_started) { 412static void resend_signal(siginfo_t* info) {
374 // Signals can either be fatal or nonfatal. 413 // Signals can either be fatal or nonfatal.
375 // For fatal signals, crash_dump will send us the signal we crashed with 414 // For fatal signals, crash_dump will send us the signal we crashed with
376 // before resuming us, so that processes using waitpid on us will see that we 415 // before resuming us, so that processes using waitpid on us will see that we
@@ -379,16 +418,6 @@ static void resend_signal(siginfo_t* info, bool crash_dump_started) {
379 // to deregister our signal handler for that signal before continuing. 418 // to deregister our signal handler for that signal before continuing.
380 if (info->si_signo != DEBUGGER_SIGNAL) { 419 if (info->si_signo != DEBUGGER_SIGNAL) {
381 signal(info->si_signo, SIG_DFL); 420 signal(info->si_signo, SIG_DFL);
382 }
383
384 // We need to return from our signal handler so that crash_dump can see the
385 // signal via ptrace and dump the thread that crashed. However, returning
386 // does not guarantee that the signal will be thrown again, even for SIGSEGV
387 // and friends, since the signal could have been sent manually. We blocked
388 // all signals when registering the handler, so resending the signal (using
389 // rt_tgsigqueueinfo(2) to preserve SA_SIGINFO) will cause it to be delivered
390 // when our signal handler returns.
391 if (crash_dump_started || info->si_signo != DEBUGGER_SIGNAL) {
392 int rc = syscall(SYS_rt_tgsigqueueinfo, __getpid(), __gettid(), info->si_signo, info); 421 int rc = syscall(SYS_rt_tgsigqueueinfo, __getpid(), __gettid(), info->si_signo, info);
393 if (rc != 0) { 422 if (rc != 0) {
394 fatal_errno("failed to resend signal during crash"); 423 fatal_errno("failed to resend signal during crash");
@@ -425,7 +454,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
425 } 454 }
426 455
427 void* abort_message = nullptr; 456 void* abort_message = nullptr;
428 if (g_callbacks.get_abort_message) { 457 if (signal_number != DEBUGGER_SIGNAL && g_callbacks.get_abort_message) {
429 abort_message = g_callbacks.get_abort_message(); 458 abort_message = g_callbacks.get_abort_message();
430 } 459 }
431 460
@@ -439,7 +468,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
439 // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing 468 // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing
440 // ANR trace. 469 // ANR trace.
441 debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message); 470 debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message);
442 resend_signal(info, false); 471 resend_signal(info);
443 return; 472 return;
444 } 473 }
445 474
@@ -450,20 +479,14 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
450 return; 479 return;
451 } 480 }
452 481
453 log_signal_summary(signal_number, info); 482 log_signal_summary(info);
454
455 // If this was a fatal crash, populate si_value with the abort message address if possible.
456 // Note that applications can set an abort message without aborting.
457 if (abort_message && signal_number != DEBUGGER_SIGNAL) {
458 info->si_value.sival_ptr = abort_message;
459 }
460 483
461 debugger_thread_info thread_info = { 484 debugger_thread_info thread_info = {
462 .crash_dump_started = false, 485 .pseudothread_tid = -1,
463 .pseudothread_tid = -1, 486 .crashing_tid = __gettid(),
464 .crashing_tid = __gettid(), 487 .siginfo = info,
465 .signal_number = signal_number, 488 .ucontext = context,
466 .info = info 489 .abort_msg = reinterpret_cast<uintptr_t>(abort_message),
467 }; 490 };
468 491
469 // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. 492 // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
@@ -472,7 +495,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
472 fatal_errno("failed to set dumpable"); 495 fatal_errno("failed to set dumpable");
473 } 496 }
474 497
475 // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread). 498 // Essentially pthread_create without CLONE_FILES, so we still work during file descriptor
499 // exhaustion.
476 pid_t child_pid = 500 pid_t child_pid =
477 clone(debuggerd_dispatch_pseudothread, pseudothread_stack, 501 clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
478 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, 502 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
@@ -484,7 +508,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
484 // Wait for the child to start... 508 // Wait for the child to start...
485 futex_wait(&thread_info.pseudothread_tid, -1); 509 futex_wait(&thread_info.pseudothread_tid, -1);
486 510
487 // and then wait for it to finish. 511 // and then wait for it to terminate.
488 futex_wait(&thread_info.pseudothread_tid, child_pid); 512 futex_wait(&thread_info.pseudothread_tid, child_pid);
489 513
490 // Restore PR_SET_DUMPABLE to its original value. 514 // Restore PR_SET_DUMPABLE to its original value.
@@ -492,21 +516,13 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
492 fatal_errno("failed to restore dumpable"); 516 fatal_errno("failed to restore dumpable");
493 } 517 }
494 518
495 // Signals can either be fatal or nonfatal.
496 // For fatal signals, crash_dump will PTRACE_CONT us with the signal we
497 // crashed with, so that processes using waitpid on us will see that we
498 // exited with the correct exit status (e.g. so that sh will report
499 // "Segmentation fault" instead of "Killed"). For this to work, we need
500 // to deregister our signal handler for that signal before continuing.
501 if (signal_number != DEBUGGER_SIGNAL) {
502 signal(signal_number, SIG_DFL);
503 }
504
505 resend_signal(info, thread_info.crash_dump_started);
506 if (info->si_signo == DEBUGGER_SIGNAL) { 519 if (info->si_signo == DEBUGGER_SIGNAL) {
507 // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from 520 // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
508 // starting to dump right before our death. 521 // starting to dump right before our death.
509 pthread_mutex_unlock(&crash_mutex); 522 pthread_mutex_unlock(&crash_mutex);
523 } else {
524 // Resend the signal, so that either gdb or the parent's waitpid sees it.
525 resend_signal(info);
510 } 526 }
511} 527}
512 528
diff --git a/debuggerd/libdebuggerd/arm/machine.cpp b/debuggerd/libdebuggerd/arm/machine.cpp
deleted file mode 100644
index bfb5ea4e9..000000000
--- a/debuggerd/libdebuggerd/arm/machine.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
1/*
2 *
3 * Copyright 2006, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "DEBUG"
19
20#include "libdebuggerd/machine.h"
21
22#include <errno.h>
23#include <stdint.h>
24#include <string.h>
25#include <sys/ptrace.h>
26
27#include <backtrace/Backtrace.h>
28#include <log/log.h>
29
30#include "libdebuggerd/utility.h"
31
32void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
33 pt_regs regs;
34 if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &regs)) {
35 ALOGE("cannot get registers: %s\n", strerror(errno));
36 return;
37 }
38
39 static const char reg_names[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
40
41 for (int reg = 0; reg < 14; reg++) {
42 dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", &reg_names[reg * 2]);
43 }
44
45 dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");
46
47 if (regs.ARM_pc != regs.ARM_lr) {
48 dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
49 }
50}
51
52#define DUMP_GP_REGISTERS(log, reg_prefix) \
53 _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n", \
54 static_cast<uint32_t>(reg_prefix##r0), static_cast<uint32_t>(reg_prefix##r1), \
55 static_cast<uint32_t>(reg_prefix##r2), static_cast<uint32_t>(reg_prefix##r3)); \
56 _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n", \
57 static_cast<uint32_t>(reg_prefix##r4), static_cast<uint32_t>(reg_prefix##r5), \
58 static_cast<uint32_t>(reg_prefix##r6), static_cast<uint32_t>(reg_prefix##r7)); \
59 _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n", \
60 static_cast<uint32_t>(reg_prefix##r8), static_cast<uint32_t>(reg_prefix##r9), \
61 static_cast<uint32_t>(reg_prefix##r10), static_cast<uint32_t>(reg_prefix##fp)); \
62 _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", \
63 static_cast<uint32_t>(reg_prefix##ip), static_cast<uint32_t>(reg_prefix##sp), \
64 static_cast<uint32_t>(reg_prefix##lr), static_cast<uint32_t>(reg_prefix##pc), \
65 static_cast<uint32_t>(reg_prefix##cpsr))
66
67void dump_registers(log_t* log, pid_t tid) {
68 pt_regs r;
69 if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
70 ALOGE("cannot get registers: %s\n", strerror(errno));
71 return;
72 }
73
74 DUMP_GP_REGISTERS(log, r.ARM_);
75
76 user_vfp vfp_regs;
77 if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
78 ALOGE("cannot get FP registers: %s\n", strerror(errno));
79 return;
80 }
81
82 for (size_t i = 0; i < 32; i += 2) {
83 _LOG(log, logtype::FP_REGISTERS, " d%-2d %016llx d%-2d %016llx\n",
84 i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
85 }
86 _LOG(log, logtype::FP_REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
87}
88
89void dump_registers(log_t* log, const ucontext_t* uc) {
90 DUMP_GP_REGISTERS(log, uc->uc_mcontext.arm_);
91}
diff --git a/debuggerd/libdebuggerd/arm64/machine.cpp b/debuggerd/libdebuggerd/arm64/machine.cpp
deleted file mode 100644
index ad1c95110..000000000
--- a/debuggerd/libdebuggerd/arm64/machine.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
1/*
2 *
3 * Copyright 2014, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "DEBUG"
19
20#include "libdebuggerd/machine.h"
21
22#include <elf.h>
23#include <errno.h>
24#include <stdint.h>
25#include <string.h>
26#include <sys/ptrace.h>
27#include <sys/uio.h>
28
29#include <backtrace/Backtrace.h>
30#include <log/log.h>
31
32#include "libdebuggerd/utility.h"
33
34void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
35 struct user_pt_regs regs;
36 struct iovec io;
37 io.iov_base = &regs;
38 io.iov_len = sizeof(regs);
39
40 if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
41 ALOGE("ptrace failed to get registers: %s", strerror(errno));
42 return;
43 }
44
45 for (int reg = 0; reg < 31; reg++) {
46 dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
47 }
48
49 dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
50
51 if (regs.pc != regs.sp) {
52 dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
53 }
54}
55
56#define DUMP_GP_REGISTERS(log) \
57 for (int i = 0; i < 28; i += 4) { \
58 const char* fmt = " x%-2d %016llx x%-2d %016llx x%-2d %016llx x%-2d %016llx\n"; \
59 _LOG(log, logtype::REGISTERS, fmt, i, r.regs[i], i + 1, r.regs[i + 1], i + 2, r.regs[i + 2], \
60 i + 3, r.regs[i + 3]); \
61 } \
62 _LOG(log, logtype::REGISTERS, " x28 %016llx x29 %016llx x30 %016llx\n", r.regs[28], \
63 r.regs[29], r.regs[30]); \
64 _LOG(log, logtype::REGISTERS, " sp %016llx pc %016llx pstate %016llx\n", r.sp, r.pc, \
65 r.pstate)
66
67void dump_registers(log_t* log, pid_t tid) {
68 struct user_pt_regs r;
69 struct iovec io;
70 io.iov_base = &r;
71 io.iov_len = sizeof(r);
72
73 if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
74 ALOGE("ptrace error: %s\n", strerror(errno));
75 return;
76 }
77
78 DUMP_GP_REGISTERS(log);
79
80 struct user_fpsimd_state f;
81 io.iov_base = &f;
82 io.iov_len = sizeof(f);
83
84 if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
85 ALOGE("ptrace error: %s\n", strerror(errno));
86 return;
87 }
88
89 for (int i = 0; i < 32; i += 2) {
90 _LOG(log, logtype::FP_REGISTERS,
91 " v%-2d %016" PRIx64 "%016" PRIx64 " v%-2d %016" PRIx64 "%016" PRIx64 "\n",
92 i,
93 static_cast<uint64_t>(f.vregs[i] >> 64),
94 static_cast<uint64_t>(f.vregs[i]),
95 i+1,
96 static_cast<uint64_t>(f.vregs[i+1] >> 64),
97 static_cast<uint64_t>(f.vregs[i+1]));
98 }
99 _LOG(log, logtype::FP_REGISTERS, " fpsr %08x fpcr %08x\n", f.fpsr, f.fpcr);
100}
101
102void dump_registers(log_t* log, const ucontext_t* ucontext) {
103 const mcontext_t& r = ucontext->uc_mcontext;
104 DUMP_GP_REGISTERS(log);
105}
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f616e1ba0..f0a01f41c 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -30,12 +30,15 @@
30#include <time.h> 30#include <time.h>
31#include <unistd.h> 31#include <unistd.h>
32 32
33#include <map>
33#include <memory> 34#include <memory>
34#include <string> 35#include <string>
35 36
37#include <android-base/unique_fd.h>
36#include <backtrace/Backtrace.h> 38#include <backtrace/Backtrace.h>
37#include <log/log.h> 39#include <log/log.h>
38 40
41#include "libdebuggerd/types.h"
39#include "libdebuggerd/utility.h" 42#include "libdebuggerd/utility.h"
40 43
41static void dump_process_header(log_t* log, pid_t pid, const char* process_name) { 44static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
@@ -56,62 +59,46 @@ static void dump_process_footer(log_t* log, pid_t pid) {
56 _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid); 59 _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
57} 60}
58 61
59static void log_thread_name(log_t* log, pid_t tid, const char* thread_name) { 62void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread) {
60 _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread_name, tid);
61}
62
63static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
64 const std::string& thread_name) {
65 log_thread_name(log, tid, thread_name.c_str());
66
67 std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
68 if (backtrace->Unwind(0)) {
69 dump_backtrace_to_log(backtrace.get(), log, " ");
70 } else {
71 ALOGE("Unwind failed: tid = %d: %s", tid,
72 backtrace->GetErrorString(backtrace->GetError()).c_str());
73 }
74}
75
76void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
77 const std::map<pid_t, std::string>& threads, std::string* amfd_data) {
78 log_t log; 63 log_t log;
79 log.tfd = fd; 64 log.tfd = output_fd;
80 log.amfd_data = amfd_data; 65 log.amfd_data = nullptr;
81 66
82 dump_process_header(&log, pid, process_name.c_str()); 67 _LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid);
83 dump_thread(&log, map, pid, tid, threads.find(tid)->second.c_str());
84 68
85 for (const auto& it : threads) { 69 std::vector<backtrace_frame_data_t> frames;
86 pid_t thread_tid = it.first; 70 if (!Backtrace::Unwind(thread.registers.get(), map, &frames, 0, nullptr)) {
87 const std::string& thread_name = it.second; 71 _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
88 if (thread_tid != tid) { 72 return;
89 dump_thread(&log, map, pid, thread_tid, thread_name.c_str());
90 }
91 } 73 }
92 74
93 dump_process_footer(&log, pid); 75 for (auto& frame : frames) {
76 _LOG(&log, logtype::BACKTRACE, " %s\n", Backtrace::FormatFrameData(&frame).c_str());
77 }
94} 78}
95 79
96void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext) { 80void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
97 pid_t pid = getpid(); 81 const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) {
98 pid_t tid = gettid();
99
100 log_t log; 82 log_t log;
101 log.tfd = output_fd; 83 log.tfd = output_fd.get();
102 log.amfd_data = nullptr; 84 log.amfd_data = nullptr;
103 85
104 char thread_name[16]; 86 auto target = thread_info.find(target_thread);
105 read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>"); 87 if (target == thread_info.end()) {
106 log_thread_name(&log, tid, thread_name); 88 ALOGE("failed to find target thread in thread info");
89 return;
90 }
107 91
108 std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid)); 92 dump_process_header(&log, target->second.pid, target->second.process_name.c_str());
109 if (backtrace->Unwind(0, ucontext)) { 93
110 dump_backtrace_to_log(backtrace.get(), &log, " "); 94 dump_backtrace_thread(output_fd.get(), map, target->second);
111 } else { 95 for (const auto& [tid, info] : thread_info) {
112 ALOGE("Unwind failed: tid = %d: %s", tid, 96 if (tid != target_thread) {
113 backtrace->GetErrorString(backtrace->GetError()).c_str()); 97 dump_backtrace_thread(output_fd.get(), map, info);
98 }
114 } 99 }
100
101 dump_process_footer(&log, target->second.pid);
115} 102}
116 103
117void dump_backtrace_header(int output_fd) { 104void dump_backtrace_header(int output_fd) {
@@ -131,9 +118,3 @@ void dump_backtrace_footer(int output_fd) {
131 118
132 dump_process_footer(&log, getpid()); 119 dump_process_footer(&log, getpid());
133} 120}
134
135void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
136 for (size_t i = 0; i < backtrace->NumFrames(); i++) {
137 _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
138 }
139}
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
index a35102f63..d7afc0b49 100644
--- a/debuggerd/libdebuggerd/elf_utils.cpp
+++ b/debuggerd/libdebuggerd/elf_utils.cpp
@@ -26,28 +26,28 @@
26#include <string> 26#include <string>
27 27
28#include <android-base/stringprintf.h> 28#include <android-base/stringprintf.h>
29#include <backtrace/Backtrace.h>
30#include <log/log.h> 29#include <log/log.h>
30#include <unwindstack/Memory.h>
31 31
32#define NOTE_ALIGN(size) (((size) + 3) & ~3) 32#define NOTE_ALIGN(size) (((size) + 3) & ~3)
33 33
34template <typename HdrType, typename PhdrType, typename NhdrType> 34template <typename HdrType, typename PhdrType, typename NhdrType>
35static bool get_build_id( 35static bool get_build_id(unwindstack::Memory* memory, uintptr_t base_addr, uint8_t* e_ident,
36 Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) { 36 std::string* build_id) {
37 HdrType hdr; 37 HdrType hdr;
38 38
39 memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT); 39 memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
40 40
41 // First read the rest of the header. 41 // First read the rest of the header.
42 if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT, 42 if (memory->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
43 sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) { 43 sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
44 return false; 44 return false;
45 } 45 }
46 46
47 for (size_t i = 0; i < hdr.e_phnum; i++) { 47 for (size_t i = 0; i < hdr.e_phnum; i++) {
48 PhdrType phdr; 48 PhdrType phdr;
49 if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize, 49 if (memory->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
50 reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) { 50 reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
51 return false; 51 return false;
52 } 52 }
53 // Looking for the .note.gnu.build-id note. 53 // Looking for the .note.gnu.build-id note.
@@ -56,7 +56,7 @@ static bool get_build_id(
56 uintptr_t addr = base_addr + phdr.p_offset; 56 uintptr_t addr = base_addr + phdr.p_offset;
57 while (hdr_size >= sizeof(NhdrType)) { 57 while (hdr_size >= sizeof(NhdrType)) {
58 NhdrType nhdr; 58 NhdrType nhdr;
59 if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) { 59 if (memory->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
60 return false; 60 return false;
61 } 61 }
62 addr += sizeof(nhdr); 62 addr += sizeof(nhdr);
@@ -69,7 +69,7 @@ static bool get_build_id(
69 nhdr.n_descsz); 69 nhdr.n_descsz);
70 return false; 70 return false;
71 } 71 }
72 if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) { 72 if (memory->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
73 return false; 73 return false;
74 } 74 }
75 75
@@ -95,10 +95,10 @@ static bool get_build_id(
95 return false; 95 return false;
96} 96}
97 97
98bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) { 98bool elf_get_build_id(unwindstack::Memory* memory, uintptr_t addr, std::string* build_id) {
99 // Read and verify the elf magic number first. 99 // Read and verify the elf magic number first.
100 uint8_t e_ident[EI_NIDENT]; 100 uint8_t e_ident[EI_NIDENT];
101 if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) { 101 if (memory->Read(addr, e_ident, SELFMAG) != SELFMAG) {
102 return false; 102 return false;
103 } 103 }
104 104
@@ -107,14 +107,14 @@ bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_i
107 } 107 }
108 108
109 // Read the rest of EI_NIDENT. 109 // Read the rest of EI_NIDENT.
110 if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) { 110 if (memory->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
111 return false; 111 return false;
112 } 112 }
113 113
114 if (e_ident[EI_CLASS] == ELFCLASS32) { 114 if (e_ident[EI_CLASS] == ELFCLASS32) {
115 return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id); 115 return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(memory, addr, e_ident, build_id);
116 } else if (e_ident[EI_CLASS] == ELFCLASS64) { 116 } else if (e_ident[EI_CLASS] == ELFCLASS64) {
117 return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id); 117 return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(memory, addr, e_ident, build_id);
118 } 118 }
119 119
120 return false; 120 return false;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
index fe738f1c7..119e59b47 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
@@ -23,21 +23,20 @@
23#include <map> 23#include <map>
24#include <string> 24#include <string>
25 25
26#include <android-base/unique_fd.h>
27
28#include "types.h"
26#include "utility.h" 29#include "utility.h"
27 30
28class Backtrace;
29class BacktraceMap; 31class BacktraceMap;
30 32
31// Dumps a backtrace using a format similar to what Dalvik uses so that the result 33// Dumps a backtrace using a format similar to what Dalvik uses so that the result
32// can be intermixed in a bug report. 34// can be intermixed in a bug report.
33void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name, 35void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
34 const std::map<pid_t, std::string>& threads, std::string* amfd_data); 36 const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread);
35
36/* Dumps the backtrace in the backtrace data structure to the log. */
37void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
38 37
39void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext);
40void dump_backtrace_header(int output_fd); 38void dump_backtrace_header(int output_fd);
39void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread);
41void dump_backtrace_footer(int output_fd); 40void dump_backtrace_footer(int output_fd);
42 41
43#endif // _DEBUGGERD_BACKTRACE_H 42#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
index 11d0a4348..5d0d92495 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
@@ -20,8 +20,10 @@
20#include <stdint.h> 20#include <stdint.h>
21#include <string> 21#include <string>
22 22
23class Backtrace; 23namespace unwindstack {
24class Memory;
25}
24 26
25bool elf_get_build_id(Backtrace*, uintptr_t, std::string*); 27bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string*);
26 28
27#endif // _DEBUGGERD_ELF_UTILS_H 29#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 5e5668253..000000000
--- a/debuggerd/libdebuggerd/include/libdebuggerd/machine.h
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _DEBUGGERD_MACHINE_H
18#define _DEBUGGERD_MACHINE_H
19
20#include <sys/types.h>
21
22#include <backtrace/Backtrace.h>
23
24#include "utility.h"
25
26void dump_memory_and_code(log_t* log, Backtrace* backtrace);
27void dump_registers(log_t* log, pid_t tid);
28void dump_registers(log_t* log, const ucontext_t* uc);
29
30#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 b37228d03..4727ca4d7 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
@@ -31,6 +31,6 @@ typedef std::vector<std::pair<int, std::string>> OpenFilesList;
31void populate_open_files_list(pid_t pid, OpenFilesList* list); 31void populate_open_files_list(pid_t pid, OpenFilesList* list);
32 32
33/* Dumps the open files list to the log. */ 33/* Dumps the open files list to the log. */
34void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix); 34void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix);
35 35
36#endif // _DEBUGGERD_OPEN_FILES_LIST_H 36#endif // _DEBUGGERD_OPEN_FILES_LIST_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 79743b61c..198c48b26 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -24,7 +24,10 @@
24#include <map> 24#include <map>
25#include <string> 25#include <string>
26 26
27#include <android-base/unique_fd.h>
28
27#include "open_files_list.h" 29#include "open_files_list.h"
30#include "types.h"
28 31
29class BacktraceMap; 32class BacktraceMap;
30 33
@@ -43,11 +46,10 @@ void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList*
43void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo, 46void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
44 ucontext_t* ucontext); 47 ucontext_t* ucontext);
45 48
46// Compatibility shim. 49void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
47__attribute__((__unused__)) 50 unwindstack::Memory* process_memory,
48static void engrave_tombstone_ucontext(int tombstone_fd, pid_t, pid_t, uintptr_t abort_msg_address, 51 const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
49 siginfo_t* siginfo, ucontext_t* ucontext) { 52 uintptr_t abort_msg_address, OpenFilesList* open_files,
50 engrave_tombstone_ucontext(tombstone_fd, abort_msg_address, siginfo, ucontext); 53 std::string* amfd_data);
51}
52 54
53#endif // _DEBUGGERD_TOMBSTONE_H 55#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/test/ptrace_fake.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index fdbb66361..70583af30 100644
--- a/debuggerd/libdebuggerd/test/ptrace_fake.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -1,5 +1,7 @@
1#pragma once
2
1/* 3/*
2 * Copyright (C) 2015 The Android Open Source Project 4 * Copyright (C) 2012 The Android Open Source Project
3 * 5 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 7 * you may not use this file except in compliance with the License.
@@ -14,11 +16,19 @@
14 * limitations under the License. 16 * limitations under the License.
15 */ 17 */
16 18
17#ifndef _DEBUGGERD_TEST_PTRACE_FAKE_H 19#include <memory>
18#define _DEBUGGERD_TEST_PTRACE_FAKE_H 20#include <string>
21
22#include <unwindstack/Regs.h>
19 23
20#include <signal.h> 24struct ThreadInfo {
25 std::unique_ptr<unwindstack::Regs> registers;
26 pid_t tid;
27 std::string thread_name;
21 28
22void ptrace_set_fake_getsiginfo(const siginfo_t&); 29 pid_t pid;
30 std::string process_name;
23 31
24#endif // _DEBUGGERD_TEST_PTRACE_FAKE_H 32 int signo = 0;
33 siginfo_t* siginfo = nullptr;
34};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index f481b78b8..c5abfe24f 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -27,21 +27,24 @@
27#include <android-base/macros.h> 27#include <android-base/macros.h>
28#include <backtrace/Backtrace.h> 28#include <backtrace/Backtrace.h>
29 29
30struct log_t{ 30struct log_t {
31 // Tombstone file descriptor. 31 // Tombstone file descriptor.
32 int tfd; 32 int tfd;
33 // Data to be sent to the Activity Manager. 33 // Data to be sent to the Activity Manager.
34 std::string* amfd_data; 34 std::string* amfd_data;
35 // The tid of the thread that crashed. 35 // The tid of the thread that crashed.
36 pid_t crashed_tid; 36 pid_t crashed_tid;
37 // The tid of the thread we are currently working with. 37 // The tid of the thread we are currently working with.
38 pid_t current_tid; 38 pid_t current_tid;
39 // logd daemon crash, can block asking for logcat data, allow suppression. 39 // logd daemon crash, can block asking for logcat data, allow suppression.
40 bool should_retrieve_logcat; 40 bool should_retrieve_logcat;
41 41
42 log_t() 42 log_t()
43 : tfd(-1), amfd_data(nullptr), crashed_tid(-1), current_tid(-1), 43 : tfd(-1),
44 should_retrieve_logcat(true) {} 44 amfd_data(nullptr),
45 crashed_tid(-1),
46 current_tid(-1),
47 should_retrieve_logcat(true) {}
45}; 48};
46 49
47// List of types of logs to simplify the logging decision in _LOG 50// List of types of logs to simplify the logging decision in _LOG
@@ -59,13 +62,20 @@ enum logtype {
59}; 62};
60 63
61// Log information onto the tombstone. 64// Log information onto the tombstone.
62void _LOG(log_t* log, logtype ltype, const char *fmt, ...) 65void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
63 __attribute__ ((format(printf, 3, 4)));
64 66
65bool wait_for_signal(pid_t tid, siginfo_t* siginfo); 67namespace unwindstack {
68class Memory;
69}
66 70
67void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...); 71void dump_memory(log_t* log, unwindstack::Memory* backtrace, uintptr_t addr, const char* fmt, ...);
68 72
69void read_with_default(const char* path, char* buf, size_t len, const char* default_value); 73void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
70 74
75void drop_capabilities();
76
77bool signal_has_si_addr(int si_signo, int si_code);
78const char* get_signame(int sig);
79const char* get_sigcode(int signo, int code);
80
71#endif // _DEBUGGERD_UTILITY_H 81#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/mips/machine.cpp b/debuggerd/libdebuggerd/mips/machine.cpp
deleted file mode 100644
index 1fc690b4a..000000000
--- a/debuggerd/libdebuggerd/mips/machine.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DEBUG"
18
19#include "libdebuggerd/machine.h"
20
21#include <errno.h>
22#include <inttypes.h>
23#include <stdint.h>
24#include <string.h>
25#include <sys/ptrace.h>
26
27#include <backtrace/Backtrace.h>
28#include <log/log.h>
29
30#include "libdebuggerd/utility.h"
31
32#define R(x) (static_cast<uintptr_t>(x))
33
34// If configured to do so, dump memory around *all* registers
35// for the crashing thread.
36void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
37 pt_regs r;
38 if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
39 ALOGE("cannot get registers: %s\n", strerror(errno));
40 return;
41 }
42
43 static const char reg_names[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
44
45 for (int reg = 0; reg < 32; reg++) {
46 // skip uninteresting registers
47 if (reg == 0 // $0
48 || reg == 26 // $k0
49 || reg == 27 // $k1
50 || reg == 31 // $ra (done below)
51 )
52 continue;
53
54 dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
55 }
56
57 uintptr_t pc = R(r.cp0_epc);
58 uintptr_t ra = R(r.regs[31]);
59 dump_memory(log, backtrace, pc, "code around pc:");
60 if (pc != ra) {
61 dump_memory(log, backtrace, ra, "code around ra:");
62 }
63}
64
65void dump_registers(log_t* log, pid_t tid) {
66 pt_regs r;
67 if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
68 ALOGE("cannot get registers: %s\n", strerror(errno));
69 return;
70 }
71
72 _LOG(log, logtype::REGISTERS, " zr %08" PRIxPTR " at %08" PRIxPTR
73 " v0 %08" PRIxPTR " v1 %08" PRIxPTR "\n",
74 R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
75 _LOG(log, logtype::REGISTERS, " a0 %08" PRIxPTR " a1 %08" PRIxPTR
76 " a2 %08" PRIxPTR " a3 %08" PRIxPTR "\n",
77 R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
78 _LOG(log, logtype::REGISTERS, " t0 %08" PRIxPTR " t1 %08" PRIxPTR
79 " t2 %08" PRIxPTR " t3 %08" PRIxPTR "\n",
80 R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
81 _LOG(log, logtype::REGISTERS, " t4 %08" PRIxPTR " t5 %08" PRIxPTR
82 " t6 %08" PRIxPTR " t7 %08" PRIxPTR "\n",
83 R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
84 _LOG(log, logtype::REGISTERS, " s0 %08" PRIxPTR " s1 %08" PRIxPTR
85 " s2 %08" PRIxPTR " s3 %08" PRIxPTR "\n",
86 R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
87 _LOG(log, logtype::REGISTERS, " s4 %08" PRIxPTR " s5 %08" PRIxPTR
88 " s6 %08" PRIxPTR " s7 %08" PRIxPTR "\n",
89 R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
90 _LOG(log, logtype::REGISTERS, " t8 %08" PRIxPTR " t9 %08" PRIxPTR
91 " k0 %08" PRIxPTR " k1 %08" PRIxPTR "\n",
92 R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
93 _LOG(log, logtype::REGISTERS, " gp %08" PRIxPTR " sp %08" PRIxPTR
94 " s8 %08" PRIxPTR " ra %08" PRIxPTR "\n",
95 R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
96 _LOG(log, logtype::REGISTERS, " hi %08" PRIxPTR " lo %08" PRIxPTR
97 " bva %08" PRIxPTR " epc %08" PRIxPTR "\n",
98 R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
99}
diff --git a/debuggerd/libdebuggerd/mips64/machine.cpp b/debuggerd/libdebuggerd/mips64/machine.cpp
deleted file mode 100644
index 955e50728..000000000
--- a/debuggerd/libdebuggerd/mips64/machine.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 * Copyright 2014, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DEBUG"
18
19#include "libdebuggerd/machine.h"
20
21#include <errno.h>
22#include <inttypes.h>
23#include <stdint.h>
24#include <string.h>
25#include <sys/ptrace.h>
26
27#include <backtrace/Backtrace.h>
28#include <log/log.h>
29
30#include "libdebuggerd/utility.h"
31
32#define R(x) (static_cast<uintptr_t>(x))
33
34// If configured to do so, dump memory around *all* registers
35// for the crashing thread.
36void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
37 pt_regs r;
38 if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
39 ALOGE("cannot get registers: %s\n", strerror(errno));
40 return;
41 }
42
43 static const char reg_names[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
44
45 for (int reg = 0; reg < 32; reg++) {
46 // skip uninteresting registers
47 if (reg == 0 // $0
48 || reg == 26 // $k0
49 || reg == 27 // $k1
50 || reg == 31 // $ra (done below)
51 )
52 continue;
53
54 dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
55 }
56
57 uintptr_t pc = R(r.cp0_epc);
58 uintptr_t ra = R(r.regs[31]);
59 dump_memory(log, backtrace, pc, "code around pc:");
60 if (pc != ra) {
61 dump_memory(log, backtrace, ra, "code around ra:");
62 }
63}
64
65void dump_registers(log_t* log, pid_t tid) {
66 pt_regs r;
67 if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
68 ALOGE("cannot get registers: %s\n", strerror(errno));
69 return;
70 }
71
72 _LOG(log, logtype::REGISTERS, " zr %016" PRIxPTR " at %016" PRIxPTR
73 " v0 %016" PRIxPTR " v1 %016" PRIxPTR "\n",
74 R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
75 _LOG(log, logtype::REGISTERS, " a0 %016" PRIxPTR " a1 %016" PRIxPTR
76 " a2 %016" PRIxPTR " a3 %016" PRIxPTR "\n",
77 R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
78 _LOG(log, logtype::REGISTERS, " a4 %016" PRIxPTR " a5 %016" PRIxPTR
79 " a6 %016" PRIxPTR " a7 %016" PRIxPTR "\n",
80 R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
81 _LOG(log, logtype::REGISTERS, " t0 %016" PRIxPTR " t1 %016" PRIxPTR
82 " t2 %016" PRIxPTR " t3 %016" PRIxPTR "\n",
83 R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
84 _LOG(log, logtype::REGISTERS, " s0 %016" PRIxPTR " s1 %016" PRIxPTR
85 " s2 %016" PRIxPTR " s3 %016" PRIxPTR "\n",
86 R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
87 _LOG(log, logtype::REGISTERS, " s4 %016" PRIxPTR " s5 %016" PRIxPTR
88 " s6 %016" PRIxPTR " s7 %016" PRIxPTR "\n",
89 R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
90 _LOG(log, logtype::REGISTERS, " t8 %016" PRIxPTR " t9 %016" PRIxPTR
91 " k0 %016" PRIxPTR " k1 %016" PRIxPTR "\n",
92 R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
93 _LOG(log, logtype::REGISTERS, " gp %016" PRIxPTR " sp %016" PRIxPTR
94 " s8 %016" PRIxPTR " ra %016" PRIxPTR "\n",
95 R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
96 _LOG(log, logtype::REGISTERS, " hi %016" PRIxPTR " lo %016" PRIxPTR
97 " bva %016" PRIxPTR " epc %016" PRIxPTR "\n",
98 R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
99}
diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp
index e199db8b4..b12703e14 100644
--- a/debuggerd/libdebuggerd/open_files_list.cpp
+++ b/debuggerd/libdebuggerd/open_files_list.cpp
@@ -61,7 +61,7 @@ void populate_open_files_list(pid_t pid, OpenFilesList* list) {
61 } 61 }
62} 62}
63 63
64void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix) { 64void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix) {
65 for (auto& file : files) { 65 for (auto& file : files) {
66 _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str()); 66 _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str());
67 } 67 }
diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h
index 6104f7e0d..e7dbed764 100644
--- a/debuggerd/libdebuggerd/test/BacktraceMock.h
+++ b/debuggerd/libdebuggerd/test/BacktraceMock.h
@@ -17,15 +17,6 @@
17#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H 17#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H
18#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H 18#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
19 19
20#include <stdint.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/ucontext.h>
24
25#include <string>
26#include <vector>
27
28#include <backtrace/Backtrace.h>
29#include <backtrace/BacktraceMap.h> 20#include <backtrace/BacktraceMap.h>
30 21
31class BacktraceMapMock : public BacktraceMap { 22class BacktraceMapMock : public BacktraceMap {
@@ -38,69 +29,4 @@ class BacktraceMapMock : public BacktraceMap {
38 } 29 }
39}; 30};
40 31
41
42class BacktraceMock : public Backtrace {
43 public:
44 explicit BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
45 if (map_ == nullptr) {
46 abort();
47 }
48 }
49 virtual ~BacktraceMock() {}
50
51 virtual bool Unwind(size_t, ucontext_t*) { return false; }
52 virtual bool ReadWord(uintptr_t, word_t*) { return false;}
53
54 virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; }
55
56 virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
57 size_t offset = 0;
58 if (last_read_addr_ > 0) {
59 offset = addr - last_read_addr_;
60 }
61 size_t bytes_available = buffer_.size() - offset;
62
63 if (do_partial_read_) {
64 // Do a partial read.
65 if (bytes > bytes_partial_read_) {
66 bytes = bytes_partial_read_;
67 }
68 bytes_partial_read_ -= bytes;
69 // Only support a single partial read.
70 do_partial_read_ = false;
71 } else if (bytes > bytes_available) {
72 bytes = bytes_available;
73 }
74
75 if (bytes > 0) {
76 memcpy(buffer, buffer_.data() + offset, bytes);
77 }
78
79 last_read_addr_ = addr;
80 return bytes;
81 }
82
83 void SetReadData(uint8_t* buffer, size_t bytes) {
84 buffer_.resize(bytes);
85 memcpy(buffer_.data(), buffer, bytes);
86 bytes_partial_read_ = 0;
87 do_partial_read_ = false;
88 last_read_addr_ = 0;
89 }
90
91 void SetPartialReadAmount(size_t bytes) {
92 if (bytes > buffer_.size()) {
93 abort();
94 }
95 bytes_partial_read_ = bytes;
96 do_partial_read_ = true;
97 }
98
99 private:
100 std::vector<uint8_t> buffer_;
101 size_t bytes_partial_read_ = 0;
102 uintptr_t last_read_addr_ = 0;
103 bool do_partial_read_ = false;
104};
105
106#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H 32#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 0fad2cf7c..7c8a0ea14 100644
--- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
@@ -19,12 +19,12 @@
19#include <memory> 19#include <memory>
20#include <string> 20#include <string>
21 21
22#include <gtest/gtest.h>
23#include <android-base/file.h> 22#include <android-base/file.h>
23#include <gtest/gtest.h>
24#include <unwindstack/Memory.h>
24 25
25#include "libdebuggerd/utility.h" 26#include "libdebuggerd/utility.h"
26 27
27#include "BacktraceMock.h"
28#include "log_fake.h" 28#include "log_fake.h"
29 29
30const char g_expected_full_dump[] = 30const char g_expected_full_dump[] =
@@ -103,11 +103,59 @@ const char g_expected_partial_dump[] = \
103" 123456d0 -------- -------- -------- -------- ................\n"; 103" 123456d0 -------- -------- -------- -------- ................\n";
104#endif 104#endif
105 105
106class MemoryMock : public unwindstack::Memory {
107 public:
108 virtual ~MemoryMock() = default;
109
110 virtual size_t Read(uint64_t addr, void* buffer, size_t bytes) override {
111 size_t offset = 0;
112 if (last_read_addr_ > 0) {
113 offset = addr - last_read_addr_;
114 }
115 size_t bytes_available = buffer_.size() - offset;
116
117 if (partial_read_) {
118 bytes = std::min(bytes, bytes_partial_read_);
119 bytes_partial_read_ -= bytes;
120 partial_read_ = bytes_partial_read_;
121 } else if (bytes > bytes_available) {
122 bytes = bytes_available;
123 }
124
125 if (bytes > 0) {
126 memcpy(buffer, buffer_.data() + offset, bytes);
127 }
128
129 last_read_addr_ = addr;
130 return bytes;
131 }
132
133 void SetReadData(uint8_t* buffer, size_t bytes) {
134 buffer_.resize(bytes);
135 memcpy(buffer_.data(), buffer, bytes);
136 bytes_partial_read_ = 0;
137 last_read_addr_ = 0;
138 }
139
140 void SetPartialReadAmount(size_t bytes) {
141 if (bytes > buffer_.size()) {
142 abort();
143 }
144 partial_read_ = true;
145 bytes_partial_read_ = bytes;
146 }
147
148 private:
149 std::vector<uint8_t> buffer_;
150 bool partial_read_ = false;
151 size_t bytes_partial_read_ = 0;
152 uintptr_t last_read_addr_ = 0;
153};
154
106class DumpMemoryTest : public ::testing::Test { 155class DumpMemoryTest : public ::testing::Test {
107 protected: 156 protected:
108 virtual void SetUp() { 157 virtual void SetUp() {
109 map_mock_.reset(new BacktraceMapMock()); 158 memory_mock_ = std::make_unique<MemoryMock>();
110 backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
111 159
112 char tmp_file[256]; 160 char tmp_file[256];
113 const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX"; 161 const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -138,10 +186,10 @@ class DumpMemoryTest : public ::testing::Test {
138 if (log_.tfd >= 0) { 186 if (log_.tfd >= 0) {
139 close(log_.tfd); 187 close(log_.tfd);
140 } 188 }
189 memory_mock_.reset();
141 } 190 }
142 191
143 std::unique_ptr<BacktraceMapMock> map_mock_; 192 std::unique_ptr<MemoryMock> memory_mock_;
144 std::unique_ptr<BacktraceMock> backtrace_mock_;
145 193
146 log_t log_; 194 log_t log_;
147}; 195};
@@ -151,9 +199,9 @@ TEST_F(DumpMemoryTest, aligned_addr) {
151 for (size_t i = 0; i < sizeof(buffer); i++) { 199 for (size_t i = 0; i < sizeof(buffer); i++) {
152 buffer[i] = i; 200 buffer[i] = i;
153 } 201 }
154 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 202 memory_mock_->SetReadData(buffer, sizeof(buffer));
155 203
156 dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1"); 204 dump_memory(&log_, memory_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
157 205
158 std::string tombstone_contents; 206 std::string tombstone_contents;
159 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 207 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -170,10 +218,10 @@ TEST_F(DumpMemoryTest, partial_read) {
170 for (size_t i = 0; i < sizeof(buffer); i++) { 218 for (size_t i = 0; i < sizeof(buffer); i++) {
171 buffer[i] = i; 219 buffer[i] = i;
172 } 220 }
173 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 221 memory_mock_->SetReadData(buffer, sizeof(buffer));
174 backtrace_mock_->SetPartialReadAmount(96); 222 memory_mock_->SetPartialReadAmount(96);
175 223
176 dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1"); 224 dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
177 225
178 std::string tombstone_contents; 226 std::string tombstone_contents;
179 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 227 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -190,9 +238,9 @@ TEST_F(DumpMemoryTest, unaligned_addr) {
190 for (size_t i = 0; i < sizeof(buffer); i++) { 238 for (size_t i = 0; i < sizeof(buffer); i++) {
191 buffer[i] = i; 239 buffer[i] = i;
192 } 240 }
193 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 241 memory_mock_->SetReadData(buffer, sizeof(buffer));
194 242
195 dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1"); 243 dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
196 244
197 std::string tombstone_contents; 245 std::string tombstone_contents;
198 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 246 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -205,7 +253,7 @@ TEST_F(DumpMemoryTest, unaligned_addr) {
205} 253}
206 254
207TEST_F(DumpMemoryTest, memory_unreadable) { 255TEST_F(DumpMemoryTest, memory_unreadable) {
208 dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:"); 256 dump_memory(&log_, memory_mock_.get(), 0xa2345678, "memory near pc:");
209 257
210 std::string tombstone_contents; 258 std::string tombstone_contents;
211 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 259 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -259,9 +307,9 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable) {
259 for (size_t i = 0; i < sizeof(buffer); i++) { 307 for (size_t i = 0; i < sizeof(buffer); i++) {
260 buffer[i] = i; 308 buffer[i] = i;
261 } 309 }
262 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 310 memory_mock_->SetReadData(buffer, sizeof(buffer));
263 311
264 dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:"); 312 dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
265 313
266 std::string tombstone_contents; 314 std::string tombstone_contents;
267 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 315 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -278,10 +326,10 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable_unaligned_return) {
278 for (size_t i = 0; i < sizeof(buffer); i++) { 326 for (size_t i = 0; i < sizeof(buffer); i++) {
279 buffer[i] = i; 327 buffer[i] = i;
280 } 328 }
281 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 329 memory_mock_->SetReadData(buffer, sizeof(buffer));
282 backtrace_mock_->SetPartialReadAmount(102); 330 memory_mock_->SetPartialReadAmount(102);
283 331
284 dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:"); 332 dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
285 333
286 std::string tombstone_contents; 334 std::string tombstone_contents;
287 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 335 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -303,10 +351,10 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) {
303 for (size_t i = 0; i < sizeof(buffer); i++) { 351 for (size_t i = 0; i < sizeof(buffer); i++) {
304 buffer[i] = i; 352 buffer[i] = i;
305 } 353 }
306 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 354 memory_mock_->SetReadData(buffer, sizeof(buffer));
307 backtrace_mock_->SetPartialReadAmount(45); 355 memory_mock_->SetPartialReadAmount(45);
308 356
309 dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:"); 357 dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
310 358
311 std::string tombstone_contents; 359 std::string tombstone_contents;
312 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 360 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -330,9 +378,9 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) {
330TEST_F(DumpMemoryTest, address_low_fence) { 378TEST_F(DumpMemoryTest, address_low_fence) {
331 uint8_t buffer[256]; 379 uint8_t buffer[256];
332 memset(buffer, 0, sizeof(buffer)); 380 memset(buffer, 0, sizeof(buffer));
333 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 381 memory_mock_->SetReadData(buffer, sizeof(buffer));
334 382
335 dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1"); 383 dump_memory(&log_, memory_mock_.get(), 0x1000, "memory near %.2s:", "r1");
336 384
337 std::string tombstone_contents; 385 std::string tombstone_contents;
338 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 386 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -384,9 +432,9 @@ TEST_F(DumpMemoryTest, address_low_fence) {
384TEST_F(DumpMemoryTest, memory_address_too_low) { 432TEST_F(DumpMemoryTest, memory_address_too_low) {
385 uint8_t buffer[256]; 433 uint8_t buffer[256];
386 memset(buffer, 0, sizeof(buffer)); 434 memset(buffer, 0, sizeof(buffer));
387 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 435 memory_mock_->SetReadData(buffer, sizeof(buffer));
388 436
389 dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1"); 437 dump_memory(&log_, memory_mock_.get(), 0, "memory near %.2s:", "r1");
390 438
391 std::string tombstone_contents; 439 std::string tombstone_contents;
392 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 440 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -401,16 +449,16 @@ TEST_F(DumpMemoryTest, memory_address_too_low) {
401TEST_F(DumpMemoryTest, memory_address_too_high) { 449TEST_F(DumpMemoryTest, memory_address_too_high) {
402 uint8_t buffer[256]; 450 uint8_t buffer[256];
403 memset(buffer, 0, sizeof(buffer)); 451 memset(buffer, 0, sizeof(buffer));
404 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 452 memory_mock_->SetReadData(buffer, sizeof(buffer));
405 453
406#if defined(__LP64__) 454#if defined(__LP64__)
407 dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1"); 455 dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
408 dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1"); 456 dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
409 dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1"); 457 dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
410#else 458#else
411 dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1"); 459 dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
412 dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1"); 460 dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
413 dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1"); 461 dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
414#endif 462#endif
415 463
416 std::string tombstone_contents; 464 std::string tombstone_contents;
@@ -426,12 +474,12 @@ TEST_F(DumpMemoryTest, memory_address_too_high) {
426TEST_F(DumpMemoryTest, memory_address_would_overflow) { 474TEST_F(DumpMemoryTest, memory_address_would_overflow) {
427 uint8_t buffer[256]; 475 uint8_t buffer[256];
428 memset(buffer, 0, sizeof(buffer)); 476 memset(buffer, 0, sizeof(buffer));
429 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 477 memory_mock_->SetReadData(buffer, sizeof(buffer));
430 478
431#if defined(__LP64__) 479#if defined(__LP64__)
432 dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1"); 480 dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
433#else 481#else
434 dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1"); 482 dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
435#endif 483#endif
436 484
437 std::string tombstone_contents; 485 std::string tombstone_contents;
@@ -449,12 +497,12 @@ TEST_F(DumpMemoryTest, memory_address_nearly_too_high) {
449 for (size_t i = 0; i < sizeof(buffer); i++) { 497 for (size_t i = 0; i < sizeof(buffer); i++) {
450 buffer[i] = i; 498 buffer[i] = i;
451 } 499 }
452 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 500 memory_mock_->SetReadData(buffer, sizeof(buffer));
453 501
454#if defined(__LP64__) 502#if defined(__LP64__)
455 dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4"); 503 dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
456#else 504#else
457 dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4"); 505 dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
458#endif 506#endif
459 507
460 std::string tombstone_contents; 508 std::string tombstone_contents;
@@ -509,12 +557,12 @@ TEST_F(DumpMemoryTest, first_read_empty) {
509 for (size_t i = 0; i < sizeof(buffer); i++) { 557 for (size_t i = 0; i < sizeof(buffer); i++) {
510 buffer[i] = i; 558 buffer[i] = i;
511 } 559 }
512 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 560 memory_mock_->SetReadData(buffer, sizeof(buffer));
513 backtrace_mock_->SetPartialReadAmount(0); 561 memory_mock_->SetPartialReadAmount(0);
514 562
515 size_t page_size = sysconf(_SC_PAGE_SIZE); 563 size_t page_size = sysconf(_SC_PAGE_SIZE);
516 uintptr_t addr = 0x10000020 + page_size - 120; 564 uintptr_t addr = 0x10000020 + page_size - 120;
517 dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); 565 dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
518 566
519 std::string tombstone_contents; 567 std::string tombstone_contents;
520 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 568 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -568,12 +616,12 @@ TEST_F(DumpMemoryTest, first_read_empty_second_read_stops) {
568 for (size_t i = 0; i < sizeof(buffer); i++) { 616 for (size_t i = 0; i < sizeof(buffer); i++) {
569 buffer[i] = i; 617 buffer[i] = i;
570 } 618 }
571 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 619 memory_mock_->SetReadData(buffer, sizeof(buffer));
572 backtrace_mock_->SetPartialReadAmount(0); 620 memory_mock_->SetPartialReadAmount(0);
573 621
574 size_t page_size = sysconf(_SC_PAGE_SIZE); 622 size_t page_size = sysconf(_SC_PAGE_SIZE);
575 uintptr_t addr = 0x10000020 + page_size - 192; 623 uintptr_t addr = 0x10000020 + page_size - 192;
576 dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); 624 dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
577 625
578 std::string tombstone_contents; 626 std::string tombstone_contents;
579 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 627 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -627,11 +675,11 @@ TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range) {
627 for (size_t i = 0; i < sizeof(buffer); i++) { 675 for (size_t i = 0; i < sizeof(buffer); i++) {
628 buffer[i] = i; 676 buffer[i] = i;
629 } 677 }
630 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 678 memory_mock_->SetReadData(buffer, sizeof(buffer));
631 backtrace_mock_->SetPartialReadAmount(0); 679 memory_mock_->SetPartialReadAmount(0);
632 680
633 uintptr_t addr = 0x10000020; 681 uintptr_t addr = 0x10000020;
634 dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); 682 dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
635 683
636 std::string tombstone_contents; 684 std::string tombstone_contents;
637 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 685 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -685,13 +733,13 @@ TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range_fence_post) {
685 for (size_t i = 0; i < sizeof(buffer); i++) { 733 for (size_t i = 0; i < sizeof(buffer); i++) {
686 buffer[i] = i; 734 buffer[i] = i;
687 } 735 }
688 backtrace_mock_->SetReadData(buffer, sizeof(buffer)); 736 memory_mock_->SetReadData(buffer, sizeof(buffer));
689 backtrace_mock_->SetPartialReadAmount(0); 737 memory_mock_->SetPartialReadAmount(0);
690 738
691 size_t page_size = sysconf(_SC_PAGE_SIZE); 739 size_t page_size = sysconf(_SC_PAGE_SIZE);
692 uintptr_t addr = 0x10000020 + page_size - 256; 740 uintptr_t addr = 0x10000020 + page_size - 256;
693 741
694 dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); 742 dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
695 743
696 std::string tombstone_contents; 744 std::string tombstone_contents;
697 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 745 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 f8cbca771..9b8281a70 100644
--- a/debuggerd/libdebuggerd/test/elf_fake.cpp
+++ b/debuggerd/libdebuggerd/test/elf_fake.cpp
@@ -20,7 +20,9 @@
20 20
21#include <string> 21#include <string>
22 22
23class Backtrace; 23namespace unwindstack {
24class Memory;
25}
24 26
25std::string g_build_id; 27std::string g_build_id;
26 28
@@ -28,7 +30,7 @@ void elf_set_fake_build_id(const std::string& build_id) {
28 g_build_id = build_id; 30 g_build_id = build_id;
29} 31}
30 32
31bool elf_get_build_id(Backtrace*, uintptr_t, std::string* build_id) { 33bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string* build_id) {
32 if (g_build_id != "") { 34 if (g_build_id != "") {
33 *build_id = g_build_id; 35 *build_id = g_build_id;
34 return true; 36 return true;
diff --git a/debuggerd/libdebuggerd/test/ptrace_fake.cpp b/debuggerd/libdebuggerd/test/ptrace_fake.cpp
deleted file mode 100644
index 0d4080ebf..000000000
--- a/debuggerd/libdebuggerd/test/ptrace_fake.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ptrace_fake.h"
18
19#include <errno.h>
20#include <signal.h>
21#include <stdarg.h>
22#include <sys/ptrace.h>
23
24#include <string>
25
26siginfo_t g_fake_si = {.si_signo = 0};
27
28void ptrace_set_fake_getsiginfo(const siginfo_t& si) {
29 g_fake_si = si;
30}
31
32#if !defined(__BIONIC__)
33extern "C" long ptrace_fake(enum __ptrace_request request, ...) {
34#else
35extern "C" long ptrace_fake(int request, ...) {
36#endif
37 if (request == PTRACE_GETSIGINFO) {
38 if (g_fake_si.si_signo == 0) {
39 errno = EFAULT;
40 return -1;
41 }
42
43 va_list ap;
44 va_start(ap, request);
45 va_arg(ap, int);
46 va_arg(ap, int);
47 siginfo_t* si = va_arg(ap, siginfo*);
48 va_end(ap);
49 *si = g_fake_si;
50 return 0;
51 }
52 return -1;
53}
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 59a43b73b..1e3a10f08 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -29,11 +29,6 @@
29#include "elf_fake.h" 29#include "elf_fake.h"
30#include "host_signal_fixup.h" 30#include "host_signal_fixup.h"
31#include "log_fake.h" 31#include "log_fake.h"
32#include "ptrace_fake.h"
33
34// In order to test this code, we need to include the tombstone.cpp code.
35// Including it, also allows us to override the ptrace function.
36#define ptrace ptrace_fake
37 32
38#include "tombstone.cpp" 33#include "tombstone.cpp"
39 34
@@ -50,7 +45,6 @@ class TombstoneTest : public ::testing::Test {
50 protected: 45 protected:
51 virtual void SetUp() { 46 virtual void SetUp() {
52 map_mock_.reset(new BacktraceMapMock()); 47 map_mock_.reset(new BacktraceMapMock());
53 backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
54 48
55 char tmp_file[256]; 49 char tmp_file[256];
56 const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX"; 50 const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -77,11 +71,6 @@ class TombstoneTest : public ::testing::Test {
77 71
78 resetLogs(); 72 resetLogs();
79 elf_set_fake_build_id(""); 73 elf_set_fake_build_id("");
80 siginfo_t si;
81 memset(&si, 0, sizeof(si));
82 si.si_signo = SIGABRT;
83 si.si_code = SI_KERNEL;
84 ptrace_set_fake_getsiginfo(si);
85 } 74 }
86 75
87 virtual void TearDown() { 76 virtual void TearDown() {
@@ -91,7 +80,6 @@ class TombstoneTest : public ::testing::Test {
91 } 80 }
92 81
93 std::unique_ptr<BacktraceMapMock> map_mock_; 82 std::unique_ptr<BacktraceMapMock> map_mock_;
94 std::unique_ptr<BacktraceMock> backtrace_mock_;
95 83
96 log_t log_; 84 log_t log_;
97 std::string amfd_data_; 85 std::string amfd_data_;
@@ -108,7 +96,7 @@ TEST_F(TombstoneTest, single_map) {
108#endif 96#endif
109 map_mock_->AddMap(map); 97 map_mock_->AddMap(map);
110 98
111 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100); 99 dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
112 100
113 std::string tombstone_contents; 101 std::string tombstone_contents;
114 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 102 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -143,7 +131,7 @@ TEST_F(TombstoneTest, single_map_elf_build_id) {
143 map_mock_->AddMap(map); 131 map_mock_->AddMap(map);
144 132
145 elf_set_fake_build_id("abcdef1234567890abcdef1234567890"); 133 elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
146 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100); 134 dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
147 135
148 std::string tombstone_contents; 136 std::string tombstone_contents;
149 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 137 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -182,7 +170,7 @@ TEST_F(TombstoneTest, single_map_no_build_id) {
182 map_mock_->AddMap(map); 170 map_mock_->AddMap(map);
183 171
184 elf_set_fake_build_id("abcdef1234567890abcdef1234567890"); 172 elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
185 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100); 173 dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
186 174
187 std::string tombstone_contents; 175 std::string tombstone_contents;
188 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 176 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -240,7 +228,7 @@ TEST_F(TombstoneTest, multiple_maps) {
240 map.name = "/system/lib/fake.so"; 228 map.name = "/system/lib/fake.so";
241 map_mock_->AddMap(map); 229 map_mock_->AddMap(map);
242 230
243 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100); 231 dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
244 232
245 std::string tombstone_contents; 233 std::string tombstone_contents;
246 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 234 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -294,13 +282,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
294 map.name = "/system/lib/fake.so"; 282 map.name = "/system/lib/fake.so";
295 map_mock_->AddMap(map); 283 map_mock_->AddMap(map);
296 284
297 siginfo_t si; 285 dump_all_maps(&log_, map_mock_.get(), nullptr, 0x1000);
298 memset(&si, 0, sizeof(si));
299 si.si_signo = SIGBUS;
300 si.si_code = SI_KERNEL;
301 si.si_addr = reinterpret_cast<void*>(0x1000);
302 ptrace_set_fake_getsiginfo(si);
303 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
304 286
305 std::string tombstone_contents; 287 std::string tombstone_contents;
306 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 288 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -352,13 +334,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
352 map.name = "/system/lib/fake.so"; 334 map.name = "/system/lib/fake.so";
353 map_mock_->AddMap(map); 335 map_mock_->AddMap(map);
354 336
355 siginfo_t si; 337 dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa533000);
356 memset(&si, 0, sizeof(si));
357 si.si_signo = SIGBUS;
358 si.si_code = SI_KERNEL;
359 si.si_addr = reinterpret_cast<void*>(0xa533000);
360 ptrace_set_fake_getsiginfo(si);
361 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
362 338
363 std::string tombstone_contents; 339 std::string tombstone_contents;
364 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 340 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -410,13 +386,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
410 map.name = "/system/lib/fake.so"; 386 map.name = "/system/lib/fake.so";
411 map_mock_->AddMap(map); 387 map_mock_->AddMap(map);
412 388
413 siginfo_t si; 389 dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa534040);
414 memset(&si, 0, sizeof(si));
415 si.si_signo = SIGBUS;
416 si.si_code = SI_KERNEL;
417 si.si_addr = reinterpret_cast<void*>(0xa534040);
418 ptrace_set_fake_getsiginfo(si);
419 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
420 390
421 std::string tombstone_contents; 391 std::string tombstone_contents;
422 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 392 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -466,17 +436,12 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
466 map.name = "/system/lib/fake.so"; 436 map.name = "/system/lib/fake.so";
467 map_mock_->AddMap(map); 437 map_mock_->AddMap(map);
468 438
469 siginfo_t si;
470 memset(&si, 0, sizeof(si));
471 si.si_signo = SIGBUS;
472 si.si_code = SI_KERNEL;
473#if defined(__LP64__) 439#if defined(__LP64__)
474 si.si_addr = reinterpret_cast<void*>(0x12345a534040UL); 440 uintptr_t addr = 0x12345a534040UL;
475#else 441#else
476 si.si_addr = reinterpret_cast<void*>(0xf534040UL); 442 uintptr_t addr = 0xf534040UL;
477#endif 443#endif
478 ptrace_set_fake_getsiginfo(si); 444 dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
479 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
480 445
481 std::string tombstone_contents; 446 std::string tombstone_contents;
482 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); 447 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -503,124 +468,6 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
503 ASSERT_STREQ("", getFakeLogPrint().c_str()); 468 ASSERT_STREQ("", getFakeLogPrint().c_str());
504} 469}
505 470
506TEST_F(TombstoneTest, multiple_maps_getsiginfo_fail) {
507 backtrace_map_t map;
508
509 map.start = 0xa434000;
510 map.end = 0xa435000;
511 map.offset = 0x1000;
512 map.load_bias = 0xd000;
513 map.flags = PROT_WRITE;
514 map_mock_->AddMap(map);
515
516 siginfo_t si;
517 memset(&si, 0, sizeof(si));
518 ptrace_set_fake_getsiginfo(si);
519 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
520
521 std::string tombstone_contents;
522 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
523 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
524 const char* expected_dump =
525 "\nmemory map (1 entry):\n"
526#if defined(__LP64__)
527 " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n";
528#else
529 " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n";
530#endif
531 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
532
533 ASSERT_STREQ("", amfd_data_.c_str());
534
535 // Verify that the log buf is empty, and no error messages.
536 ASSERT_STREQ("", getFakeLogBuf().c_str());
537 ASSERT_STREQ("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
538}
539
540TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) {
541 backtrace_map_t map;
542
543 map.start = 0xa434000;
544 map.end = 0xa435000;
545 map.flags = PROT_WRITE;
546 map_mock_->AddMap(map);
547
548 for (int i = 1; i < 255; i++) {
549 ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
550 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
551
552 siginfo_t si;
553 memset(&si, 0, sizeof(si));
554 si.si_signo = i;
555 si.si_code = SI_KERNEL;
556 si.si_addr = reinterpret_cast<void*>(0x1000);
557 ptrace_set_fake_getsiginfo(si);
558 dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
559
560 std::string tombstone_contents;
561 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
562 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
563 bool has_addr = false;
564 switch (si.si_signo) {
565 case SIGBUS:
566 case SIGFPE:
567 case SIGILL:
568 case SIGSEGV:
569 case SIGTRAP:
570 has_addr = true;
571 break;
572 }
573
574 const char* expected_addr_dump = \
575"\nmemory map (1 entry):\n"
576#if defined(__LP64__)
577"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
578" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
579#else
580"--->Fault address falls at 00001000 before any mapped regions\n"
581" 0a434000-0a434fff -w- 0 1000\n";
582#endif
583 const char* expected_dump = \
584"\nmemory map (1 entry):\n"
585#if defined(__LP64__)
586" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
587#else
588" 0a434000-0a434fff -w- 0 1000\n";
589#endif
590 if (has_addr) {
591 ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
592 << "Signal " << si.si_signo << " expected to include an address.";
593 } else {
594 ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
595 << "Signal " << si.si_signo << " is not expected to include an address.";
596 }
597
598 ASSERT_STREQ("", amfd_data_.c_str());
599
600 // Verify that the log buf is empty, and no error messages.
601 ASSERT_STREQ("", getFakeLogBuf().c_str());
602 ASSERT_STREQ("", getFakeLogPrint().c_str());
603 }
604}
605
606TEST_F(TombstoneTest, dump_signal_info_error) {
607 siginfo_t si;
608 memset(&si, 0, sizeof(si));
609 ptrace_set_fake_getsiginfo(si);
610
611 dump_signal_info(&log_, 123);
612
613 std::string tombstone_contents;
614 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
615 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
616 ASSERT_STREQ("", tombstone_contents.c_str());
617
618 ASSERT_STREQ("", getFakeLogBuf().c_str());
619 ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
620
621 ASSERT_STREQ("", amfd_data_.c_str());
622}
623
624TEST_F(TombstoneTest, dump_log_file_error) { 471TEST_F(TombstoneTest, dump_log_file_error) {
625 log_.should_retrieve_logcat = true; 472 log_.should_retrieve_logcat = true;
626 dump_log_file(&log_, 123, "/fake/filename", 10); 473 dump_log_file(&log_, 123, "/fake/filename", 10);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index a0ba81b68..99da8011b 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -35,8 +35,10 @@
35#include <string> 35#include <string>
36 36
37#include <android-base/file.h> 37#include <android-base/file.h>
38#include <android-base/logging.h>
38#include <android-base/properties.h> 39#include <android-base/properties.h>
39#include <android-base/stringprintf.h> 40#include <android-base/stringprintf.h>
41#include <android-base/strings.h>
40#include <android-base/unique_fd.h> 42#include <android-base/unique_fd.h>
41#include <android/log.h> 43#include <android/log.h>
42#include <backtrace/Backtrace.h> 44#include <backtrace/Backtrace.h>
@@ -44,168 +46,26 @@
44#include <log/log.h> 46#include <log/log.h>
45#include <log/logprint.h> 47#include <log/logprint.h>
46#include <private/android_filesystem_config.h> 48#include <private/android_filesystem_config.h>
49#include <unwindstack/Memory.h>
50#include <unwindstack/Regs.h>
47 51
48// Needed to get DEBUGGER_SIGNAL. 52// Needed to get DEBUGGER_SIGNAL.
49#include "debuggerd/handler.h" 53#include "debuggerd/handler.h"
50 54
51#include "libdebuggerd/backtrace.h" 55#include "libdebuggerd/backtrace.h"
52#include "libdebuggerd/elf_utils.h" 56#include "libdebuggerd/elf_utils.h"
53#include "libdebuggerd/machine.h"
54#include "libdebuggerd/open_files_list.h" 57#include "libdebuggerd/open_files_list.h"
58#include "libdebuggerd/utility.h"
55 59
56using android::base::GetBoolProperty; 60using android::base::GetBoolProperty;
57using android::base::GetProperty; 61using android::base::GetProperty;
58using android::base::StringPrintf; 62using android::base::StringPrintf;
63using android::base::unique_fd;
59 64
60#define STACK_WORDS 16 65using unwindstack::Memory;
66using unwindstack::Regs;
61 67
62static bool signal_has_si_addr(int si_signo, int si_code) { 68#define STACK_WORDS 16
63 // Manually sent signals won't have si_addr.
64 if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
65 return false;
66 }
67
68 switch (si_signo) {
69 case SIGBUS:
70 case SIGFPE:
71 case SIGILL:
72 case SIGSEGV:
73 case SIGTRAP:
74 return true;
75 default:
76 return false;
77 }
78}
79
80static const char* get_signame(int sig) {
81 switch (sig) {
82 case SIGABRT: return "SIGABRT";
83 case SIGBUS: return "SIGBUS";
84 case SIGFPE: return "SIGFPE";
85 case SIGILL: return "SIGILL";
86 case SIGSEGV: return "SIGSEGV";
87#if defined(SIGSTKFLT)
88 case SIGSTKFLT: return "SIGSTKFLT";
89#endif
90 case SIGSTOP: return "SIGSTOP";
91 case SIGSYS: return "SIGSYS";
92 case SIGTRAP: return "SIGTRAP";
93 case DEBUGGER_SIGNAL: return "<debuggerd signal>";
94 default: return "?";
95 }
96}
97
98static const char* get_sigcode(int signo, int code) {
99 // Try the signal-specific codes...
100 switch (signo) {
101 case SIGILL:
102 switch (code) {
103 case ILL_ILLOPC: return "ILL_ILLOPC";
104 case ILL_ILLOPN: return "ILL_ILLOPN";
105 case ILL_ILLADR: return "ILL_ILLADR";
106 case ILL_ILLTRP: return "ILL_ILLTRP";
107 case ILL_PRVOPC: return "ILL_PRVOPC";
108 case ILL_PRVREG: return "ILL_PRVREG";
109 case ILL_COPROC: return "ILL_COPROC";
110 case ILL_BADSTK: return "ILL_BADSTK";
111 }
112 static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
113 break;
114 case SIGBUS:
115 switch (code) {
116 case BUS_ADRALN: return "BUS_ADRALN";
117 case BUS_ADRERR: return "BUS_ADRERR";
118 case BUS_OBJERR: return "BUS_OBJERR";
119 case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
120 case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
121 }
122 static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
123 break;
124 case SIGFPE:
125 switch (code) {
126 case FPE_INTDIV: return "FPE_INTDIV";
127 case FPE_INTOVF: return "FPE_INTOVF";
128 case FPE_FLTDIV: return "FPE_FLTDIV";
129 case FPE_FLTOVF: return "FPE_FLTOVF";
130 case FPE_FLTUND: return "FPE_FLTUND";
131 case FPE_FLTRES: return "FPE_FLTRES";
132 case FPE_FLTINV: return "FPE_FLTINV";
133 case FPE_FLTSUB: return "FPE_FLTSUB";
134 }
135 static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
136 break;
137 case SIGSEGV:
138 switch (code) {
139 case SEGV_MAPERR: return "SEGV_MAPERR";
140 case SEGV_ACCERR: return "SEGV_ACCERR";
141#if defined(SEGV_BNDERR)
142 case SEGV_BNDERR: return "SEGV_BNDERR";
143#endif
144#if defined(SEGV_PKUERR)
145 case SEGV_PKUERR: return "SEGV_PKUERR";
146#endif
147 }
148#if defined(SEGV_PKUERR)
149 static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
150#elif defined(SEGV_BNDERR)
151 static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
152#else
153 static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
154#endif
155 break;
156#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
157 case SIGSYS:
158 switch (code) {
159 case SYS_SECCOMP: return "SYS_SECCOMP";
160 }
161 static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
162 break;
163#endif
164 case SIGTRAP:
165 switch (code) {
166 case TRAP_BRKPT: return "TRAP_BRKPT";
167 case TRAP_TRACE: return "TRAP_TRACE";
168 case TRAP_BRANCH: return "TRAP_BRANCH";
169 case TRAP_HWBKPT: return "TRAP_HWBKPT";
170 }
171 if ((code & 0xff) == SIGTRAP) {
172 switch ((code >> 8) & 0xff) {
173 case PTRACE_EVENT_FORK:
174 return "PTRACE_EVENT_FORK";
175 case PTRACE_EVENT_VFORK:
176 return "PTRACE_EVENT_VFORK";
177 case PTRACE_EVENT_CLONE:
178 return "PTRACE_EVENT_CLONE";
179 case PTRACE_EVENT_EXEC:
180 return "PTRACE_EVENT_EXEC";
181 case PTRACE_EVENT_VFORK_DONE:
182 return "PTRACE_EVENT_VFORK_DONE";
183 case PTRACE_EVENT_EXIT:
184 return "PTRACE_EVENT_EXIT";
185 case PTRACE_EVENT_SECCOMP:
186 return "PTRACE_EVENT_SECCOMP";
187 case PTRACE_EVENT_STOP:
188 return "PTRACE_EVENT_STOP";
189 }
190 }
191 static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
192 break;
193 }
194 // Then the other codes...
195 switch (code) {
196 case SI_USER: return "SI_USER";
197 case SI_KERNEL: return "SI_KERNEL";
198 case SI_QUEUE: return "SI_QUEUE";
199 case SI_TIMER: return "SI_TIMER";
200 case SI_MESGQ: return "SI_MESGQ";
201 case SI_ASYNCIO: return "SI_ASYNCIO";
202 case SI_SIGIO: return "SI_SIGIO";
203 case SI_TKILL: return "SI_TKILL";
204 case SI_DETHREAD: return "SI_DETHREAD";
205 }
206 // Then give up...
207 return "?";
208}
209 69
210static void dump_header_info(log_t* log) { 70static void dump_header_info(log_t* log) {
211 auto fingerprint = GetProperty("ro.build.fingerprint", "unknown"); 71 auto fingerprint = GetProperty("ro.build.fingerprint", "unknown");
@@ -216,73 +76,64 @@ static void dump_header_info(log_t* log) {
216 _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING); 76 _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
217} 77}
218 78
219static void dump_probable_cause(log_t* log, const siginfo_t& si) { 79static void dump_probable_cause(log_t* log, const siginfo_t* si) {
220 std::string cause; 80 std::string cause;
221 if (si.si_signo == SIGSEGV && si.si_code == SEGV_MAPERR) { 81 if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
222 if (si.si_addr < reinterpret_cast<void*>(4096)) { 82 if (si->si_addr < reinterpret_cast<void*>(4096)) {
223 cause = StringPrintf("null pointer dereference"); 83 cause = StringPrintf("null pointer dereference");
224 } else if (si.si_addr == reinterpret_cast<void*>(0xffff0ffc)) { 84 } else if (si->si_addr == reinterpret_cast<void*>(0xffff0ffc)) {
225 cause = "call to kuser_helper_version"; 85 cause = "call to kuser_helper_version";
226 } else if (si.si_addr == reinterpret_cast<void*>(0xffff0fe0)) { 86 } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fe0)) {
227 cause = "call to kuser_get_tls"; 87 cause = "call to kuser_get_tls";
228 } else if (si.si_addr == reinterpret_cast<void*>(0xffff0fc0)) { 88 } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fc0)) {
229 cause = "call to kuser_cmpxchg"; 89 cause = "call to kuser_cmpxchg";
230 } else if (si.si_addr == reinterpret_cast<void*>(0xffff0fa0)) { 90 } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fa0)) {
231 cause = "call to kuser_memory_barrier"; 91 cause = "call to kuser_memory_barrier";
232 } else if (si.si_addr == r