1053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown/* 2053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Copyright (C) 2012 The Android Open Source Project 3053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 4053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * you may not use this file except in compliance with the License. 6053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * You may obtain a copy of the License at 7053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 8053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 10053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Unless required by applicable law or agreed to in writing, software 11053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * See the License for the specific language governing permissions and 14053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * limitations under the License. 15053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 16053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 17053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <stddef.h> 18053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <stdbool.h> 19053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <stdlib.h> 20053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <signal.h> 21053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <string.h> 22053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <stdio.h> 23053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <fcntl.h> 24053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <errno.h> 25053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <dirent.h> 26053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <time.h> 27053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <sys/ptrace.h> 28053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <sys/stat.h> 29053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 30053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <private/android_filesystem_config.h> 31053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 32053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <cutils/logger.h> 33053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <cutils/properties.h> 34053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 35053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <corkscrew/demangle.h> 36053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include <corkscrew/backtrace.h> 37053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 38f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig#ifdef HAVE_SELINUX 39f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig#include <selinux/android.h> 40f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig#endif 41f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig 42053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include "machine.h" 43053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include "tombstone.h" 44053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#include "utility.h" 45053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 46053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#define STACK_DEPTH 32 47053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#define STACK_WORDS 16 48053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 49053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#define MAX_TOMBSTONES 10 50053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#define TOMBSTONE_DIR "/data/tombstones" 51053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 52053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown#define typecheck(x,y) { \ 53053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown typeof(x) __dummy1; \ 54053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown typeof(y) __dummy2; \ 55053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown (void)(&__dummy1 == &__dummy2); } 56053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 57053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 58053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic bool signal_has_address(int sig) { 59053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch (sig) { 60053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGILL: 61053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGFPE: 62053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGSEGV: 63053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGBUS: 64053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return true; 65053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown default: 66053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return false; 67053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 68053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 69053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 70053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic const char *get_signame(int sig) 71053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 72053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch(sig) { 73053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGILL: return "SIGILL"; 74053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGABRT: return "SIGABRT"; 75053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGBUS: return "SIGBUS"; 76053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGFPE: return "SIGFPE"; 77053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGSEGV: return "SIGSEGV"; 78053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGPIPE: return "SIGPIPE"; 79231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#ifdef SIGSTKFLT 80053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGSTKFLT: return "SIGSTKFLT"; 81231e3c83a3a70b11160fb0da108ebf2e0e7470e2Chris Dearman#endif 82053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGSTOP: return "SIGSTOP"; 83053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown default: return "?"; 84053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 85053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 86053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 87053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic const char *get_sigcode(int signo, int code) 88053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 89053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch (signo) { 90053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGILL: 91053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch (code) { 92053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_ILLOPC: return "ILL_ILLOPC"; 93053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_ILLOPN: return "ILL_ILLOPN"; 94053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_ILLADR: return "ILL_ILLADR"; 95053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_ILLTRP: return "ILL_ILLTRP"; 96053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_PRVOPC: return "ILL_PRVOPC"; 97053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_PRVREG: return "ILL_PRVREG"; 98053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_COPROC: return "ILL_COPROC"; 99053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case ILL_BADSTK: return "ILL_BADSTK"; 100053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 101053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 102053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGBUS: 103053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch (code) { 104053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case BUS_ADRALN: return "BUS_ADRALN"; 105053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case BUS_ADRERR: return "BUS_ADRERR"; 106053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case BUS_OBJERR: return "BUS_OBJERR"; 107053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 108053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 109053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGFPE: 110053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch (code) { 111053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_INTDIV: return "FPE_INTDIV"; 112053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_INTOVF: return "FPE_INTOVF"; 113053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_FLTDIV: return "FPE_FLTDIV"; 114053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_FLTOVF: return "FPE_FLTOVF"; 115053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_FLTUND: return "FPE_FLTUND"; 116053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_FLTRES: return "FPE_FLTRES"; 117053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_FLTINV: return "FPE_FLTINV"; 118053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case FPE_FLTSUB: return "FPE_FLTSUB"; 119053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 120053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 121053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SIGSEGV: 122053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown switch (code) { 123053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SEGV_MAPERR: return "SEGV_MAPERR"; 124053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown case SEGV_ACCERR: return "SEGV_ACCERR"; 125053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 126053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 127053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 128053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return "?"; 129053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 130053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 131d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Chengstatic void dump_revision_info(log_t* log) 132d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng{ 133d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng char revision[PROPERTY_VALUE_MAX]; 134d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng 135d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng property_get("ro.revision", revision, "unknown"); 136d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng 137d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng _LOG(log, false, "Revision: '%s'\n", revision); 138d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng} 139d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng 140053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_build_info(log_t* log) 141053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 142053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char fingerprint[PROPERTY_VALUE_MAX]; 143053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 144053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown property_get("ro.build.fingerprint", fingerprint, "unknown"); 145053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 146053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "Build fingerprint: '%s'\n", fingerprint); 147053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 148053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 149053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_fault_addr(log_t* log, pid_t tid, int sig) 150053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 151053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown siginfo_t si; 152053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 153053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown memset(&si, 0, sizeof(si)); 154053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){ 155053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "cannot get siginfo: %s\n", strerror(errno)); 156053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else if (signal_has_address(sig)) { 157053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "signal %d (%s), code %d (%s), fault addr %08x\n", 158053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown sig, get_signame(sig), 159053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown si.si_code, get_sigcode(sig, si.si_code), 160053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown (uintptr_t) si.si_addr); 161053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 162053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "signal %d (%s), code %d (%s), fault addr --------\n", 163053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code)); 164053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 165053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 166053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 167053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) { 168053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char path[64]; 169053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char threadnamebuf[1024]; 170053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* threadname = NULL; 171053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown FILE *fp; 172053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 173053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown snprintf(path, sizeof(path), "/proc/%d/comm", tid); 174053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if ((fp = fopen(path, "r"))) { 175053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp); 176053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown fclose(fp); 177053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (threadname) { 178053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown size_t len = strlen(threadname); 179053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (len && threadname[len - 1] == '\n') { 180053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown threadname[len - 1] = '\0'; 181053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 182053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 183053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 184053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 185053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (at_fault) { 186053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char procnamebuf[1024]; 187053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* procname = NULL; 188053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 189053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 190053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if ((fp = fopen(path, "r"))) { 191053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown procname = fgets(procnamebuf, sizeof(procnamebuf), fp); 192053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown fclose(fp); 193053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 194053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 195053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, 196053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown threadname ? threadname : "UNKNOWN", 197053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown procname ? procname : "UNKNOWN"); 198053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 199053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "pid: %d, tid: %d, name: %s\n", pid, tid, 200053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown threadname ? threadname : "UNKNOWN"); 201053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 202053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 203053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 204053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_backtrace(const ptrace_context_t* context __attribute((unused)), 205053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown log_t* log, pid_t tid __attribute((unused)), bool at_fault, 206053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const backtrace_frame_t* backtrace, size_t frames) { 207053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, !at_fault, "\nbacktrace:\n"); 208053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 209053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; 210053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); 211053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown for (size_t i = 0; i < frames; i++) { 212053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char line[MAX_BACKTRACE_LINE_LENGTH]; 213053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], 214053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown line, MAX_BACKTRACE_LINE_LENGTH); 215053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, !at_fault, " %s\n", line); 216053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 217053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown free_backtrace_symbols(backtrace_symbols, frames); 218053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 219053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 220053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid, 221053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool only_in_tombstone, uintptr_t* sp, size_t words, int label) { 222053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown for (size_t i = 0; i < words; i++) { 223053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown uint32_t stack_content; 224053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!try_get_word_ptrace(tid, *sp, &stack_content)) { 225053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 226053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 227053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 228053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const map_info_t* mi; 229053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const symbol_t* symbol; 230053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown find_symbol_ptrace(context, stack_content, &mi, &symbol); 231053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 232053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (symbol) { 233053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* demangled_name = demangle_symbol_name(symbol->name); 234053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const char* symbol_name = demangled_name ? demangled_name : symbol->name; 235053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown uint32_t offset = stack_content - (mi->start + symbol->start); 236053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!i && label >= 0) { 237053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (offset) { 238053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " #%02d %08x %08x %s (%s+%u)\n", 239053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset); 240053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 241053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " #%02d %08x %08x %s (%s)\n", 242053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown label, *sp, stack_content, mi ? mi->name : "", symbol_name); 243053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 244053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 245053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (offset) { 246053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " %08x %08x %s (%s+%u)\n", 247053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *sp, stack_content, mi ? mi->name : "", symbol_name, offset); 248053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 249053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " %08x %08x %s (%s)\n", 250053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *sp, stack_content, mi ? mi->name : "", symbol_name); 251053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 252053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 253053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown free(demangled_name); 254053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 255053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!i && label >= 0) { 256053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " #%02d %08x %08x %s\n", 257053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown label, *sp, stack_content, mi ? mi->name : ""); 258053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 259053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " %08x %08x %s\n", 260053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *sp, stack_content, mi ? mi->name : ""); 261053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 262053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 263053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 264053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *sp += sizeof(uint32_t); 265053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 266053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 267053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 268053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault, 269053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const backtrace_frame_t* backtrace, size_t frames) { 270053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool have_first = false; 271053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown size_t first, last; 272053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown for (size_t i = 0; i < frames; i++) { 273053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (backtrace[i].stack_top) { 274053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!have_first) { 275053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown have_first = true; 276053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown first = i; 277053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 278053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown last = i; 279053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 280053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 281053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!have_first) { 282053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return; 283053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 284053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 285053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, !at_fault, "\nstack:\n"); 286053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 287053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown // Dump a few words before the first frame. 288053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool only_in_tombstone = !at_fault; 289053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t); 290053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, -1); 291053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 292053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown // Dump a few words from all successive frames. 293053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown // Only log the first 3 frames, put the rest in the tombstone. 294053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown for (size_t i = first; i <= last; i++) { 295053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const backtrace_frame_t* frame = &backtrace[i]; 296053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (sp != frame->stack_top) { 297053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " ........ ........\n"); 298053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown sp = frame->stack_top; 299053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 300053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (i - first == 3) { 301053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown only_in_tombstone = true; 302053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 303053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (i == last) { 304053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, i); 305053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (sp < frame->stack_top + frame->stack_size) { 306053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, only_in_tombstone, " ........ ........\n"); 307053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 308053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 309053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown size_t words = frame->stack_size / sizeof(uint32_t); 310053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (words == 0) { 311053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown words = 1; 312053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else if (words > STACK_WORDS) { 313053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown words = STACK_WORDS; 314053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 315053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_stack_segment(context, log, tid, only_in_tombstone, &sp, words, i); 316053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 317053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 318053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 319053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 320053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_backtrace_and_stack(const ptrace_context_t* context, log_t* log, pid_t tid, 321053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool at_fault) { 322053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown backtrace_frame_t backtrace[STACK_DEPTH]; 323053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH); 324053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (frames > 0) { 325053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_backtrace(context, log, tid, at_fault, backtrace, frames); 326053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_stack(context, log, tid, at_fault, backtrace, frames); 327053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 328053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 329053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 330053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid) { 331053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown siginfo_t si; 332053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown memset(&si, 0, sizeof(si)); 333053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { 334053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "cannot get siginfo for %d: %s\n", 335053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown tid, strerror(errno)); 336053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return; 337053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 338053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!signal_has_address(si.si_signo)) { 339053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return; 340053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 341053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 342053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown uintptr_t addr = (uintptr_t) si.si_addr; 343053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown addr &= ~0xfff; /* round to 4K page boundary */ 344053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (addr == 0) { /* null-pointer deref */ 345053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return; 346053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 347053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 348053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr); 349053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 350053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 351053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Search for a match, or for a hole where the match would be. The list 352053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * is backward from the file content, so it starts at high addresses. 353053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 354053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown map_info_t* map = context->map_info_list; 355053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown map_info_t *next = NULL; 356053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown map_info_t *prev = NULL; 357053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown while (map != NULL) { 358053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (addr >= map->start && addr < map->end) { 359053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown next = map->next; 360053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 361053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else if (addr >= map->end) { 362053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* map would be between "prev" and this entry */ 363053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown next = map; 364053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown map = NULL; 365053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 366053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 367053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 368053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown prev = map; 369053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown map = map->next; 370053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 371053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 372053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 373053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Show "next" then "match" then "prev" so that the addresses appear in 374053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * ascending order (like /proc/pid/maps). 375053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 376053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (next != NULL) { 377053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, " %08x-%08x %s\n", next->start, next->end, next->name); 378053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 379053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, " (no map below)\n"); 380053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 381053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (map != NULL) { 382053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, " %08x-%08x %s\n", map->start, map->end, map->name); 383053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 384053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, " (no map for address)\n"); 385053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 386053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (prev != NULL) { 387053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, " %08x-%08x %s\n", prev->start, prev->end, prev->name); 388053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 389053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, " (no map above)\n"); 390053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 391053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 392053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 393053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault, 394053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int* total_sleep_time_usec) { 395053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown wait_for_stop(tid, total_sleep_time_usec); 396053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 397053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_registers(context, log, tid, at_fault); 398053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_backtrace_and_stack(context, log, tid, at_fault); 399053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (at_fault) { 400053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_memory_and_code(context, log, tid, at_fault); 401053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_nearby_maps(context, log, tid); 402053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 403053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 404053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 405053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown/* Return true if some thread is not detached cleanly */ 406053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic bool dump_sibling_thread_report(const ptrace_context_t* context, 407053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec) { 408053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char task_path[64]; 409053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); 410053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 411053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown DIR* d = opendir(task_path); 412053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* Bail early if cannot open the task directory */ 413053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (d == NULL) { 414053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown XLOG("Cannot open /proc/%d/task\n", pid); 415053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return false; 416053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 417053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 418053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool detach_failed = false; 419053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct dirent debuf; 420053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct dirent *de; 421053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown while (!readdir_r(d, &debuf, &de) && de) { 422053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* Ignore "." and ".." */ 423053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { 424053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 425053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 426053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 427053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* The main thread at fault has been handled individually */ 428053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* end; 429053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown pid_t new_tid = strtoul(de->d_name, &end, 10); 430053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (*end || new_tid == tid) { 431053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 432053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 433053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 434053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* Skip this thread if cannot ptrace it */ 435053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) { 436053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 437053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 438053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 439053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); 440053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_thread_info(log, pid, new_tid, false); 441053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_thread(context, log, new_tid, false, total_sleep_time_usec); 442053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 443053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) { 444053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno)); 445053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown detach_failed = true; 446053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 447053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 448053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 449053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown closedir(d); 450053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return detach_failed; 451053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 452053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 453053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown/* 454053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Reads the contents of the specified log device, filters out the entries 455053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * that don't match the specified pid, and writes them to the tombstone file. 456053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 457053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * If "tailOnly" is set, we only print the last few lines. 458053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 459053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_log_file(log_t* log, pid_t pid, const char* filename, 460053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool tailOnly) 461053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 462053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool first = true; 463053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 464053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* circular buffer, for "tailOnly" mode */ 465053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const int kShortLogMaxLines = 5; 466053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown const int kShortLogLineLen = 256; 467053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char shortLog[kShortLogMaxLines][kShortLogLineLen]; 468053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int shortLogCount = 0; 469053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int shortLogNext = 0; 470053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 471053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int logfd = open(filename, O_RDONLY | O_NONBLOCK); 472053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (logfd < 0) { 473053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown XLOG("Unable to open %s: %s\n", filename, strerror(errno)); 474053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return; 475053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 476053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 477053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown union { 478053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1]; 479053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct logger_entry entry; 480053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } log_entry; 481053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 482053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown while (true) { 483053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN); 484053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (actual < 0) { 485053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (errno == EINTR) { 486053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* interrupted by signal, retry */ 487053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 488053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else if (errno == EAGAIN) { 489053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* non-blocking EOF; we're done */ 490053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 491053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 492053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "Error while reading log: %s\n", 493053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown strerror(errno)); 494053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 495053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 496053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else if (actual == 0) { 497053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "Got zero bytes while reading log: %s\n", 498053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown strerror(errno)); 499053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown break; 500053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 501053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 502053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 503053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * NOTE: if you XLOG something here, this will spin forever, 504053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * because you will be writing as fast as you're reading. Any 505053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * high-frequency debug diagnostics should just be written to 506053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * the tombstone file. 507053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 508053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 509053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct logger_entry* entry = &log_entry.entry; 510053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 511053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (entry->pid != (int32_t) pid) { 512053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* wrong pid, ignore */ 513053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 514053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 515053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 516053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (first) { 517053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "--------- %slog %s\n", 518053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown tailOnly ? "tail end of " : "", filename); 519053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown first = false; 520053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 521053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 522053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 523053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Msg format is: <priority:1><tag:N>\0<message:N>\0 524053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 525053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * We want to display it in the same format as "logcat -v threadtime" 526053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * (although in this case the pid is redundant). 527053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 528053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * TODO: scan for line breaks ('\n') and display each text line 529053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * on a separate line, prefixed with the header, like logcat does. 530053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 531053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown static const char* kPrioChars = "!.VDIWEFS"; 532053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown unsigned char prio = entry->msg[0]; 533053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* tag = entry->msg + 1; 534053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* msg = tag + strlen(tag) + 1; 535053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 536053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* consume any trailing newlines */ 537053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* eatnl = msg + strlen(msg) - 1; 538053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown while (eatnl >= msg && *eatnl == '\n') { 539053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *eatnl-- = '\0'; 540053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 541053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 542053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?'); 543053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 544053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char timeBuf[32]; 545053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown time_t sec = (time_t) entry->sec; 546053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct tm tmBuf; 547053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct tm* ptm; 548053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown ptm = localtime_r(&sec, &tmBuf); 549053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm); 550053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 551053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (tailOnly) { 552053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown snprintf(shortLog[shortLogNext], kShortLogLineLen, 553053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown "%s.%03d %5d %5d %c %-8s: %s", 554053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, 555053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown prioChar, tag, msg); 556053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown shortLogNext = (shortLogNext + 1) % kShortLogMaxLines; 557053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown shortLogCount++; 558053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 559053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "%s.%03d %5d %5d %c %-8s: %s\n", 560053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, 561053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown prioChar, tag, msg); 562053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 563053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 564053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 565053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (tailOnly) { 566053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int i; 567053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 568053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 569053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * If we filled the buffer, we want to start at "next", which has 570053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * the oldest entry. If we didn't, we want to start at zero. 571053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 572053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (shortLogCount < kShortLogMaxLines) { 573053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown shortLogNext = 0; 574053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } else { 575053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown shortLogCount = kShortLogMaxLines; /* cap at window size */ 576053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 577053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 578053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown for (i = 0; i < shortLogCount; i++) { 579053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, true, "%s\n", shortLog[shortLogNext]); 580053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown shortLogNext = (shortLogNext + 1) % kShortLogMaxLines; 581053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 582053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 583053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 584053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown close(logfd); 585053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 586053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 587053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown/* 588053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Dumps the logs generated by the specified pid to the tombstone, from both 589053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * "system" and "main" log devices. Ideally we'd interleave the output. 590053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 591053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic void dump_logs(log_t* log, pid_t pid, bool tailOnly) 592053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 593053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_log_file(log, pid, "/dev/log/system", tailOnly); 594053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_log_file(log, pid, "/dev/log/main", tailOnly); 595053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 596053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 597053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown/* 598053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Dumps all information about the specified pid to the tombstone. 599053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 600053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, 601053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool dump_sibling_threads, int* total_sleep_time_usec) 602053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 603053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* don't copy log messages to tombstone unless this is a dev device */ 604053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char value[PROPERTY_VALUE_MAX]; 605053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown property_get("ro.debuggable", value, "0"); 606053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool want_logs = (value[0] == '1'); 607053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 608053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown _LOG(log, false, 609053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); 610053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_build_info(log); 611d7760c1688f8276a05e33345d81639f8cb5e7c3fBen Cheng dump_revision_info(log); 612053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_thread_info(log, pid, tid, true); 613053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if(signal) { 614053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_fault_addr(log, tid, signal); 615053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 616053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 617053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown ptrace_context_t* context = load_ptrace_context(tid); 618053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_thread(context, log, tid, true, total_sleep_time_usec); 619053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 620053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (want_logs) { 621053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_logs(log, pid, true); 622053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 623053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 624053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool detach_failed = false; 625053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (dump_sibling_threads) { 626053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown detach_failed = dump_sibling_thread_report(context, log, pid, tid, total_sleep_time_usec); 627053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 628053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 629053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown free_ptrace_context(context); 630053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 631053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (want_logs) { 632053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown dump_logs(log, pid, false); 633053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 634053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return detach_failed; 635053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 636053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 637053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown/* 638053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * find_and_open_tombstone - find an available tombstone slot, if any, of the 639053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no 640053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * file is available, we reuse the least-recently-modified file. 641053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * 642053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * Returns the path of the tombstone file, allocated using malloc(). Caller must free() it. 643053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 644053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownstatic char* find_and_open_tombstone(int* fd) 645053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown{ 646053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown unsigned long mtime = ULONG_MAX; 647053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown struct stat sb; 648053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 649053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 650053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought 651053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * to, our logic breaks. This check will generate a warning if that happens. 652053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 653053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown typecheck(mtime, sb.st_mtime); 654053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 655053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* 656053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * In a single wolf-like pass, find an available slot and, in case none 657053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown * exist, find and record the least-recently-modified file. 658053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown */ 659053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char path[128]; 660053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int oldest = 0; 661053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown for (int i = 0; i < MAX_TOMBSTONES; i++) { 662053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i); 663053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 664053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!stat(path, &sb)) { 665053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (sb.st_mtime < mtime) { 666053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown oldest = i; 667053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown mtime = sb.st_mtime; 668053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 669053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 670053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 671053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (errno != ENOENT) 672053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; 673053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 674053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600); 675053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (*fd < 0) 676053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown continue; /* raced ? */ 677053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 678053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown fchown(*fd, AID_SYSTEM, AID_SYSTEM); 679053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return strdup(path); 680053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 681053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 682053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown /* we didn't find an available file, so we clobber the oldest one */ 683053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest); 684053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); 685053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (*fd < 0) { 686053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno)); 687053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return NULL; 688053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 689053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown fchown(*fd, AID_SYSTEM, AID_SYSTEM); 690053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return strdup(path); 691053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 692053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 693053b865412d1982ad1dc0e840898d82527deeb99Jeff Brownchar* engrave_tombstone(pid_t pid, pid_t tid, int signal, 694053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown bool dump_sibling_threads, bool quiet, bool* detach_failed, 695053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int* total_sleep_time_usec) { 696053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown mkdir(TOMBSTONE_DIR, 0755); 697053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM); 698053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 699f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig#ifdef HAVE_SELINUX 700f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) { 701f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig *detach_failed = false; 702f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig return NULL; 703f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig } 704f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig#endif 705f1186f3e980f5ebcc3380d8a7f746bf8a45e3531rpcraig 706053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown int fd; 707053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown char* path = find_and_open_tombstone(&fd); 708053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown if (!path) { 709053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *detach_failed = false; 710053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return NULL; 711053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown } 712053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 713053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown log_t log; 714053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown log.tfd = fd; 715053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown log.quiet = quiet; 716053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown *detach_failed = dump_crash(&log, pid, tid, signal, dump_sibling_threads, 717053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown total_sleep_time_usec); 718053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown 719053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown close(fd); 720053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown return path; 721053b865412d1982ad1dc0e840898d82527deeb99Jeff Brown} 722