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