| //===-- 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; |
| } |