blob: 91d9dda3a871db4a95d17f00f089583ed4553535 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/* system/debuggerd/debuggerd.c
2**
3** Copyright 2006, The Android Open Source Project
4**
Ben Cheng09e71372009-09-28 11:06:09 -07005** 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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08008**
Ben Cheng09e71372009-09-28 11:06:09 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080010**
Ben Cheng09e71372009-09-28 11:06:09 -070011** 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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080015** limitations under the License.
16*/
17
18#include <stdio.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080019#include <errno.h>
20#include <signal.h>
21#include <pthread.h>
22#include <stdarg.h>
23#include <fcntl.h>
24#include <sys/types.h>
25#include <dirent.h>
26
27#include <sys/ptrace.h>
28#include <sys/wait.h>
29#include <sys/exec_elf.h>
30#include <sys/stat.h>
31
32#include <cutils/sockets.h>
33#include <cutils/logd.h>
Andy McFadden41e0cef2011-10-13 16:05:08 -070034#include <cutils/logger.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080035#include <cutils/properties.h>
36
37#include <linux/input.h>
38
39#include <private/android_filesystem_config.h>
40
Bruce Beare84924902010-10-13 14:21:30 -070041#include "debuggerd.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042#include "utility.h"
43
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080044#define ANDROID_LOG_INFO 4
45
46/* Log information onto the tombstone */
47void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
48{
Meng Huae7b91b2009-11-05 16:10:50 -060049 char buf[512];
Ben Cheng09e71372009-09-28 11:06:09 -070050
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080051 va_list ap;
52 va_start(ap, fmt);
53
54 if (tfd >= 0) {
55 int len;
56 vsnprintf(buf, sizeof(buf), fmt, ap);
57 len = strlen(buf);
58 if(tfd >= 0) write(tfd, buf, len);
59 }
60
61 if (!in_tombstone_only)
62 __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
63}
64
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080065// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
66// 012345678901234567890123456789012345678901234567890123456789
67// 0 1 2 3 4 5
68
69mapinfo *parse_maps_line(char *line)
70{
71 mapinfo *mi;
72 int len = strlen(line);
73
Andy McFadden136dcc52011-09-22 16:37:06 -070074 if (len < 1) return 0; /* not expected */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080075 line[--len] = 0;
Ben Cheng09e71372009-09-28 11:06:09 -070076
Andy McFadden136dcc52011-09-22 16:37:06 -070077 if (len < 50) {
78 mi = malloc(sizeof(mapinfo) + 1);
79 } else {
80 mi = malloc(sizeof(mapinfo) + (len - 47));
81 }
82 if (mi == 0) return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080083
Andy McFadden136dcc52011-09-22 16:37:06 -070084 mi->isExecutable = (line[20] == 'x');
Ben Cheng09e71372009-09-28 11:06:09 -070085
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080086 mi->start = strtoul(line, 0, 16);
87 mi->end = strtoul(line + 9, 0, 16);
Meng Huae7b91b2009-11-05 16:10:50 -060088 /* To be filled in parse_elf_info if the mapped section starts with
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080089 * elf_header
90 */
91 mi->exidx_start = mi->exidx_end = 0;
Meng Huae7b91b2009-11-05 16:10:50 -060092 mi->symbols = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080093 mi->next = 0;
Andy McFadden136dcc52011-09-22 16:37:06 -070094 if (len < 50) {
95 mi->name[0] = '\0';
96 } else {
97 strcpy(mi->name, line + 49);
98 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080099
100 return mi;
101}
102
103void dump_build_info(int tfd)
104{
105 char fingerprint[PROPERTY_VALUE_MAX];
106
107 property_get("ro.build.fingerprint", fingerprint, "unknown");
108
109 _LOG(tfd, false, "Build fingerprint: '%s'\n", fingerprint);
110}
111
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800112const char *get_signame(int sig)
113{
114 switch(sig) {
115 case SIGILL: return "SIGILL";
116 case SIGABRT: return "SIGABRT";
117 case SIGBUS: return "SIGBUS";
118 case SIGFPE: return "SIGFPE";
119 case SIGSEGV: return "SIGSEGV";
120 case SIGSTKFLT: return "SIGSTKFLT";
121 default: return "?";
122 }
123}
124
Carl Shapiro83c6b052010-10-08 18:10:24 -0700125const char *get_sigcode(int signo, int code)
126{
127 switch (signo) {
128 case SIGILL:
129 switch (code) {
130 case ILL_ILLOPC: return "ILL_ILLOPC";
131 case ILL_ILLOPN: return "ILL_ILLOPN";
132 case ILL_ILLADR: return "ILL_ILLADR";
133 case ILL_ILLTRP: return "ILL_ILLTRP";
134 case ILL_PRVOPC: return "ILL_PRVOPC";
135 case ILL_PRVREG: return "ILL_PRVREG";
136 case ILL_COPROC: return "ILL_COPROC";
137 case ILL_BADSTK: return "ILL_BADSTK";
138 }
139 break;
140 case SIGBUS:
141 switch (code) {
142 case BUS_ADRALN: return "BUS_ADRALN";
143 case BUS_ADRERR: return "BUS_ADRERR";
144 case BUS_OBJERR: return "BUS_OBJERR";
145 }
146 break;
147 case SIGFPE:
148 switch (code) {
149 case FPE_INTDIV: return "FPE_INTDIV";
150 case FPE_INTOVF: return "FPE_INTOVF";
151 case FPE_FLTDIV: return "FPE_FLTDIV";
152 case FPE_FLTOVF: return "FPE_FLTOVF";
153 case FPE_FLTUND: return "FPE_FLTUND";
154 case FPE_FLTRES: return "FPE_FLTRES";
155 case FPE_FLTINV: return "FPE_FLTINV";
156 case FPE_FLTSUB: return "FPE_FLTSUB";
157 }
158 break;
159 case SIGSEGV:
160 switch (code) {
161 case SEGV_MAPERR: return "SEGV_MAPERR";
162 case SEGV_ACCERR: return "SEGV_ACCERR";
163 }
164 break;
165 }
166 return "?";
167}
168
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800169void dump_fault_addr(int tfd, int pid, int sig)
170{
171 siginfo_t si;
Ben Cheng09e71372009-09-28 11:06:09 -0700172
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800173 memset(&si, 0, sizeof(si));
174 if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){
175 _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno));
Andy McFadden136dcc52011-09-22 16:37:06 -0700176 } else if (signal_has_address(sig)) {
Carl Shapiro83c6b052010-10-08 18:10:24 -0700177 _LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
178 sig, get_signame(sig),
179 si.si_code, get_sigcode(sig, si.si_code),
180 si.si_addr);
Andy McFadden136dcc52011-09-22 16:37:06 -0700181 } else {
182 _LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr --------\n",
183 sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800184 }
185}
186
187void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig)
188{
189 char data[1024];
190 char *x = 0;
191 FILE *fp;
Ben Cheng09e71372009-09-28 11:06:09 -0700192
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800193 sprintf(data, "/proc/%d/cmdline", pid);
194 fp = fopen(data, "r");
195 if(fp) {
196 x = fgets(data, 1024, fp);
197 fclose(fp);
198 }
Ben Cheng09e71372009-09-28 11:06:09 -0700199
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800200 _LOG(tfd, false,
201 "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
202 dump_build_info(tfd);
203 _LOG(tfd, false, "pid: %d, tid: %d >>> %s <<<\n",
204 pid, tid, x ? x : "UNKNOWN");
Ben Cheng09e71372009-09-28 11:06:09 -0700205
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800206 if(sig) dump_fault_addr(tfd, tid, sig);
207}
208
Meng Huae7b91b2009-11-05 16:10:50 -0600209static void parse_elf_info(mapinfo *milist, pid_t pid)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800210{
211 mapinfo *mi;
212 for (mi = milist; mi != NULL; mi = mi->next) {
Andy McFadden136dcc52011-09-22 16:37:06 -0700213 if (!mi->isExecutable)
214 continue;
215
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800216 Elf32_Ehdr ehdr;
217
218 memset(&ehdr, 0, sizeof(Elf32_Ehdr));
Ben Cheng09e71372009-09-28 11:06:09 -0700219 /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800220 * mapped section.
221 */
Ben Cheng09e71372009-09-28 11:06:09 -0700222 get_remote_struct(pid, (void *) (mi->start), &ehdr,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223 sizeof(Elf32_Ehdr));
224 /* Check if it has the matching magic words */
225 if (IS_ELF(ehdr)) {
226 Elf32_Phdr phdr;
227 Elf32_Phdr *ptr;
228 int i;
229
230 ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff);
231 for (i = 0; i < ehdr.e_phnum; i++) {
232 /* Parse the program header */
Mike Dodd6b657472010-07-14 11:28:29 -0700233 get_remote_struct(pid, (char *) (ptr+i), &phdr,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234 sizeof(Elf32_Phdr));
Bruce Beare84924902010-10-13 14:21:30 -0700235#ifdef __arm__
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800236 /* Found a EXIDX segment? */
237 if (phdr.p_type == PT_ARM_EXIDX) {
238 mi->exidx_start = mi->start + phdr.p_offset;
239 mi->exidx_end = mi->exidx_start + phdr.p_filesz;
240 break;
241 }
Bruce Beare84924902010-10-13 14:21:30 -0700242#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800243 }
Meng Huae7b91b2009-11-05 16:10:50 -0600244
245 /* Try to load symbols from this file */
246 mi->symbols = symbol_table_create(mi->name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800247 }
248 }
249}
250
251void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault)
252{
253 char data[1024];
254 FILE *fp;
255 mapinfo *milist = 0;
256 unsigned int sp_list[STACK_CONTENT_DEPTH];
257 int stack_depth;
Bruce Beare84924902010-10-13 14:21:30 -0700258#ifdef __arm__
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800259 int frame0_pc_sane = 1;
Bruce Beare84924902010-10-13 14:21:30 -0700260#endif
Ben Cheng09e71372009-09-28 11:06:09 -0700261
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800262 if (!at_fault) {
263 _LOG(tfd, true,
264 "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
265 _LOG(tfd, true, "pid: %d, tid: %d\n", pid, tid);
266 }
267
268 dump_registers(tfd, tid, at_fault);
Ben Cheng09e71372009-09-28 11:06:09 -0700269
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800270 /* Clear stack pointer records */
271 memset(sp_list, 0, sizeof(sp_list));
272
273 sprintf(data, "/proc/%d/maps", pid);
274 fp = fopen(data, "r");
275 if(fp) {
276 while(fgets(data, 1024, fp)) {
277 mapinfo *mi = parse_maps_line(data);
278 if(mi) {
279 mi->next = milist;
280 milist = mi;
281 }
282 }
283 fclose(fp);
284 }
285
Meng Huae7b91b2009-11-05 16:10:50 -0600286 parse_elf_info(milist, tid);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800287
Bruce Beare84924902010-10-13 14:21:30 -0700288#if __arm__
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800289 /* If stack unwinder fails, use the default solution to dump the stack
290 * content.
291 */
292 stack_depth = unwind_backtrace_with_ptrace(tfd, tid, milist, sp_list,
293 &frame0_pc_sane, at_fault);
294
295 /* The stack unwinder should at least unwind two levels of stack. If less
296 * level is seen we make sure at lease pc and lr are dumped.
297 */
298 if (stack_depth < 2) {
299 dump_pc_and_lr(tfd, tid, milist, stack_depth, at_fault);
300 }
301
Ben Cheng2854db82010-01-28 10:00:03 -0800302 dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, at_fault);
Bruce Beare6cc49232010-10-13 16:11:15 -0700303#elif __i386__
304 /* If stack unwinder fails, use the default solution to dump the stack
305 * content.
306 */
307 stack_depth = unwind_backtrace_with_ptrace_x86(tfd, tid, milist,at_fault);
308#else
309#error "Unsupported architecture"
Bruce Beare84924902010-10-13 14:21:30 -0700310#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800311
312 while(milist) {
313 mapinfo *next = milist->next;
Meng Huae7b91b2009-11-05 16:10:50 -0600314 symbol_table_free(milist->symbols);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800315 free(milist);
316 milist = next;
317 }
318}
319
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800320#define MAX_TOMBSTONES 10
321
322#define typecheck(x,y) { \
323 typeof(x) __dummy1; \
324 typeof(y) __dummy2; \
325 (void)(&__dummy1 == &__dummy2); }
326
327#define TOMBSTONE_DIR "/data/tombstones"
328
329/*
330 * find_and_open_tombstone - find an available tombstone slot, if any, of the
331 * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
332 * file is available, we reuse the least-recently-modified file.
333 */
334static int find_and_open_tombstone(void)
335{
336 unsigned long mtime = ULONG_MAX;
337 struct stat sb;
338 char path[128];
339 int fd, i, oldest = 0;
340
341 /*
342 * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
343 * to, our logic breaks. This check will generate a warning if that happens.
344 */
345 typecheck(mtime, sb.st_mtime);
346
347 /*
348 * In a single wolf-like pass, find an available slot and, in case none
349 * exist, find and record the least-recently-modified file.
350 */
351 for (i = 0; i < MAX_TOMBSTONES; i++) {
352 snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
353
354 if (!stat(path, &sb)) {
355 if (sb.st_mtime < mtime) {
356 oldest = i;
357 mtime = sb.st_mtime;
358 }
359 continue;
360 }
361 if (errno != ENOENT)
362 continue;
363
364 fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
365 if (fd < 0)
366 continue; /* raced ? */
367
368 fchown(fd, AID_SYSTEM, AID_SYSTEM);
369 return fd;
370 }
371
372 /* we didn't find an available file, so we clobber the oldest one */
373 snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
374 fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
375 fchown(fd, AID_SYSTEM, AID_SYSTEM);
376
377 return fd;
378}
379
380/* Return true if some thread is not detached cleanly */
381static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid)
382{
383 char task_path[1024];
384
385 sprintf(task_path, "/proc/%d/task", pid);
386 DIR *d;
387 struct dirent *de;
388 int need_cleanup = 0;
389
390 d = opendir(task_path);
391 /* Bail early if cannot open the task directory */
392 if (d == NULL) {
393 XLOG("Cannot open /proc/%d/task\n", pid);
394 return false;
395 }
396 while ((de = readdir(d)) != NULL) {
397 unsigned new_tid;
398 /* Ignore "." and ".." */
Ben Cheng09e71372009-09-28 11:06:09 -0700399 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800400 continue;
401 new_tid = atoi(de->d_name);
402 /* The main thread at fault has been handled individually */
403 if (new_tid == tid)
404 continue;
405
406 /* Skip this thread if cannot ptrace it */
407 if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0)
408 continue;
409
410 dump_crash_report(tfd, pid, new_tid, false);
411 need_cleanup |= ptrace(PTRACE_DETACH, new_tid, 0, 0);
412 }
413 closedir(d);
414 return need_cleanup != 0;
415}
416
Andy McFadden41e0cef2011-10-13 16:05:08 -0700417/*
418 * Reads the contents of the specified log device, filters out the entries
419 * that don't match the specified pid, and writes them to the tombstone file.
420 */
421static void dump_log_file(int tfd, unsigned pid, const char* filename)
422{
423 int logfd = open(filename, O_RDONLY | O_NONBLOCK);
424 if (logfd < 0) {
425 XLOG("Unable to open %s: %s\n", filename, strerror(errno));
426 return;
427 }
428 _LOG(tfd, true, "--------- log %s\n", filename);
429
430 union {
431 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
432 struct logger_entry entry;
433 } log_entry;
434
435 while (true) {
436 ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
437 if (actual < 0) {
438 if (errno == EINTR) {
439 /* interrupted by signal, retry */
440 continue;
441 } else if (errno == EAGAIN) {
442 /* non-blocking EOF; we're done */
443 break;
444 } else {
445 _LOG(tfd, true, "Error while reading log: %s\n",
446 strerror(errno));
447 break;
448 }
449 } else if (actual == 0) {
450 _LOG(tfd, true, "Got zero bytes while reading log: %s\n",
451 strerror(errno));
452 break;
453 }
454
455 /*
456 * NOTE: if you XLOG something here, this will spin forever,
457 * because you will be writing as fast as you're reading. Any
458 * high-frequency debug diagnostics should just be written to
459 * the tombstone file.
460 */
461
462 struct logger_entry* entry = &log_entry.entry;
463
464 if (entry->pid != (int32_t) pid) {
465 /* wrong pid, ignore */
466 continue;
467 }
468
469 /*
470 * Msg format is: <priority:1><tag:N>\0<message:N>\0
471 *
472 * We want to display it in the same format as "logcat -v threadtime"
473 * (although in this case the pid is redundant).
474 *
475 * TODO: scan for line breaks ('\n') and display each text line
476 * on a separate line, prefixed with the header, like logcat does.
477 */
478 static const char* kPrioChars = "!.VDIWEFS";
479 unsigned char prio = entry->msg[0];
480 const char* tag = entry->msg + 1;
481 const char* msg = tag + strlen(tag) + 1;
482
483 log_entry.entry.msg[entry->len] = '\0';
484
485 char timeBuf[32];
486 time_t sec = (time_t) entry->sec;
487 struct tm tmBuf;
488 struct tm* ptm;
489 ptm = localtime_r(&sec, &tmBuf);
490 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
491
492 _LOG(tfd, true, "%s.%03ld %5d %5d %c %-8s: %s\n",
493 timeBuf, entry->nsec / 1000000,
494 entry->pid, entry->tid,
495 (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?'),
496 tag, msg);
497 }
498
499 close(logfd);
500}
501
502/*
503 * Dumps the logs generated by the specified pid to the tombstone, from both
504 * "system" and "main" log devices. Ideally we'd interleave the output.
505 */
506static void dump_logs(int tfd, unsigned pid)
507{
508 dump_log_file(tfd, pid, "/dev/log/system");
509 dump_log_file(tfd, pid, "/dev/log/main");
510}
511
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800512/* Return true if some thread is not detached cleanly */
Ben Cheng09e71372009-09-28 11:06:09 -0700513static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800514 int signal)
515{
516 int fd;
517 bool need_cleanup = false;
518
519 mkdir(TOMBSTONE_DIR, 0755);
520 chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
521
522 fd = find_and_open_tombstone();
523 if (fd < 0)
524 return need_cleanup;
525
526 dump_crash_banner(fd, pid, tid, signal);
527 dump_crash_report(fd, pid, tid, true);
Ben Cheng09e71372009-09-28 11:06:09 -0700528 /*
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800529 * If the user has requested to attach gdb, don't collect the per-thread
530 * information as it increases the chance to lose track of the process.
531 */
532 if ((signed)pid > debug_uid) {
533 need_cleanup = dump_sibling_thread_report(fd, pid, tid);
534 }
535
Andy McFadden41e0cef2011-10-13 16:05:08 -0700536 /* don't copy log to tombstone unless this is a dev device */
537 char value[PROPERTY_VALUE_MAX];
538 property_get("ro.debuggable", value, "0");
539 if (value[0] == '1') {
540 dump_logs(fd, pid);
541 }
542
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800543 close(fd);
544 return need_cleanup;
545}
546
547static int
548write_string(const char* file, const char* string)
549{
550 int len;
551 int fd;
552 ssize_t amt;
553 fd = open(file, O_RDWR);
554 len = strlen(string);
555 if (fd < 0)
556 return -errno;
557 amt = write(fd, string, len);
558 close(fd);
559 return amt >= 0 ? 0 : -errno;
560}
561
562static
563void init_debug_led(void)
564{
565 // trout leds
566 write_string("/sys/class/leds/red/brightness", "0");
567 write_string("/sys/class/leds/green/brightness", "0");
568 write_string("/sys/class/leds/blue/brightness", "0");
569 write_string("/sys/class/leds/red/device/blink", "0");
570 // sardine leds
571 write_string("/sys/class/leds/left/cadence", "0,0");
572}
573
574static
575void enable_debug_led(void)
576{
577 // trout leds
578 write_string("/sys/class/leds/red/brightness", "255");
579 // sardine leds
580 write_string("/sys/class/leds/left/cadence", "1,0");
581}
582
583static
584void disable_debug_led(void)
585{
586 // trout leds
587 write_string("/sys/class/leds/red/brightness", "0");
588 // sardine leds
589 write_string("/sys/class/leds/left/cadence", "0,0");
590}
591
592extern int init_getevent();
593extern void uninit_getevent();
594extern int get_event(struct input_event* event, int timeout);
595
596static void wait_for_user_action(unsigned tid, struct ucred* cr)
597{
598 (void)tid;
599 /* First log a helpful message */
600 LOG( "********************************************************\n"
Andy McFadden3bfdcc92009-12-01 12:37:26 -0800601 "* Process %d has been suspended while crashing. To\n"
602 "* attach gdbserver for a gdb connection on port 5039:\n"
603 "*\n"
604 "* adb shell gdbserver :5039 --attach %d &\n"
605 "*\n"
606 "* Press HOME key to let the process continue crashing.\n"
Ben Cheng09e71372009-09-28 11:06:09 -0700607 "********************************************************\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800608 cr->pid, cr->pid);
609
Andy McFadden3bfdcc92009-12-01 12:37:26 -0800610 /* wait for HOME key (TODO: something useful for devices w/o HOME key) */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800611 if (init_getevent() == 0) {
612 int ms = 1200 / 10;
613 int dit = 1;
614 int dah = 3*dit;
615 int _ = -dit;
616 int ___ = 3*_;
617 int _______ = 7*_;
618 const signed char codes[] = {
619 dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
620 };
621 size_t s = 0;
622 struct input_event e;
623 int home = 0;
624 init_debug_led();
625 enable_debug_led();
626 do {
627 int timeout = abs((int)(codes[s])) * ms;
628 int res = get_event(&e, timeout);
629 if (res == 0) {
630 if (e.type==EV_KEY && e.code==KEY_HOME && e.value==0)
631 home = 1;
632 } else if (res == 1) {
633 if (++s >= sizeof(codes)/sizeof(*codes))
634 s = 0;
635 if (codes[s] > 0) {
636 enable_debug_led();
637 } else {
638 disable_debug_led();
639 }
640 }
Ben Cheng09e71372009-09-28 11:06:09 -0700641 } while (!home);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800642 uninit_getevent();
643 }
644
645 /* don't forget to turn debug led off */
646 disable_debug_led();
Ben Cheng09e71372009-09-28 11:06:09 -0700647
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800648 /* close filedescriptor */
649 LOG("debuggerd resuming process %d", cr->pid);
650 }
651
652static void handle_crashing_process(int fd)
653{
654 char buf[64];
655 struct stat s;
656 unsigned tid;
657 struct ucred cr;
Ben Cheng09e71372009-09-28 11:06:09 -0700658 int n, len, status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800659 int tid_attach_status = -1;
660 unsigned retry = 30;
661 bool need_cleanup = false;
662
663 char value[PROPERTY_VALUE_MAX];
664 property_get("debug.db.uid", value, "-1");
665 int debug_uid = atoi(value);
Ben Cheng09e71372009-09-28 11:06:09 -0700666
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800667 XLOG("handle_crashing_process(%d)\n", fd);
Ben Cheng09e71372009-09-28 11:06:09 -0700668
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800669 len = sizeof(cr);
670 n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
671 if(n != 0) {
672 LOG("cannot get credentials\n");
673 goto done;
674 }
675
Ben Cheng09e71372009-09-28 11:06:09 -0700676 XLOG("reading tid\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800677 fcntl(fd, F_SETFL, O_NONBLOCK);
678 while((n = read(fd, &tid, sizeof(unsigned))) != sizeof(unsigned)) {
679 if(errno == EINTR) continue;
680 if(errno == EWOULDBLOCK) {
681 if(retry-- > 0) {
682 usleep(100 * 1000);
683 continue;
684 }
685 LOG("timed out reading tid\n");
686 goto done;
687 }
688 LOG("read failure? %s\n", strerror(errno));
689 goto done;
690 }
691
David 'Digit' Turner02526d42011-01-21 04:27:12 +0100692 snprintf(buf, sizeof buf, "/proc/%d/task/%d", cr.pid, tid);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800693 if(stat(buf, &s)) {
Andy McFadden3bfdcc92009-12-01 12:37:26 -0800694 LOG("tid %d does not exist in pid %d. ignoring debug request\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800695 tid, cr.pid);
696 close(fd);
697 return;
698 }
Ben Cheng09e71372009-09-28 11:06:09 -0700699
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800700 XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid);
701
David 'Digit' Turner02526d42011-01-21 04:27:12 +0100702 /* Note that at this point, the target thread's signal handler
703 * is blocked in a read() call. This gives us the time to PTRACE_ATTACH
704 * to it before it has a chance to really fault.
705 *
706 * After the attach, the thread is stopped, and we write to the file
707 * descriptor to ensure that it will run as soon as we call PTRACE_CONT
708 * below. See details in bionic/libc/linker/debugger.c, in function
709 * debugger_signal_handler().
710 */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800711 tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0);
Andy McFadden655835b2011-07-26 07:50:37 -0700712 int ptrace_error = errno;
David 'Digit' Turner02526d42011-01-21 04:27:12 +0100713
Andy McFadden655835b2011-07-26 07:50:37 -0700714 if (TEMP_FAILURE_RETRY(write(fd, &tid, 1)) != 1) {
715 XLOG("failed responding to client: %s\n",
716 strerror(errno));
717 goto done;
718 }
David 'Digit' Turner02526d42011-01-21 04:27:12 +0100719
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800720 if(tid_attach_status < 0) {
Andy McFadden655835b2011-07-26 07:50:37 -0700721 LOG("ptrace attach failed: %s\n", strerror(ptrace_error));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800722 goto done;
723 }
724
725 close(fd);
726 fd = -1;
727
Andy McFadden655835b2011-07-26 07:50:37 -0700728 const int sleep_time_usec = 200000; /* 0.2 seconds */
729 const int max_total_sleep_usec = 3000000; /* 3 seconds */
730 int loop_limit = max_total_sleep_usec / sleep_time_usec;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800731 for(;;) {
Andy McFadden655835b2011-07-26 07:50:37 -0700732 if (loop_limit-- == 0) {
733 LOG("timed out waiting for pid=%d tid=%d uid=%d to die\n",
734 cr.pid, tid, cr.uid);
735 goto done;
736 }
737 n = waitpid(tid, &status, __WALL | WNOHANG);
738
739 if (n == 0) {
740 /* not ready yet */
741 XLOG("not ready yet\n");
742 usleep(sleep_time_usec);
743 continue;
744 }
Ben Cheng09e71372009-09-28 11:06:09 -0700745
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800746 if(n < 0) {
747 if(errno == EAGAIN) continue;
748 LOG("waitpid failed: %s\n", strerror(errno));
749 goto done;
750 }
751
752 XLOG("waitpid: n=%d status=%08x\n", n, status);
753
754 if(WIFSTOPPED(status)){
755 n = WSTOPSIG(status);
756 switch(n) {
757 case SIGSTOP:
758 XLOG("stopped -- continuing\n");
759 n = ptrace(PTRACE_CONT, tid, 0, 0);
760 if(n) {
761 LOG("ptrace failed: %s\n", strerror(errno));
762 goto done;
763 }
764 continue;
Ben Cheng09e71372009-09-28 11:06:09 -0700765
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800766 case SIGILL:
767 case SIGABRT:
768 case SIGBUS:
769 case SIGFPE:
770 case SIGSEGV:
771 case SIGSTKFLT: {
772 XLOG("stopped -- fatal signal\n");
773 need_cleanup = engrave_tombstone(cr.pid, tid, debug_uid, n);
774 kill(tid, SIGSTOP);
775 goto done;
776 }
777
778 default:
779 XLOG("stopped -- unexpected signal\n");
780 goto done;
781 }
782 } else {
783 XLOG("unexpected waitpid response\n");
784 goto done;
785 }
786 }
Ben Cheng09e71372009-09-28 11:06:09 -0700787
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800788done:
789 XLOG("detaching\n");
Ben Cheng09e71372009-09-28 11:06:09 -0700790
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800791 /* stop the process so we can debug */
792 kill(cr.pid, SIGSTOP);
793
Ben Cheng09e71372009-09-28 11:06:09 -0700794 /*
795 * If a thread has been attached by ptrace, make sure it is detached
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800796 * successfully otherwise we will get a zombie.
Ben Cheng09e71372009-09-28 11:06:09 -0700797 */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800798 if (tid_attach_status == 0) {
799 int detach_status;
800 /* detach so we can attach gdbserver */
801 detach_status = ptrace(PTRACE_DETACH, tid, 0, 0);
802 need_cleanup |= (detach_status != 0);
803 }
804
805 /*
806 * if debug.db.uid is set, its value indicates if we should wait
807 * for user action for the crashing process.
808 * in this case, we log a message and turn the debug LED on
809 * waiting for a gdb connection (for instance)
810 */
811
812 if ((signed)cr.uid <= debug_uid) {
813 wait_for_user_action(tid, &cr);
814 }
815
816 /* resume stopped process (so it can crash in peace) */
817 kill(cr.pid, SIGCONT);
818
819 if (need_cleanup) {
820 LOG("debuggerd committing suicide to free the zombie!\n");
821 kill(getpid(), SIGKILL);
822 }
823
824 if(fd != -1) close(fd);
825}
826
Bruce Beare84924902010-10-13 14:21:30 -0700827
Ben Cheng09e71372009-09-28 11:06:09 -0700828int main()
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800829{
830 int s;
831 struct sigaction act;
Bruce Beare84924902010-10-13 14:21:30 -0700832 int logsocket = -1;
Ben Cheng09e71372009-09-28 11:06:09 -0700833
Andy McFadden44e12ec2011-07-29 12:36:47 -0700834 /*
835 * debuggerd crashes can't be reported to debuggerd. Reset all of the
836 * crash handlers.
837 */
838 signal(SIGILL, SIG_DFL);
839 signal(SIGABRT, SIG_DFL);
840 signal(SIGBUS, SIG_DFL);
841 signal(SIGFPE, SIG_DFL);
842 signal(SIGSEGV, SIG_DFL);
843 signal(SIGSTKFLT, SIG_DFL);
844 signal(SIGPIPE, SIG_DFL);
845
Ben Cheng09e71372009-09-28 11:06:09 -0700846 logsocket = socket_local_client("logd",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800847 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
848 if(logsocket < 0) {
849 logsocket = -1;
850 } else {
851 fcntl(logsocket, F_SETFD, FD_CLOEXEC);
852 }
853
854 act.sa_handler = SIG_DFL;
855 sigemptyset(&act.sa_mask);
856 sigaddset(&act.sa_mask,SIGCHLD);
857 act.sa_flags = SA_NOCLDWAIT;
858 sigaction(SIGCHLD, &act, 0);
Ben Cheng09e71372009-09-28 11:06:09 -0700859
860 s = socket_local_server("android:debuggerd",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800861 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
862 if(s < 0) return -1;
863 fcntl(s, F_SETFD, FD_CLOEXEC);
864
865 LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
Ben Cheng09e71372009-09-28 11:06:09 -0700866
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800867 for(;;) {
868 struct sockaddr addr;
869 socklen_t alen;
870 int fd;
Ben Cheng09e71372009-09-28 11:06:09 -0700871
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800872 alen = sizeof(addr);
Andy McFadden655835b2011-07-26 07:50:37 -0700873 XLOG("waiting for connection\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800874 fd = accept(s, &addr, &alen);
Andy McFadden655835b2011-07-26 07:50:37 -0700875 if(fd < 0) {
876 XLOG("accept failed: %s\n", strerror(errno));
877 continue;
878 }
Ben Cheng09e71372009-09-28 11:06:09 -0700879
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800880 fcntl(fd, F_SETFD, FD_CLOEXEC);
881
882 handle_crashing_process(fd);
883 }
884 return 0;
885}