1 //===-- CrashReason.cpp ---------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "CrashReason.h"
10
11 #include "llvm/Support/raw_ostream.h"
12
13 #include <sstream>
14
15 namespace {
16
AppendFaultAddr(std::string & str,lldb::addr_t addr)17 void AppendFaultAddr(std::string &str, lldb::addr_t addr) {
18 std::stringstream ss;
19 ss << " (fault address: 0x" << std::hex << addr << ")";
20 str += ss.str();
21 }
22
23 #if defined(si_lower) && defined(si_upper)
AppendBounds(std::string & str,lldb::addr_t lower_bound,lldb::addr_t upper_bound,lldb::addr_t addr)24 void AppendBounds(std::string &str, lldb::addr_t lower_bound,
25 lldb::addr_t upper_bound, lldb::addr_t addr) {
26 llvm::raw_string_ostream stream(str);
27 if ((unsigned long)addr < lower_bound)
28 stream << ": lower bound violation ";
29 else
30 stream << ": upper bound violation ";
31 stream << "(fault address: 0x";
32 stream.write_hex(addr);
33 stream << ", lower bound: 0x";
34 stream.write_hex(lower_bound);
35 stream << ", upper bound: 0x";
36 stream.write_hex(upper_bound);
37 stream << ")";
38 stream.flush();
39 }
40 #endif
41
GetCrashReasonForSIGSEGV(const siginfo_t & info)42 CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) {
43 assert(info.si_signo == SIGSEGV);
44
45 switch (info.si_code) {
46 #ifdef SI_KERNEL
47 case SI_KERNEL:
48 // Some platforms will occasionally send nonstandard spurious SI_KERNEL
49 // codes. One way to get this is via unaligned SIMD loads.
50 return CrashReason::eInvalidAddress; // for lack of anything better
51 #endif
52 case SEGV_MAPERR:
53 return CrashReason::eInvalidAddress;
54 case SEGV_ACCERR:
55 return CrashReason::ePrivilegedAddress;
56 #ifndef SEGV_BNDERR
57 #define SEGV_BNDERR 3
58 #endif
59 case SEGV_BNDERR:
60 return CrashReason::eBoundViolation;
61 }
62
63 return CrashReason::eInvalidCrashReason;
64 }
65
GetCrashReasonForSIGILL(const siginfo_t & info)66 CrashReason GetCrashReasonForSIGILL(const siginfo_t &info) {
67 assert(info.si_signo == SIGILL);
68
69 switch (info.si_code) {
70 case ILL_ILLOPC:
71 return CrashReason::eIllegalOpcode;
72 case ILL_ILLOPN:
73 return CrashReason::eIllegalOperand;
74 case ILL_ILLADR:
75 return CrashReason::eIllegalAddressingMode;
76 case ILL_ILLTRP:
77 return CrashReason::eIllegalTrap;
78 case ILL_PRVOPC:
79 return CrashReason::ePrivilegedOpcode;
80 case ILL_PRVREG:
81 return CrashReason::ePrivilegedRegister;
82 case ILL_COPROC:
83 return CrashReason::eCoprocessorError;
84 case ILL_BADSTK:
85 return CrashReason::eInternalStackError;
86 }
87
88 return CrashReason::eInvalidCrashReason;
89 }
90
GetCrashReasonForSIGFPE(const siginfo_t & info)91 CrashReason GetCrashReasonForSIGFPE(const siginfo_t &info) {
92 assert(info.si_signo == SIGFPE);
93
94 switch (info.si_code) {
95 case FPE_INTDIV:
96 return CrashReason::eIntegerDivideByZero;
97 case FPE_INTOVF:
98 return CrashReason::eIntegerOverflow;
99 case FPE_FLTDIV:
100 return CrashReason::eFloatDivideByZero;
101 case FPE_FLTOVF:
102 return CrashReason::eFloatOverflow;
103 case FPE_FLTUND:
104 return CrashReason::eFloatUnderflow;
105 case FPE_FLTRES:
106 return CrashReason::eFloatInexactResult;
107 case FPE_FLTINV:
108 return CrashReason::eFloatInvalidOperation;
109 case FPE_FLTSUB:
110 return CrashReason::eFloatSubscriptRange;
111 }
112
113 return CrashReason::eInvalidCrashReason;
114 }
115
GetCrashReasonForSIGBUS(const siginfo_t & info)116 CrashReason GetCrashReasonForSIGBUS(const siginfo_t &info) {
117 assert(info.si_signo == SIGBUS);
118
119 switch (info.si_code) {
120 case BUS_ADRALN:
121 return CrashReason::eIllegalAlignment;
122 case BUS_ADRERR:
123 return CrashReason::eIllegalAddress;
124 case BUS_OBJERR:
125 return CrashReason::eHardwareError;
126 }
127
128 return CrashReason::eInvalidCrashReason;
129 }
130 }
131
GetCrashReasonString(CrashReason reason,const siginfo_t & info)132 std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info) {
133 std::string str;
134
135 // make sure that siginfo_t has the bound fields available.
136 #if defined(si_lower) && defined(si_upper)
137 if (reason == CrashReason::eBoundViolation) {
138 str = "signal SIGSEGV";
139 AppendBounds(str, reinterpret_cast<uintptr_t>(info.si_lower),
140 reinterpret_cast<uintptr_t>(info.si_upper),
141 reinterpret_cast<uintptr_t>(info.si_addr));
142 return str;
143 }
144 #endif
145
146 return GetCrashReasonString(reason,
147 reinterpret_cast<uintptr_t>(info.si_addr));
148 }
149
GetCrashReasonString(CrashReason reason,lldb::addr_t fault_addr)150 std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) {
151 std::string str;
152
153 switch (reason) {
154 default:
155 str = "unknown crash reason";
156 break;
157
158 case CrashReason::eInvalidAddress:
159 str = "signal SIGSEGV: invalid address";
160 AppendFaultAddr(str, fault_addr);
161 break;
162 case CrashReason::ePrivilegedAddress:
163 str = "signal SIGSEGV: address access protected";
164 AppendFaultAddr(str, fault_addr);
165 break;
166 case CrashReason::eBoundViolation:
167 str = "signal SIGSEGV: bound violation";
168 break;
169 case CrashReason::eIllegalOpcode:
170 str = "signal SIGILL: illegal instruction";
171 break;
172 case CrashReason::eIllegalOperand:
173 str = "signal SIGILL: illegal instruction operand";
174 break;
175 case CrashReason::eIllegalAddressingMode:
176 str = "signal SIGILL: illegal addressing mode";
177 break;
178 case CrashReason::eIllegalTrap:
179 str = "signal SIGILL: illegal trap";
180 break;
181 case CrashReason::ePrivilegedOpcode:
182 str = "signal SIGILL: privileged instruction";
183 break;
184 case CrashReason::ePrivilegedRegister:
185 str = "signal SIGILL: privileged register";
186 break;
187 case CrashReason::eCoprocessorError:
188 str = "signal SIGILL: coprocessor error";
189 break;
190 case CrashReason::eInternalStackError:
191 str = "signal SIGILL: internal stack error";
192 break;
193 case CrashReason::eIllegalAlignment:
194 str = "signal SIGBUS: illegal alignment";
195 break;
196 case CrashReason::eIllegalAddress:
197 str = "signal SIGBUS: illegal address";
198 break;
199 case CrashReason::eHardwareError:
200 str = "signal SIGBUS: hardware error";
201 break;
202 case CrashReason::eIntegerDivideByZero:
203 str = "signal SIGFPE: integer divide by zero";
204 break;
205 case CrashReason::eIntegerOverflow:
206 str = "signal SIGFPE: integer overflow";
207 break;
208 case CrashReason::eFloatDivideByZero:
209 str = "signal SIGFPE: floating point divide by zero";
210 break;
211 case CrashReason::eFloatOverflow:
212 str = "signal SIGFPE: floating point overflow";
213 break;
214 case CrashReason::eFloatUnderflow:
215 str = "signal SIGFPE: floating point underflow";
216 break;
217 case CrashReason::eFloatInexactResult:
218 str = "signal SIGFPE: inexact floating point result";
219 break;
220 case CrashReason::eFloatInvalidOperation:
221 str = "signal SIGFPE: invalid floating point operation";
222 break;
223 case CrashReason::eFloatSubscriptRange:
224 str = "signal SIGFPE: invalid floating point subscript range";
225 break;
226 }
227
228 return str;
229 }
230
CrashReasonAsString(CrashReason reason)231 const char *CrashReasonAsString(CrashReason reason) {
232 const char *str = nullptr;
233
234 switch (reason) {
235 case CrashReason::eInvalidCrashReason:
236 str = "eInvalidCrashReason";
237 break;
238
239 // SIGSEGV crash reasons.
240 case CrashReason::eInvalidAddress:
241 str = "eInvalidAddress";
242 break;
243 case CrashReason::ePrivilegedAddress:
244 str = "ePrivilegedAddress";
245 break;
246 case CrashReason::eBoundViolation:
247 str = "eBoundViolation";
248 break;
249
250 // SIGILL crash reasons.
251 case CrashReason::eIllegalOpcode:
252 str = "eIllegalOpcode";
253 break;
254 case CrashReason::eIllegalOperand:
255 str = "eIllegalOperand";
256 break;
257 case CrashReason::eIllegalAddressingMode:
258 str = "eIllegalAddressingMode";
259 break;
260 case CrashReason::eIllegalTrap:
261 str = "eIllegalTrap";
262 break;
263 case CrashReason::ePrivilegedOpcode:
264 str = "ePrivilegedOpcode";
265 break;
266 case CrashReason::ePrivilegedRegister:
267 str = "ePrivilegedRegister";
268 break;
269 case CrashReason::eCoprocessorError:
270 str = "eCoprocessorError";
271 break;
272 case CrashReason::eInternalStackError:
273 str = "eInternalStackError";
274 break;
275
276 // SIGBUS crash reasons:
277 case CrashReason::eIllegalAlignment:
278 str = "eIllegalAlignment";
279 break;
280 case CrashReason::eIllegalAddress:
281 str = "eIllegalAddress";
282 break;
283 case CrashReason::eHardwareError:
284 str = "eHardwareError";
285 break;
286
287 // SIGFPE crash reasons:
288 case CrashReason::eIntegerDivideByZero:
289 str = "eIntegerDivideByZero";
290 break;
291 case CrashReason::eIntegerOverflow:
292 str = "eIntegerOverflow";
293 break;
294 case CrashReason::eFloatDivideByZero:
295 str = "eFloatDivideByZero";
296 break;
297 case CrashReason::eFloatOverflow:
298 str = "eFloatOverflow";
299 break;
300 case CrashReason::eFloatUnderflow:
301 str = "eFloatUnderflow";
302 break;
303 case CrashReason::eFloatInexactResult:
304 str = "eFloatInexactResult";
305 break;
306 case CrashReason::eFloatInvalidOperation:
307 str = "eFloatInvalidOperation";
308 break;
309 case CrashReason::eFloatSubscriptRange:
310 str = "eFloatSubscriptRange";
311 break;
312 }
313 return str;
314 }
315
GetCrashReason(const siginfo_t & info)316 CrashReason GetCrashReason(const siginfo_t &info) {
317 switch (info.si_signo) {
318 case SIGSEGV:
319 return GetCrashReasonForSIGSEGV(info);
320 case SIGBUS:
321 return GetCrashReasonForSIGBUS(info);
322 case SIGFPE:
323 return GetCrashReasonForSIGFPE(info);
324 case SIGILL:
325 return GetCrashReasonForSIGILL(info);
326 }
327
328 assert(false && "unexpected signal");
329 return CrashReason::eInvalidCrashReason;
330 }
331