<rdar://problem/12649160>

Added the ability to debug through your process exec'ing itself to the same architecture.



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@169340 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 0f43040..5455a24 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -5111,3 +5111,22 @@
 {
     m_thread_list.Flush();
 }
+
+void
+Process::DidExec ()
+{
+    Target &target = GetTarget();
+    target.CleanupProcess ();
+    ModuleList unloaded_modules (target.GetImages());
+    target.ModulesDidUnload (unloaded_modules);
+    target.GetSectionLoadList().Clear();
+    m_dynamic_checkers_ap.reset();
+    m_abi_sp.reset();
+    m_os_ap.reset();
+    m_dyld_ap.reset();    
+    m_image_tokens.clear();
+    m_allocated_memory_cache.Clear();
+    m_language_runtimes.clear();
+    DoDidExec();
+    CompleteAttach ();
+}
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 082fddd..0a45d33 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -147,6 +147,7 @@
                             {
                             case eStopReasonWatchpoint:
                             case eStopReasonException:
+                            case eStopReasonExec:
                             case eStopReasonSignal:
                                 // In all these cases we want to stop in the deepest most frame.
                                 m_current_inlined_pc = curr_pc;
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index bae1e4a..de76748 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -862,6 +862,49 @@
     ThreadPlanSP m_plan_sp;
     ValueObjectSP m_return_valobj_sp;
 };
+    
+class StopInfoExec : public StopInfo
+{
+public:
+    
+    StopInfoExec (Thread &thread) :
+        StopInfo (thread, LLDB_INVALID_UID),
+        m_performed_action (false)
+    {
+    }
+    
+    virtual
+    ~StopInfoExec ()
+    {
+    }
+    
+    virtual StopReason
+    GetStopReason () const
+    {
+        return eStopReasonExec;
+    }
+    
+    virtual const char *
+    GetDescription ()
+    {
+        return "exec";
+    }
+protected:
+protected:
+    
+    virtual void
+    PerformAction (Event *event_ptr)
+    {
+        // Only perform the action once
+        if (m_performed_action)
+            return;
+        m_performed_action = true;
+        m_thread.GetProcess()->DidExec();
+    }
+    
+    bool m_performed_action;
+};
+
 } // namespace lldb_private
 
 StopInfoSP
@@ -906,6 +949,12 @@
     return StopInfoSP (new StopInfoException (thread, description));
 }
 
+StopInfoSP
+StopInfo::CreateStopReasonWithExec (Thread &thread)
+{
+    return StopInfoSP (new StopInfoExec (thread));
+}
+
 ValueObjectSP
 StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp)
 {
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index 77daef6..433ddd0 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -130,6 +130,21 @@
 }
 
 void
+Target::CleanupProcess ()
+{
+    // Do any cleanup of the target we need to do between process instances.
+    // NB It is better to do this before destroying the process in case the
+    // clean up needs some help from the process.
+    m_breakpoint_list.ClearAllBreakpointSites();
+    m_internal_breakpoint_list.ClearAllBreakpointSites();
+    // Disable watchpoints just on the debugger side.
+    Mutex::Locker locker;
+    this->GetWatchpointList().GetListMutex(locker);
+    DisableAllWatchpoints(false);
+    ClearAllWatchpointHitCounts();
+}
+
+void
 Target::DeleteCurrentProcess ()
 {
     if (m_process_sp.get())
@@ -140,16 +155,8 @@
         
         m_process_sp->Finalize();
 
-        // Do any cleanup of the target we need to do between process instances.
-        // NB It is better to do this before destroying the process in case the
-        // clean up needs some help from the process.
-        m_breakpoint_list.ClearAllBreakpointSites();
-        m_internal_breakpoint_list.ClearAllBreakpointSites();
-        // Disable watchpoints just on the debugger side.
-        Mutex::Locker locker;
-        this->GetWatchpointList().GetListMutex(locker);
-        DisableAllWatchpoints(false);
-        ClearAllWatchpointHitCounts();
+        CleanupProcess ();
+
         m_process_sp.reset();
     }
 }
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 4c6995c..7a5aafb 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -1574,6 +1574,7 @@
     case eStopReasonWatchpoint:   return "watchpoint";
     case eStopReasonSignal:       return "signal";
     case eStopReasonException:    return "exception";
+    case eStopReasonExec:         return "exec";
     case eStopReasonPlanComplete: return "plan complete";
     }
 
diff --git a/source/Target/ThreadPlanBase.cpp b/source/Target/ThreadPlanBase.cpp
index f8e4b6a..ebf4686 100644
--- a/source/Target/ThreadPlanBase.cpp
+++ b/source/Target/ThreadPlanBase.cpp
@@ -139,6 +139,14 @@
             m_thread.DiscardThreadPlans(false);
             return true;
 
+        case eStopReasonExec:
+            // If we crashed, discard thread plans and stop.  Don't force the discard, however,
+            // since on rerun the target may clean up this exception and continue normally from there.
+            if (log)
+                log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exec.)", m_thread.GetID());
+            m_thread.DiscardThreadPlans(false);
+            return true;
+            
         case eStopReasonSignal:
             if (stop_info_sp->ShouldStop(event_ptr))
             {
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index ca24172..f4339a4 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -335,6 +335,7 @@
         case eStopReasonWatchpoint:
         case eStopReasonSignal:
         case eStopReasonException:
+        case eStopReasonExec:
             {
                 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
                 if (log)
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index 540539e..5343324 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -251,6 +251,7 @@
         case eStopReasonWatchpoint:
         case eStopReasonSignal:
         case eStopReasonException:
+        case eStopReasonExec:
             return false;
 
         default:
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index ba21eda..66754d2 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -319,6 +319,7 @@
         case eStopReasonWatchpoint:
         case eStopReasonSignal:
         case eStopReasonException:
+        case eStopReasonExec:
         default:
             if (log)
                 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp
index 1e454e7..95b0a35 100644
--- a/source/Target/ThreadPlanStepUntil.cpp
+++ b/source/Target/ThreadPlanStepUntil.cpp
@@ -291,6 +291,7 @@
             case eStopReasonWatchpoint:
             case eStopReasonSignal:
             case eStopReasonException:
+            case eStopReasonExec:
                 m_explains_stop = false;
                 break;
             default: