Share crash information between LLGS and local POSIX debugging with
CrashReason class. Deliver crash information from LLGS to lldb via
description field of thread stop packet.

llvm-svn: 227926
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 13b9c27..918eb4a 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -2255,7 +2255,7 @@
 
         if (thread_sp)
         {
-            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedByTrace ();
         }
 
         // This thread is currently stopped.
@@ -2281,7 +2281,7 @@
         // Mark the thread as stopped at breakpoint.
         if (thread_sp)
         {
-            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedByBreakpoint ();
             Error error = FixupBreakpointPCAsNeeded (thread_sp);
             if (error.Fail ())
             {
@@ -2538,8 +2538,7 @@
     case SIGFPE:
     case SIGBUS:
         if (thread_sp)
-            reinterpret_cast<NativeThreadLinux*>(thread_sp.get())->SetCrashedWithException(
-                signo, reinterpret_cast<lldb::addr_t>(info->si_addr));
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetCrashedWithException (*info);
         break;
     default:
         // This is just a pre-signal-delivery notification of the incoming signal.
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index c24e3fd..66af7de 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -24,6 +24,8 @@
 
 #include "llvm/ADT/SmallString.h"
 
+#include "Plugins/Process/POSIX/CrashReason.h"
+
 #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
 #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
 #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
@@ -57,7 +59,8 @@
     NativeThreadProtocol (process, tid),
     m_state (StateType::eStateInvalid),
     m_stop_info (),
-    m_reg_context_sp ()
+    m_reg_context_sp (),
+    m_stop_description ()
 {
 }
 
@@ -82,9 +85,12 @@
 
 
 bool
-NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info)
+NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info, std::string& description)
 {
     Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    description.clear();
+
     switch (m_state)
     {
     case eStateStopped:
@@ -95,8 +101,11 @@
         if (log)
             LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:");
         stop_info = m_stop_info;
+        if (m_stop_info.reason == StopReason::eStopReasonException)
+            description = m_stop_description;
         if (log)
             LogThreadStopInfo (*log, stop_info, "returned stop_info:");
+
         return true;
 
     case eStateInvalid:
@@ -233,6 +242,7 @@
     m_state = new_state;
 
     m_stop_info.reason = StopReason::eStopReasonNone;
+    m_stop_description.clear();
 }
 
 void
@@ -301,7 +311,7 @@
     MaybeLogStateChange (new_state);
     m_state = new_state;
 
-    m_stop_info.reason = StopReason::eStopReasonSignal;
+    m_stop_info.reason = StopReason::eStopReasonBreakpoint;
     m_stop_info.details.signal.signo = SIGTRAP;
 }
 
@@ -313,23 +323,34 @@
         return false;
 
     // Was the stop reason a signal with signal number SIGTRAP? If not, not a breakpoint.
-    return (m_stop_info.reason == StopReason::eStopReasonSignal) &&
+    return (m_stop_info.reason == StopReason::eStopReasonBreakpoint) &&
             (m_stop_info.details.signal.signo == SIGTRAP);
 }
 
 void
-NativeThreadLinux::SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr)
+NativeThreadLinux::SetStoppedByTrace ()
+{
+    const StateType new_state = StateType::eStateStopped;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonTrace;
+    m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void
+NativeThreadLinux::SetCrashedWithException (const siginfo_t& info)
 {
     const StateType new_state = StateType::eStateCrashed;
     MaybeLogStateChange (new_state);
     m_state = new_state;
 
     m_stop_info.reason = StopReason::eStopReasonException;
-    m_stop_info.details.exception.type = exception_type;
-    m_stop_info.details.exception.data_count = 1;
-    m_stop_info.details.exception.data[0] = exception_addr;
-}
+    m_stop_info.details.signal.signo = info.si_signo;
 
+    const auto reason = GetCrashReason (info);
+    m_stop_description = GetCrashReasonString (reason, reinterpret_cast<lldb::addr_t> (info.si_addr));
+}
 
 void
 NativeThreadLinux::SetSuspended ()
@@ -371,33 +392,3 @@
     // Log it.
     log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state));
 }
-
-uint32_t
-NativeThreadLinux::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
-{
-    switch (stop_info.reason)
-    {
-        case eStopReasonSignal:
-            // No translation.
-            return stop_info.details.signal.signo;
-
-        case eStopReasonException:
-            {
-                Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
-                // FIXME I think the eStopReasonException is a xnu/Mach exception, which we
-                // shouldn't see on Linux.
-                // No translation.
-                if (log)
-                    log->Printf ("NativeThreadLinux::%s saw an exception stop type (signo %"
-                                 PRIu64 "), not expecting to see exceptions on Linux",
-                                 __FUNCTION__,
-                                 stop_info.details.exception.type);
-                return static_cast<uint32_t> (stop_info.details.exception.type);
-            }
-
-        default:
-            assert (0 && "unexpected stop_info.reason found");
-            return 0;
-    }
-}
-
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
index 2effd84..1e4ae53 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -34,7 +34,7 @@
         GetState () override;
 
         bool
-        GetStopReason (ThreadStopInfo &stop_info) override;
+        GetStopReason (ThreadStopInfo &stop_info, std::string& description) override;
 
         NativeRegisterContextSP
         GetRegisterContext () override;
@@ -45,9 +45,6 @@
         Error
         RemoveWatchpoint (lldb::addr_t addr) override;
 
-        uint32_t
-        TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const override;
-
     private:
         // ---------------------------------------------------------------------
         // Interface for friend classes
@@ -80,7 +77,10 @@
         IsStoppedAtBreakpoint ();
 
         void
-        SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr);
+        SetStoppedByTrace ();
+
+        void
+        SetCrashedWithException (const siginfo_t& info);
 
         void
         SetSuspended ();
@@ -100,6 +100,7 @@
         lldb::StateType m_state;
         ThreadStopInfo m_stop_info;
         NativeRegisterContextSP m_reg_context_sp;
+        std::string m_stop_description;
     };
 }
 
diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
index 3efeb5d..43a1942 100644
--- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -46,6 +46,7 @@
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Utility/PseudoTerminal.h"
 
+#include "Plugins/Process/POSIX/CrashReason.h"
 #include "Plugins/Process/POSIX/POSIXThread.h"
 #include "ProcessLinux.h"
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
@@ -1836,27 +1837,14 @@
     if (log)
         log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
 
-    if (signo == SIGSEGV) {
+    switch (signo)
+    {
+    case SIGSEGV:
+    case SIGILL:
+    case SIGFPE:
+    case SIGBUS:
         lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
-        ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
-        return ProcessMessage::Crash(pid, reason, signo, fault_addr);
-    }
-
-    if (signo == SIGILL) {
-        lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
-        ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
-        return ProcessMessage::Crash(pid, reason, signo, fault_addr);
-    }
-
-    if (signo == SIGFPE) {
-        lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
-        ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
-        return ProcessMessage::Crash(pid, reason, signo, fault_addr);
-    }
-
-    if (signo == SIGBUS) {
-        lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
-        ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
+        const auto reason = GetCrashReason(*info);
         return ProcessMessage::Crash(pid, reason, signo, fault_addr);
     }
 
@@ -2114,147 +2102,6 @@
     return false;
 }
 
-ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
-{
-    ProcessMessage::CrashReason reason;
-    assert(info->si_signo == SIGSEGV);
-
-    reason = ProcessMessage::eInvalidCrashReason;
-
-    switch (info->si_code)
-    {
-    default:
-        assert(false && "unexpected si_code for SIGSEGV");
-        break;
-    case SI_KERNEL:
-        // Linux will occasionally send spurious SI_KERNEL codes.
-        // (this is poorly documented in sigaction)
-        // One way to get this is via unaligned SIMD loads.
-        reason = ProcessMessage::eInvalidAddress; // for lack of anything better
-        break;
-    case SEGV_MAPERR:
-        reason = ProcessMessage::eInvalidAddress;
-        break;
-    case SEGV_ACCERR:
-        reason = ProcessMessage::ePrivilegedAddress;
-        break;
-    }
-
-    return reason;
-}
-
-ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGILL(const siginfo_t *info)
-{
-    ProcessMessage::CrashReason reason;
-    assert(info->si_signo == SIGILL);
-
-    reason = ProcessMessage::eInvalidCrashReason;
-
-    switch (info->si_code)
-    {
-    default:
-        assert(false && "unexpected si_code for SIGILL");
-        break;
-    case ILL_ILLOPC:
-        reason = ProcessMessage::eIllegalOpcode;
-        break;
-    case ILL_ILLOPN:
-        reason = ProcessMessage::eIllegalOperand;
-        break;
-    case ILL_ILLADR:
-        reason = ProcessMessage::eIllegalAddressingMode;
-        break;
-    case ILL_ILLTRP:
-        reason = ProcessMessage::eIllegalTrap;
-        break;
-    case ILL_PRVOPC:
-        reason = ProcessMessage::ePrivilegedOpcode;
-        break;
-    case ILL_PRVREG:
-        reason = ProcessMessage::ePrivilegedRegister;
-        break;
-    case ILL_COPROC:
-        reason = ProcessMessage::eCoprocessorError;
-        break;
-    case ILL_BADSTK:
-        reason = ProcessMessage::eInternalStackError;
-        break;
-    }
-
-    return reason;
-}
-
-ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGFPE(const siginfo_t *info)
-{
-    ProcessMessage::CrashReason reason;
-    assert(info->si_signo == SIGFPE);
-
-    reason = ProcessMessage::eInvalidCrashReason;
-
-    switch (info->si_code)
-    {
-    default:
-        assert(false && "unexpected si_code for SIGFPE");
-        break;
-    case FPE_INTDIV:
-        reason = ProcessMessage::eIntegerDivideByZero;
-        break;
-    case FPE_INTOVF:
-        reason = ProcessMessage::eIntegerOverflow;
-        break;
-    case FPE_FLTDIV:
-        reason = ProcessMessage::eFloatDivideByZero;
-        break;
-    case FPE_FLTOVF:
-        reason = ProcessMessage::eFloatOverflow;
-        break;
-    case FPE_FLTUND:
-        reason = ProcessMessage::eFloatUnderflow;
-        break;
-    case FPE_FLTRES:
-        reason = ProcessMessage::eFloatInexactResult;
-        break;
-    case FPE_FLTINV:
-        reason = ProcessMessage::eFloatInvalidOperation;
-        break;
-    case FPE_FLTSUB:
-        reason = ProcessMessage::eFloatSubscriptRange;
-        break;
-    }
-
-    return reason;
-}
-
-ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info)
-{
-    ProcessMessage::CrashReason reason;
-    assert(info->si_signo == SIGBUS);
-
-    reason = ProcessMessage::eInvalidCrashReason;
-
-    switch (info->si_code)
-    {
-    default:
-        assert(false && "unexpected si_code for SIGBUS");
-        break;
-    case BUS_ADRALN:
-        reason = ProcessMessage::eIllegalAlignment;
-        break;
-    case BUS_ADRERR:
-        reason = ProcessMessage::eIllegalAddress;
-        break;
-    case BUS_OBJERR:
-        reason = ProcessMessage::eHardwareError;
-        break;
-    }
-
-    return reason;
-}
-
 void
 ProcessMonitor::ServeOperation(OperationArgs *args)
 {
diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.h b/lldb/source/Plugins/Process/Linux/ProcessMonitor.h
index 5e83665..27beaef 100644
--- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.h
+++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.h
@@ -299,18 +299,6 @@
     MonitorSignal(ProcessMonitor *monitor, 
                   const siginfo_t *info, lldb::pid_t pid);
 
-    static ProcessMessage::CrashReason
-    GetCrashReasonForSIGSEGV(const siginfo_t *info);
-
-    static ProcessMessage::CrashReason
-    GetCrashReasonForSIGILL(const siginfo_t *info);
-
-    static ProcessMessage::CrashReason
-    GetCrashReasonForSIGFPE(const siginfo_t *info);
-
-    static ProcessMessage::CrashReason
-    GetCrashReasonForSIGBUS(const siginfo_t *info);
-
     void
     DoOperation(Operation *op);