blob: c4d4b3ca10f02a4836e6270d2b15e8843e464c4d [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Elliott Hughesffe67362011-07-17 12:09:27 -070016
17#include "runtime.h"
18
Elliott Hughes82870722011-08-29 19:04:51 -070019#include <cxxabi.h>
Elliott Hughesffe67362011-07-17 12:09:27 -070020#include <execinfo.h>
Elliott Hughes457005c2012-04-16 13:54:25 -070021#include <signal.h>
Elliott Hughesffe67362011-07-17 12:09:27 -070022
23#include "logging.h"
Elliott Hughesffe67362011-07-17 12:09:27 -070024#include "stringprintf.h"
25
26namespace art {
27
Elliott Hughes457005c2012-04-16 13:54:25 -070028static std::string Demangle(const std::string& mangled_name) {
Elliott Hughes82870722011-08-29 19:04:51 -070029 if (mangled_name.empty()) {
30 return "??";
31 }
32
33 // http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
34 int status;
Elliott Hughes34023802011-08-30 12:06:17 -070035 char* name(abi::__cxa_demangle(mangled_name.c_str(), NULL, NULL, &status));
36 if (name != NULL) {
37 std::string result(name);
38 free(name);
39 return result;
Elliott Hughes82870722011-08-29 19:04:51 -070040 }
41
42 return mangled_name + "()";
43}
44
Elliott Hughes457005c2012-04-16 13:54:25 -070045static void Backtrace() {
Elliott Hughesffe67362011-07-17 12:09:27 -070046 // Get the raw stack frames.
47 size_t MAX_STACK_FRAMES = 64;
48 void* frames[MAX_STACK_FRAMES];
49 size_t frame_count = backtrace(frames, MAX_STACK_FRAMES);
50
51 // Turn them into something human-readable with symbols.
Elliott Hughes34023802011-08-30 12:06:17 -070052 char** symbols = backtrace_symbols(frames, frame_count);
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070053 if (symbols == NULL) {
Elliott Hughesffe67362011-07-17 12:09:27 -070054 PLOG(ERROR) << "backtrace_symbols failed";
55 return;
56 }
57
Elliott Hughes82870722011-08-29 19:04:51 -070058 // backtrace_symbols(3) gives us lines like this:
59 // "/usr/local/google/home/enh/a1/out/host/linux-x86/bin/../lib/libartd.so(_ZN3art7Runtime13PlatformAbortEPKci+0x15b) [0xf76c5af3]"
Elliott Hughesa0957642011-09-02 14:27:33 -070060 // "[0xf7b62057]"
Elliott Hughes82870722011-08-29 19:04:51 -070061
62 // We extract the pieces and demangle, so we can produce output like this:
Elliott Hughes362f9bc2011-10-17 18:56:41 -070063 // libartd.so:-1] #00 art::Runtime::PlatformAbort(char const*, int) +0x15b [0xf770dd51]
Elliott Hughes82870722011-08-29 19:04:51 -070064
Elliott Hughesffe67362011-07-17 12:09:27 -070065 for (size_t i = 0; i < frame_count; ++i) {
Elliott Hughes34023802011-08-30 12:06:17 -070066 std::string text(symbols[i]);
Elliott Hughesa0957642011-09-02 14:27:33 -070067 std::string filename("??");
68 std::string function_name;
Elliott Hughes82870722011-08-29 19:04:51 -070069
70 size_t index = text.find('(');
Elliott Hughesa0957642011-09-02 14:27:33 -070071 if (index != std::string::npos) {
72 filename = text.substr(0, index);
73 text.erase(0, index + 1);
Elliott Hughes82870722011-08-29 19:04:51 -070074
Elliott Hughesa0957642011-09-02 14:27:33 -070075 index = text.find_first_of("+)");
76 function_name = Demangle(text.substr(0, index));
77 text.erase(0, index);
78 index = text.find(')');
79 text.erase(index, 1);
80 }
Elliott Hughesad6c9c32012-01-19 17:39:12 -080081 std::string log_line(StringPrintf("\t#%02zd ", i) + function_name + text);
Elliott Hughes9ee5f9c2012-02-03 18:33:16 -080082 LogMessage(filename.c_str(), -1, INTERNAL_FATAL, -1).stream() << log_line;
Elliott Hughesffe67362011-07-17 12:09:27 -070083 }
Elliott Hughes34023802011-08-30 12:06:17 -070084
85 free(symbols);
Elliott Hughesffe67362011-07-17 12:09:27 -070086}
87
Elliott Hughes457005c2012-04-16 13:54:25 -070088static const char* GetSignalCodeName(int signal_number, int signal_code) {
89 // Try the signal-specific codes...
90 switch (signal_number) {
91 case SIGILL:
92 switch (signal_code) {
93 case ILL_ILLOPC: return "ILL_ILLOPC";
94 case ILL_ILLOPN: return "ILL_ILLOPN";
95 case ILL_ILLADR: return "ILL_ILLADR";
96 case ILL_ILLTRP: return "ILL_ILLTRP";
97 case ILL_PRVOPC: return "ILL_PRVOPC";
98 case ILL_PRVREG: return "ILL_PRVREG";
99 case ILL_COPROC: return "ILL_COPROC";
100 case ILL_BADSTK: return "ILL_BADSTK";
101 }
102 break;
103 case SIGBUS:
104 switch (signal_code) {
105 case BUS_ADRALN: return "BUS_ADRALN";
106 case BUS_ADRERR: return "BUS_ADRERR";
107 case BUS_OBJERR: return "BUS_OBJERR";
108 }
109 break;
110 case SIGFPE:
111 switch (signal_code) {
112 case FPE_INTDIV: return "FPE_INTDIV";
113 case FPE_INTOVF: return "FPE_INTOVF";
114 case FPE_FLTDIV: return "FPE_FLTDIV";
115 case FPE_FLTOVF: return "FPE_FLTOVF";
116 case FPE_FLTUND: return "FPE_FLTUND";
117 case FPE_FLTRES: return "FPE_FLTRES";
118 case FPE_FLTINV: return "FPE_FLTINV";
119 case FPE_FLTSUB: return "FPE_FLTSUB";
120 }
121 break;
122 case SIGSEGV:
123 switch (signal_code) {
124 case SEGV_MAPERR: return "SEGV_MAPERR";
125 case SEGV_ACCERR: return "SEGV_ACCERR";
126 }
127 break;
128 case SIGTRAP:
129 switch (signal_code) {
130 case TRAP_BRKPT: return "TRAP_BRKPT";
131 case TRAP_TRACE: return "TRAP_TRACE";
132 }
133 break;
134 }
135 // Then the other codes...
136 switch (signal_code) {
137 case SI_USER: return "SI_USER";
Elliott Hughesac8097f2012-04-16 14:59:44 -0700138#if defined(SI_KERNEL)
Elliott Hughes457005c2012-04-16 13:54:25 -0700139 case SI_KERNEL: return "SI_KERNEL";
Elliott Hughesac8097f2012-04-16 14:59:44 -0700140#endif
Elliott Hughes457005c2012-04-16 13:54:25 -0700141 case SI_QUEUE: return "SI_QUEUE";
142 case SI_TIMER: return "SI_TIMER";
143 case SI_MESGQ: return "SI_MESGQ";
144 case SI_ASYNCIO: return "SI_ASYNCIO";
Elliott Hughesac8097f2012-04-16 14:59:44 -0700145#if defined(SI_SIGIO)
Elliott Hughes457005c2012-04-16 13:54:25 -0700146 case SI_SIGIO: return "SI_SIGIO";
Elliott Hughesac8097f2012-04-16 14:59:44 -0700147#endif
148#if defined(SI_TKILL)
Elliott Hughes457005c2012-04-16 13:54:25 -0700149 case SI_TKILL: return "SI_TKILL";
Elliott Hughesac8097f2012-04-16 14:59:44 -0700150#endif
Elliott Hughes457005c2012-04-16 13:54:25 -0700151 }
152 // Then give up...
153 return "?";
154}
155
156static void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void*) {
157 const char* signal_name = "?";
158 bool has_address = false;
159 if (signal_number == SIGILL) {
160 signal_name = "SIGILL";
161 has_address = true;
162 } else if (signal_number == SIGTRAP) {
163 signal_name = "SIGTRAP";
164 } else if (signal_number == SIGABRT) {
165 signal_name = "SIGABRT";
166 } else if (signal_number == SIGBUS) {
167 signal_name = "SIGBUS";
168 has_address = true;
169 } else if (signal_number == SIGFPE) {
170 signal_name = "SIGFPE";
171 has_address = true;
172 } else if (signal_number == SIGSEGV) {
173 signal_name = "SIGSEGV";
174 has_address = true;
Elliott Hughesac8097f2012-04-16 14:59:44 -0700175#if defined(SIGSTKFLT)
Elliott Hughes457005c2012-04-16 13:54:25 -0700176 } else if (signal_number == SIGSTKFLT) {
177 signal_name = "SIGSTKFLT";
Elliott Hughesac8097f2012-04-16 14:59:44 -0700178#endif
Elliott Hughes457005c2012-04-16 13:54:25 -0700179 } else if (signal_number == SIGPIPE) {
180 signal_name = "SIGPIPE";
181 }
182
183 LOG(INTERNAL_FATAL) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
184 << StringPrintf("Fatal signal %d (%s), code %d (%s)",
185 signal_number, signal_name,
186 info->si_code,
187 GetSignalCodeName(signal_number, info->si_code))
188 << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "");
189 Backtrace();
190
Elliott Hughes2554cb92012-04-18 17:19:26 -0700191 // TODO: instead, get debuggerd running on the host, try to connect, and hang around on success.
192 if (getenv("debug_db_uid") != NULL) {
193 LOG(INTERNAL_FATAL) << "********************************************************\n"
194 << "* Process " << getpid() << " has been suspended while crashing. Attach gdb:\n"
195 << "* gdb -p " << getpid() << "\n"
196 << "********************************************************\n";
197 // Wait for debugger to attach.
198 while (true) {
199 }
Elliott Hughes457005c2012-04-16 13:54:25 -0700200 }
201}
202
203void Runtime::PlatformAbort(const char* /*file*/, int /*line_number*/) {
204 // On the host, we don't have debuggerd to dump a stack for us when we LOG(FATAL).
205 Backtrace();
206}
207
208void Runtime::InitPlatformSignalHandlers() {
209 // On the host, we don't have debuggerd to dump a stack for us when something unexpected happens.
210 struct sigaction action;
211 memset(&action, 0, sizeof(action));
212 sigemptyset(&action.sa_mask);
213 action.sa_sigaction = HandleUnexpectedSignal;
Elliott Hughesd8af1592012-04-16 20:40:15 -0700214 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
Elliott Hughes457005c2012-04-16 13:54:25 -0700215
216 int rc = 0;
217 rc += sigaction(SIGILL, &action, NULL);
218 rc += sigaction(SIGTRAP, &action, NULL);
219 rc += sigaction(SIGABRT, &action, NULL);
220 rc += sigaction(SIGBUS, &action, NULL);
221 rc += sigaction(SIGFPE, &action, NULL);
222 rc += sigaction(SIGSEGV, &action, NULL);
Elliott Hughesac8097f2012-04-16 14:59:44 -0700223#if defined(SIGSTKFLT)
Elliott Hughes457005c2012-04-16 13:54:25 -0700224 rc += sigaction(SIGSTKFLT, &action, NULL);
Elliott Hughesac8097f2012-04-16 14:59:44 -0700225#endif
Elliott Hughes457005c2012-04-16 13:54:25 -0700226 rc += sigaction(SIGPIPE, &action, NULL);
227 CHECK_EQ(rc, 0);
228}
229
Elliott Hughesffe67362011-07-17 12:09:27 -0700230} // namespace art