summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/POSIX/CrashReason.cpp
blob: 70c2687e3b8c020250017bdec74084c80d7b606d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
//===-- CrashReason.cpp -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "CrashReason.h"

#include "llvm/Support/raw_ostream.h"

#include <sstream>

namespace {

void AppendFaultAddr(std::string &str, lldb::addr_t addr) {
  std::stringstream ss;
  ss << " (fault address: 0x" << std::hex << addr << ")";
  str += ss.str();
}

#if defined(si_lower) && defined(si_upper)
void AppendBounds(std::string &str, lldb::addr_t lower_bound,
                  lldb::addr_t upper_bound, lldb::addr_t addr) {
  llvm::raw_string_ostream stream(str);
  if ((unsigned long)addr < lower_bound)
    stream << ": lower bound violation ";
  else
    stream << ": upper bound violation ";
  stream << "(fault address: 0x";
  stream.write_hex(addr);
  stream << ", lower bound: 0x";
  stream.write_hex(lower_bound);
  stream << ", upper bound: 0x";
  stream.write_hex(upper_bound);
  stream << ")";
  stream.flush();
}
#endif

CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) {
  assert(info.si_signo == SIGSEGV);

  switch (info.si_code) {
#ifdef SI_KERNEL
  case SI_KERNEL:
    // Some platforms will occasionally send nonstandard spurious SI_KERNEL
    // codes. One way to get this is via unaligned SIMD loads.
    return CrashReason::eInvalidAddress; // for lack of anything better
#endif
  case SEGV_MAPERR:
    return CrashReason::eInvalidAddress;
  case SEGV_ACCERR:
    return CrashReason::ePrivilegedAddress;
#ifndef SEGV_BNDERR
#define SEGV_BNDERR 3
#endif
  case SEGV_BNDERR:
    return CrashReason::eBoundViolation;
  }

  return CrashReason::eInvalidCrashReason;
}

CrashReason GetCrashReasonForSIGILL(const siginfo_t &info) {
  assert(info.si_signo == SIGILL);

  switch (info.si_code) {
  case ILL_ILLOPC:
    return CrashReason::eIllegalOpcode;
  case ILL_ILLOPN:
    return CrashReason::eIllegalOperand;
  case ILL_ILLADR:
    return CrashReason::eIllegalAddressingMode;
  case ILL_ILLTRP:
    return CrashReason::eIllegalTrap;
  case ILL_PRVOPC:
    return CrashReason::ePrivilegedOpcode;
  case ILL_PRVREG:
    return CrashReason::ePrivilegedRegister;
  case ILL_COPROC:
    return CrashReason::eCoprocessorError;
  case ILL_BADSTK:
    return CrashReason::eInternalStackError;
  }

  return CrashReason::eInvalidCrashReason;
}

CrashReason GetCrashReasonForSIGFPE(const siginfo_t &info) {
  assert(info.si_signo == SIGFPE);

  switch (info.si_code) {
  case FPE_INTDIV:
    return CrashReason::eIntegerDivideByZero;
  case FPE_INTOVF:
    return CrashReason::eIntegerOverflow;
  case FPE_FLTDIV:
    return CrashReason::eFloatDivideByZero;
  case FPE_FLTOVF:
    return CrashReason::eFloatOverflow;
  case FPE_FLTUND:
    return CrashReason::eFloatUnderflow;
  case FPE_FLTRES:
    return CrashReason::eFloatInexactResult;
  case FPE_FLTINV:
    return CrashReason::eFloatInvalidOperation;
  case FPE_FLTSUB:
    return CrashReason::eFloatSubscriptRange;
  }

  return CrashReason::eInvalidCrashReason;
}

CrashReason GetCrashReasonForSIGBUS(const siginfo_t &info) {
  assert(info.si_signo == SIGBUS);

  switch (info.si_code) {
  case BUS_ADRALN:
    return CrashReason::eIllegalAlignment;
  case BUS_ADRERR:
    return CrashReason::eIllegalAddress;
  case BUS_OBJERR:
    return CrashReason::eHardwareError;
  }

  return CrashReason::eInvalidCrashReason;
}
}

std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info) {
  std::string str;

// make sure that siginfo_t has the bound fields available.
#if defined(si_lower) && defined(si_upper)
  if (reason == CrashReason::eBoundViolation) {
    str = "signal SIGSEGV";
    AppendBounds(str, reinterpret_cast<lldb::addr_t>(info.si_lower),
                 reinterpret_cast<lldb::addr_t>(info.si_upper),
                 reinterpret_cast<lldb::addr_t>(info.si_addr));
    return str;
  }
#endif

  return GetCrashReasonString(reason,
                              reinterpret_cast<lldb::addr_t>(info.si_addr));
}

std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) {
  std::string str;

  switch (reason) {
  default:
    str = "unknown crash reason";
    break;

  case CrashReason::eInvalidAddress:
    str = "signal SIGSEGV: invalid address";
    AppendFaultAddr(str, fault_addr);
    break;
  case CrashReason::ePrivilegedAddress:
    str = "signal SIGSEGV: address access protected";
    AppendFaultAddr(str, fault_addr);
    break;
  case CrashReason::eBoundViolation:
    str = "signal SIGSEGV: bound violation";
    break;
  case CrashReason::eIllegalOpcode:
    str = "signal SIGILL: illegal instruction";
    break;
  case CrashReason::eIllegalOperand:
    str = "signal SIGILL: illegal instruction operand";
    break;
  case CrashReason::eIllegalAddressingMode:
    str = "signal SIGILL: illegal addressing mode";
    break;
  case CrashReason::eIllegalTrap:
    str = "signal SIGILL: illegal trap";
    break;
  case CrashReason::ePrivilegedOpcode:
    str = "signal SIGILL: privileged instruction";
    break;
  case CrashReason::ePrivilegedRegister:
    str = "signal SIGILL: privileged register";
    break;
  case CrashReason::eCoprocessorError:
    str = "signal SIGILL: coprocessor error";
    break;
  case CrashReason::eInternalStackError:
    str = "signal SIGILL: internal stack error";
    break;
  case CrashReason::eIllegalAlignment:
    str = "signal SIGBUS: illegal alignment";
    break;
  case CrashReason::eIllegalAddress:
    str = "signal SIGBUS: illegal address";
    break;
  case CrashReason::eHardwareError:
    str = "signal SIGBUS: hardware error";
    break;
  case CrashReason::eIntegerDivideByZero:
    str = "signal SIGFPE: integer divide by zero";
    break;
  case CrashReason::eIntegerOverflow:
    str = "signal SIGFPE: integer overflow";
    break;
  case CrashReason::eFloatDivideByZero:
    str = "signal SIGFPE: floating point divide by zero";
    break;
  case CrashReason::eFloatOverflow:
    str = "signal SIGFPE: floating point overflow";
    break;
  case CrashReason::eFloatUnderflow:
    str = "signal SIGFPE: floating point underflow";
    break;
  case CrashReason::eFloatInexactResult:
    str = "signal SIGFPE: inexact floating point result";
    break;
  case CrashReason::eFloatInvalidOperation:
    str = "signal SIGFPE: invalid floating point operation";
    break;
  case CrashReason::eFloatSubscriptRange:
    str = "signal SIGFPE: invalid floating point subscript range";
    break;
  }

  return str;
}

const char *CrashReasonAsString(CrashReason reason) {
#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
  // Just return the code in ascii for integration builds.
  chcar str[8];
  sprintf(str, "%d", reason);
#else
  const char *str = nullptr;

  switch (reason) {
  case CrashReason::eInvalidCrashReason:
    str = "eInvalidCrashReason";
    break;

  // SIGSEGV crash reasons.
  case CrashReason::eInvalidAddress:
    str = "eInvalidAddress";
    break;
  case CrashReason::ePrivilegedAddress:
    str = "ePrivilegedAddress";
    break;
  case CrashReason::eBoundViolation:
    str = "eBoundViolation";
    break;

  // SIGILL crash reasons.
  case CrashReason::eIllegalOpcode:
    str = "eIllegalOpcode";
    break;
  case CrashReason::eIllegalOperand:
    str = "eIllegalOperand";
    break;
  case CrashReason::eIllegalAddressingMode:
    str = "eIllegalAddressingMode";
    break;
  case CrashReason::eIllegalTrap:
    str = "eIllegalTrap";
    break;
  case CrashReason::ePrivilegedOpcode:
    str = "ePrivilegedOpcode";
    break;
  case CrashReason::ePrivilegedRegister:
    str = "ePrivilegedRegister";
    break;
  case CrashReason::eCoprocessorError:
    str = "eCoprocessorError";
    break;
  case CrashReason::eInternalStackError:
    str = "eInternalStackError";
    break;

  // SIGBUS crash reasons:
  case CrashReason::eIllegalAlignment:
    str = "eIllegalAlignment";
    break;
  case CrashReason::eIllegalAddress:
    str = "eIllegalAddress";
    break;
  case CrashReason::eHardwareError:
    str = "eHardwareError";
    break;

  // SIGFPE crash reasons:
  case CrashReason::eIntegerDivideByZero:
    str = "eIntegerDivideByZero";
    break;
  case CrashReason::eIntegerOverflow:
    str = "eIntegerOverflow";
    break;
  case CrashReason::eFloatDivideByZero:
    str = "eFloatDivideByZero";
    break;
  case CrashReason::eFloatOverflow:
    str = "eFloatOverflow";
    break;
  case CrashReason::eFloatUnderflow:
    str = "eFloatUnderflow";
    break;
  case CrashReason::eFloatInexactResult:
    str = "eFloatInexactResult";
    break;
  case CrashReason::eFloatInvalidOperation:
    str = "eFloatInvalidOperation";
    break;
  case CrashReason::eFloatSubscriptRange:
    str = "eFloatSubscriptRange";
    break;
  }
#endif

  return str;
}

CrashReason GetCrashReason(const siginfo_t &info) {
  switch (info.si_signo) {
  case SIGSEGV:
    return GetCrashReasonForSIGSEGV(info);
  case SIGBUS:
    return GetCrashReasonForSIGBUS(info);
  case SIGFPE:
    return GetCrashReasonForSIGFPE(info);
  case SIGILL:
    return GetCrashReasonForSIGILL(info);
  }

  assert(false && "unexpected signal");
  return CrashReason::eInvalidCrashReason;
}