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