[Lldb-commits] [lldb] r137102 - in /lldb/trunk: include/lldb/Breakpoint/Breakpoint.h include/lldb/Core/UserID.h include/lldb/Core/ValueObject.h include/lldb/Target/Process.h include/lldb/Target/StopInfo.h include/lldb/lldb-forward.h source/Breakpoint/BreakpointLocation.cpp source/Core/ValueObject.cpp source/Target/Process.cpp source/Target/StopInfo.cpp test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py

Jim Ingham jingham at apple.com
Mon Aug 8 19:12:22 PDT 2011


Author: jingham
Date: Mon Aug  8 21:12:22 2011
New Revision: 137102

URL: http://llvm.org/viewvc/llvm-project?rev=137102&view=rev
Log:
Move the handling of breakpoint conditions from the Private event loop to the StopInfoBreakpoint::DoActions, which happens as the 
event is removed.  Also use the return value of asynchronous breakpoint callbacks, they get checked before, and override the 
breakpoint conditions.

Added ProcessModInfo class, to unify "stop_id generation" and "memory modification generation", and use where needed.

Modified:
    lldb/trunk/include/lldb/Breakpoint/Breakpoint.h
    lldb/trunk/include/lldb/Core/UserID.h
    lldb/trunk/include/lldb/Core/ValueObject.h
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/include/lldb/Target/StopInfo.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/source/Breakpoint/BreakpointLocation.cpp
    lldb/trunk/source/Core/ValueObject.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/StopInfo.cpp
    lldb/trunk/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py

Modified: lldb/trunk/include/lldb/Breakpoint/Breakpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/Breakpoint.h?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Breakpoint/Breakpoint.h (original)
+++ lldb/trunk/include/lldb/Breakpoint/Breakpoint.h Mon Aug  8 21:12:22 2011
@@ -349,12 +349,20 @@
     GetThreadID ();
 
     //------------------------------------------------------------------
-    /// Set the callback action invoked when the breakpoint is hit.  The callback
-    /// Will return a bool indicating whether the target should stop at this breakpoint or not.
+    /// Set the callback action invoked when the breakpoint is hit.  
+    /// 
     /// @param[in] callback
     ///    The method that will get called when the breakpoint is hit.
     /// @param[in] baton
     ///    A void * pointer that will get passed back to the callback function.
+    /// @param[in] is_synchronous
+    ///    If \b true the callback will be run on the private event thread
+    ///    before the stop event gets reported.  If false, the callback will get
+    ///    handled on the public event thead after the stop has been posted.
+    ///
+    /// @return
+    ///    \b true if the process should stop when you hit the breakpoint.
+    ///    \b false if it should continue.
     //------------------------------------------------------------------
     void
     SetCallback (BreakpointHitCallback callback, 

Modified: lldb/trunk/include/lldb/Core/UserID.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/UserID.h?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/UserID.h (original)
+++ lldb/trunk/include/lldb/Core/UserID.h Mon Aug  8 21:12:22 2011
@@ -111,9 +111,6 @@
     lldb::user_id_t m_uid; ///< The user ID that uniquely identifies an object.
 };
 
-//--------------------------------------------------------------
-/// Stream the UserID object to a Stream.
-//--------------------------------------------------------------
 inline bool operator== (const UserID& lhs, const UserID& rhs)
 {
   return lhs.GetID() == rhs.GetID();
@@ -124,6 +121,9 @@
   return lhs.GetID() != rhs.GetID();
 }
 
+//--------------------------------------------------------------
+/// Stream the UserID object to a Stream.
+//--------------------------------------------------------------
 Stream& operator << (Stream& strm, const UserID& uid);
 
 } // namespace lldb_private

Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Mon Aug  8 21:12:22 2011
@@ -26,6 +26,7 @@
 #include "lldb/Core/Value.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/StackID.h"
 #include "lldb/Utility/PriorityPointerPair.h"
 #include "lldb/Utility/SharedCluster.h"
@@ -240,25 +241,25 @@
         SetIsConstant ()
         {
             SetUpdated();
-            m_stop_id = LLDB_INVALID_UID;
+            m_mod_id.SetInvalid();
         }
         
         bool
         IsConstant () const
         {
-            return m_stop_id == LLDB_INVALID_UID;
+            return !m_mod_id.IsValid();
         }
         
-        lldb::user_id_t
-        GetUpdateID () const
+        ProcessModID
+        GetModID () const
         {
-            return m_stop_id;
+            return m_mod_id;
         }
 
         void
-        SetUpdateID (lldb::user_id_t new_id)
+        SetUpdateID (ProcessModID new_id)
         {
-            m_stop_id = new_id;
+            m_mod_id = new_id;
         }
         
         bool
@@ -286,11 +287,11 @@
         bool
         IsValid ()
         {
-            if (m_stop_id == LLDB_INVALID_UID)
+            if (!m_mod_id.IsValid())
                 return false;
             else if (SyncWithProcessState ())
             {
-                if (m_stop_id == LLDB_INVALID_UID)
+                if (!m_mod_id.IsValid())
                     return false;
             }
             return true;
@@ -301,13 +302,11 @@
         {
             // Use the stop id to mark us as invalid, leave the thread id and the stack id around for logging and
             // history purposes.
-            m_stop_id = LLDB_INVALID_UID;
+            m_mod_id.SetInvalid();
             
             // Can't update an invalid state.
             m_needs_update = false;
             
-//            m_thread_id = LLDB_INVALID_THREAD_ID;
-//            m_stack_id.Clear();
         }
         
     private:
@@ -323,7 +322,7 @@
         lldb::ProcessSP  m_process_sp;
         lldb::user_id_t  m_thread_id;
         StackID          m_stack_id;
-        lldb::user_id_t  m_stop_id; // This is the stop id when this ValueObject was last evaluated.
+        ProcessModID     m_mod_id; // This is the stop id when this ValueObject was last evaluated.
     };
 
     const EvaluationPoint &
@@ -691,7 +690,7 @@
     SetCustomSummaryFormat(lldb::SummaryFormatSP format)
     {
         m_forced_summary_format = format;
-        m_user_id_of_forced_summary = m_update_point.GetUpdateID();
+        m_user_id_of_forced_summary = m_update_point.GetModID();
         m_summary_str.clear();
     }
     
@@ -789,7 +788,7 @@
     lldb::SummaryFormatSP       m_forced_summary_format;
     lldb::ValueFormatSP         m_last_value_format;
     lldb::SyntheticChildrenSP   m_last_synthetic_filter;
-    lldb::user_id_t             m_user_id_of_forced_summary;
+    ProcessModID                m_user_id_of_forced_summary;
     
     bool                m_value_is_valid:1,
                         m_value_did_change:1,

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Mon Aug  8 21:12:22 2011
@@ -911,6 +911,84 @@
 };
 
 
+// This class tracks the Modification state of the process.  Things that can currently modify
+// the program are running the program (which will up the StopID) and writing memory (which
+// will up the MemoryID.)  
+// FIXME: Should we also include modification of register states?
+
+class ProcessModID
+{
+friend bool operator== (const ProcessModID &lhs, const ProcessModID &rhs);   
+public:
+    ProcessModID () : 
+        m_stop_id (0), 
+        m_memory_id (0) 
+    {}
+    
+    ProcessModID (const ProcessModID &rhs) :
+        m_stop_id (rhs.m_stop_id),
+        m_memory_id (rhs.m_memory_id)
+    {}
+    
+    const ProcessModID & operator= (const ProcessModID &rhs)
+    {
+        if (this != &rhs)
+        {
+            m_stop_id = rhs.m_stop_id;
+            m_memory_id = rhs.m_memory_id;
+        }
+        return *this;
+    }
+    
+    ~ProcessModID () {}
+    
+    void BumpStopID () { m_stop_id++; }
+    void BumpMemoryID () { m_memory_id++; }
+    
+    uint32_t GetStopID() const { return m_stop_id; }
+    uint32_t GetMemoryID () const { return m_memory_id; }
+    
+    bool MemoryIDEqual (const ProcessModID &compare) const
+    {
+        return m_memory_id == compare.m_memory_id;
+    }
+    
+    bool StopIDEqual (const ProcessModID &compare) const
+    {
+        return m_stop_id == compare.m_stop_id;
+    }
+    
+    void SetInvalid ()
+    {
+        m_stop_id = UINT32_MAX;
+    }
+    
+    bool IsValid () const
+    {
+        return m_stop_id != UINT32_MAX;
+    }
+private:
+    uint32_t m_stop_id;
+    uint32_t m_memory_id;
+};
+inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs)
+{
+    if (lhs.StopIDEqual (rhs)
+        && lhs.MemoryIDEqual (rhs))
+        return true;
+    else
+        return false;
+}
+
+inline bool operator!= (const ProcessModID &lhs, const ProcessModID &rhs)
+{
+    if (!lhs.StopIDEqual (rhs)
+        || !lhs.MemoryIDEqual (rhs))
+        return true;
+    else
+        return false;
+}
+
 //----------------------------------------------------------------------
 /// @class Process Process.h "lldb/Target/Process.h"
 /// @brief A plug-in interface definition class for debugging a process.
@@ -924,6 +1002,10 @@
 {
 friend class ThreadList;
 friend class ClangFunction; // For WaitForStateChangeEventsPrivate
+friend class CommandObjectProcessLaunch;
+friend class ProcessEventData;
+friend class CommandObjectBreakpointCommand;
+friend class StopInfo;
 
 public:
 
@@ -1079,6 +1161,7 @@
         DISALLOW_COPY_AND_ASSIGN (SettingsController);
     };
 
+
 #endif
 
     static void
@@ -1909,9 +1992,6 @@
                      uint32_t num_frames_with_source);
 
 protected:
-    friend class CommandObjectProcessLaunch;
-    friend class ProcessEventData;
-    friend class CommandObjectBreakpointCommand;
     
     void
     SetState (lldb::EventSP &event_sp);
@@ -1953,15 +2033,23 @@
     }
 
     //------------------------------------------------------------------
-    /// Get the number of times this process has posted a stop event.
+    /// Get the Modification ID of the process.
     ///
     /// @return
-    ///     The number of times this process has stopped while being
-    ///     debugged.
+    ///     The modification ID of the process.
     //------------------------------------------------------------------
+    ProcessModID
+    GetModID () const
+    {
+        return m_mod_id;
+    }
+    
     uint32_t
-    GetStopID () const;
-
+    GetStopID () const
+    {
+        return m_mod_id.GetStopID();
+    }
+    
     //------------------------------------------------------------------
     /// Set accessor for the process exit status (return code).
     ///
@@ -2619,7 +2707,12 @@
     
 protected:
     //------------------------------------------------------------------
-    // lldb::ExecutionContextScope pure virtual functions
+    // NextEventAction provides a way to register an action on the next
+    // event that is delivered to this process.  There is currently only
+    // one next event action allowed in the process at one time.  If a
+    // new "NextEventAction" is added while one is already present, the
+    // old action will be discarded (with HandleBeingUnshipped called 
+    // after it is discarded.)
     //------------------------------------------------------------------
     class NextEventAction
     {
@@ -2691,7 +2784,7 @@
     Listener                    m_private_state_listener;     // This is the listener for the private state thread.
     Predicate<bool>             m_private_state_control_wait; /// This Predicate is used to signal that a control operation is complete.
     lldb::thread_t              m_private_state_thread;  // Thread ID for the thread that watches interal state events
-    uint32_t                    m_stop_id;              ///< A count of many times the process has stopped.
+    ProcessModID                m_mod_id;              ///< Tracks the state of the process over stops and other alterations.
     uint32_t                    m_thread_index_id;      ///< Each thread is created with a 1 based index that won't get re-used.
     int                         m_exit_status;          ///< The exit status of the process, or -1 if not set.
     std::string                 m_exit_string;          ///< A textual description of why a process exited.

Modified: lldb/trunk/include/lldb/Target/StopInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StopInfo.h?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/StopInfo.h (original)
+++ lldb/trunk/include/lldb/Target/StopInfo.h Mon Aug  8 21:12:22 2011
@@ -138,6 +138,12 @@
     uint32_t        m_stop_id;  // The process stop ID for which this stop info is valid
     uint64_t        m_value;    // A generic value that can be used for things pertaining to this stop info
     std::string     m_description; // A textual description describing this stop.
+    
+    // This provides an accessor to the PrivateEventState of the process for StopInfo's w/o having to make each
+    // StopInfo subclass a friend of Process.
+    lldb::StateType
+    GetPrivateState ();
+
 private:
     friend class Thread;
     
@@ -149,7 +155,6 @@
     DISALLOW_COPY_AND_ASSIGN (StopInfo);
 };
 
-
 } // namespace lldb_private
 
 #endif  // liblldb_StopInfo_h_

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Mon Aug  8 21:12:22 2011
@@ -104,6 +104,7 @@
 class   PathMappingList;
 class   Platform;
 class   Process;
+class   ProcessModID;
 class   ProcessInfo;
 class   ProcessInstanceInfo;
 class   ProcessInstanceInfoList;

Modified: lldb/trunk/source/Breakpoint/BreakpointLocation.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/BreakpointLocation.cpp?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/source/Breakpoint/BreakpointLocation.cpp (original)
+++ lldb/trunk/source/Breakpoint/BreakpointLocation.cpp Mon Aug  8 21:12:22 2011
@@ -224,37 +224,6 @@
     context->is_synchronous = true;
     should_stop = InvokeCallback (context);
     
-    // The SYNCHRONOUS callback says we should stop, next try the condition.
-    
-    if (should_stop && 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.
-        
-        StreamString errors;
-        ThreadPlanSP condition_plan_sp(GetThreadPlanToTestCondition(context->exe_ctx, errors));
-        
-        if (condition_plan_sp == NULL)
-        {
-            if (log)
-                log->Printf("Error evaluating condition: \"%s\"\n", errors.GetData());
-                
-            Debugger &debugger = context->exe_ctx.target->GetDebugger();
-            StreamSP error_sp = debugger.GetAsyncErrorStream ();
-            error_sp->PutCString ("Error parsing breakpoint condition:\n");
-            error_sp->PutCString (errors.GetData());
-            error_sp->EOL();                       
-            error_sp->Flush();
-
-        }
-        else
-        {
-            // Queue our condition, then continue so that we can run it.
-            context->exe_ctx.thread->QueueThreadPlan(condition_plan_sp, false);
-            should_stop = false;
-        }
-    }
-    
     if (log)
     {
         StreamString s;

Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Mon Aug  8 21:12:22 2011
@@ -82,7 +82,7 @@
     m_forced_summary_format(),
     m_last_value_format(),
     m_last_synthetic_filter(),
-    m_user_id_of_forced_summary(0),
+    m_user_id_of_forced_summary(),
     m_value_is_valid (false),
     m_value_did_change (false),
     m_children_count_valid (false),
@@ -128,7 +128,7 @@
     m_forced_summary_format(),
     m_last_value_format(),
     m_last_synthetic_filter(),
-    m_user_id_of_forced_summary(0),
+    m_user_id_of_forced_summary(),
     m_value_is_valid (false),
     m_value_did_change (false),
     m_children_count_valid (false),
@@ -223,7 +223,7 @@
            GetName().GetCString(),
            m_last_format_mgr_revision,
            Debugger::Formatting::ValueFormats::GetCurrentRevision());
-    if (HasCustomSummaryFormat() && m_update_point.GetUpdateID() != m_user_id_of_forced_summary)
+    if (HasCustomSummaryFormat() && m_update_point.GetModID() != m_user_id_of_forced_summary)
     {
         ClearCustomSummaryFormat();
         m_summary_str.clear();
@@ -1236,7 +1236,21 @@
             unsigned long long ull_val = strtoull(value_str, &end, 0);
             if (end && *end != '\0')
                 return false;
-            m_value.GetScalar() = ull_val;
+            Value::ValueType value_type = m_value.GetValueType();
+            switch (value_type)
+            {
+            case Value::eValueTypeLoadAddress:
+            case Value::eValueTypeHostAddress:
+                // The value in these cases lives in the data.  So update the data:
+                
+                break;
+            case Value::eValueTypeScalar:
+                m_value.GetScalar() = ull_val;
+                break;
+            case Value::eValueTypeFileAddress:    
+                // Try to convert the file address to a load address and then write the new value there.
+                break;
+            }
             // Limit the bytes in our m_data appropriately.
             m_value.GetScalar().GetData (m_data, byte_size);
         }
@@ -3093,7 +3107,7 @@
 
 ValueObject::EvaluationPoint::EvaluationPoint () :
     m_thread_id (LLDB_INVALID_UID),
-    m_stop_id (0)
+    m_mod_id ()
 {
 }
 
@@ -3101,7 +3115,7 @@
     m_needs_update (true),
     m_first_update (true),
     m_thread_id (LLDB_INVALID_THREAD_ID),
-    m_stop_id (0)
+    m_mod_id ()
     
 {
     ExecutionContext exe_ctx;
@@ -3120,7 +3134,8 @@
         
         if (m_process_sp != NULL)
         {
-            m_stop_id = m_process_sp->GetStopID();
+            m_mod_id = m_process_sp->GetModID();
+            
             Thread *thread = NULL;
             
             if (exe_ctx.thread == NULL)
@@ -3166,7 +3181,7 @@
     m_process_sp (rhs.m_process_sp),
     m_thread_id (rhs.m_thread_id),
     m_stack_id (rhs.m_stack_id),
-    m_stop_id (0)
+    m_mod_id ()
 {
 }
 
@@ -3193,7 +3208,7 @@
 ValueObject::EvaluationPoint::SyncWithProcessState()
 {
     // If we're already invalid, we don't need to do anything, and nothing has changed:
-    if (m_stop_id == LLDB_INVALID_UID)
+    if (!m_mod_id.IsValid())
     {
         // Can't update with an invalid state.
         m_needs_update = false;
@@ -3205,16 +3220,17 @@
         return false;
         
     // If our stop id is the current stop ID, nothing has changed:
-    uint32_t cur_stop_id = m_process_sp->GetStopID();
-    if (m_stop_id == cur_stop_id)
+    ProcessModID current_mod_id = m_process_sp->GetModID();
+    
+    if (m_mod_id == current_mod_id)
         return false;
     
     // If the current stop id is 0, either we haven't run yet, or the process state has been cleared.
     // In either case, we aren't going to be able to sync with the process state.
-    if (cur_stop_id == 0)
+    if (current_mod_id.GetStopID() == 0)
         return false;
         
-    m_stop_id = cur_stop_id;
+    m_mod_id = current_mod_id;
     m_needs_update = true;
     m_exe_scope = m_process_sp.get();
     
@@ -3251,7 +3267,9 @@
     m_first_update = false;
     m_needs_update = false;
     if (m_process_sp)
-        m_stop_id = m_process_sp->GetStopID();
+    {
+        m_mod_id = m_process_sp->GetModID();
+    }
 }
         
 
@@ -3276,12 +3294,11 @@
             // FOR NOW - assume you can't update variable objects across process boundaries.
             Process *old_process = m_process_sp.get();
             assert (process == old_process);
-            
-            lldb::user_id_t stop_id = process->GetStopID();
-            if (stop_id != m_stop_id)
+            ProcessModID current_mod_id = process->GetModID();
+            if (m_mod_id != current_mod_id)
             {
                 needs_update = true;
-                m_stop_id = stop_id;
+                m_mod_id = current_mod_id;
             }
             // See if we're switching the thread or stack context.  If no thread is given, this is
             // being evaluated in a global context.            

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Mon Aug  8 21:12:22 2011
@@ -581,7 +581,7 @@
     m_private_state_listener ("lldb.process.internal_state_listener"),
     m_private_state_control_wait(),
     m_private_state_thread (LLDB_INVALID_HOST_THREAD),
-    m_stop_id (0),
+    m_mod_id (),
     m_thread_index_id (0),
     m_exit_status (-1),
     m_exit_string (),
@@ -709,8 +709,36 @@
 StateType
 Process::WaitForProcessToStop (const TimeValue *timeout)
 {
-    StateType match_states[] = { eStateStopped, eStateCrashed, eStateDetached, eStateExited, eStateUnloaded };
-    return WaitForState (timeout, match_states, sizeof(match_states) / sizeof(StateType));
+    // We can't just wait for a "stopped" event, because the stopped event may have restarted the target.
+    // We have to actually check each event, and in the case of a stopped event check the restarted flag
+    // on the event.
+    EventSP event_sp;
+    StateType state = GetState();
+    // If we are exited or detached, we won't ever get back to any
+    // other valid state...
+    if (state == eStateDetached || state == eStateExited)
+        return state;
+
+    while (state != eStateInvalid)
+    {
+        state = WaitForStateChangedEvents (timeout, event_sp);
+        switch (state)
+        {
+        case eStateCrashed:
+        case eStateDetached:
+        case eStateExited:
+        case eStateUnloaded:
+            return state;
+        case eStateStopped:
+            if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+                continue;
+            else
+                return state;
+        default:
+            continue;
+        }
+    }
+    return state;
 }
 
 
@@ -1047,10 +1075,10 @@
         m_private_state.SetValueNoLock (new_state);
         if (StateIsStoppedState(new_state))
         {
-            m_stop_id++;
+            m_mod_id.BumpStopID();
             m_memory_cache.Clear();
             if (log)
-                log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_stop_id);
+                log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_mod_id.GetStopID());
         }
         // Use our target to get a shared pointer to ourselves...
         m_private_state_broadcaster.BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (GetTarget().GetProcessSP(), new_state));
@@ -1062,13 +1090,6 @@
     }
 }
 
-
-uint32_t
-Process::GetStopID() const
-{
-    return m_stop_id;
-}
-
 addr_t
 Process::GetImageInfoAddress()
 {
@@ -1774,10 +1795,7 @@
     if (buf == NULL || size == 0)
         return 0;
 
-    // Need to bump the stop ID after writing so that ValueObjects will know to re-read themselves.
-    // FUTURE: Doing this should be okay, but if anybody else gets upset about the stop_id changing when
-    // the target hasn't run, then we will need to add a "memory generation" as well as a stop_id...
-    m_stop_id++;
+    m_mod_id.BumpMemoryID();
 
     // We need to write any data that would go where any current software traps
     // (enabled software breakpoints) any software traps (breakpoints) that we
@@ -1910,11 +1928,12 @@
     addr_t allocated_addr = DoAllocateMemory (size, permissions, error);
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
     if (log)
-        log->Printf("Process::AllocateMemory(size=%4zu, permissions=%s) => 0x%16.16llx (m_stop_id = %u)", 
+        log->Printf("Process::AllocateMemory(size=%4zu, permissions=%s) => 0x%16.16llx (m_stop_id = %u m_memory_id = %u)", 
                     size, 
                     GetPermissionsAsCString (permissions),
                     (uint64_t)allocated_addr,
-                    m_stop_id);
+                    m_mod_id.GetStopID(),
+                    m_mod_id.GetMemoryID());
     return allocated_addr;
 #endif
 }
@@ -1933,10 +1952,11 @@
     
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
     if (log)
-        log->Printf("Process::DeallocateMemory(addr=0x%16.16llx) => err = %s (m_stop_id = %u)", 
+        log->Printf("Process::DeallocateMemory(addr=0x%16.16llx) => err = %s (m_stop_id = %u, m_memory_id = %u)", 
                     ptr, 
                     error.AsCString("SUCCESS"),
-                    m_stop_id);
+                    m_mod_id.GetStopID(),
+                    m_mod_id.GetMemoryID());
 #endif
     return error;
 }
@@ -2360,7 +2380,7 @@
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
     if (log)
         log->Printf("Process::Resume() m_stop_id = %u, public state: %s private state: %s", 
-                    m_stop_id,
+                    m_mod_id.GetStopID(),
                     StateAsCString(m_public_state.GetValue()),
                     StateAsCString(m_private_state.GetValue()));
 
@@ -2944,6 +2964,10 @@
         int num_threads = m_process_sp->GetThreadList().GetSize();
         int idx;
 
+        // The actions might change one of the thread's stop_info's opinions about whether we should
+        // stop the process, so we need to query that as we go.
+        bool still_should_stop = true;
+        
         for (idx = 0; idx < num_threads; ++idx)
         {
             lldb::ThreadSP thread_sp = m_process_sp->GetThreadList().GetThreadAtIndex(idx);
@@ -2952,22 +2976,39 @@
             if (stop_info_sp)
             {
                 stop_info_sp->PerformAction(event_ptr);
+                // The stop action might restart the target.  If it does, then we want to mark that in the
+                // event so that whoever is receiving it will know to wait for the running event and reflect
+                // that state appropriately.
+                // We also need to stop processing actions, since they aren't expecting the target to be running.
+                if (m_process_sp->GetPrivateState() == eStateRunning)
+                {
+                    SetRestarted (true);
+                    break;
+                }
+                else if (!stop_info_sp->ShouldStop(event_ptr))
+                {
+                    still_should_stop = false;
+                }
             }
         }
-        
-        // The stop action might restart the target.  If it does, then we want to mark that in the
-        // event so that whoever is receiving it will know to wait for the running event and reflect
-        // that state appropriately.
 
-        if (m_process_sp->GetPrivateState() == eStateRunning)
-            SetRestarted(true);
-        else
+        
+        if (m_process_sp->GetPrivateState() != eStateRunning)
         {
-            // Finally, if we didn't restart, run the Stop Hooks here:
-            // They might also restart the target, so watch for that.
-            m_process_sp->GetTarget().RunStopHooks();
-            if (m_process_sp->GetPrivateState() == eStateRunning)
+            if (!still_should_stop)
+            {
+                // We've been asked to continue, so do that here.
                 SetRestarted(true);
+                m_process_sp->Resume();
+            }
+            else
+            {
+                // If we didn't restart, run the Stop Hooks here:
+                // They might also restart the target, so watch for that.
+                m_process_sp->GetTarget().RunStopHooks();
+                if (m_process_sp->GetPrivateState() == eStateRunning)
+                    SetRestarted(true);
+            }
         }
         
     }
@@ -3776,6 +3817,7 @@
             if (discard_on_error && thread_plan_sp)
             {
                 exe_ctx.thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+                thread_plan_sp->SetPrivate (orig_plan_private);
             }
         }
     }
@@ -3787,6 +3829,7 @@
         if (discard_on_error && thread_plan_sp)
         {
             exe_ctx.thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+            thread_plan_sp->SetPrivate (orig_plan_private);
         }
     }
     else
@@ -3812,6 +3855,7 @@
                 if (log)
                     log->Printf("Process::RunThreadPlan(): discarding thread plan 'cause discard_on_error is set.");
                 exe_ctx.thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+                thread_plan_sp->SetPrivate (orig_plan_private);
             }
         }
     }

Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Mon Aug  8 21:12:22 2011
@@ -19,7 +19,10 @@
 #include "lldb/Breakpoint/Breakpoint.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
 #include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 #include "lldb/Target/ThreadPlan.h"
 #include "lldb/Target/Process.h"
@@ -47,10 +50,18 @@
     m_stop_id = m_thread.GetProcess().GetStopID();
 }
 
+lldb::StateType
+StopInfo::GetPrivateState ()
+{
+    return m_thread.GetProcess().GetPrivateState();
+}
+
 //----------------------------------------------------------------------
 // StopInfoBreakpoint
 //----------------------------------------------------------------------
 
+namespace lldb_private
+{
 class StopInfoBreakpoint : public StopInfo
 {
 public:
@@ -121,21 +132,122 @@
             return;
         m_should_perform_action = false;
         
+        LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+        // We're going to calculate whether we should stop or not in some way during the course of
+        // this code.  So set the valid flag here.  Also by default we're going to stop, so 
+        // set that here too.
+        // m_should_stop_is_valid = true;
+        m_should_stop = true;
+        
         BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value));
         if (bp_site_sp)
         {
             size_t num_owners = bp_site_sp->GetNumberOfOwners();
+            
+            // We only continue from the callbacks if ALL the callbacks want us to continue.  
+            // However we want to run all the callbacks, except of course if one of them actually
+            // resumes the target.
+            // So we use stop_requested to track what we're were asked to do.
+            bool stop_requested = true;
             for (size_t j = 0; j < num_owners; j++)
             {
-                // The breakpoint action is an asynchronous breakpoint callback.  If we ever need to have both
-                // callbacks and actions on the same breakpoint, we'll have to split this into two.
                 lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
                 StoppointCallbackContext context (event_ptr, 
                                                   &m_thread.GetProcess(), 
                                                   &m_thread, 
                                                   m_thread.GetStackFrameAtIndex(0).get(),
                                                   false);
-                bp_loc_sp->InvokeCallback (&context);
+                stop_requested = bp_loc_sp->InvokeCallback (&context);
+                // 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 (GetPrivateState() == eStateRunning)
+                    m_should_stop = false;
+            }
+            
+            if (m_should_stop && !stop_requested)
+            {
+                m_should_stop_is_valid = true;
+                m_should_stop = false;
+            }
+
+            // Okay, so now if all the callbacks say we should stop, let's try the Conditions:
+            if (m_should_stop)
+            {
+                size_t num_owners = bp_site_sp->GetNumberOfOwners();
+                for (size_t j = 0; j < num_owners; j++)
+                {
+                    lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+                    if (bp_loc_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.
+                        
+                        StoppointCallbackContext context (event_ptr, 
+                                                          &m_thread.GetProcess(), 
+                                                          &m_thread, 
+                                                          m_thread.GetStackFrameAtIndex(0).get(),
+                                                          false);
+                        ValueObjectSP result_valobj_sp;
+                        
+                        ExecutionResults result_code;
+                        ValueObjectSP result_value_sp;
+                        const bool discard_on_error = true;
+                        Error error;
+                        result_code = ClangUserExpression::EvaluateWithError (context.exe_ctx,
+                                                                discard_on_error,
+                                                                bp_loc_sp->GetConditionText(),
+                                                                NULL,
+                                                                result_value_sp,
+                                                                error);
+                        if (result_code == eExecutionCompleted)
+                        {
+                            if (result_value_sp)
+                            {
+                                Scalar scalar_value;
+                                if (result_value_sp->ResolveValue (scalar_value))
+                                {
+                                    if (scalar_value.ULongLong(1) == 0)
+                                        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("Failed to get an integer result from the expression.");
+                                }
+                            }
+                        }
+                        else
+                        {
+                            Debugger &debugger = context.exe_ctx.target->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 = 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 any condition says we should stop, then we're going to stop, so we don't need
+                    // to evaluate the others.
+                    if (m_should_stop)
+                        break;
+                }
             }
         }
         else
@@ -145,6 +257,8 @@
             if (log)
                 log->Printf ("Process::%s could not find breakpoint site id: %lld...", __FUNCTION__, m_value);
         }
+        if (log)
+            log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
     }
         
     virtual bool
@@ -417,6 +531,7 @@
 private:
     ThreadPlanSP m_plan_sp;
 };
+} // namespace lldb_private
 
 StopInfoSP
 StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id)

Modified: lldb/trunk/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py?rev=137102&r1=137101&r2=137102&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py (original)
+++ lldb/trunk/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py Mon Aug  8 21:12:22 2011
@@ -144,7 +144,7 @@
 
         # Frame #0 should be on self.line1 and the break condition should hold.
         from lldbutil import get_stopped_thread
-        thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete)
+        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
         self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition")
         frame0 = thread.GetFrameAtIndex(0)
         var = frame0.FindValue('val', lldb.eValueTypeVariableArgument)





More information about the lldb-commits mailing list