Home | History | Annotate | Download | only in debuggerd
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 */
    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  */
    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  */
    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  */
    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  */
    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 
    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