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 #ifdef __linux__
62 #ifndef SEGV_MTEAERR
63 #define SEGV_MTEAERR 8
64 #endif
65 case SEGV_MTEAERR:
66 return CrashReason::eAsyncTagCheckFault;
67 #ifndef SEGV_MTESERR
68 #define SEGV_MTESERR 9
69 #endif
70 case SEGV_MTESERR:
71 return CrashReason::eSyncTagCheckFault;
72 #endif // __linux__
73 }
74
75 return CrashReason::eInvalidCrashReason;
76 }
77
GetCrashReasonForSIGILL(const siginfo_t & info)78 CrashReason GetCrashReasonForSIGILL(const siginfo_t &info) {
79 assert(info.si_signo == SIGILL);
80
81 switch (info.si_code) {
82 case ILL_ILLOPC:
83 return CrashReason::eIllegalOpcode;
84 case ILL_ILLOPN:
85 return CrashReason::eIllegalOperand;
86 case ILL_ILLADR:
87 return CrashReason::eIllegalAddressingMode;
88 case ILL_ILLTRP:
89 return CrashReason::eIllegalTrap;
90 case ILL_PRVOPC:
91 return CrashReason::ePrivilegedOpcode;
92 case ILL_PRVREG:
93 return CrashReason::ePrivilegedRegister;
94 case ILL_COPROC:
95 return CrashReason::eCoprocessorError;
96 case ILL_BADSTK:
97 return CrashReason::eInternalStackError;
98 }
99
100 return CrashReason::eInvalidCrashReason;
101 }
102
GetCrashReasonForSIGFPE(const siginfo_t & info)103 CrashReason GetCrashReasonForSIGFPE(const siginfo_t &info) {
104 assert(info.si_signo == SIGFPE);
105
106 switch (info.si_code) {
107 case FPE_INTDIV:
108 return CrashReason::eIntegerDivideByZero;
109 case FPE_INTOVF:
110 return CrashReason::eIntegerOverflow;
111 case FPE_FLTDIV:
112 return CrashReason::eFloatDivideByZero;
113 case FPE_FLTOVF:
114 return CrashReason::eFloatOverflow;
115 case FPE_FLTUND:
116 return CrashReason::eFloatUnderflow;
117 case FPE_FLTRES:
118 return CrashReason::eFloatInexactResult;
119 case FPE_FLTINV:
120 return CrashReason::eFloatInvalidOperation;
121 case FPE_FLTSUB:
122 return CrashReason::eFloatSubscriptRange;
123 }
124
125 return CrashReason::eInvalidCrashReason;
126 }
127
GetCrashReasonForSIGBUS(const siginfo_t & info)128 CrashReason GetCrashReasonForSIGBUS(const siginfo_t &info) {
129 assert(info.si_signo == SIGBUS);
130
131 switch (info.si_code) {
132 case BUS_ADRALN:
133 return CrashReason::eIllegalAlignment;
134 case BUS_ADRERR:
135 return CrashReason::eIllegalAddress;
136 case BUS_OBJERR:
137 return CrashReason::eHardwareError;
138 }
139
140 return CrashReason::eInvalidCrashReason;
141 }
142 }
143
GetCrashReasonString(CrashReason reason,const siginfo_t & info)144 std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info) {
145 std::string str;
146
147 // make sure that siginfo_t has the bound fields available.
148 #if defined(si_lower) && defined(si_upper)
149 if (reason == CrashReason::eBoundViolation) {
150 str = "signal SIGSEGV";
151 AppendBounds(str, reinterpret_cast<uintptr_t>(info.si_lower),
152 reinterpret_cast<uintptr_t>(info.si_upper),
153 reinterpret_cast<uintptr_t>(info.si_addr));
154 return str;
155 }
156 #endif
157
158 return GetCrashReasonString(reason,
159 reinterpret_cast<uintptr_t>(info.si_addr));
160 }
161
GetCrashReasonString(CrashReason reason,lldb::addr_t fault_addr)162 std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) {
163 std::string str;
164
165 switch (reason) {
166 default:
167 str = "unknown crash reason";
168 break;
169
170 case CrashReason::eInvalidAddress:
171 str = "signal SIGSEGV: invalid address";
172 AppendFaultAddr(str, fault_addr);
173 break;
174 case CrashReason::ePrivilegedAddress:
175 str = "signal SIGSEGV: address access protected";
176 AppendFaultAddr(str, fault_addr);
177 break;
178 case CrashReason::eBoundViolation:
179 str = "signal SIGSEGV: bound violation";
180 break;
181 case CrashReason::eAsyncTagCheckFault:
182 str = "signal SIGSEGV: async tag check fault";
183 break;
184 case CrashReason::eSyncTagCheckFault:
185 str = "signal SIGSEGV: sync tag check fault";
186 AppendFaultAddr(str, fault_addr);
187 break;
188 case CrashReason::eIllegalOpcode:
189 str = "signal SIGILL: illegal instruction";
190 break;
191 case CrashReason::eIllegalOperand:
192 str = "signal SIGILL: illegal instruction operand";
193 break;
194 case CrashReason::eIllegalAddressingMode:
195 str = "signal SIGILL: illegal addressing mode";
196 break;
197 case CrashReason::eIllegalTrap:
198 str = "signal SIGILL: illegal trap";
199 break;
200 case CrashReason::ePrivilegedOpcode:
201 str = "signal SIGILL: privileged instruction";
202 break;
203 case CrashReason::ePrivilegedRegister:
204 str = "signal SIGILL: privileged register";
205 break;
206 case CrashReason::eCoprocessorError:
207 str = "signal SIGILL: coprocessor error";
208 break;
209 case CrashReason::eInternalStackError:
210 str = "signal SIGILL: internal stack error";
211 break;
212 case CrashReason::eIllegalAlignment:
213 str = "signal SIGBUS: illegal alignment";
214 break;
215 case CrashReason::eIllegalAddress:
216 str = "signal SIGBUS: illegal address";
217 break;
218 case CrashReason::eHardwareError:
219 str = "signal SIGBUS: hardware error";
220 break;
221 case CrashReason::eIntegerDivideByZero:
222 str = "signal SIGFPE: integer divide by zero";
223 break;
224 case CrashReason::eIntegerOverflow:
225 str = "signal SIGFPE: integer overflow";
226 break;
227 case CrashReason::eFloatDivideByZero:
228 str = "signal SIGFPE: floating point divide by zero";
229 break;
230 case CrashReason::eFloatOverflow:
231 str = "signal SIGFPE: floating point overflow";
232 break;
233 case CrashReason::eFloatUnderflow:
234 str = "signal SIGFPE: floating point underflow";
235 break;
236 case CrashReason::eFloatInexactResult:
237 str = "signal SIGFPE: inexact floating point result";
238 break;
239 case CrashReason::eFloatInvalidOperation:
240 str = "signal SIGFPE: invalid floating point operation";
241 break;
242 case CrashReason::eFloatSubscriptRange:
243 str = "signal SIGFPE: invalid floating point subscript range";
244 break;
245 }
246
247 return str;
248 }
249
CrashReasonAsString(CrashReason reason)250 const char *CrashReasonAsString(CrashReason reason) {
251 const char *str = nullptr;
252
253 switch (reason) {
254 case CrashReason::eInvalidCrashReason:
255 str = "eInvalidCrashReason";
256 break;
257
258 // SIGSEGV crash reasons.
259 case CrashReason::eInvalidAddress:
260 str = "eInvalidAddress";
261 break;
262 case CrashReason::ePrivilegedAddress:
263 str = "ePrivilegedAddress";
264 break;
265 case CrashReason::eBoundViolation:
266 str = "eBoundViolation";
267 break;
268 case CrashReason::eAsyncTagCheckFault:
269 str = "eAsyncTagCheckFault";
270 break;
271 case CrashReason::eSyncTagCheckFault:
272 str = "eSyncTagCheckFault";
273 break;
274
275 // SIGILL crash reasons.
276 case CrashReason::eIllegalOpcode:
277 str = "eIllegalOpcode";
278 break;
279 case CrashReason::eIllegalOperand:
280 str = "eIllegalOperand";
281 break;
282 case CrashReason::eIllegalAddressingMode:
283 str = "eIllegalAddressingMode";
284 break;
285 case CrashReason::eIllegalTrap:
286 str = "eIllegalTrap";
287 break;
288 case CrashReason::ePrivilegedOpcode:
289 str = "ePrivilegedOpcode";
290 break;
291 case CrashReason::ePrivilegedRegister:
292 str = "ePrivilegedRegister";
293 break;
294 case CrashReason::eCoprocessorError:
295 str = "eCoprocessorError";
296 break;
297 case CrashReason::eInternalStackError:
298 str = "eInternalStackError";
299 break;
300
301 // SIGBUS crash reasons:
302 case CrashReason::eIllegalAlignment:
303 str = "eIllegalAlignment";
304 break;
305 case CrashReason::eIllegalAddress:
306 str = "eIllegalAddress";
307 break;
308 case CrashReason::eHardwareError:
309 str = "eHardwareError";
310 break;
311
312 // SIGFPE crash reasons:
313 case CrashReason::eIntegerDivideByZero:
314 str = "eIntegerDivideByZero";
315 break;
316 case CrashReason::eIntegerOverflow:
317 str = "eIntegerOverflow";
318 break;
319 case CrashReason::eFloatDivideByZero:
320 str = "eFloatDivideByZero";
321 break;
322 case CrashReason::eFloatOverflow:
323 str = "eFloatOverflow";
324 break;
325 case CrashReason::eFloatUnderflow:
326 str = "eFloatUnderflow";
327 break;
328 case CrashReason::eFloatInexactResult:
329 str = "eFloatInexactResult";
330 break;
331 case CrashReason::eFloatInvalidOperation:
332 str = "eFloatInvalidOperation";
333 break;
334 case CrashReason::eFloatSubscriptRange:
335 str = "eFloatSubscriptRange";
336 break;
337 }
338 return str;
339 }
340
GetCrashReason(const siginfo_t & info)341 CrashReason GetCrashReason(const siginfo_t &info) {
342 switch (info.si_signo) {
343 case SIGSEGV:
344 return GetCrashReasonForSIGSEGV(info);
345 case SIGBUS:
346 return GetCrashReasonForSIGBUS(info);
347 case SIGFPE:
348 return GetCrashReasonForSIGFPE(info);
349 case SIGILL:
350 return GetCrashReasonForSIGILL(info);
351 }
352
353 assert(false && "unexpected signal");
354 return CrashReason::eInvalidCrashReason;
355 }
356