//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "StopInfoMachException.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/ArchSpec.h" #include "lldb/Core/StreamString.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/UnixSignals.h" using namespace lldb; using namespace lldb_private; const char * StopInfoMachException::GetDescription () { if (m_description.empty() && m_value != 0) { const llvm::Triple::ArchType cpu = m_thread.GetProcess().GetTarget().GetArchitecture().GetMachine(); const char *exc_desc = NULL; const char *code_label = "code"; const char *code_desc = NULL; const char *subcode_label = "subcode"; const char *subcode_desc = NULL; switch (m_value) { case 1: // EXC_BAD_ACCESS exc_desc = "EXC_BAD_ACCESS"; subcode_label = "address"; switch (cpu) { case llvm::Triple::arm: switch (m_exc_code) { case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break; case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break; } break; case llvm::Triple::ppc: case llvm::Triple::ppc64: switch (m_exc_code) { case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break; case 0x102: code_desc = "EXC_PPC_BADSPACE"; break; case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break; } break; default: break; } break; case 2: // EXC_BAD_INSTRUCTION exc_desc = "EXC_BAD_INSTRUCTION"; switch (cpu) { case llvm::Triple::x86: case llvm::Triple::x86_64: if (m_exc_code == 1) code_desc = "EXC_I386_INVOP"; break; case llvm::Triple::ppc: case llvm::Triple::ppc64: switch (m_exc_code) { case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break; case 2: code_desc = "EXC_PPC_UNIPL_INST"; break; case 3: code_desc = "EXC_PPC_PRIVINST"; break; case 4: code_desc = "EXC_PPC_PRIVREG"; break; case 5: code_desc = "EXC_PPC_TRACE"; break; case 6: code_desc = "EXC_PPC_PERFMON"; break; } break; case llvm::Triple::arm: if (m_exc_code == 1) code_desc = "EXC_ARM_UNDEFINED"; break; default: break; } break; case 3: // EXC_ARITHMETIC exc_desc = "EXC_ARITHMETIC"; switch (cpu) { case llvm::Triple::x86: case llvm::Triple::x86_64: switch (m_exc_code) { case 1: code_desc = "EXC_I386_DIV"; break; case 2: code_desc = "EXC_I386_INTO"; break; case 3: code_desc = "EXC_I386_NOEXT"; break; case 4: code_desc = "EXC_I386_EXTOVR"; break; case 5: code_desc = "EXC_I386_EXTERR"; break; case 6: code_desc = "EXC_I386_EMERR"; break; case 7: code_desc = "EXC_I386_BOUND"; break; case 8: code_desc = "EXC_I386_SSEEXTERR"; break; } break; case llvm::Triple::ppc: case llvm::Triple::ppc64: switch (m_exc_code) { case 1: code_desc = "EXC_PPC_OVERFLOW"; break; case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break; case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break; case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break; case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break; case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break; case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break; } break; default: break; } break; case 4: // EXC_EMULATION exc_desc = "EXC_EMULATION"; break; case 5: // EXC_SOFTWARE exc_desc = "EXC_SOFTWARE"; if (m_exc_code == 0x10003) { subcode_desc = "EXC_SOFT_SIGNAL"; subcode_label = "signo"; } break; case 6: // EXC_BREAKPOINT { exc_desc = "EXC_BREAKPOINT"; switch (cpu) { case llvm::Triple::x86: case llvm::Triple::x86_64: switch (m_exc_code) { case 1: code_desc = "EXC_I386_SGL"; break; case 2: code_desc = "EXC_I386_BPT"; break; } break; case llvm::Triple::ppc: case llvm::Triple::ppc64: switch (m_exc_code) { case 1: code_desc = "EXC_PPC_BREAKPOINT"; break; } break; case llvm::Triple::arm: switch (m_exc_code) { case 1: code_desc = "EXC_ARM_BREAKPOINT"; break; } break; default: break; } } break; case 7: exc_desc = "EXC_SYSCALL"; break; case 8: exc_desc = "EXC_MACH_SYSCALL"; break; case 9: exc_desc = "EXC_RPC_ALERT"; break; case 10: exc_desc = "EXC_CRASH"; break; } StreamString strm; if (exc_desc) strm.PutCString(exc_desc); else strm.Printf("EXC_??? (%llu)", m_value); if (m_exc_data_count >= 1) { if (code_desc) strm.Printf(" (%s=%s", code_label, code_desc); else strm.Printf(" (%s=%llu", code_label, m_exc_code); } if (m_exc_data_count >= 2) { if (subcode_desc) strm.Printf(", %s=%s", subcode_label, subcode_desc); else strm.Printf(", %s=0x%llx", subcode_label, m_exc_subcode); } if (m_exc_data_count > 0) strm.PutChar(')'); m_description.swap (strm.GetString()); } return m_description.c_str(); } StopInfoSP StopInfoMachException::CreateStopReasonWithMachException ( Thread &thread, uint32_t exc_type, uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code ) { if (exc_type != 0) { const llvm::Triple::ArchType cpu = thread.GetProcess().GetTarget().GetArchitecture().GetMachine(); switch (exc_type) { case 1: // EXC_BAD_ACCESS break; case 2: // EXC_BAD_INSTRUCTION switch (cpu) { case llvm::Triple::ppc: case llvm::Triple::ppc64: switch (exc_code) { case 1: // EXC_PPC_INVALID_SYSCALL case 2: // EXC_PPC_UNIPL_INST case 3: // EXC_PPC_PRIVINST case 4: // EXC_PPC_PRIVREG break; case 5: // EXC_PPC_TRACE return StopInfo::CreateStopReasonToTrace (thread); case 6: // EXC_PPC_PERFMON break; } break; default: break; } break; case 3: // EXC_ARITHMETIC case 4: // EXC_EMULATION break; case 5: // EXC_SOFTWARE if (exc_code == 0x10003) // EXC_SOFT_SIGNAL return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code); break; case 6: // EXC_BREAKPOINT { bool is_software_breakpoint = false; switch (cpu) { case llvm::Triple::x86: case llvm::Triple::x86_64: if (exc_code == 1) // EXC_I386_SGL { return StopInfo::CreateStopReasonToTrace(thread); } else if (exc_code == 2) // EXC_I386_BPT { is_software_breakpoint = true; } break; case llvm::Triple::ppc: case llvm::Triple::ppc64: is_software_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT break; case llvm::Triple::arm: is_software_breakpoint = exc_code == 1; // EXC_ARM_BREAKPOINT break; default: break; } if (is_software_breakpoint) { addr_t pc = thread.GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread.GetProcess().GetBreakpointSiteList().FindByAddress(pc); if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. if (bp_site_sp->ValidForThisThread (&thread)) return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID()); else return StopInfoSP(); } else if (cpu == llvm::Triple::arm) { return StopInfo::CreateStopReasonToTrace (thread); } } } break; case 7: // EXC_SYSCALL case 8: // EXC_MACH_SYSCALL case 9: // EXC_RPC_ALERT case 10: // EXC_CRASH break; } return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code)); } return StopInfoSP(); }