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