• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 #include <stddef.h>
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <dirent.h>
26 #include <time.h>
27 #include <sys/ptrace.h>
28 #include <sys/stat.h>
29 
30 #include <private/android_filesystem_config.h>
31 
32 #include <cutils/logger.h>
33 #include <cutils/properties.h>
34 
35 #include <corkscrew/demangle.h>
36 #include <corkscrew/backtrace.h>
37 
38 #ifdef HAVE_SELINUX
39 #include <selinux/android.h>
40 #endif
41 
42 #include "machine.h"
43 #include "tombstone.h"
44 #include "utility.h"
45 
46 #define STACK_DEPTH 32
47 #define STACK_WORDS 16
48 
49 #define MAX_TOMBSTONES  10
50 #define TOMBSTONE_DIR   "/data/tombstones"
51 
52 #define typecheck(x,y) {    \
53     typeof(x) __dummy1;     \
54     typeof(y) __dummy2;     \
55     (void)(&__dummy1 == &__dummy2); }
56 
57 
signal_has_address(int sig)58 static bool signal_has_address(int sig) {
59     switch (sig) {
60         case SIGILL:
61         case SIGFPE:
62         case SIGSEGV:
63         case SIGBUS:
64             return true;
65         default:
66             return false;
67     }
68 }
69 
get_signame(int sig)70 static const char *get_signame(int sig)
71 {
72     switch(sig) {
73     case SIGILL:     return "SIGILL";
74     case SIGABRT:    return "SIGABRT";
75     case SIGBUS:     return "SIGBUS";
76     case SIGFPE:     return "SIGFPE";
77     case SIGSEGV:    return "SIGSEGV";
78     case SIGPIPE:    return "SIGPIPE";
79 #ifdef SIGSTKFLT
80     case SIGSTKFLT:  return "SIGSTKFLT";
81 #endif
82     case SIGSTOP:    return "SIGSTOP";
83     default:         return "?";
84     }
85 }
86 
get_sigcode(int signo,int code)87 static const char *get_sigcode(int signo, int code)
88 {
89     switch (signo) {
90     case SIGILL:
91         switch (code) {
92         case ILL_ILLOPC: return "ILL_ILLOPC";
93         case ILL_ILLOPN: return "ILL_ILLOPN";
94         case ILL_ILLADR: return "ILL_ILLADR";
95         case ILL_ILLTRP: return "ILL_ILLTRP";
96         case ILL_PRVOPC: return "ILL_PRVOPC";
97         case ILL_PRVREG: return "ILL_PRVREG";
98         case ILL_COPROC: return "ILL_COPROC";
99         case ILL_BADSTK: return "ILL_BADSTK";
100         }
101         break;
102     case SIGBUS:
103         switch (code) {
104         case BUS_ADRALN: return "BUS_ADRALN";
105         case BUS_ADRERR: return "BUS_ADRERR";
106         case BUS_OBJERR: return "BUS_OBJERR";
107         }
108         break;
109     case SIGFPE:
110         switch (code) {
111         case FPE_INTDIV: return "FPE_INTDIV";
112         case FPE_INTOVF: return "FPE_INTOVF";
113         case FPE_FLTDIV: return "FPE_FLTDIV";
114         case FPE_FLTOVF: return "FPE_FLTOVF";
115         case FPE_FLTUND: return "FPE_FLTUND";
116         case FPE_FLTRES: return "FPE_FLTRES";
117         case FPE_FLTINV: return "FPE_FLTINV";
118         case FPE_FLTSUB: return "FPE_FLTSUB";
119         }
120         break;
121     case SIGSEGV:
122         switch (code) {
123         case SEGV_MAPERR: return "SEGV_MAPERR";
124         case SEGV_ACCERR: return "SEGV_ACCERR";
125         }
126         break;
127     }
128     return "?";
129 }
130 
dump_revision_info(log_t * log)131 static void dump_revision_info(log_t* log)
132 {
133     char revision[PROPERTY_VALUE_MAX];
134 
135     property_get("ro.revision", revision, "unknown");
136 
137     _LOG(log, false, "Revision: '%s'\n", revision);
138 }
139 
dump_build_info(log_t * log)140 static void dump_build_info(log_t* log)
141 {
142     char fingerprint[PROPERTY_VALUE_MAX];
143 
144     property_get("ro.build.fingerprint", fingerprint, "unknown");
145 
146     _LOG(log, false, "Build fingerprint: '%s'\n", fingerprint);
147 }
148 
dump_fault_addr(log_t * log,pid_t tid,int sig)149 static void dump_fault_addr(log_t* log, pid_t tid, int sig)
150 {
151     siginfo_t si;
152 
153     memset(&si, 0, sizeof(si));
154     if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
155         _LOG(log, false, "cannot get siginfo: %s\n", strerror(errno));
156     } else if (signal_has_address(sig)) {
157         _LOG(log, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
158              sig, get_signame(sig),
159              si.si_code, get_sigcode(sig, si.si_code),
160              (uintptr_t) si.si_addr);
161     } else {
162         _LOG(log, false, "signal %d (%s), code %d (%s), fault addr --------\n",
163              sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
164     }
165 }
166 
dump_thread_info(log_t * log,pid_t pid,pid_t tid,bool at_fault)167 static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
168     char path[64];
169     char threadnamebuf[1024];
170     char* threadname = NULL;
171     FILE *fp;
172 
173     snprintf(path, sizeof(path), "/proc/%d/comm", tid);
174     if ((fp = fopen(path, "r"))) {
175         threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
176         fclose(fp);
177         if (threadname) {
178             size_t len = strlen(threadname);
179             if (len && threadname[len - 1] == '\n') {
180                 threadname[len - 1] = '\0';
181             }
182         }
183     }
184 
185     if (at_fault) {
186         char procnamebuf[1024];
187         char* procname = NULL;
188 
189         snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
190         if ((fp = fopen(path, "r"))) {
191             procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
192             fclose(fp);
193         }
194 
195         _LOG(log, false, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
196                 threadname ? threadname : "UNKNOWN",
197                 procname ? procname : "UNKNOWN");
198     } else {
199         _LOG(log, true, "pid: %d, tid: %d, name: %s\n", pid, tid,
200                 threadname ? threadname : "UNKNOWN");
201     }
202 }
203 
dump_backtrace(const ptrace_context_t * context __attribute ((unused)),log_t * log,pid_t tid __attribute ((unused)),bool at_fault,const backtrace_frame_t * backtrace,size_t frames)204 static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
205         log_t* log, pid_t tid __attribute((unused)), bool at_fault,
206         const backtrace_frame_t* backtrace, size_t frames) {
207     _LOG(log, !at_fault, "\nbacktrace:\n");
208 
209     backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
210     get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
211     for (size_t i = 0; i < frames; i++) {
212         char line[MAX_BACKTRACE_LINE_LENGTH];
213         format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
214                 line, MAX_BACKTRACE_LINE_LENGTH);
215         _LOG(log, !at_fault, "    %s\n", line);
216     }
217     free_backtrace_symbols(backtrace_symbols, frames);
218 }
219 
dump_stack_segment(const ptrace_context_t * context,log_t * log,pid_t tid,bool only_in_tombstone,uintptr_t * sp,size_t words,int label)220 static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid,
221         bool only_in_tombstone, uintptr_t* sp, size_t words, int label) {
222     for (size_t i = 0; i < words; i++) {
223         uint32_t stack_content;
224         if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
225             break;
226         }
227 
228         const map_info_t* mi;
229         const symbol_t* symbol;
230         find_symbol_ptrace(context, stack_content, &mi, &symbol);
231 
232         if (symbol) {
233             char* demangled_name = demangle_symbol_name(symbol->name);
234             const char* symbol_name = demangled_name ? demangled_name : symbol->name;
235             uint32_t offset = stack_content - (mi->start + symbol->start);
236             if (!i && label >= 0) {
237                 if (offset) {
238                     _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s (%s+%u)\n",
239                             label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
240                 } else {
241                     _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s (%s)\n",
242                             label, *sp, stack_content, mi ? mi->name : "", symbol_name);
243                 }
244             } else {
245                 if (offset) {
246                     _LOG(log, only_in_tombstone, "         %08x  %08x  %s (%s+%u)\n",
247                             *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
248                 } else {
249                     _LOG(log, only_in_tombstone, "         %08x  %08x  %s (%s)\n",
250                             *sp, stack_content, mi ? mi->name : "", symbol_name);
251                 }
252             }
253             free(demangled_name);
254         } else {
255             if (!i && label >= 0) {
256                 _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s\n",
257                         label, *sp, stack_content, mi ? mi->name : "");
258             } else {
259                 _LOG(log, only_in_tombstone, "         %08x  %08x  %s\n",
260                         *sp, stack_content, mi ? mi->name : "");
261             }
262         }
263 
264         *sp += sizeof(uint32_t);
265     }
266 }
267 
dump_stack(const ptrace_context_t * context,log_t * log,pid_t tid,bool at_fault,const backtrace_frame_t * backtrace,size_t frames)268 static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
269         const backtrace_frame_t* backtrace, size_t frames) {
270     bool have_first = false;
271     size_t first, last;
272     for (size_t i = 0; i < frames; i++) {
273         if (backtrace[i].stack_top) {
274             if (!have_first) {
275                 have_first = true;
276                 first = i;
277             }
278             last = i;
279         }
280     }
281     if (!have_first) {
282         return;
283     }
284 
285     _LOG(log, !at_fault, "\nstack:\n");
286 
287     // Dump a few words before the first frame.
288     bool only_in_tombstone = !at_fault;
289     uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t);
290     dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, -1);
291 
292     // Dump a few words from all successive frames.
293     // Only log the first 3 frames, put the rest in the tombstone.
294     for (size_t i = first; i <= last; i++) {
295         const backtrace_frame_t* frame = &backtrace[i];
296         if (sp != frame->stack_top) {
297             _LOG(log, only_in_tombstone, "         ........  ........\n");
298             sp = frame->stack_top;
299         }
300         if (i - first == 3) {
301             only_in_tombstone = true;
302         }
303         if (i == last) {
304             dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, i);
305             if (sp < frame->stack_top + frame->stack_size) {
306                 _LOG(log, only_in_tombstone, "         ........  ........\n");
307             }
308         } else {
309             size_t words = frame->stack_size / sizeof(uint32_t);
310             if (words == 0) {
311                 words = 1;
312             } else if (words > STACK_WORDS) {
313                 words = STACK_WORDS;
314             }
315             dump_stack_segment(context, log, tid, only_in_tombstone, &sp, words, i);
316         }
317     }
318 }
319 
dump_backtrace_and_stack(const ptrace_context_t * context,log_t * log,pid_t tid,bool at_fault)320 static void dump_backtrace_and_stack(const ptrace_context_t* context, log_t* log, pid_t tid,
321         bool at_fault) {
322     backtrace_frame_t backtrace[STACK_DEPTH];
323     ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
324     if (frames > 0) {
325         dump_backtrace(context, log, tid, at_fault, backtrace, frames);
326         dump_stack(context, log, tid, at_fault, backtrace, frames);
327     }
328 }
329 
dump_nearby_maps(const ptrace_context_t * context,log_t * log,pid_t tid)330 static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid) {
331     siginfo_t si;
332     memset(&si, 0, sizeof(si));
333     if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
334         _LOG(log, false, "cannot get siginfo for %d: %s\n",
335                 tid, strerror(errno));
336         return;
337     }
338     if (!signal_has_address(si.si_signo)) {
339         return;
340     }
341 
342     uintptr_t addr = (uintptr_t) si.si_addr;
343     addr &= ~0xfff;     /* round to 4K page boundary */
344     if (addr == 0) {    /* null-pointer deref */
345         return;
346     }
347 
348     _LOG(log, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
349 
350     /*
351      * Search for a match, or for a hole where the match would be.  The list
352      * is backward from the file content, so it starts at high addresses.
353      */
354     map_info_t* map = context->map_info_list;
355     map_info_t *next = NULL;
356     map_info_t *prev = NULL;
357     while (map != NULL) {
358         if (addr >= map->start && addr < map->end) {
359             next = map->next;
360             break;
361         } else if (addr >= map->end) {
362             /* map would be between "prev" and this entry */
363             next = map;
364             map = NULL;
365             break;
366         }
367 
368         prev = map;
369         map = map->next;
370     }
371 
372     /*
373      * Show "next" then "match" then "prev" so that the addresses appear in
374      * ascending order (like /proc/pid/maps).
375      */
376     if (next != NULL) {
377         _LOG(log, false, "    %08x-%08x %s\n", next->start, next->end, next->name);
378     } else {
379         _LOG(log, false, "    (no map below)\n");
380     }
381     if (map != NULL) {
382         _LOG(log, false, "    %08x-%08x %s\n", map->start, map->end, map->name);
383     } else {
384         _LOG(log, false, "    (no map for address)\n");
385     }
386     if (prev != NULL) {
387         _LOG(log, false, "    %08x-%08x %s\n", prev->start, prev->end, prev->name);
388     } else {
389         _LOG(log, false, "    (no map above)\n");
390     }
391 }
392 
dump_thread(const ptrace_context_t * context,log_t * log,pid_t tid,bool at_fault,int * total_sleep_time_usec)393 static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
394         int* total_sleep_time_usec) {
395     wait_for_stop(tid, total_sleep_time_usec);
396 
397     dump_registers(context, log, tid, at_fault);
398     dump_backtrace_and_stack(context, log, tid, at_fault);
399     if (at_fault) {
400         dump_memory_and_code(context, log, tid, at_fault);
401         dump_nearby_maps(context, log, tid);
402     }
403 }
404 
405 /* Return true if some thread is not detached cleanly */
dump_sibling_thread_report(const ptrace_context_t * context,log_t * log,pid_t pid,pid_t tid,int * total_sleep_time_usec)406 static bool dump_sibling_thread_report(const ptrace_context_t* context,
407         log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec) {
408     char task_path[64];
409     snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
410 
411     DIR* d = opendir(task_path);
412     /* Bail early if cannot open the task directory */
413     if (d == NULL) {
414         XLOG("Cannot open /proc/%d/task\n", pid);
415         return false;
416     }
417 
418     bool detach_failed = false;
419     struct dirent debuf;
420     struct dirent *de;
421     while (!readdir_r(d, &debuf, &de) && de) {
422         /* Ignore "." and ".." */
423         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
424             continue;
425         }
426 
427         /* The main thread at fault has been handled individually */
428         char* end;
429         pid_t new_tid = strtoul(de->d_name, &end, 10);
430         if (*end || new_tid == tid) {
431             continue;
432         }
433 
434         /* Skip this thread if cannot ptrace it */
435         if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
436             continue;
437         }
438 
439         _LOG(log, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
440         dump_thread_info(log, pid, new_tid, false);
441         dump_thread(context, log, new_tid, false, total_sleep_time_usec);
442 
443         if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
444             LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
445             detach_failed = true;
446         }
447     }
448 
449     closedir(d);
450     return detach_failed;
451 }
452 
453 /*
454  * Reads the contents of the specified log device, filters out the entries
455  * that don't match the specified pid, and writes them to the tombstone file.
456  *
457  * If "tailOnly" is set, we only print the last few lines.
458  */
dump_log_file(log_t * log,pid_t pid,const char * filename,bool tailOnly)459 static void dump_log_file(log_t* log, pid_t pid, const char* filename,
460     bool tailOnly)
461 {
462     bool first = true;
463 
464     /* circular buffer, for "tailOnly" mode */
465     const int kShortLogMaxLines = 5;
466     const int kShortLogLineLen = 256;
467     char shortLog[kShortLogMaxLines][kShortLogLineLen];
468     int shortLogCount = 0;
469     int shortLogNext = 0;
470 
471     int logfd = open(filename, O_RDONLY | O_NONBLOCK);
472     if (logfd < 0) {
473         XLOG("Unable to open %s: %s\n", filename, strerror(errno));
474         return;
475     }
476 
477     union {
478         unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
479         struct logger_entry entry;
480     } log_entry;
481 
482     while (true) {
483         ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
484         if (actual < 0) {
485             if (errno == EINTR) {
486                 /* interrupted by signal, retry */
487                 continue;
488             } else if (errno == EAGAIN) {
489                 /* non-blocking EOF; we're done */
490                 break;
491             } else {
492                 _LOG(log, true, "Error while reading log: %s\n",
493                     strerror(errno));
494                 break;
495             }
496         } else if (actual == 0) {
497             _LOG(log, true, "Got zero bytes while reading log: %s\n",
498                 strerror(errno));
499             break;
500         }
501 
502         /*
503          * NOTE: if you XLOG something here, this will spin forever,
504          * because you will be writing as fast as you're reading.  Any
505          * high-frequency debug diagnostics should just be written to
506          * the tombstone file.
507          */
508 
509         struct logger_entry* entry = &log_entry.entry;
510 
511         if (entry->pid != (int32_t) pid) {
512             /* wrong pid, ignore */
513             continue;
514         }
515 
516         if (first) {
517             _LOG(log, true, "--------- %slog %s\n",
518                 tailOnly ? "tail end of " : "", filename);
519             first = false;
520         }
521 
522         /*
523          * Msg format is: <priority:1><tag:N>\0<message:N>\0
524          *
525          * We want to display it in the same format as "logcat -v threadtime"
526          * (although in this case the pid is redundant).
527          *
528          * TODO: scan for line breaks ('\n') and display each text line
529          * on a separate line, prefixed with the header, like logcat does.
530          */
531         static const char* kPrioChars = "!.VDIWEFS";
532         unsigned char prio = entry->msg[0];
533         char* tag = entry->msg + 1;
534         char* msg = tag + strlen(tag) + 1;
535 
536         /* consume any trailing newlines */
537         char* eatnl = msg + strlen(msg) - 1;
538         while (eatnl >= msg && *eatnl == '\n') {
539             *eatnl-- = '\0';
540         }
541 
542         char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
543 
544         char timeBuf[32];
545         time_t sec = (time_t) entry->sec;
546         struct tm tmBuf;
547         struct tm* ptm;
548         ptm = localtime_r(&sec, &tmBuf);
549         strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
550 
551         if (tailOnly) {
552             snprintf(shortLog[shortLogNext], kShortLogLineLen,
553                 "%s.%03d %5d %5d %c %-8s: %s",
554                 timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
555                 prioChar, tag, msg);
556             shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
557             shortLogCount++;
558         } else {
559             _LOG(log, true, "%s.%03d %5d %5d %c %-8s: %s\n",
560                 timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
561                 prioChar, tag, msg);
562         }
563     }
564 
565     if (tailOnly) {
566         int i;
567 
568         /*
569          * If we filled the buffer, we want to start at "next", which has
570          * the oldest entry.  If we didn't, we want to start at zero.
571          */
572         if (shortLogCount < kShortLogMaxLines) {
573             shortLogNext = 0;
574         } else {
575             shortLogCount = kShortLogMaxLines;  /* cap at window size */
576         }
577 
578         for (i = 0; i < shortLogCount; i++) {
579             _LOG(log, true, "%s\n", shortLog[shortLogNext]);
580             shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
581         }
582     }
583 
584     close(logfd);
585 }
586 
587 /*
588  * Dumps the logs generated by the specified pid to the tombstone, from both
589  * "system" and "main" log devices.  Ideally we'd interleave the output.
590  */
dump_logs(log_t * log,pid_t pid,bool tailOnly)591 static void dump_logs(log_t* log, pid_t pid, bool tailOnly)
592 {
593     dump_log_file(log, pid, "/dev/log/system", tailOnly);
594     dump_log_file(log, pid, "/dev/log/main", tailOnly);
595 }
596 
597 /*
598  * Dumps all information about the specified pid to the tombstone.
599  */
dump_crash(log_t * log,pid_t pid,pid_t tid,int signal,bool dump_sibling_threads,int * total_sleep_time_usec)600 static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal,
601         bool dump_sibling_threads, int* total_sleep_time_usec)
602 {
603     /* don't copy log messages to tombstone unless this is a dev device */
604     char value[PROPERTY_VALUE_MAX];
605     property_get("ro.debuggable", value, "0");
606     bool want_logs = (value[0] == '1');
607 
608     _LOG(log, false,
609             "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
610     dump_build_info(log);
611     dump_revision_info(log);
612     dump_thread_info(log, pid, tid, true);
613     if(signal) {
614         dump_fault_addr(log, tid, signal);
615     }
616 
617     ptrace_context_t* context = load_ptrace_context(tid);
618     dump_thread(context, log, tid, true, total_sleep_time_usec);
619 
620     if (want_logs) {
621         dump_logs(log, pid, true);
622     }
623 
624     bool detach_failed = false;
625     if (dump_sibling_threads) {
626         detach_failed = dump_sibling_thread_report(context, log, pid, tid, total_sleep_time_usec);
627     }
628 
629     free_ptrace_context(context);
630 
631     if (want_logs) {
632         dump_logs(log, pid, false);
633     }
634     return detach_failed;
635 }
636 
637 /*
638  * find_and_open_tombstone - find an available tombstone slot, if any, of the
639  * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
640  * file is available, we reuse the least-recently-modified file.
641  *
642  * Returns the path of the tombstone file, allocated using malloc().  Caller must free() it.
643  */
find_and_open_tombstone(int * fd)644 static char* find_and_open_tombstone(int* fd)
645 {
646     unsigned long mtime = ULONG_MAX;
647     struct stat sb;
648 
649     /*
650      * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
651      * to, our logic breaks. This check will generate a warning if that happens.
652      */
653     typecheck(mtime, sb.st_mtime);
654 
655     /*
656      * In a single wolf-like pass, find an available slot and, in case none
657      * exist, find and record the least-recently-modified file.
658      */
659     char path[128];
660     int oldest = 0;
661     for (int i = 0; i < MAX_TOMBSTONES; i++) {
662         snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
663 
664         if (!stat(path, &sb)) {
665             if (sb.st_mtime < mtime) {
666                 oldest = i;
667                 mtime = sb.st_mtime;
668             }
669             continue;
670         }
671         if (errno != ENOENT)
672             continue;
673 
674         *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
675         if (*fd < 0)
676             continue;   /* raced ? */
677 
678         fchown(*fd, AID_SYSTEM, AID_SYSTEM);
679         return strdup(path);
680     }
681 
682     /* we didn't find an available file, so we clobber the oldest one */
683     snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
684     *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
685     if (*fd < 0) {
686         LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
687         return NULL;
688     }
689     fchown(*fd, AID_SYSTEM, AID_SYSTEM);
690     return strdup(path);
691 }
692 
engrave_tombstone(pid_t pid,pid_t tid,int signal,bool dump_sibling_threads,bool quiet,bool * detach_failed,int * total_sleep_time_usec)693 char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
694         bool dump_sibling_threads, bool quiet, bool* detach_failed,
695         int* total_sleep_time_usec) {
696     mkdir(TOMBSTONE_DIR, 0755);
697     chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
698 
699 #ifdef HAVE_SELINUX
700     if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) {
701         *detach_failed = false;
702         return NULL;
703     }
704 #endif
705 
706     int fd;
707     char* path = find_and_open_tombstone(&fd);
708     if (!path) {
709         *detach_failed = false;
710         return NULL;
711     }
712 
713     log_t log;
714     log.tfd = fd;
715     log.quiet = quiet;
716     *detach_failed = dump_crash(&log, pid, tid, signal, dump_sibling_threads,
717             total_sleep_time_usec);
718 
719     close(fd);
720     return path;
721 }
722