|  | //===-- 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) | 
|  | { | 
|  | ArchSpec::CPU cpu = m_thread.GetProcess().GetTarget().GetArchitecture().GetGenericCPUType(); | 
|  |  | 
|  | 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 ArchSpec::eCPU_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 ArchSpec::eCPU_ppc: | 
|  | case ArchSpec::eCPU_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 ArchSpec::eCPU_i386: | 
|  | case ArchSpec::eCPU_x86_64: | 
|  | if (m_exc_code == 1) | 
|  | code_desc = "EXC_I386_INVOP"; | 
|  | break; | 
|  |  | 
|  | case ArchSpec::eCPU_ppc: | 
|  | case ArchSpec::eCPU_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 ArchSpec::eCPU_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 ArchSpec::eCPU_i386: | 
|  | case ArchSpec::eCPU_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 ArchSpec::eCPU_ppc: | 
|  | case ArchSpec::eCPU_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 ArchSpec::eCPU_i386: | 
|  | case ArchSpec::eCPU_x86_64: | 
|  | switch (m_exc_code) | 
|  | { | 
|  | case 1: subcode_desc = "EXC_I386_SGL"; break; | 
|  | case 2: subcode_desc = "EXC_I386_BPT"; break; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ArchSpec::eCPU_ppc: | 
|  | case ArchSpec::eCPU_ppc64: | 
|  | switch (m_exc_code) | 
|  | { | 
|  | case 1: subcode_desc = "EXC_PPC_BREAKPOINT"; break; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ArchSpec::eCPU_arm: | 
|  | switch (m_exc_code) | 
|  | { | 
|  | case 1: subcode_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) | 
|  | { | 
|  | ArchSpec::CPU cpu = thread.GetProcess().GetTarget().GetArchitecture().GetGenericCPUType(); | 
|  |  | 
|  | switch (exc_type) | 
|  | { | 
|  | case 1: // EXC_BAD_ACCESS | 
|  | break; | 
|  |  | 
|  | case 2: // EXC_BAD_INSTRUCTION | 
|  | switch (cpu) | 
|  | { | 
|  | case ArchSpec::eCPU_ppc: | 
|  | case ArchSpec::eCPU_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 ArchSpec::eCPU_i386: | 
|  | case ArchSpec::eCPU_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 ArchSpec::eCPU_ppc: | 
|  | case ArchSpec::eCPU_ppc64: | 
|  | is_software_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT | 
|  | break; | 
|  |  | 
|  | case ArchSpec::eCPU_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(); | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | 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(); | 
|  | } |