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 */
363