[Lldb-commits] [lldb] r180749 - lldb_private::StopInfo now holds onto a ThreadWP (a std::weak_ptr<lldb_private::Thread>) in case the thread goes away while the stop info still exists.

Greg Clayton gclayton at apple.com
Mon Apr 29 16:30:46 PDT 2013


Author: gclayton
Date: Mon Apr 29 18:30:46 2013
New Revision: 180749

URL: http://llvm.org/viewvc/llvm-project?rev=180749&view=rev
Log:
lldb_private::StopInfo now holds onto a ThreadWP (a std::weak_ptr<lldb_private::Thread>) in case the thread goes away while the stop info still exists.


Modified:
    lldb/trunk/include/lldb/Target/StopInfo.h
    lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.cpp
    lldb/trunk/source/Target/StopInfo.cpp

Modified: lldb/trunk/include/lldb/Target/StopInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StopInfo.h?rev=180749&r1=180748&r2=180749&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/StopInfo.h (original)
+++ lldb/trunk/include/lldb/Target/StopInfo.h Mon Apr 29 18:30:46 2013
@@ -40,16 +40,10 @@ public:
     bool
     IsValid () const;
 
-    Thread &
-    GetThread()
-    {
-        return m_thread;
-    }
-
-    const Thread &
+    lldb::ThreadSP
     GetThread() const
     {
-        return m_thread;
+        return m_thread_wp.lock();
     }
 
     // The value of the StopInfo depends on the StopReason.
@@ -184,7 +178,7 @@ protected:
     //------------------------------------------------------------------
     // Classes that inherit from StackID can see and modify these
     //------------------------------------------------------------------
-    Thread &        m_thread;   // The thread corresponding to the stop reason.
+    lldb::ThreadWP  m_thread_wp;   // The thread corresponding to the stop reason.
     uint32_t        m_stop_id;  // The process stop ID for which this stop info is valid
     uint32_t        m_resume_id; // This is the resume ID when we made this stop ID.
     uint64_t        m_value;    // A generic value that can be used for things pertaining to this stop info

Modified: lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.cpp?rev=180749&r1=180748&r2=180749&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.cpp Mon Apr 29 18:30:46 2013
@@ -34,7 +34,7 @@ StopInfoMachException::GetDescription ()
 {
     if (m_description.empty() && m_value != 0)
     {
-        ExecutionContext exe_ctx (m_thread.shared_from_this());
+        ExecutionContext exe_ctx (m_thread_wp.lock());
         Target *target = exe_ctx.GetTargetPtr();
         const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
 

Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=180749&r1=180748&r2=180749&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Mon Apr 29 18:30:46 2013
@@ -35,7 +35,7 @@ using namespace lldb;
 using namespace lldb_private;
 
 StopInfo::StopInfo (Thread &thread, uint64_t value) :
-    m_thread (thread),
+    m_thread_wp (thread.shared_from_this()),
     m_stop_id (thread.GetProcess()->GetStopID()),
     m_resume_id (thread.GetProcess()->GetResumeID()),
     m_value (value),
@@ -47,41 +47,53 @@ StopInfo::StopInfo (Thread &thread, uint
 bool
 StopInfo::IsValid () const
 {
-    return m_thread.GetProcess()->GetStopID() == m_stop_id;
+    ThreadSP thread_sp (m_thread_wp.lock());
+    if (thread_sp)
+        return thread_sp->GetProcess()->GetStopID() == m_stop_id;
+    return false;
 }
 
 void
 StopInfo::MakeStopInfoValid ()
 {
-    m_stop_id = m_thread.GetProcess()->GetStopID();
-    m_resume_id = m_thread.GetProcess()->GetResumeID();
+    ThreadSP thread_sp (m_thread_wp.lock());
+    if (thread_sp)
+    {
+        m_stop_id = thread_sp->GetProcess()->GetStopID();
+        m_resume_id = thread_sp->GetProcess()->GetResumeID();
+    }
 }
 
 bool
 StopInfo::HasTargetRunSinceMe ()
 {
-    lldb::StateType ret_type = m_thread.GetProcess()->GetPrivateState();
-    if (ret_type == eStateRunning)
-    {
-        return true;
-    }
-    else if (ret_type == eStateStopped)
+    ThreadSP thread_sp (m_thread_wp.lock());
+
+    if (thread_sp)
     {
-        // This is a little tricky.  We want to count "run and stopped again before you could
-        // ask this question as a "TRUE" answer to HasTargetRunSinceMe.  But we don't want to 
-        // include any running of the target done for expressions.  So we track both resumes,
-        // and resumes caused by expressions, and check if there are any resumes NOT caused
-        // by expressions.
-        
-        uint32_t curr_resume_id = m_thread.GetProcess()->GetResumeID();
-        uint32_t last_user_expression_id = m_thread.GetProcess()->GetLastUserExpressionResumeID ();
-        if (curr_resume_id == m_resume_id)
+        lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState();
+        if (ret_type == eStateRunning)
         {
-            return false;
+            return true;
         }
-        else if (curr_resume_id > last_user_expression_id)
+        else if (ret_type == eStateStopped)
         {
-            return true;
+            // This is a little tricky.  We want to count "run and stopped again before you could
+            // ask this question as a "TRUE" answer to HasTargetRunSinceMe.  But we don't want to 
+            // include any running of the target done for expressions.  So we track both resumes,
+            // and resumes caused by expressions, and check if there are any resumes NOT caused
+            // by expressions.
+            
+            uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID();
+            uint32_t last_user_expression_id = thread_sp->GetProcess()->GetLastUserExpressionResumeID ();
+            if (curr_resume_id == m_resume_id)
+            {
+                return false;
+            }
+            else if (curr_resume_id > last_user_expression_id)
+            {
+                return true;
+            }
         }
     }
     return false;
@@ -123,21 +135,26 @@ public:
         StoreBPInfo();
     }
 
-    void StoreBPInfo ()
+    void
+    StoreBPInfo ()
     {
-        BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-        if (bp_site_sp)
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
         {
-            if (bp_site_sp->GetNumberOfOwners() == 1)
+            BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+            if (bp_site_sp)
             {
-                BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0);
-                if (bp_loc_sp)
+                if (bp_site_sp->GetNumberOfOwners() == 1)
                 {
-                    m_break_id = bp_loc_sp->GetBreakpoint().GetID();
-                    m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot();
+                    BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0);
+                    if (bp_loc_sp)
+                    {
+                        m_break_id = bp_loc_sp->GetBreakpoint().GetID();
+                        m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot();
+                    }
                 }
+                m_address = bp_site_sp->GetLoadAddress();
             }
-            m_address = bp_site_sp->GetLoadAddress();
         }
     }
 
@@ -154,47 +171,56 @@ public:
     virtual bool
     ShouldStopSynchronous (Event *event_ptr)
     {
-        if (!m_should_stop_is_valid)
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
         {
-            // Only check once if we should stop at a breakpoint
-            BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-            if (bp_site_sp)
-            {
-                ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0));
-                StoppointCallbackContext context (event_ptr, exe_ctx, true);
-                m_should_stop = bp_site_sp->ShouldStop (&context);
-            }
-            else
+            if (!m_should_stop_is_valid)
             {
-                Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+                // Only check once if we should stop at a breakpoint
+                BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+                if (bp_site_sp)
+                {
+                    ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+                    StoppointCallbackContext context (event_ptr, exe_ctx, true);
+                    m_should_stop = bp_site_sp->ShouldStop (&context);
+                }
+                else
+                {
+                    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
 
-                if (log)
-                    log->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
+                    if (log)
+                        log->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
 
-                m_should_stop = true;
+                    m_should_stop = true;
+                }
+                m_should_stop_is_valid = true;
             }
-            m_should_stop_is_valid = true;
+            return m_should_stop;
         }
-        return m_should_stop;
+        return false;
     }
     
     virtual bool
     ShouldNotify (Event *event_ptr)
     {
-        BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-        if (bp_site_sp)
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
         {
-            bool all_internal = true;
-
-            for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
+            BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+            if (bp_site_sp)
             {
-                if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
+                bool all_internal = true;
+
+                for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
                 {
-                    all_internal = false;
-                    break;
+                    if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
+                    {
+                        all_internal = false;
+                        break;
+                    }
                 }
+                return all_internal == false;
             }
-            return all_internal == false;
         }
         return true;
     }
@@ -204,65 +230,69 @@ public:
     {
         if (m_description.empty())
         {
-            BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-            if (bp_site_sp)
+            ThreadSP thread_sp (m_thread_wp.lock());
+            if (thread_sp)
             {
-                StreamString strm;
-                // If we have just hit an internal breakpoint, and it has a kind description, print that instead of the
-                // full breakpoint printing:
-                if (bp_site_sp->IsInternal())
+                BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+                if (bp_site_sp)
                 {
-                    size_t num_owners = bp_site_sp->GetNumberOfOwners();
-                    for (size_t idx = 0; idx < num_owners; idx++)
+                    StreamString strm;
+                    // If we have just hit an internal breakpoint, and it has a kind description, print that instead of the
+                    // full breakpoint printing:
+                    if (bp_site_sp->IsInternal())
                     {
-                        const char *kind = bp_site_sp->GetOwnerAtIndex(idx)->GetBreakpoint().GetBreakpointKind();
-                        if (kind != NULL)
+                        size_t num_owners = bp_site_sp->GetNumberOfOwners();
+                        for (size_t idx = 0; idx < num_owners; idx++)
                         {
-                            m_description.assign (kind);
-                            return kind;
+                            const char *kind = bp_site_sp->GetOwnerAtIndex(idx)->GetBreakpoint().GetBreakpointKind();
+                            if (kind != NULL)
+                            {
+                                m_description.assign (kind);
+                                return kind;
+                            }
                         }
                     }
+                    
+                    strm.Printf("breakpoint ");
+                    bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
+                    m_description.swap (strm.GetString());
                 }
-                
-                strm.Printf("breakpoint ");
-                bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
-                m_description.swap (strm.GetString());
-            }
-            else
-            {
-                StreamString strm;
-                if (m_break_id != LLDB_INVALID_BREAK_ID)
+                else
                 {
-                    BreakpointSP break_sp = m_thread.GetProcess()->GetTarget().GetBreakpointByID(m_break_id);
-                    if (break_sp)
+                    StreamString strm;
+                    if (m_break_id != LLDB_INVALID_BREAK_ID)
                     {
-                        if (break_sp->IsInternal())
+                        BreakpointSP break_sp = thread_sp->GetProcess()->GetTarget().GetBreakpointByID(m_break_id);
+                        if (break_sp)
                         {
-                            const char *kind = break_sp->GetBreakpointKind();
-                            if (kind)
-                                strm.Printf ("internal %s breakpoint(%d).", kind, m_break_id);
+                            if (break_sp->IsInternal())
+                            {
+                                const char *kind = break_sp->GetBreakpointKind();
+                                if (kind)
+                                    strm.Printf ("internal %s breakpoint(%d).", kind, m_break_id);
+                                else
+                                    strm.Printf ("internal breakpoint(%d).", m_break_id);
+                            }
                             else
-                                strm.Printf ("internal breakpoint(%d).", m_break_id);
-                        }
+                            {
+                                strm.Printf ("breakpoint %d.", m_break_id);
+                            }
+                        } 
                         else
                         {
-                            strm.Printf ("breakpoint %d.", m_break_id);
+                            if (m_was_one_shot)
+                                strm.Printf ("one-shot breakpoint %d", m_break_id);
+                            else
+                                strm.Printf ("breakpoint %d which has been deleted.", m_break_id);
                         }
-                    } 
-                    else
-                    {
-                        if (m_was_one_shot)
-                            strm.Printf ("one-shot breakpoint %d", m_break_id);
-                        else
-                            strm.Printf ("breakpoint %d which has been deleted.", m_break_id);
                     }
+                    else if (m_address == LLDB_INVALID_ADDRESS)
+                        strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value);
+                    else
+                        strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address);
+                    
+                    m_description.swap (strm.GetString());
                 }
-                else if (m_address == LLDB_INVALID_ADDRESS)
-                    strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value);
-                else
-                    strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address);
-                
-                m_description.swap (strm.GetString());
             }
         }
         return m_description.c_str();
@@ -285,186 +315,191 @@ protected:
             return;
         m_should_perform_action = false;
         
-        Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
-        
-        if (!m_thread.IsValid())
-        {
-            // This shouldn't ever happen, but just in case, don't do more harm.
-            log->Printf ("PerformAction got called with an invalid thread.");
-            m_should_stop = true;
-            m_should_stop_is_valid = true;
-            return;
-        }
-        
-        BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-        
-        if (bp_site_sp)
+        ThreadSP thread_sp (m_thread_wp.lock());
+
+        if (thread_sp)
         {
-            size_t num_owners = bp_site_sp->GetNumberOfOwners();
-                
-            if (num_owners == 0)
+            Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+            
+            if (!thread_sp->IsValid())
             {
+                // This shouldn't ever happen, but just in case, don't do more harm.
+                log->Printf ("PerformAction got called with an invalid thread.");
                 m_should_stop = true;
+                m_should_stop_is_valid = true;
+                return;
             }
-            else
+            
+            BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+            
+            if (bp_site_sp)
             {
-                // We go through each location, and test first its condition.  If the condition says to stop,
-                // then we run the callback for that location.  If that callback says to stop as well, then 
-                // we set m_should_stop to true; we are going to stop.
-                // But we still want to give all the breakpoints whose conditions say we are going to stop a
-                // chance to run their callbacks.
-                // Of course if any callback restarts the target by putting "continue" in the callback, then 
-                // we're going to restart, without running the rest of the callbacks.  And in this case we will
-                // end up not stopping even if another location said we should stop.  But that's better than not
-                // running all the callbacks.
-                
-                m_should_stop = false;
-
-                ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0));
-                Process *process  = exe_ctx.GetProcessPtr();
-                if (process->GetModIDRef().IsLastResumeForUserExpression())
-                {
-                    // If we are in the middle of evaluating an expression, don't run asynchronous breakpoint commands or
-                    // expressions.  That could lead to infinite recursion if the command or condition re-calls the function
-                    // with this breakpoint.
-                    // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested
-                    // PerformAction calls that can arise when the action runs a function that hits another breakpoint,
-                    // and only stop running commands when we see the same breakpoint hit a second time.
+                size_t num_owners = bp_site_sp->GetNumberOfOwners();
                     
-                    m_should_stop_is_valid = true;
-                    if (log)
-                        log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression,"
-                                     " not running commands to avoid recursion.");
-                    bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions();
-                    if (ignoring_breakpoints)
-                    {
-                        m_should_stop = false;
-                        // Internal breakpoints will always stop.  
-                        for (size_t j = 0; j < num_owners; j++)
-                        {
-                            lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
-                            if (bp_loc_sp->GetBreakpoint().IsInternal())
-                            {
-                                m_should_stop = true;
-                                break;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        m_should_stop = true;
-                    }
-                    if (log)
-                        log->Printf ("StopInfoBreakpoint::PerformAction - in expression, continuing: %s.",
-                                     m_should_stop ? "true" : "false");
-                    process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: hit breakpoint while "
-                                           "running function, skipping commands and conditions to prevent recursion.");
-                    return;
+                if (num_owners == 0)
+                {
+                    m_should_stop = true;
                 }
-                
-                StoppointCallbackContext context (event_ptr, exe_ctx, false);
-                
-                // Let's copy the breakpoint locations out of the site and store them in a local list.  That way if
-                // one of the breakpoint actions changes the site, then we won't be operating on a bad list.
-                
-                BreakpointLocationCollection site_locations;
-                for (size_t j = 0; j < num_owners; j++)
-                    site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
-
-                for (size_t j = 0; j < num_owners; j++)
+                else
                 {
-                    lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
+                    // We go through each location, and test first its condition.  If the condition says to stop,
+                    // then we run the callback for that location.  If that callback says to stop as well, then 
+                    // we set m_should_stop to true; we are going to stop.
+                    // But we still want to give all the breakpoints whose conditions say we are going to stop a
+                    // chance to run their callbacks.
+                    // Of course if any callback restarts the target by putting "continue" in the callback, then 
+                    // we're going to restart, without running the rest of the callbacks.  And in this case we will
+                    // end up not stopping even if another location said we should stop.  But that's better than not
+                    // running all the callbacks.
                     
-                    // If another action disabled this breakpoint or its location, then don't run the actions.
-                    if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled())
-                        continue;
-                    
-                    // The breakpoint site may have many locations associated with it, not all of them valid for
-                    // this thread.  Skip the ones that aren't:
-                    if (!bp_loc_sp->ValidForThisThread(&m_thread))
-                        continue;
-                                                      
-                    // First run the condition for the breakpoint.  If that says we should stop, then we'll run
-                    // the callback for the breakpoint.  If the callback says we shouldn't stop that will win.                    
-                    
-                    if (bp_loc_sp->GetConditionText() != NULL)
+                    m_should_stop = false;
+
+                    ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+                    Process *process  = exe_ctx.GetProcessPtr();
+                    if (process->GetModIDRef().IsLastResumeForUserExpression())
                     {
-                        Error condition_error;
-                        bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
+                        // If we are in the middle of evaluating an expression, don't run asynchronous breakpoint commands or
+                        // expressions.  That could lead to infinite recursion if the command or condition re-calls the function
+                        // with this breakpoint.
+                        // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested
+                        // PerformAction calls that can arise when the action runs a function that hits another breakpoint,
+                        // and only stop running commands when we see the same breakpoint hit a second time.
                         
-                        if (!condition_error.Success())
+                        m_should_stop_is_valid = true;
+                        if (log)
+                            log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression,"
+                                         " not running commands to avoid recursion.");
+                        bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions();
+                        if (ignoring_breakpoints)
                         {
-                            Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
-                            StreamSP error_sp = debugger.GetAsyncErrorStream ();
-                            error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint ");
-                            bp_loc_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
-                            error_sp->Printf (": \"%s\"",
-                                              bp_loc_sp->GetConditionText());
-                            error_sp->EOL();
-                            const char *err_str = condition_error.AsCString("<Unknown Error>");
-                            if (log)
-                                log->Printf("Error evaluating condition: \"%s\"\n", err_str);
-                            
-                            error_sp->PutCString (err_str);
-                            error_sp->EOL();
-                            error_sp->Flush();
-                            // If the condition fails to be parsed or run, we should stop.
-                            condition_says_stop = true;
+                            m_should_stop = false;
+                            // Internal breakpoints will always stop.  
+                            for (size_t j = 0; j < num_owners; j++)
+                            {
+                                lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+                                if (bp_loc_sp->GetBreakpoint().IsInternal())
+                                {
+                                    m_should_stop = true;
+                                    break;
+                                }
+                            }
                         }
                         else
                         {
-                            if (!condition_says_stop)
-                                continue;
+                            m_should_stop = true;
                         }
+                        if (log)
+                            log->Printf ("StopInfoBreakpoint::PerformAction - in expression, continuing: %s.",
+                                         m_should_stop ? "true" : "false");
+                        process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: hit breakpoint while "
+                                               "running function, skipping commands and conditions to prevent recursion.");
+                        return;
                     }
-                                
-                    bool callback_says_stop;
-                    
-                    // FIXME: For now the callbacks have to run in async mode - the first time we restart we need
-                    // to get out of there.  So set it here.
-                    // When we figure out how to nest breakpoint hits then this will change.
-                    
-                    Debugger &debugger = m_thread.CalculateTarget()->GetDebugger();
-                    bool old_async = debugger.GetAsyncExecution();
-                    debugger.SetAsyncExecution (true);
                     
-                    callback_says_stop = bp_loc_sp->InvokeCallback (&context);
+                    StoppointCallbackContext context (event_ptr, exe_ctx, false);
                     
-                    debugger.SetAsyncExecution (old_async);
+                    // Let's copy the breakpoint locations out of the site and store them in a local list.  That way if
+                    // one of the breakpoint actions changes the site, then we won't be operating on a bad list.
                     
-                    if (callback_says_stop)
-                        m_should_stop = true;
-                    
-                    // If we are going to stop for this breakpoint, then remove the breakpoint.
-                    if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot())
+                    BreakpointLocationCollection site_locations;
+                    for (size_t j = 0; j < num_owners; j++)
+                        site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
+
+                    for (size_t j = 0; j < num_owners; j++)
                     {
-                        m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID());
-                    }
+                        lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
                         
-                    // Also make sure that the callback hasn't continued the target.  
-                    // If it did, when we'll set m_should_start to false and get out of here.
-                    if (HasTargetRunSinceMe ())
-                    {
-                        m_should_stop = false;
-                        break;
+                        // If another action disabled this breakpoint or its location, then don't run the actions.
+                        if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled())
+                            continue;
+                        
+                        // The breakpoint site may have many locations associated with it, not all of them valid for
+                        // this thread.  Skip the ones that aren't:
+                        if (!bp_loc_sp->ValidForThisThread(thread_sp.get()))
+                            continue;
+                                                          
+                        // First run the condition for the breakpoint.  If that says we should stop, then we'll run
+                        // the callback for the breakpoint.  If the callback says we shouldn't stop that will win.                    
+                        
+                        if (bp_loc_sp->GetConditionText() != NULL)
+                        {
+                            Error condition_error;
+                            bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
+                            
+                            if (!condition_error.Success())
+                            {
+                                Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+                                StreamSP error_sp = debugger.GetAsyncErrorStream ();
+                                error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint ");
+                                bp_loc_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
+                                error_sp->Printf (": \"%s\"",
+                                                  bp_loc_sp->GetConditionText());
+                                error_sp->EOL();
+                                const char *err_str = condition_error.AsCString("<Unknown Error>");
+                                if (log)
+                                    log->Printf("Error evaluating condition: \"%s\"\n", err_str);
+                                
+                                error_sp->PutCString (err_str);
+                                error_sp->EOL();
+                                error_sp->Flush();
+                                // If the condition fails to be parsed or run, we should stop.
+                                condition_says_stop = true;
+                            }
+                            else
+                            {
+                                if (!condition_says_stop)
+                                    continue;
+                            }
+                        }
+                                    
+                        bool callback_says_stop;
+                        
+                        // FIXME: For now the callbacks have to run in async mode - the first time we restart we need
+                        // to get out of there.  So set it here.
+                        // When we figure out how to nest breakpoint hits then this will change.
+                        
+                        Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();
+                        bool old_async = debugger.GetAsyncExecution();
+                        debugger.SetAsyncExecution (true);
+                        
+                        callback_says_stop = bp_loc_sp->InvokeCallback (&context);
+                        
+                        debugger.SetAsyncExecution (old_async);
+                        
+                        if (callback_says_stop)
+                            m_should_stop = true;
+                        
+                        // If we are going to stop for this breakpoint, then remove the breakpoint.
+                        if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot())
+                        {
+                            thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID());
+                        }
+                            
+                        // Also make sure that the callback hasn't continued the target.  
+                        // If it did, when we'll set m_should_start to false and get out of here.
+                        if (HasTargetRunSinceMe ())
+                        {
+                            m_should_stop = false;
+                            break;
+                        }
                     }
                 }
-            }
-            // We've figured out what this stop wants to do, so mark it as valid so we don't compute it again.
-            m_should_stop_is_valid = true;
+                // We've figured out what this stop wants to do, so mark it as valid so we don't compute it again.
+                m_should_stop_is_valid = true;
 
-        }
-        else
-        {
-            m_should_stop = true;
-            m_should_stop_is_valid = true;
-            Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+            }
+            else
+            {
+                m_should_stop = true;
+                m_should_stop_is_valid = true;
+                Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
 
-            if (log_process)
-                log_process->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
+                if (log_process)
+                    log_process->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
+            }
+            if (log)
+                log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
         }
-        if (log)
-            log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
     }
 
 private:
@@ -563,24 +598,27 @@ protected:
         if (m_should_stop_is_valid)
             return m_should_stop;
 
-        WatchpointSP wp_sp =
-            m_thread.CalculateTarget()->GetWatchpointList().FindByID(GetValue());
-        if (wp_sp)
-        {
-            // Check if we should stop at a watchpoint.
-            ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0));
-            StoppointCallbackContext context (event_ptr, exe_ctx, true);
-            m_should_stop = wp_sp->ShouldStop (&context);
-        }
-        else
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
         {
-            Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+            WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
+            if (wp_sp)
+            {
+                // Check if we should stop at a watchpoint.
+                ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+                StoppointCallbackContext context (event_ptr, exe_ctx, true);
+                m_should_stop = wp_sp->ShouldStop (&context);
+            }
+            else
+            {
+                Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
 
-            if (log)
-                log->Printf ("Process::%s could not find watchpoint location id: %" PRId64 "...",
-                             __FUNCTION__, GetValue());
+                if (log)
+                    log->Printf ("Process::%s could not find watchpoint location id: %" PRId64 "...",
+                                 __FUNCTION__, GetValue());
 
-            m_should_stop = true;
+                m_should_stop = true;
+            }
         }
         m_should_stop_is_valid = true;
         return m_should_stop;
@@ -603,155 +641,158 @@ protected:
         // this code.  Also by default we're going to stop, so set that here.
         m_should_stop = true;
         
-        WatchpointSP wp_sp =
-            m_thread.CalculateTarget()->GetWatchpointList().FindByID(GetValue());
-        if (wp_sp)
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
         {
-            ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0));
-            Process* process = exe_ctx.GetProcessPtr();
-
-            // This sentry object makes sure the current watchpoint is disabled while performing watchpoint actions,
-            // and it is then enabled after we are finished.
-            WatchpointSentry sentry(process, wp_sp.get());
 
+            WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
+            if (wp_sp)
             {
-                // check if this process is running on an architecture where watchpoints trigger
-				// before the associated instruction runs. if so, disable the WP, single-step and then
-				// re-enable the watchpoint
-                if (process)
+                ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+                Process* process = exe_ctx.GetProcessPtr();
+
+                // This sentry object makes sure the current watchpoint is disabled while performing watchpoint actions,
+                // and it is then enabled after we are finished.
+                WatchpointSentry sentry(process, wp_sp.get());
+
                 {
-                    uint32_t num; bool wp_triggers_after;
-                    if (process->GetWatchpointSupportInfo(num, wp_triggers_after).Success())
+                    // check if this process is running on an architecture where watchpoints trigger
+                    // before the associated instruction runs. if so, disable the WP, single-step and then
+                    // re-enable the watchpoint
+                    if (process)
                     {
-                        if (!wp_triggers_after)
+                        uint32_t num; bool wp_triggers_after;
+                        if (process->GetWatchpointSupportInfo(num, wp_triggers_after).Success())
                         {
-                            ThreadPlan *new_plan = m_thread.QueueThreadPlanForStepSingleInstruction(false, // step-over
-                                                                                                    false, // abort_other_plans
-                                                                                                    true); // stop_other_threads
-                            new_plan->SetIsMasterPlan (true);
-                            new_plan->SetOkayToDiscard (false);
-                            process->GetThreadList().SetSelectedThreadByID (m_thread.GetID());
-                            process->Resume ();
-                            process->WaitForProcessToStop (NULL);
-                            process->GetThreadList().SetSelectedThreadByID (m_thread.GetID());
-                            MakeStopInfoValid(); // make sure we do not fail to stop because of the single-step taken above
+                            if (!wp_triggers_after)
+                            {
+                                ThreadPlan *new_plan = thread_sp->QueueThreadPlanForStepSingleInstruction(false, // step-over
+                                                                                                        false, // abort_other_plans
+                                                                                                        true); // stop_other_threads
+                                new_plan->SetIsMasterPlan (true);
+                                new_plan->SetOkayToDiscard (false);
+                                process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
+                                process->Resume ();
+                                process->WaitForProcessToStop (NULL);
+                                process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
+                                MakeStopInfoValid(); // make sure we do not fail to stop because of the single-step taken above
+                            }
                         }
                     }
                 }
-            }
 
-            if (m_should_stop && wp_sp->GetConditionText() != NULL)
-            {
-                // We need to make sure the user sees any parse errors in their condition, so we'll hook the
-                // constructor errors up to the debugger's Async I/O.
-                ExecutionResults result_code;
-                ValueObjectSP result_value_sp;
-                const bool unwind_on_error = true;
-                const bool ignore_breakpoints = true;
-                Error error;
-                result_code = ClangUserExpression::EvaluateWithError (exe_ctx,
-                                                                      eExecutionPolicyOnlyWhenNeeded,
-                                                                      lldb::eLanguageTypeUnknown,
-                                                                      ClangUserExpression::eResultTypeAny,
-                                                                      unwind_on_error,
-                                                                      ignore_breakpoints,
-                                                                      wp_sp->GetConditionText(),
-                                                                      NULL,
-                                                                      result_value_sp,
-                                                                      error,
-                                                                      true,
-                                                                      ClangUserExpression::kDefaultTimeout);
-                if (result_code == eExecutionCompleted)
+                if (m_should_stop && wp_sp->GetConditionText() != NULL)
                 {
-                    if (result_value_sp)
+                    // We need to make sure the user sees any parse errors in their condition, so we'll hook the
+                    // constructor errors up to the debugger's Async I/O.
+                    ExecutionResults result_code;
+                    ValueObjectSP result_value_sp;
+                    const bool unwind_on_error = true;
+                    const bool ignore_breakpoints = true;
+                    Error error;
+                    result_code = ClangUserExpression::EvaluateWithError (exe_ctx,
+                                                                          eExecutionPolicyOnlyWhenNeeded,
+                                                                          lldb::eLanguageTypeUnknown,
+                                                                          ClangUserExpression::eResultTypeAny,
+                                                                          unwind_on_error,
+                                                                          ignore_breakpoints,
+                                                                          wp_sp->GetConditionText(),
+                                                                          NULL,
+                                                                          result_value_sp,
+                                                                          error,
+                                                                          true,
+                                                                          ClangUserExpression::kDefaultTimeout);
+                    if (result_code == eExecutionCompleted)
                     {
-                        Scalar scalar_value;
-                        if (result_value_sp->ResolveValue (scalar_value))
+                        if (result_value_sp)
                         {
-                            if (scalar_value.ULongLong(1) == 0)
+                            Scalar scalar_value;
+                            if (result_value_sp->ResolveValue (scalar_value))
                             {
-                                // We have been vetoed.  This takes precedence over querying
-                                // the watchpoint whether it should stop (aka ignore count and
-                                // friends).  See also StopInfoWatchpoint::ShouldStop() as well
-                                // as Process::ProcessEventData::DoOnRemoval().
-                                m_should_stop = false;
+                                if (scalar_value.ULongLong(1) == 0)
+                                {
+                                    // We have been vetoed.  This takes precedence over querying
+                                    // the watchpoint whether it should stop (aka ignore count and
+                                    // friends).  See also StopInfoWatchpoint::ShouldStop() as well
+                                    // as Process::ProcessEventData::DoOnRemoval().
+                                    m_should_stop = false;
+                                }
+                                else
+                                    m_should_stop = true;
+                                if (log)
+                                    log->Printf("Condition successfully evaluated, result is %s.\n", 
+                                                m_should_stop ? "true" : "false");
                             }
                             else
+                            {
                                 m_should_stop = true;
-                            if (log)
-                                log->Printf("Condition successfully evaluated, result is %s.\n", 
-                                            m_should_stop ? "true" : "false");
-                        }
-                        else
-                        {
-                            m_should_stop = true;
-                            if (log)
-                                log->Printf("Failed to get an integer result from the expression.");
+                                if (log)
+                                    log->Printf("Failed to get an integer result from the expression.");
+                            }
                         }
                     }
+                    else
+                    {
+                        Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+                        StreamSP error_sp = debugger.GetAsyncErrorStream ();
+                        error_sp->Printf ("Stopped due to an error evaluating condition of watchpoint ");
+                        wp_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
+                        error_sp->Printf (": \"%s\"", 
+                                          wp_sp->GetConditionText());
+                        error_sp->EOL();
+                        const char *err_str = error.AsCString("<Unknown Error>");
+                        if (log)
+                            log->Printf("Error evaluating condition: \"%s\"\n", err_str);
+
+                        error_sp->PutCString (err_str);
+                        error_sp->EOL();                       
+                        error_sp->Flush();
+                        // If the condition fails to be parsed or run, we should stop.
+                        m_should_stop = true;
+                    }
                 }
-                else
-                {
-                    Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
-                    StreamSP error_sp = debugger.GetAsyncErrorStream ();
-                    error_sp->Printf ("Stopped due to an error evaluating condition of watchpoint ");
-                    wp_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
-                    error_sp->Printf (": \"%s\"", 
-                                      wp_sp->GetConditionText());
-                    error_sp->EOL();
-                    const char *err_str = error.AsCString("<Unknown Error>");
-                    if (log)
-                        log->Printf("Error evaluating condition: \"%s\"\n", err_str);
 
-                    error_sp->PutCString (err_str);
-                    error_sp->EOL();                       
-                    error_sp->Flush();
-                    // If the condition fails to be parsed or run, we should stop.
-                    m_should_stop = true;
+                // If the condition says to stop, we run the callback to further decide whether to stop.
+                if (m_should_stop)
+                {
+                    StoppointCallbackContext context (event_ptr, exe_ctx, false);
+                    bool stop_requested = wp_sp->InvokeCallback (&context);
+                    // Also make sure that the callback hasn't continued the target.  
+                    // If it did, when we'll set m_should_stop to false and get out of here.
+                    if (HasTargetRunSinceMe ())
+                        m_should_stop = false;
+                    
+                    if (m_should_stop && !stop_requested)
+                    {
+                        // We have been vetoed by the callback mechanism.
+                        m_should_stop = false;
+                    }
                 }
-            }
-
-            // If the condition says to stop, we run the callback to further decide whether to stop.
-            if (m_should_stop)
-            {
-                StoppointCallbackContext context (event_ptr, exe_ctx, false);
-                bool stop_requested = wp_sp->InvokeCallback (&context);
-                // Also make sure that the callback hasn't continued the target.  
-                // If it did, when we'll set m_should_stop to false and get out of here.
-                if (HasTargetRunSinceMe ())
-                    m_should_stop = false;
-                
-                if (m_should_stop && !stop_requested)
+                // Finally, if we are going to stop, print out the new & old values:
+                if (m_should_stop)
                 {
-                    // We have been vetoed by the callback mechanism.
-                    m_should_stop = false;
+                    wp_sp->CaptureWatchedValue(exe_ctx);
+                    
+                    Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+                    StreamSP output_sp = debugger.GetAsyncOutputStream ();
+                    wp_sp->DumpSnapshots(output_sp.get());
+                    output_sp->EOL();
+                    output_sp->Flush();
                 }
+                
             }
-            // Finally, if we are going to stop, print out the new & old values:
-            if (m_should_stop)
+            else
             {
-                wp_sp->CaptureWatchedValue(exe_ctx);
-                
-                Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
-                StreamSP output_sp = debugger.GetAsyncOutputStream ();
-                wp_sp->DumpSnapshots(output_sp.get());
-                output_sp->EOL();
-                output_sp->Flush();
+                Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+                if (log_process)
+                    log_process->Printf ("Process::%s could not find watchpoint id: %" PRId64 "...", __FUNCTION__, m_value);
             }
+            if (log)
+                log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
             
+            m_should_stop_is_valid = true;
         }
-        else
-        {
-            Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-
-            if (log_process)
-                log_process->Printf ("Process::%s could not find watchpoint id: %" PRId64 "...", __FUNCTION__, m_value);
-        }
-        if (log)
-            log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
-        
-        m_should_stop_is_valid = true;
-        
     }
         
 private:
@@ -789,13 +830,19 @@ public:
     virtual bool
     ShouldStopSynchronous (Event *event_ptr)
     {
-        return m_thread.GetProcess()->GetUnixSignals().GetShouldStop (m_value);
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
+            return thread_sp->GetProcess()->GetUnixSignals().GetShouldStop (m_value);
+        return false;
     }
 
     virtual bool
     ShouldStop (Event *event_ptr)
     {
-        return m_thread.GetProcess()->GetUnixSignals().GetShouldStop (m_value);
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
+            return thread_sp->GetProcess()->GetUnixSignals().GetShouldStop (m_value);
+        return false;
     }
     
     
@@ -803,24 +850,33 @@ public:
     virtual bool
     ShouldNotify (Event *event_ptr)
     {
-        bool should_notify = m_thread.GetProcess()->GetUnixSignals().GetShouldNotify (m_value);
-        if (should_notify)
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
         {
-            StreamString strm;
-            strm.Printf ("thread %d received signal: %s",
-                         m_thread.GetIndexID(),
-                         m_thread.GetProcess()->GetUnixSignals().GetSignalAsCString (m_value));
-            Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData());
+            bool should_notify = thread_sp->GetProcess()->GetUnixSignals().GetShouldNotify (m_value);
+            if (should_notify)
+            {
+                StreamString strm;
+                strm.Printf ("thread %d received signal: %s",
+                             thread_sp->GetIndexID(),
+                             thread_sp->GetProcess()->GetUnixSignals().GetSignalAsCString (m_value));
+                Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData());
+            }
+            return should_notify;
         }
-        return should_notify;
+        return true;
     }
 
     
     virtual void
     WillResume (lldb::StateType resume_state)
     {
-        if (m_thread.GetProcess()->GetUnixSignals().GetShouldSuppress(m_value) == false)
-            m_thread.SetResumeSignal(m_value);
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
+        {
+            if (thread_sp->GetProcess()->GetUnixSignals().GetShouldSuppress(m_value) == false)
+                thread_sp->SetResumeSignal(m_value);
+        }
     }
 
     virtual const char *
@@ -828,13 +884,17 @@ public:
     {
         if (m_description.empty())
         {
-            StreamString strm;
-            const char *signal_name = m_thread.GetProcess()->GetUnixSignals().GetSignalAsCString (m_value);
-            if (signal_name)
-                strm.Printf("signal %s", signal_name);
-            else
-                strm.Printf("signal %" PRIi64, m_value);
-            m_description.swap (strm.GetString());
+            ThreadSP thread_sp (m_thread_wp.lock());
+            if (thread_sp)
+            {
+                StreamString strm;
+                const char *signal_name = thread_sp->GetProcess()->GetUnixSignals().GetSignalAsCString (m_value);
+                if (signal_name)
+                    strm.Printf("signal %s", signal_name);
+                else
+                    strm.Printf("signal %" PRIi64, m_value);
+                m_description.swap (strm.GetString());
+            }
         }
         return m_description.c_str();
     }
@@ -1004,7 +1064,9 @@ protected:
         if (m_performed_action)
             return;
         m_performed_action = true;
-        m_thread.GetProcess()->DidExec();
+        ThreadSP thread_sp (m_thread_wp.lock());
+        if (thread_sp)
+            thread_sp->GetProcess()->DidExec();
     }
     
     bool m_performed_action;





More information about the lldb-commits mailing list