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 
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)
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 
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 
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 
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 
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 
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 
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 
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 
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