[Lldb-commits] [lldb] r161638 - in /lldb/trunk: include/lldb/ include/lldb/Breakpoint/ include/lldb/Interpreter/ lldb.xcodeproj/ scripts/Python/ source/Breakpoint/ source/Commands/ source/Interpreter/ test/functionalities/watchpoint/watchpoint_commands/command/

Johnny Chen johnny.chen at apple.com
Thu Aug 9 16:09:42 PDT 2012


Author: johnny
Date: Thu Aug  9 18:09:42 2012
New Revision: 161638

URL: http://llvm.org/viewvc/llvm-project?rev=161638&view=rev
Log:
rdar://problem/11457143 [ER] need "watchpoint command ..."

Add 'watchpoint command add/delete/list' to lldb, plus two .py test files.

Added:
    lldb/trunk/include/lldb/Breakpoint/WatchpointOptions.h
    lldb/trunk/source/Breakpoint/WatchpointOptions.cpp
    lldb/trunk/source/Commands/CommandObjectWatchpointCommand.cpp
    lldb/trunk/source/Commands/CommandObjectWatchpointCommand.h
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/Makefile
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp
Modified:
    lldb/trunk/include/lldb/Breakpoint/BreakpointOptions.h
    lldb/trunk/include/lldb/Breakpoint/Watchpoint.h
    lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
    lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/include/lldb/lldb-private-interfaces.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/scripts/Python/python-wrapper.swig
    lldb/trunk/source/Breakpoint/Watchpoint.cpp
    lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreter.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp

Modified: lldb/trunk/include/lldb/Breakpoint/BreakpointOptions.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/BreakpointOptions.h?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Breakpoint/BreakpointOptions.h (original)
+++ lldb/trunk/include/lldb/Breakpoint/BreakpointOptions.h Thu Aug  9 18:09:42 2012
@@ -142,8 +142,8 @@
     //------------------------------------------------------------------
     /// Used in InvokeCallback to tell whether it is the right time to run this kind of callback.
     ///
-    /// @param[in] condition
-    ///    The condition expression to evaluate when the breakpoint is hit.
+    /// @return
+    ///     The synchronicity of our callback.
     //------------------------------------------------------------------
     bool IsCallbackSynchronous () {
         return m_callback_is_synchronous;

Modified: lldb/trunk/include/lldb/Breakpoint/Watchpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/Watchpoint.h?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Breakpoint/Watchpoint.h (original)
+++ lldb/trunk/include/lldb/Breakpoint/Watchpoint.h Thu Aug  9 18:09:42 2012
@@ -22,6 +22,7 @@
 #include "lldb/lldb-private.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Core/UserID.h"
+#include "lldb/Breakpoint/WatchpointOptions.h"
 #include "lldb/Breakpoint/StoppointLocation.h"
 
 namespace lldb_private {
@@ -52,8 +53,6 @@
     uint32_t    GetIgnoreCount () const;
     void        SetIgnoreCount (uint32_t n);
     void        SetWatchpointType (uint32_t type);
-    bool        SetCallback (WatchpointHitCallback callback, void *callback_baton);
-    void        ClearCallback();
     void        SetDeclInfo (std::string &str);
     void        SetWatchSpec (std::string &str);
     void        GetDescription (Stream *s, lldb::DescriptionLevel level);
@@ -63,6 +62,43 @@
     const Error &GetError() { return m_error; }
 
     //------------------------------------------------------------------
+    /// Returns the WatchpointOptions structure set for this watchpoint.
+    ///
+    /// @return
+    ///     A pointer to this watchpoint's WatchpointOptions.
+    //------------------------------------------------------------------
+    WatchpointOptions *
+    GetOptions () { return &m_options; }
+
+    //------------------------------------------------------------------
+    /// Set the callback action invoked when the watchpoint is hit.  
+    /// 
+    /// @param[in] callback
+    ///    The method that will get called when the watchpoint is hit.
+    /// @param[in] callback_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 watchpoint.
+    ///    \b false if it should continue.
+    //------------------------------------------------------------------
+    void
+    SetCallback (WatchpointHitCallback callback, 
+                 void *callback_baton,
+                 bool is_synchronous = false);
+
+    void
+    SetCallback (WatchpointHitCallback callback, 
+                 const lldb::BatonSP &callback_baton_sp,
+                 bool is_synchronous = false);
+
+    void        ClearCallback();
+
+    //------------------------------------------------------------------
     /// Invoke the callback action when the watchpoint is hit.
     ///
     /// @param[in] context
@@ -78,10 +114,10 @@
     // Condition
     //------------------------------------------------------------------
     //------------------------------------------------------------------
-    /// Set the breakpoint's condition.
+    /// Set the watchpoint's condition.
     ///
     /// @param[in] condition
-    ///    The condition expression to evaluate when the breakpoint is hit.
+    ///    The condition expression to evaluate when the watchpoint is hit.
     ///    Pass in NULL to clear the condition.
     //------------------------------------------------------------------
     void SetCondition (const char *condition);
@@ -111,11 +147,11 @@
                 m_watch_was_read:1,    // Set to 1 when watchpoint is hit for a read access
                 m_watch_was_written:1; // Set to 1 when watchpoint is hit for a write access
     uint32_t    m_ignore_count;        // Number of times to ignore this breakpoint
-    WatchpointHitCallback m_callback;
-    void *      m_callback_baton;      // Callback user data to pass to callback
     std::string m_decl_str;            // Declaration information, if any.
     std::string m_watch_spec_str;      // Spec for the watchpoint (for future use).
     Error       m_error;               // An error object describing errors associated with this watchpoint.
+    WatchpointOptions m_options;       // Settable watchpoint options, which is a delegate to handle
+                                       // the callback machinery.
 
     std::auto_ptr<ClangUserExpression> m_condition_ap;  // The condition to test.
 

Added: lldb/trunk/include/lldb/Breakpoint/WatchpointOptions.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/WatchpointOptions.h?rev=161638&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Breakpoint/WatchpointOptions.h (added)
+++ lldb/trunk/include/lldb/Breakpoint/WatchpointOptions.h Thu Aug  9 18:09:42 2012
@@ -0,0 +1,256 @@
+//===-- WatchpointOptions.h -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_WatchpointOptions_h_
+#define liblldb_WatchpointOptions_h_
+
+// C Includes
+// C++ Includes
+#include <memory>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Baton.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class WatchpointOptions WatchpointOptions.h "lldb/Breakpoint/WatchpointOptions.h"
+/// @brief Class that manages the options on a watchpoint.
+//----------------------------------------------------------------------
+
+class WatchpointOptions
+{
+public:
+    //------------------------------------------------------------------
+    // Constructors and Destructors
+    //------------------------------------------------------------------
+    //------------------------------------------------------------------
+    /// Default constructor.  The watchpoint is enabled, and has no condition,
+    /// callback, ignore count, etc...
+    //------------------------------------------------------------------
+    WatchpointOptions();
+    WatchpointOptions(const WatchpointOptions& rhs);
+
+    static WatchpointOptions *
+    CopyOptionsNoCallback (WatchpointOptions &rhs);
+    //------------------------------------------------------------------
+    /// This constructor allows you to specify all the watchpoint options.
+    ///
+    /// @param[in] callback
+    ///    This is the plugin for some code that gets run, returns \b true if we are to stop.
+    ///
+    /// @param[in] baton
+    ///    Client data that will get passed to the callback.
+    ///
+    /// @param[in] thread_id
+    ///    Only stop if \a thread_id hits the watchpoint.
+    //------------------------------------------------------------------
+    WatchpointOptions(WatchpointHitCallback callback,
+                      void *baton,
+                      lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
+
+    virtual ~WatchpointOptions();
+
+    //------------------------------------------------------------------
+    // Operators
+    //------------------------------------------------------------------
+    const WatchpointOptions&
+    operator=(const WatchpointOptions& rhs);
+
+    //------------------------------------------------------------------
+    // Callbacks
+    //
+    // Watchpoint callbacks come in two forms, synchronous and asynchronous.  Synchronous callbacks will get
+    // run before any of the thread plans are consulted, and if they return false the target will continue
+    // "under the radar" of the thread plans.  There are a couple of restrictions to synchronous callbacks:
+    // 1) They should NOT resume the target themselves.  Just return false if you want the target to restart.
+    // 2) Watchpoints with synchronous callbacks can't have conditions (or rather, they can have them, but they
+    //    won't do anything.  Ditto with ignore counts, etc...  You are supposed to control that all through the
+    //    callback.
+    // Asynchronous callbacks get run as part of the "ShouldStop" logic in the thread plan.  The logic there is:
+    //   a) If the watchpoint is thread specific and not for this thread, continue w/o running the callback.
+    //   b) If the ignore count says we shouldn't stop, then ditto.
+    //   c) If the condition says we shouldn't stop, then ditto.
+    //   d) Otherwise, the callback will get run, and if it returns true we will stop, and if false we won't.
+    //  The asynchronous callback can run the target itself, but at present that should be the last action the
+    //  callback does.  We will relax this condition at some point, but it will take a bit of plumbing to get
+    //  that to work.
+    // 
+    //------------------------------------------------------------------
+    
+    //------------------------------------------------------------------
+    /// Adds a callback to the watchpoint option set.
+    ///
+    /// @param[in] callback
+    ///    The function to be called when the watchpoint gets hit.
+    ///
+    /// @param[in] baton_sp
+    ///    A baton which will get passed back to the callback when it is invoked.
+    ///
+    /// @param[in] synchronous
+    ///    Whether this is a synchronous or asynchronous callback.  See discussion above.
+    //------------------------------------------------------------------
+    void SetCallback (WatchpointHitCallback callback, const lldb::BatonSP &baton_sp, bool synchronous = false);
+    
+    
+    //------------------------------------------------------------------
+    /// Remove the callback from this option set.
+    //------------------------------------------------------------------
+    void ClearCallback ();
+
+    // The rest of these functions are meant to be used only within the watchpoint handling mechanism.
+    
+    //------------------------------------------------------------------
+    /// Use this function to invoke the callback for a specific stop.
+    ///
+    /// @param[in] context
+    ///    The context in which the callback is to be invoked.  This includes the stop event, the
+    ///    execution context of the stop (since you might hit the same watchpoint on multiple threads) and
+    ///    whether we are currently executing synchronous or asynchronous callbacks.
+    /// 
+    /// @param[in] watch_id
+    ///    The watchpoint ID that owns this option set.
+    ///
+    /// @return
+    ///     The callback return value.
+    //------------------------------------------------------------------
+    bool InvokeCallback (StoppointCallbackContext *context, lldb::user_id_t watch_id);
+    
+    //------------------------------------------------------------------
+    /// Used in InvokeCallback to tell whether it is the right time to run this kind of callback.
+    ///
+    /// @return
+    ///     The synchronicity of our callback.
+    //------------------------------------------------------------------
+    bool IsCallbackSynchronous () {
+        return m_callback_is_synchronous;
+    }
+    
+    //------------------------------------------------------------------
+    /// Fetch the baton from the callback.
+    ///
+    /// @return
+    ///     The baton.
+    //------------------------------------------------------------------
+    Baton *GetBaton ();
+    
+    //------------------------------------------------------------------
+    /// Fetch  a const version of the baton from the callback.
+    ///
+    /// @return
+    ///     The baton.
+    //------------------------------------------------------------------
+    const Baton *GetBaton () const;
+    
+    //------------------------------------------------------------------
+    /// Return the current thread spec for this option.  This will return NULL if the no thread
+    /// specifications have been set for this Option yet.     
+    /// @return
+    ///     The thread specification pointer for this option, or NULL if none has
+    ///     been set yet.
+    //------------------------------------------------------------------
+    const ThreadSpec *
+    GetThreadSpecNoCreate () const;
+
+    //------------------------------------------------------------------
+    /// Returns a pointer to the ThreadSpec for this option, creating it.
+    /// if it hasn't been created already.   This API is used for setting the
+    /// ThreadSpec items for this option.
+    //------------------------------------------------------------------
+    ThreadSpec *
+    GetThreadSpec ();
+    
+    void
+    SetThreadID(lldb::tid_t thread_id);
+    
+    void
+    GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+    
+    //------------------------------------------------------------------
+    /// Get description for callback only.
+    //------------------------------------------------------------------
+    void
+    GetCallbackDescription (Stream *s, lldb::DescriptionLevel level) const;
+    
+    //------------------------------------------------------------------
+    /// Returns true if the watchpoint option has a callback set.
+    //------------------------------------------------------------------
+    bool
+    HasCallback();
+
+    //------------------------------------------------------------------
+    /// This is the default empty callback.
+    /// @return
+    ///     The thread id for which the watchpoint hit will stop, 
+    ///     LLDB_INVALID_THREAD_ID for all threads.
+    //------------------------------------------------------------------
+    static bool 
+    NullCallback (void *baton, 
+                  StoppointCallbackContext *context, 
+                  lldb::user_id_t watch_id);
+    
+    
+    struct CommandData
+    {
+        CommandData () :
+            user_source(),
+            script_source(),
+            stop_on_error(true)
+        {
+        }
+
+        ~CommandData ()
+        {
+        }
+        
+        StringList user_source;
+        std::string script_source;
+        bool stop_on_error;
+    };
+
+    class CommandBaton : public Baton
+    {
+    public:
+        CommandBaton (CommandData *data) :
+            Baton (data)
+        {
+        }
+
+        virtual
+        ~CommandBaton ()
+        {
+            delete ((CommandData *)m_data);
+            m_data = NULL;
+        }
+        
+        virtual void
+        GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+    };
+
+protected:
+    //------------------------------------------------------------------
+    // Classes that inherit from WatchpointOptions can see and modify these
+    //------------------------------------------------------------------
+
+private:
+    //------------------------------------------------------------------
+    // For WatchpointOptions only
+    //------------------------------------------------------------------
+    WatchpointHitCallback m_callback; // This is the callback function pointer
+    lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback
+    bool m_callback_is_synchronous;
+    std::auto_ptr<ThreadSpec> m_thread_spec_ap; // Thread for which this watchpoint will take
+};
+
+} // namespace lldb_private
+
+#endif  // liblldb_WatchpointOptions_h_

Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Thu Aug  9 18:09:42 2012
@@ -68,6 +68,11 @@
                                                     const lldb::StackFrameSP& frame_sp,
                                                     const lldb::BreakpointLocationSP &bp_loc_sp);
     
+    typedef bool (*SWIGWatchpointCallbackFunction) (const char *python_function_name,
+                                                    const char *session_dictionary_name,
+                                                    const lldb::StackFrameSP& frame_sp,
+                                                    const lldb::WatchpointSP &wp_sp);
+    
     typedef bool (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
                                                           void *session_dictionary,
                                                           const lldb::ValueObjectSP& valobj_sp,
@@ -148,6 +153,12 @@
     }
     
     virtual bool
+    GenerateWatchpointCommandCallbackData (StringList &input, std::string& output)
+    {
+        return false;
+    }
+    
+    virtual bool
     GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token = NULL)
     {
         return false;
@@ -194,6 +205,10 @@
     CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
                                              CommandReturnObject &result);
 
+    virtual void 
+    CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                             CommandReturnObject &result);
+
     /// Set a one-liner as the callback for the breakpoint.
     virtual void 
     SetBreakpointCommandCallback (BreakpointOptions *bp_options,
@@ -202,6 +217,14 @@
         return;
     }
     
+    /// Set a one-liner as the callback for the watchpoint.
+    virtual void 
+    SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                  const char *oneliner)
+    {
+        return;
+    }
+    
     virtual bool
     GetScriptedSummary (const char *function_name,
                         lldb::ValueObjectSP valobj,

Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h Thu Aug  9 18:09:42 2012
@@ -101,6 +101,9 @@
     bool
     GenerateBreakpointCommandCallbackData (StringList &input, std::string& output);
 
+    bool
+    GenerateWatchpointCommandCallbackData (StringList &input, std::string& output);
+
     static size_t
     GenerateBreakpointOptionsCommandCallback (void *baton, 
                                               InputReader &reader, 
@@ -108,12 +111,24 @@
                                               const char *bytes, 
                                               size_t bytes_len);
         
+    static size_t
+    GenerateWatchpointOptionsCommandCallback (void *baton, 
+                                              InputReader &reader, 
+                                              lldb::InputReaderAction notification,
+                                              const char *bytes, 
+                                              size_t bytes_len);
+        
     static bool
     BreakpointCallbackFunction (void *baton, 
                                 StoppointCallbackContext *context, 
                                 lldb::user_id_t break_id,
                                 lldb::user_id_t break_loc_id);
     
+    static bool
+    WatchpointCallbackFunction (void *baton, 
+                                StoppointCallbackContext *context, 
+                                lldb::user_id_t watch_id);
+    
     virtual bool
     GetScriptedSummary (const char *function_name,
                         lldb::ValueObjectSP valobj,
@@ -135,11 +150,20 @@
     CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
                                              CommandReturnObject &result);
 
+    void 
+    CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                             CommandReturnObject &result);
+
     /// Set a Python one-liner as the callback for the breakpoint.
     void 
     SetBreakpointCommandCallback (BreakpointOptions *bp_options,
                                   const char *oneliner);
 
+    /// Set a one-liner as the callback for the watchpoint.
+    void 
+    SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                  const char *oneliner);
+
     StringList
     ReadCommandInputFromUser (FILE *in_file);
     

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Thu Aug  9 18:09:42 2012
@@ -235,6 +235,7 @@
 class   VariableList;
 class   Watchpoint;
 class   WatchpointList;
+class   WatchpointOptions;
 struct  LineEntry;
 
 } // namespace lldb_private

Modified: lldb/trunk/include/lldb/lldb-private-interfaces.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-interfaces.h?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-interfaces.h (original)
+++ lldb/trunk/include/lldb/lldb-private-interfaces.h Thu Aug  9 18:09:42 2012
@@ -31,7 +31,7 @@
     typedef SymbolFile* (*SymbolFileCreateInstance) (ObjectFile* obj_file);
     typedef SymbolVendor* (*SymbolVendorCreateInstance) (const lldb::ModuleSP &module_sp);   // Module can be NULL for default system symbol vendor
     typedef bool (*BreakpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
-    typedef bool (*WatchpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id, uint32_t type);
+    typedef bool (*WatchpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id);
     typedef ThreadPlan * (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, void *baton);
     typedef UnwindAssembly* (*UnwindAssemblyCreateInstance) (const ArchSpec &arch);
     typedef int (*ComparisonFunction)(const void *, const void *);

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Thu Aug  9 18:09:42 2012
@@ -520,6 +520,8 @@
 		B299580B14F2FA1400050A04 /* DisassemblerLLVMC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B299580A14F2FA1400050A04 /* DisassemblerLLVMC.cpp */; };
 		B2A58722143119810092BFBA /* SBWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = B2A58721143119810092BFBA /* SBWatchpoint.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		B2A58724143119D50092BFBA /* SBWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2A58723143119D50092BFBA /* SBWatchpoint.cpp */; };
+		B2B7CCEB15D1BD6700EEFB57 /* CommandObjectWatchpointCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2B7CCEA15D1BD6600EEFB57 /* CommandObjectWatchpointCommand.cpp */; };
+		B2B7CCF015D1C20F00EEFB57 /* WatchpointOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2B7CCEF15D1C20F00EEFB57 /* WatchpointOptions.cpp */; };
 		ED88244E15114A9200BC98B9 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; };
 		ED88245015114CA200BC98B9 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED88244F15114CA200BC98B9 /* main.mm */; };
 		ED88245115114CA200BC98B9 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED88244F15114CA200BC98B9 /* main.mm */; };
@@ -1557,6 +1559,10 @@
 		B2A58721143119810092BFBA /* SBWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBWatchpoint.h; path = include/lldb/API/SBWatchpoint.h; sourceTree = "<group>"; };
 		B2A58723143119D50092BFBA /* SBWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBWatchpoint.cpp; path = source/API/SBWatchpoint.cpp; sourceTree = "<group>"; };
 		B2A5872514313B480092BFBA /* SBWatchpoint.i */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = SBWatchpoint.i; sourceTree = "<group>"; };
+		B2B7CCEA15D1BD6600EEFB57 /* CommandObjectWatchpointCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectWatchpointCommand.cpp; path = source/Commands/CommandObjectWatchpointCommand.cpp; sourceTree = "<group>"; };
+		B2B7CCEC15D1BD9600EEFB57 /* CommandObjectWatchpointCommand.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectWatchpointCommand.h; path = source/Commands/CommandObjectWatchpointCommand.h; sourceTree = "<group>"; };
+		B2B7CCED15D1BFB700EEFB57 /* WatchpointOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WatchpointOptions.h; path = include/lldb/Breakpoint/WatchpointOptions.h; sourceTree = "<group>"; };
+		B2B7CCEF15D1C20F00EEFB57 /* WatchpointOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WatchpointOptions.cpp; path = source/Breakpoint/WatchpointOptions.cpp; sourceTree = "<group>"; };
 		B2D3033612EFA5C500F84EB3 /* InstructionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InstructionUtils.h; path = Utility/InstructionUtils.h; sourceTree = "<group>"; };
 		ED88244F15114CA200BC98B9 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
 		ED88245215114CFC00BC98B9 /* LauncherRootXPCService.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LauncherRootXPCService.mm; sourceTree = "<group>"; };
@@ -2599,6 +2605,8 @@
 				B27318431416AC43006039C8 /* WatchpointList.h */,
 				26BC7E1810F1B83100F91463 /* Watchpoint.cpp */,
 				B27318411416AC12006039C8 /* WatchpointList.cpp */,
+				B2B7CCED15D1BFB700EEFB57 /* WatchpointOptions.h */,
+				B2B7CCEF15D1C20F00EEFB57 /* WatchpointOptions.cpp */,
 			);
 			name = Breakpoint;
 			sourceTree = "<group>";
@@ -2654,6 +2662,8 @@
 				B296983412C2FB2B002D92C3 /* CommandObjectVersion.cpp */,
 				B207C4941429609C00F36E4E /* CommandObjectWatchpoint.h */,
 				B207C4921429607D00F36E4E /* CommandObjectWatchpoint.cpp */,
+				B2B7CCEC15D1BD9600EEFB57 /* CommandObjectWatchpointCommand.h */,
+				B2B7CCEA15D1BD6600EEFB57 /* CommandObjectWatchpointCommand.cpp */,
 			);
 			name = Commands;
 			sourceTree = "<group>";
@@ -3928,6 +3938,8 @@
 				2694E9A414FC0BBD0076DE67 /* PlatformLinux.cpp in Sources */,
 				26B1EFAE154638AF00E2DAC7 /* DWARFDeclContext.cpp in Sources */,
 				B21EB71515CC99F100E60059 /* cxa_demangle.cpp in Sources */,
+				B2B7CCEB15D1BD6700EEFB57 /* CommandObjectWatchpointCommand.cpp in Sources */,
+				B2B7CCF015D1C20F00EEFB57 /* WatchpointOptions.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

Modified: lldb/trunk/scripts/Python/python-wrapper.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/python-wrapper.swig?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/python-wrapper.swig (original)
+++ lldb/trunk/scripts/Python/python-wrapper.swig Thu Aug  9 18:09:42 2012
@@ -176,6 +176,85 @@
     return stop_at_breakpoint;
 }
 
+// This function is called by lldb_private::ScriptInterpreterPython::WatchpointCallbackFunction(...)
+// and is used when a script command is attached to a watchpoint for execution.
+
+SWIGEXPORT bool
+LLDBSwigPythonWatchpointCallbackFunction 
+(
+    const char *python_function_name,
+    const char *session_dictionary_name,
+    const lldb::StackFrameSP& frame_sp, 
+    const lldb::WatchpointSP& wp_sp
+)
+{
+    lldb::SBFrame sb_frame (frame_sp);
+    lldb::SBWatchpoint sb_wp(wp_sp);
+
+    bool stop_at_watchpoint = true;
+    PyObject *Frame_PyObj = SWIG_NewPointerObj((void *) &sb_frame, SWIGTYPE_p_lldb__SBFrame, 0);
+    PyObject *Wp_PyObj = SWIG_NewPointerObj ((void *) &sb_wp, SWIGTYPE_p_lldb__SBWatchpoint, 0);
+    
+    if (Frame_PyObj == NULL || Wp_PyObj == NULL)
+        return stop_at_watchpoint;
+        
+    if (!python_function_name || !session_dictionary_name)
+        return stop_at_watchpoint;
+
+    PyObject *session_dict, *pfunc;
+    PyObject *pargs, *pvalue;
+    
+    session_dict = FindSessionDictionary (session_dictionary_name);
+    if (session_dict != NULL)
+    {
+        pfunc = ResolvePythonName (python_function_name, session_dict);
+        if (pfunc != NULL)
+        {
+            // Set up the arguments and call the function.
+                
+            if (PyCallable_Check (pfunc))
+            {
+                pargs = PyTuple_New (3);
+                if (pargs == NULL)
+                {
+                    if (PyErr_Occurred())
+                        PyErr_Clear();
+                    return stop_at_watchpoint;
+                }
+                
+                PyTuple_SetItem (pargs, 0, Frame_PyObj);  // This "steals" a reference to Frame_PyObj
+                PyTuple_SetItem (pargs, 1, Wp_PyObj);     // This "steals" a reference to Wp_PyObj
+                PyTuple_SetItem (pargs, 2, session_dict); // This "steals" a reference to session_dict
+                pvalue = PyObject_CallObject (pfunc, pargs);
+                Py_DECREF (pargs);
+                
+                if (pvalue != NULL)
+                {
+                    Py_DECREF (pvalue);
+                }
+                else if (PyErr_Occurred ())
+                {
+                    PyErr_Clear();
+                }
+                Py_INCREF (session_dict);
+            }
+            else if (PyErr_Occurred())
+            {
+                PyErr_Clear();
+            }
+        }
+        else if (PyErr_Occurred())
+        {
+            PyErr_Clear();
+        }
+    }
+    else if (PyErr_Occurred ())
+    {
+        PyErr_Clear ();
+    }
+    return stop_at_watchpoint;
+}
+
 SWIGEXPORT bool
 LLDBSwigPythonCallTypeScript 
 (

Modified: lldb/trunk/source/Breakpoint/Watchpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/Watchpoint.cpp?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/source/Breakpoint/Watchpoint.cpp (original)
+++ lldb/trunk/source/Breakpoint/Watchpoint.cpp Thu Aug  9 18:09:42 2012
@@ -33,11 +33,10 @@
     m_watch_was_read(0),
     m_watch_was_written(0),
     m_ignore_count(0),
-    m_callback(NULL),
-    m_callback_baton(NULL),
     m_decl_str(),
     m_watch_spec_str(),
-    m_error()
+    m_error(),
+    m_options ()
 {
 }
 
@@ -45,12 +44,29 @@
 {
 }
 
-bool
-Watchpoint::SetCallback (WatchpointHitCallback callback, void *callback_baton)
+// This function is used when "baton" doesn't need to be freed
+void
+Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
 {
-    m_callback = callback;
-    m_callback_baton = callback_baton;
-    return true;
+    // The default "Baton" class will keep a copy of "baton" and won't free
+    // or delete it when it goes goes out of scope.
+    m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+    
+    //SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is 
+// contained in a "Baton" subclass.
+void
+Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
+{
+    m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
+}
+
+void
+Watchpoint::ClearCallback ()
+{
+    m_options.ClearCallback ();
 }
 
 void
@@ -129,26 +145,15 @@
             s->Printf("\n    static watchpoint spec = '%s'", m_watch_spec_str.c_str());
         if (GetConditionText())
             s->Printf("\n    condition = '%s'", GetConditionText());
+        m_options.GetCallbackDescription(s, description_level);
     }
 
     if (description_level >= lldb::eDescriptionLevelVerbose)
     {
-        if (m_callback)
-        {
-            s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u  callback = %8p baton = %8p",
-                      GetHardwareIndex(),
-                      GetHitCount(),
-                      GetIgnoreCount(),
-                      m_callback,
-                      m_callback_baton);
-        }
-        else
-        {
-            s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
-                      GetHardwareIndex(),
-                      GetHitCount(),
-                      GetIgnoreCount());
-        }
+        s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
+                  GetHardwareIndex(),
+                  GetHitCount(),
+                  GetIgnoreCount());
     }
 }
 
@@ -198,17 +203,7 @@
 bool
 Watchpoint::InvokeCallback (StoppointCallbackContext *context)
 {
-    if (m_callback && context->is_synchronous)
-    {
-        uint32_t access = 0;
-        if (m_watch_was_read)
-            access |= LLDB_WATCH_TYPE_READ;
-        if (m_watch_was_written)
-            access |= LLDB_WATCH_TYPE_WRITE;
-        return m_callback(m_callback_baton, context, GetID(), access);
-    }
-    else
-        return true;
+    return m_options.InvokeCallback (context, GetID());
 }
 
 void 

Added: lldb/trunk/source/Breakpoint/WatchpointOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/WatchpointOptions.cpp?rev=161638&view=auto
==============================================================================
--- lldb/trunk/source/Breakpoint/WatchpointOptions.cpp (added)
+++ lldb/trunk/source/Breakpoint/WatchpointOptions.cpp Thu Aug  9 18:09:42 2012
@@ -0,0 +1,244 @@
+//===-- WatchpointOptions.cpp -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/WatchpointOptions.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+WatchpointOptions::NullCallback (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id)
+{
+    return true;
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions constructor
+//----------------------------------------------------------------------
+WatchpointOptions::WatchpointOptions() :
+    m_callback (WatchpointOptions::NullCallback),
+    m_callback_baton_sp (),
+    m_callback_is_synchronous (false),
+    m_thread_spec_ap (NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions copy constructor
+//----------------------------------------------------------------------
+WatchpointOptions::WatchpointOptions(const WatchpointOptions& rhs) :
+    m_callback (rhs.m_callback),
+    m_callback_baton_sp (rhs.m_callback_baton_sp),
+    m_callback_is_synchronous (rhs.m_callback_is_synchronous),
+    m_thread_spec_ap (NULL)
+{
+    if (rhs.m_thread_spec_ap.get() != NULL)
+        m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions assignment operator
+//----------------------------------------------------------------------
+const WatchpointOptions&
+WatchpointOptions::operator=(const WatchpointOptions& rhs)
+{
+    m_callback = rhs.m_callback;
+    m_callback_baton_sp = rhs.m_callback_baton_sp;
+    m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+    if (rhs.m_thread_spec_ap.get() != NULL)
+        m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+    return *this;
+}
+
+WatchpointOptions *
+WatchpointOptions::CopyOptionsNoCallback (WatchpointOptions &orig)
+{
+    WatchpointHitCallback orig_callback = orig.m_callback;
+    lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
+    bool orig_is_sync = orig.m_callback_is_synchronous;
+    
+    orig.ClearCallback();
+    WatchpointOptions *ret_val = new WatchpointOptions(orig);
+    
+    orig.SetCallback (orig_callback, orig_callback_baton_sp, orig_is_sync);
+    
+    return ret_val;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+WatchpointOptions::~WatchpointOptions()
+{
+}
+
+//------------------------------------------------------------------
+// Callbacks
+//------------------------------------------------------------------
+void
+WatchpointOptions::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool callback_is_synchronous)
+{
+    m_callback_is_synchronous = callback_is_synchronous;
+    m_callback = callback;
+    m_callback_baton_sp = callback_baton_sp;
+}
+
+void
+WatchpointOptions::ClearCallback ()
+{
+    m_callback = WatchpointOptions::NullCallback;
+    m_callback_is_synchronous = false;
+    m_callback_baton_sp.reset();
+}
+
+Baton *
+WatchpointOptions::GetBaton ()
+{
+    return m_callback_baton_sp.get();
+}
+
+const Baton *
+WatchpointOptions::GetBaton () const
+{
+    return m_callback_baton_sp.get();
+}
+
+bool
+WatchpointOptions::InvokeCallback (StoppointCallbackContext *context, 
+                                   lldb::user_id_t watch_id)
+{
+    if (m_callback && context->is_synchronous == IsCallbackSynchronous())
+    {
+        return m_callback (m_callback_baton_sp ? m_callback_baton_sp->m_data : NULL,
+                           context, 
+                           watch_id);
+    }
+    else
+        return true;
+}
+
+bool
+WatchpointOptions::HasCallback ()
+{
+    return m_callback != WatchpointOptions::NullCallback;
+}
+
+const ThreadSpec *
+WatchpointOptions::GetThreadSpecNoCreate () const
+{
+    return m_thread_spec_ap.get();
+}
+
+ThreadSpec *
+WatchpointOptions::GetThreadSpec ()
+{
+    if (m_thread_spec_ap.get() == NULL)
+        m_thread_spec_ap.reset (new ThreadSpec());
+        
+    return m_thread_spec_ap.get();
+}
+
+void
+WatchpointOptions::SetThreadID (lldb::tid_t thread_id)
+{
+    GetThreadSpec()->SetTID(thread_id);
+}
+
+void
+WatchpointOptions::GetCallbackDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+    if (m_callback_baton_sp.get())
+    {
+        if (level != eDescriptionLevelBrief)
+        {
+            s->EOL();
+            m_callback_baton_sp->GetDescription (s, level);
+        }
+    }
+}
+void
+WatchpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+
+    // Figure out if there are any options not at their default value, and only print 
+    // anything if there are:
+    
+    if ((GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ()))
+    {
+        if (level == lldb::eDescriptionLevelVerbose)
+        {
+            s->EOL ();
+            s->IndentMore();
+            s->Indent();
+            s->PutCString("Watchpoint Options:\n");
+            s->IndentMore();
+            s->Indent();
+        }
+        else
+            s->PutCString(" Options: ");
+                
+        if (m_thread_spec_ap.get())
+            m_thread_spec_ap->GetDescription (s, level);
+        else if (level == eDescriptionLevelBrief)
+            s->PutCString ("thread spec: no ");
+        if (level == lldb::eDescriptionLevelFull)
+        {
+            s->IndentLess();
+            s->IndentMore();
+        }
+    }
+            
+    GetCallbackDescription(s, level);
+}
+
+void
+WatchpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+    CommandData *data = (CommandData *)m_data;
+
+    if (level == eDescriptionLevelBrief)
+    {
+        s->Printf (", commands = %s", (data && data->user_source.GetSize() > 0) ? "yes" : "no");
+        return;
+    }
+    
+    s->IndentMore ();
+    s->Indent("Watchpoint commands:\n");
+    
+    s->IndentMore ();
+    if (data && data->user_source.GetSize() > 0)
+    {
+        const size_t num_strings = data->user_source.GetSize();
+        for (size_t i = 0; i < num_strings; ++i)
+        {
+            s->Indent(data->user_source.GetStringAtIndex(i));
+            s->EOL();
+        }
+    }
+    else
+    {
+        s->PutCString ("No commands.\n");
+    }
+    s->IndentLess ();
+    s->IndentLess ();
+}
+

Modified: lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp Thu Aug  9 18:09:42 2012
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CommandObjectWatchpoint.h"
+#include "CommandObjectWatchpointCommand.h"
 
 // C Includes
 // C++ Includes
@@ -1300,6 +1301,7 @@
     CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter));
     CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter));
     CommandObjectSP ignore_command_object (new CommandObjectWatchpointIgnore (interpreter));
+    CommandObjectSP command_command_object (new CommandObjectWatchpointCommand (interpreter));
     CommandObjectSP modify_command_object (new CommandObjectWatchpointModify (interpreter));
     CommandObjectSP set_command_object (new CommandObjectWatchpointSet (interpreter));
 
@@ -1308,6 +1310,7 @@
     disable_command_object->SetCommandName("watchpoint disable");
     delete_command_object->SetCommandName("watchpoint delete");
     ignore_command_object->SetCommandName("watchpoint ignore");
+    command_command_object->SetCommandName ("watchpoint command");
     modify_command_object->SetCommandName("watchpoint modify");
     set_command_object->SetCommandName("watchpoint set");
 
@@ -1316,6 +1319,7 @@
     LoadSubCommand ("disable",    disable_command_object);
     LoadSubCommand ("delete",     delete_command_object);
     LoadSubCommand ("ignore",     ignore_command_object);
+    LoadSubCommand ("command",    command_command_object);
     LoadSubCommand ("modify",     modify_command_object);
     LoadSubCommand ("set",        set_command_object);
 }

Added: lldb/trunk/source/Commands/CommandObjectWatchpointCommand.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectWatchpointCommand.cpp?rev=161638&view=auto
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectWatchpointCommand.cpp (added)
+++ lldb/trunk/source/Commands/CommandObjectWatchpointCommand.cpp Thu Aug  9 18:09:42 2012
@@ -0,0 +1,849 @@
+//===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+
+
+#include "CommandObjectWatchpointCommand.h"
+#include "CommandObjectWatchpoint.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/State.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+class CommandObjectWatchpointCommandAdd : public CommandObjectParsed
+{
+public:
+
+    CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) :
+        CommandObjectParsed (interpreter,
+                             "add",
+                             "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.",
+                             NULL),
+        m_options (interpreter)
+    {
+        SetHelpLong (
+"\nGeneral information about entering watchpoint commands \n\
+------------------------------------------------------ \n\
+ \n\
+This command will cause you to be prompted to enter the command or set \n\
+of commands you wish to be executed when the specified watchpoint is \n\
+hit.  You will be told to enter your command(s), and will see a '> ' \n\
+prompt. Because you can enter one or many commands to be executed when \n\
+a watchpoint is hit, you will continue to be prompted after each \n\
+new-line that you enter, until you enter the word 'DONE', which will \n\
+cause the commands you have entered to be stored with the watchpoint \n\
+and executed when the watchpoint is hit. \n\
+ \n\
+Syntax checking is not necessarily done when watchpoint commands are \n\
+entered.  An improperly written watchpoint command will attempt to get \n\
+executed when the watchpoint gets hit, and usually silently fail.  If \n\
+your watchpoint command does not appear to be getting executed, go \n\
+back and check your syntax. \n\
+ \n\
+ \n\
+Special information about PYTHON watchpoint commands                            \n\
+----------------------------------------------------                            \n\
+                                                                                \n\
+You may enter either one line of Python or multiple lines of Python             \n\
+(including defining whole functions, if desired).  If you enter a               \n\
+single line of Python, that will be passed to the Python interpreter            \n\
+'as is' when the watchpoint gets hit.  If you enter function                    \n\
+definitions, they will be passed to the Python interpreter as soon as           \n\
+you finish entering the watchpoint command, and they can be called              \n\
+later (don't forget to add calls to them, if you want them called when          \n\
+the watchpoint is hit).  If you enter multiple lines of Python that             \n\
+are not function definitions, they will be collected into a new,                \n\
+automatically generated Python function, and a call to the newly                \n\
+generated function will be attached to the watchpoint.                          \n\
+                                                                                \n\
+This auto-generated function is passed in two arguments:                        \n\
+                                                                                \n\
+    frame:  an SBFrame object representing the frame which hit the watchpoint.  \n\
+            From the frame you can get back to the thread and process.          \n\
+    wp:     the watchpoint that was hit.                                        \n\
+                                                                                \n\
+Important Note: Because loose Python code gets collected into functions,        \n\
+if you want to access global variables in the 'loose' code, you need to         \n\
+specify that they are global, using the 'global' keyword.  Be sure to           \n\
+use correct Python syntax, including indentation, when entering Python          \n\
+watchpoint commands.                                                            \n\
+                                                                                \n\
+As a third option, you can pass the name of an already existing Python function \n\
+and that function will be attached to the watchpoint. It will get passed the    \n\
+frame and wp_loc arguments mentioned above.                                     \n\
+                                                                                \n\
+Example Python one-line watchpoint command: \n\
+ \n\
+(lldb) watchpoint command add -s python 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> print \"Hit this watchpoint!\" \n\
+> DONE \n\
+ \n\
+As a convenience, this also works for a short Python one-liner: \n\
+(lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\
+(lldb) run \n\
+Launching '.../a.out'  (x86_64) \n\
+(lldb) Fri Sep 10 12:17:45 2010 \n\
+Process 21778 Stopped \n\
+* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\
+  36   	\n\
+  37   	int c(int val)\n\
+  38   	{\n\
+  39 ->	    return val + 3;\n\
+  40   	}\n\
+  41   	\n\
+  42   	int main (int argc, char const *argv[])\n\
+(lldb) \n\
+ \n\
+Example multiple line Python watchpoint command, using function definition: \n\
+ \n\
+(lldb) watchpoint command add -s python 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> def watchpoint_output (wp_no): \n\
+>     out_string = \"Hit watchpoint number \" + repr (wp_no) \n\
+>     print out_string \n\
+>     return True \n\
+> watchpoint_output (1) \n\
+> DONE \n\
+ \n\
+ \n\
+Example multiple line Python watchpoint command, using 'loose' Python: \n\
+ \n\
+(lldb) watchpoint command add -s p 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> global wp_count \n\
+> wp_count = wp_count + 1 \n\
+> print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\
+> DONE \n\
+ \n\
+In this case, since there is a reference to a global variable, \n\
+'wp_count', you will also need to make sure 'wp_count' exists and is \n\
+initialized: \n\
+ \n\
+(lldb) script \n\
+>>> wp_count = 0 \n\
+>>> quit() \n\
+ \n\
+(lldb)  \n\
+ \n\
+ \n\
+Final Note:  If you get a warning that no watchpoint command was generated, \n\
+but you did not get any syntax errors, you probably forgot to add a call \n\
+to your functions. \n\
+ \n\
+Special information about debugger command watchpoint commands \n\
+-------------------------------------------------------------- \n\
+ \n\
+You may enter any debugger command, exactly as you would at the \n\
+debugger prompt.  You may enter as many debugger commands as you like, \n\
+but do NOT enter more than one command per line. \n" );
+
+        CommandArgumentEntry arg;
+        CommandArgumentData wp_id_arg;
+
+        // Define the first (and only) variant of this arg.
+        wp_id_arg.arg_type = eArgTypeWatchpointID;
+        wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg.push_back (wp_id_arg);
+
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg);
+    }
+
+    virtual
+    ~CommandObjectWatchpointCommandAdd () {}
+
+    virtual Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    void
+    CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, 
+                                             CommandReturnObject &result)
+    {
+        InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+        std::auto_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+        if (reader_sp && data_ap.get())
+        {
+            BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+            wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+
+            Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback,
+                                              wp_options,                   // callback_data
+                                              eInputReaderGranularityLine,  // token size, to pass to callback function
+                                              "DONE",                       // end token
+                                              "> ",                         // prompt
+                                              true));                       // echo input
+            if (err.Success())
+            {
+                m_interpreter.GetDebugger().PushInputReader (reader_sp);
+                result.SetStatus (eReturnStatusSuccessFinishNoResult);
+            }
+            else
+            {
+                result.AppendError (err.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendError("out of memory");
+            result.SetStatus (eReturnStatusFailed);
+        }
+
+    }
+    
+    /// Set a one-liner as the callback for the watchpoint.
+    void 
+    SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                  const char *oneliner)
+    {
+        std::auto_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+
+        // It's necessary to set both user_source and script_source to the oneliner.
+        // The former is used to generate callback description (as in watchpoint command list)
+        // while the latter is used for Python to interpret during the actual callback.
+        data_ap->user_source.AppendString (oneliner);
+        data_ap->script_source.assign (oneliner);
+        data_ap->stop_on_error = m_options.m_stop_on_error;
+
+        BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+        wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+
+        return;
+    }
+
+    static size_t
+    GenerateWatchpointCommandCallback (void *callback_data, 
+                                       InputReader &reader, 
+                                       lldb::InputReaderAction notification,
+                                       const char *bytes, 
+                                       size_t bytes_len)
+    {
+        StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+        bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+        
+        switch (notification)
+        {
+        case eInputReaderActivate:
+            if (!batch_mode)
+            {
+                out_stream->Printf ("%s\n", g_reader_instructions);
+                if (reader.GetPrompt())
+                    out_stream->Printf ("%s", reader.GetPrompt());
+                out_stream->Flush();
+            }
+            break;
+
+        case eInputReaderDeactivate:
+            break;
+
+        case eInputReaderReactivate:
+            if (reader.GetPrompt() && !batch_mode)
+            {
+                out_stream->Printf ("%s", reader.GetPrompt());
+                out_stream->Flush();
+            }
+            break;
+
+        case eInputReaderAsynchronousOutputWritten:
+            break;
+            
+        case eInputReaderGotToken:
+            if (bytes && bytes_len && callback_data)
+            {
+                WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
+                if (wp_options)
+                {
+                    Baton *wp_options_baton = wp_options->GetBaton();
+                    if (wp_options_baton)
+                        ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 
+                }
+            }
+            if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+            {
+                out_stream->Printf ("%s", reader.GetPrompt());
+                out_stream->Flush();
+            }
+            break;
+            
+        case eInputReaderInterrupt:
+            {
+                // Finish, and cancel the watchpoint command.
+                reader.SetIsDone (true);
+                WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
+                if (wp_options)
+                {
+                    Baton *wp_options_baton = wp_options->GetBaton ();
+                    if (wp_options_baton)
+                    {
+                        ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear();
+                        ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear();
+                    }
+                }
+                if (!batch_mode)
+                {
+                    out_stream->Printf ("Warning: No command attached to watchpoint.\n");
+                    out_stream->Flush();
+                }
+            }
+            break;
+            
+        case eInputReaderEndOfFile:
+            reader.SetIsDone (true);
+            break;
+            
+        case eInputReaderDone:
+            break;
+        }
+
+        return bytes_len;
+    }
+    
+    static bool
+    WatchpointOptionsCallbackFunction (void *baton,
+                                       StoppointCallbackContext *context, 
+                                       lldb::user_id_t watch_id)
+    {
+        bool ret_value = true;
+        if (baton == NULL)
+            return true;
+        
+        
+        WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
+        StringList &commands = data->user_source;
+        
+        if (commands.GetSize() > 0)
+        {
+            ExecutionContext exe_ctx (context->exe_ctx_ref);
+            Target *target = exe_ctx.GetTargetPtr();
+            if (target)
+            {
+                CommandReturnObject result;
+                Debugger &debugger = target->GetDebugger();
+                // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
+                // if the debugger is set up that way.
+                    
+                StreamSP output_stream (debugger.GetAsyncOutputStream());
+                StreamSP error_stream (debugger.GetAsyncErrorStream());
+                result.SetImmediateOutputStream (output_stream);
+                result.SetImmediateErrorStream (error_stream);
+        
+                bool stop_on_continue = true;
+                bool echo_commands    = false;
+                bool print_results    = true;
+
+                debugger.GetCommandInterpreter().HandleCommands (commands, 
+                                                                 &exe_ctx,
+                                                                 stop_on_continue, 
+                                                                 data->stop_on_error, 
+                                                                 echo_commands, 
+                                                                 print_results,
+                                                                 eLazyBoolNo,
+                                                                 result);
+                result.GetImmediateOutputStream()->Flush();
+                result.GetImmediateErrorStream()->Flush();
+           }
+        }
+        return ret_value;
+    }    
+
+    class CommandOptions : public Options
+    {
+    public:
+
+        CommandOptions (CommandInterpreter &interpreter) :
+            Options (interpreter),
+            m_use_commands (false),
+            m_use_script_language (false),
+            m_script_language (eScriptLanguageNone),
+            m_use_one_liner (false),
+            m_one_liner(),
+            m_function_name()
+        {
+        }
+
+        virtual
+        ~CommandOptions () {}
+
+        virtual Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+
+            switch (short_option)
+            {
+            case 'o':
+                m_use_one_liner = true;
+                m_one_liner = option_arg;
+                break;
+
+            case 's':
+                m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 
+                                                                                     g_option_table[option_idx].enum_values, 
+                                                                                     eScriptLanguageNone,
+                                                                                     error);
+
+                if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
+                {
+                    m_use_script_language = true;
+                }
+                else
+                {
+                    m_use_script_language = false;
+                }          
+                break;
+
+            case 'e':
+                {
+                    bool success = false;
+                    m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
+                }
+                break;
+                    
+            case 'F':
+                {
+                    m_use_one_liner = false;
+                    m_use_script_language = true;
+                    m_function_name.assign(option_arg);
+                }
+                break;
+
+            default:
+                break;
+            }
+            return error;
+        }
+        void
+        OptionParsingStarting ()
+        {
+            m_use_commands = true;
+            m_use_script_language = false;
+            m_script_language = eScriptLanguageNone;
+
+            m_use_one_liner = false;
+            m_stop_on_error = true;
+            m_one_liner.clear();
+            m_function_name.clear();
+        }
+
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        // Options table: Required for subclasses of Options.
+
+        static OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+
+        bool m_use_commands;
+        bool m_use_script_language;
+        lldb::ScriptLanguage m_script_language;
+
+        // Instance variables to hold the values for one_liner options.
+        bool m_use_one_liner;
+        std::string m_one_liner;
+        bool m_stop_on_error;
+        std::string m_function_name;
+    };
+
+protected:
+    virtual bool
+    DoExecute (Args& command, CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+        if (target == NULL)
+        {
+            result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        const WatchpointList &watchpoints = target->GetWatchpointList();
+        size_t num_watchpoints = watchpoints.GetSize();
+
+        if (num_watchpoints == 0)
+        {
+            result.AppendError ("No watchpoints exist to have commands added");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        if (m_options.m_use_script_language == false && m_options.m_function_name.size())
+        {
+            result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+        
+        std::vector<uint32_t> valid_wp_ids;
+        if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, valid_wp_ids))
+        {
+            result.AppendError("Invalid watchpoints specification.");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        result.SetStatus(eReturnStatusSuccessFinishNoResult);
+        const size_t count = valid_wp_ids.size();
+        for (size_t i = 0; i < count; ++i)
+        {
+            uint32_t cur_wp_id = valid_wp_ids.at (i);
+            if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+            {
+                Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+                // Sanity check wp first.
+                if (wp == NULL) continue;
+
+                WatchpointOptions *wp_options = wp->GetOptions();
+                // Skip this watchpoint if wp_options is not good.
+                if (wp_options == NULL) continue;
+
+                // If we are using script language, get the script interpreter
+                // in order to set or collect command callback.  Otherwise, call
+                // the methods associated with this object.
+                if (m_options.m_use_script_language)
+                {
+                    // Special handling for one-liner specified inline.
+                    if (m_options.m_use_one_liner)
+                    {
+                        m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
+                                                                                            m_options.m_one_liner.c_str());
+                    }
+                    // Special handling for using a Python function by name
+                    // instead of extending the watchpoint callback data structures, we just automatize
+                    // what the user would do manually: make their watchpoint command be a function call
+                    else if (m_options.m_function_name.size())
+                    {
+                        std::string oneliner(m_options.m_function_name);
+                        oneliner += "(frame, wp, internal_dict)";
+                        m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
+                                                                                            oneliner.c_str());
+                    }
+                    else
+                    {
+                        m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
+                                                                                                       result);
+                    }
+                }
+                else
+                {
+                    // Special handling for one-liner specified inline.
+                    if (m_options.m_use_one_liner)
+                        SetWatchpointCommandCallback (wp_options,
+                                                      m_options.m_one_liner.c_str());
+                    else
+                        CollectDataForWatchpointCommandCallback (wp_options, 
+                                                                 result);
+                }
+            }
+        }
+
+        return result.Succeeded();
+    }
+
+private:
+    CommandOptions m_options;
+    static const char *g_reader_instructions;
+
+};
+
+const char *
+CommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.";
+
+// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
+// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
+
+static OptionEnumValueElement
+g_script_option_enumeration[4] =
+{
+    { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
+    { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
+    { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
+    { 0,                      NULL,              NULL }
+};
+
+OptionDefinition
+CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
+{
+    { LLDB_OPT_SET_1,   false, "one-liner",       'o', required_argument, NULL, NULL, eArgTypeOneLiner,
+        "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
+
+    { LLDB_OPT_SET_ALL, false, "stop-on-error",   'e', required_argument, NULL, NULL, eArgTypeBoolean,
+        "Specify whether watchpoint command execution should terminate on error." },
+
+    { LLDB_OPT_SET_ALL, false, "script-type",     's', required_argument, g_script_option_enumeration, NULL, eArgTypeNone,
+        "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
+
+    { LLDB_OPT_SET_2,   false, "python-function", 'F', required_argument, NULL, NULL, eArgTypePythonFunction,
+        "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
+    
+    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
+{
+public:
+    CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
+        CommandObjectParsed (interpreter, 
+                             "delete",
+                             "Delete the set of commands from a watchpoint.",
+                             NULL)
+    {
+        CommandArgumentEntry arg;
+        CommandArgumentData wp_id_arg;
+
+        // Define the first (and only) variant of this arg.
+        wp_id_arg.arg_type = eArgTypeWatchpointID;
+        wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg.push_back (wp_id_arg);
+
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg);
+    }
+
+
+    virtual
+    ~CommandObjectWatchpointCommandDelete () {}
+
+protected:
+    virtual bool
+    DoExecute (Args& command, CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+        if (target == NULL)
+        {
+            result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        const WatchpointList &watchpoints = target->GetWatchpointList();
+        size_t num_watchpoints = watchpoints.GetSize();
+
+        if (num_watchpoints == 0)
+        {
+            result.AppendError ("No watchpoints exist to have commands deleted");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        if (command.GetArgumentCount() == 0)
+        {
+            result.AppendError ("No watchpoint specified from which to delete the commands");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        std::vector<uint32_t> valid_wp_ids;
+        if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, valid_wp_ids))
+        {
+            result.AppendError("Invalid watchpoints specification.");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        result.SetStatus(eReturnStatusSuccessFinishNoResult);
+        const size_t count = valid_wp_ids.size();
+        for (size_t i = 0; i < count; ++i)
+        {
+            uint32_t cur_wp_id = valid_wp_ids.at (i);
+            if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+            {
+                Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+                if (wp)
+                    wp->ClearCallback();
+            }
+            else
+            {
+                result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 
+                                             cur_wp_id);
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+        }
+        return result.Succeeded();
+    }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandList
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommandList : public CommandObjectParsed
+{
+public:
+    CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
+        CommandObjectParsed (interpreter,
+                             "list",
+                             "List the script or set of commands to be executed when the watchpoint is hit.",
+                              NULL)
+    {
+        CommandArgumentEntry arg;
+        CommandArgumentData wp_id_arg;
+
+        // Define the first (and only) variant of this arg.
+        wp_id_arg.arg_type = eArgTypeWatchpointID;
+        wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg.push_back (wp_id_arg);
+
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg);
+    }
+
+    virtual
+    ~CommandObjectWatchpointCommandList () {}
+
+protected:
+    virtual bool
+    DoExecute (Args& command,
+             CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+        if (target == NULL)
+        {
+            result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        const WatchpointList &watchpoints = target->GetWatchpointList();
+        size_t num_watchpoints = watchpoints.GetSize();
+
+        if (num_watchpoints == 0)
+        {
+            result.AppendError ("No watchpoints exist for which to list commands");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        if (command.GetArgumentCount() == 0)
+        {
+            result.AppendError ("No watchpoint specified for which to list the commands");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        std::vector<uint32_t> valid_wp_ids;
+        if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, valid_wp_ids))
+        {
+            result.AppendError("Invalid watchpoints specification.");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        result.SetStatus(eReturnStatusSuccessFinishNoResult);
+        const size_t count = valid_wp_ids.size();
+        for (size_t i = 0; i < count; ++i)
+        {
+            uint32_t cur_wp_id = valid_wp_ids.at (i);
+            if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+            {
+                Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+                
+                if (wp)
+                {
+                    const WatchpointOptions *wp_options = wp->GetOptions();
+                    if (wp_options)
+                    {
+                        // Get the callback baton associated with the current watchpoint.
+                        const Baton *baton = wp_options->GetBaton();
+                        if (baton)
+                        {
+                            result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
+                            result.GetOutputStream().IndentMore ();
+                            baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
+                            result.GetOutputStream().IndentLess ();
+                        }
+                        else
+                        {
+                            result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n", 
+                                                            cur_wp_id);
+                        }
+                    }
+                    result.SetStatus (eReturnStatusSuccessFinishResult);
+                }
+                else
+                {
+                    result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
+                    result.SetStatus (eReturnStatusFailed);
+                }
+            }
+        }
+
+        return result.Succeeded();
+    }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommand
+//-------------------------------------------------------------------------
+
+CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
+    CommandObjectMultiword (interpreter,
+                            "command",
+                            "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
+                            "command <sub-command> [<sub-command-options>] <watchpoint-id>")
+{
+    bool status;
+    CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
+    CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
+    CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
+
+    add_command_object->SetCommandName ("watchpoint command add");
+    delete_command_object->SetCommandName ("watchpoint command delete");
+    list_command_object->SetCommandName ("watchpoint command list");
+
+    status = LoadSubCommand ("add",    add_command_object);
+    status = LoadSubCommand ("delete", delete_command_object);
+    status = LoadSubCommand ("list",   list_command_object);
+}
+
+CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
+{
+}
+
+

Added: lldb/trunk/source/Commands/CommandObjectWatchpointCommand.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectWatchpointCommand.h?rev=161638&view=auto
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectWatchpointCommand.h (added)
+++ lldb/trunk/source/Commands/CommandObjectWatchpointCommand.h Thu Aug  9 18:09:42 2012
@@ -0,0 +1,46 @@
+//===-- CommandObjectWatchpointCommand.h ------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectWatchpointCommand_h_
+#define liblldb_CommandObjectWatchpointCommand_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommand : public CommandObjectMultiword
+{
+public:
+    CommandObjectWatchpointCommand (CommandInterpreter &interpreter);
+
+    virtual
+    ~CommandObjectWatchpointCommand ();
+
+};
+
+} // namespace lldb_private
+
+#endif  // liblldb_CommandObjectWatchpointCommand_h_

Modified: lldb/trunk/source/Interpreter/ScriptInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreter.cpp?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreter.cpp Thu Aug  9 18:09:42 2012
@@ -50,6 +50,17 @@
     result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented.");
 }
 
+void 
+ScriptInterpreter::CollectDataForWatchpointCommandCallback 
+(
+    WatchpointOptions *bp_options,
+    CommandReturnObject &result
+)
+{
+    result.SetStatus (eReturnStatusFailed);
+    result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented.");
+}
+
 std::string
 ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language)
 {

Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=161638&r1=161637&r2=161638&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Thu Aug  9 18:09:42 2012
@@ -31,6 +31,7 @@
 #include "lldb/API/SBValue.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/WatchpointOptions.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Timer.h"
 #include "lldb/Host/Host.h"
@@ -44,6 +45,7 @@
 
 static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
 static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
+static ScriptInterpreter::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = NULL;
 static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
 static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = NULL;
 static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = NULL;
@@ -69,6 +71,15 @@
  );
 
 extern "C" bool
+LLDBSwigPythonWatchpointCallbackFunction 
+(
+ const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame, 
+ const lldb::WatchpointSP& sb_wp
+ );
+
+extern "C" bool
 LLDBSwigPythonCallTypeScript 
 (
  const char *python_function_name,
@@ -1388,6 +1399,112 @@
     return bytes_len;
 }
 
+size_t
+ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback
+(
+    void *baton, 
+    InputReader &reader, 
+    InputReaderAction notification,
+    const char *bytes, 
+    size_t bytes_len
+)
+{
+    static StringList commands_in_progress;
+    
+    StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+    bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+    
+    switch (notification)
+    {
+    case eInputReaderActivate:
+        {
+            commands_in_progress.Clear();
+            if (!batch_mode)
+            {
+                out_stream->Printf ("%s\n", g_reader_instructions);
+                if (reader.GetPrompt())
+                    out_stream->Printf ("%s", reader.GetPrompt());
+                out_stream->Flush ();
+            }
+        }
+        break;
+
+    case eInputReaderDeactivate:
+        break;
+
+    case eInputReaderReactivate:
+        if (reader.GetPrompt() && !batch_mode)
+        {
+            out_stream->Printf ("%s", reader.GetPrompt());
+            out_stream->Flush ();
+        }
+        break;
+
+    case eInputReaderAsynchronousOutputWritten:
+        break;
+        
+    case eInputReaderGotToken:
+        {
+            std::string temp_string (bytes, bytes_len);
+            commands_in_progress.AppendString (temp_string.c_str());
+            if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+            {
+                out_stream->Printf ("%s", reader.GetPrompt());
+                out_stream->Flush ();
+            }
+        }
+        break;
+
+    case eInputReaderEndOfFile:
+    case eInputReaderInterrupt:
+        // Control-c (SIGINT) & control-d both mean finish & exit.
+        reader.SetIsDone(true);
+        
+        // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command.
+        if (notification == eInputReaderInterrupt)
+            commands_in_progress.Clear();  
+        
+        // Fall through here...
+
+    case eInputReaderDone:
+        {
+            WatchpointOptions *wp_options = (WatchpointOptions *)baton;
+            std::auto_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+            data_ap->user_source.AppendList (commands_in_progress);
+            if (data_ap.get())
+            {
+                ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+                if (interpreter)
+                {
+                    if (interpreter->GenerateWatchpointCommandCallbackData (data_ap->user_source, 
+                                                                            data_ap->script_source))
+                    {
+                        BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+                        wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp);
+                    }
+                    else if (!batch_mode)
+                    {
+                        out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+                        out_stream->Flush();
+                    }
+                }
+                else
+                {
+		            if (!batch_mode)
+                    {
+                        out_stream->Printf ("Warning:  Unable to find script intepreter; no command attached to breakpoint.\n");
+                        out_stream->Flush();
+                    }
+                }
+            }
+        }
+        break;
+        
+    }
+
+    return bytes_len;
+}
+
 void
 ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
                                                                   CommandReturnObject &result)
@@ -1421,6 +1538,39 @@
     }
 }
 
+void
+ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                                                  CommandReturnObject &result)
+{
+    Debugger &debugger = GetCommandInterpreter().GetDebugger();
+    
+    InputReaderSP reader_sp (new InputReader (debugger));
+
+    if (reader_sp)
+    {
+        Error err = reader_sp->Initialize (
+                ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback,
+                wp_options,                 // baton
+                eInputReaderGranularityLine, // token size, for feeding data to callback function
+                "DONE",                     // end token
+                "> ",                       // prompt
+                true);                      // echo input
+    
+        if (err.Success())
+            debugger.PushInputReader (reader_sp);
+        else
+        {
+            result.AppendError (err.AsCString());
+            result.SetStatus (eReturnStatusFailed);
+        }
+    }
+    else
+    {
+        result.AppendError("out of memory");
+        result.SetStatus (eReturnStatusFailed);
+    }
+}
+
 // Set a Python one-liner as the callback for the breakpoint.
 void
 ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
@@ -1433,6 +1583,7 @@
     // while the latter is used for Python to interpret during the actual callback.
 
     data_ap->user_source.AppendString (oneliner);
+    data_ap->script_source.assign (oneliner);
 
     if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
     {
@@ -1443,6 +1594,29 @@
     return;
 }
 
+// Set a Python one-liner as the callback for the watchpoint.
+void
+ScriptInterpreterPython::SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+                                                       const char *oneliner)
+{
+    std::auto_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+
+    // It's necessary to set both user_source and script_source to the oneliner.
+    // The former is used to generate callback description (as in watchpoint command list)
+    // while the latter is used for Python to interpret during the actual callback.
+
+    data_ap->user_source.AppendString (oneliner);
+    data_ap->script_source.assign (oneliner);
+
+    if (GenerateWatchpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
+    {
+        BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+        wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp);
+    }
+    
+    return;
+}
+
 bool
 ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def)
 {
@@ -1662,6 +1836,27 @@
 }
 
 bool
+ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user_input, std::string& output)
+{
+    static uint32_t num_created_functions = 0;
+    user_input.RemoveBlankLines ();
+    StreamString sstr;
+
+    if (user_input.GetSize() == 0)
+        return false;
+
+    std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions));
+    sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str());
+    
+    if (!GenerateFunction(sstr.GetData(), user_input))
+        return false;
+    
+    // Store the name of the auto-generated function to be called.
+    output.assign(auto_generated_function_name);
+    return true;
+}
+
+bool
 ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
                                              lldb::ValueObjectSP valobj,
                                              lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
@@ -1764,6 +1959,59 @@
     return true;
 }
 
+bool
+ScriptInterpreterPython::WatchpointCallbackFunction 
+(
+    void *baton,
+    StoppointCallbackContext *context,
+    user_id_t watch_id
+)
+{
+    WatchpointOptions::CommandData *wp_option_data = (WatchpointOptions::CommandData *) baton;
+    const char *python_function_name = wp_option_data->script_source.c_str();
+
+    if (!context)
+        return true;
+        
+    ExecutionContext exe_ctx (context->exe_ctx_ref);
+    Target *target = exe_ctx.GetTargetPtr();
+    
+    if (!target)
+        return true;
+        
+    Debugger &debugger = target->GetDebugger();
+    ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+    ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
+    
+    if (!script_interpreter)
+        return true;
+    
+    if (python_function_name != NULL 
+        && python_function_name[0] != '\0')
+    {
+        const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP());
+        WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id);
+        if (wp_sp)
+        {
+            if (stop_frame_sp && wp_sp)
+            {
+                bool ret_val = true;
+                {
+                    Locker py_lock(python_interpreter);
+                    ret_val = g_swig_watchpoint_callback (python_function_name, 
+                                                          python_interpreter->m_dictionary_name.c_str(),
+                                                          stop_frame_sp, 
+                                                          wp_sp);
+                }
+                return ret_val;
+            }
+        }
+    }
+    // We currently always true so we stop in case anything goes wrong when
+    // trying to call the script function
+    return true;
+}
+
 lldb::thread_result_t
 ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
 {
@@ -2176,6 +2424,7 @@
 {
     g_swig_init_callback = python_swig_init_callback;
     g_swig_breakpoint_callback = LLDBSwigPythonBreakpointCallbackFunction;
+    g_swig_watchpoint_callback = LLDBSwigPythonWatchpointCallbackFunction;
     g_swig_typescript_callback = LLDBSwigPythonCallTypeScript;
     g_swig_synthetic_script = LLDBSwigPythonCreateSyntheticProvider;
     g_swig_calc_children = LLDBSwigPython_CalculateNumChildren;

Added: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/Makefile?rev=161638&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/Makefile (added)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/Makefile Thu Aug  9 18:09:42 2012
@@ -0,0 +1,5 @@
+LEVEL = ../../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py?rev=161638&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py (added)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py Thu Aug  9 18:09:42 2012
@@ -0,0 +1,93 @@
+"""
+Test 'watchpoint command'.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class WatchpointLLDBCommandTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "watchpoint", "watchpoint_commands", "command")
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Our simple source filename.
+        self.source = 'main.cpp'
+        # Find the line number to break inside main().
+        self.line = line_number(self.source, '// Set break point at this line.')
+        # And the watchpoint variable declaration line number.
+        self.decl = line_number(self.source, '// Watchpoint variable declaration.')
+        # Build dictionary to have unique executable names for each test method.
+        self.exe_name = self.testMethodName
+        self.d = {'CXX_SOURCES': self.source, 'EXE': self.exe_name}
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_watchpoint_command_with_dsym(self):
+        """Test 'watchpoint command'."""
+        self.buildDsym(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.watchpoint_command()
+
+    @dwarf_test
+    def test_watchpoint_command_with_dwarf(self):
+        """Test 'watchpoint command'."""
+        self.buildDwarf(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.watchpoint_command()
+
+    def watchpoint_command(self):
+        """Do 'watchpoint command add'."""
+        exe = os.path.join(os.getcwd(), self.exe_name)
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Add a breakpoint to set a watchpoint when stopped on the breakpoint.
+        self.expect("breakpoint set -l %d" % self.line, BREAKPOINT_CREATED,
+            startstr = "Breakpoint created: 1: file ='%s', line = %d, locations = 1" %
+                       (self.source, self.line))
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # We should be stopped again due to the breakpoint.
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Now let's set a write-type watchpoint for 'global'.
+        self.expect("watchpoint set variable -w write global", WATCHPOINT_CREATED,
+            substrs = ['Watchpoint created', 'size = 4', 'type = w',
+                       '%s:%d' % (self.source, self.decl)])
+
+        self.runCmd('watchpoint command add 1 -o "expr -- global = 777"')
+
+        # List the watchpoint command we just added.
+        self.expect("watchpoint command list 1",
+            substrs = ['expr -- global = 777'])
+
+        # Use the '-v' option to do verbose listing of the watchpoint.
+        # The hit count should be 0 initially.
+        self.expect("watchpoint list -v",
+            substrs = ['hit_count = 0'])
+
+        self.runCmd("process continue")
+
+        # We should be stopped again due to the watchpoint (write type).
+        # The stop reason of the thread should be watchpoint.
+        self.expect("thread backtrace", STOPPED_DUE_TO_WATCHPOINT,
+            substrs = ['stop reason = watchpoint'])
+
+        # The watchpoint command "forced" our global variable to become 777.
+        self.expect("frame variable -g global",
+            substrs = ['(int32_t)', 'global = 777'])
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py?rev=161638&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py (added)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py Thu Aug  9 18:09:42 2012
@@ -0,0 +1,93 @@
+"""
+Test 'watchpoint command'.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class WatchpointPythonCommandTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "watchpoint", "watchpoint_commands", "command")
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Our simple source filename.
+        self.source = 'main.cpp'
+        # Find the line number to break inside main().
+        self.line = line_number(self.source, '// Set break point at this line.')
+        # And the watchpoint variable declaration line number.
+        self.decl = line_number(self.source, '// Watchpoint variable declaration.')
+        # Build dictionary to have unique executable names for each test method.
+        self.exe_name = self.testMethodName
+        self.d = {'CXX_SOURCES': self.source, 'EXE': self.exe_name}
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_watchpoint_command_with_dsym(self):
+        """Test 'watchpoint command'."""
+        self.buildDsym(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.watchpoint_command()
+
+    @dwarf_test
+    def test_watchpoint_command_with_dwarf(self):
+        """Test 'watchpoint command'."""
+        self.buildDwarf(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.watchpoint_command()
+
+    def watchpoint_command(self):
+        """Do 'watchpoint command add'."""
+        exe = os.path.join(os.getcwd(), self.exe_name)
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Add a breakpoint to set a watchpoint when stopped on the breakpoint.
+        self.expect("breakpoint set -l %d" % self.line, BREAKPOINT_CREATED,
+            startstr = "Breakpoint created: 1: file ='%s', line = %d, locations = 1" %
+                       (self.source, self.line))
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # We should be stopped again due to the breakpoint.
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Now let's set a write-type watchpoint for 'global'.
+        self.expect("watchpoint set variable -w write global", WATCHPOINT_CREATED,
+            substrs = ['Watchpoint created', 'size = 4', 'type = w',
+                       '%s:%d' % (self.source, self.decl)])
+
+        self.runCmd('watchpoint command add -s python 1 -o \'frame.EvaluateExpression("global = 777")\'')
+
+        # List the watchpoint command we just added.
+        self.expect("watchpoint command list 1",
+            substrs = ['frame.EvaluateExpression', 'global = 777'])
+
+        # Use the '-v' option to do verbose listing of the watchpoint.
+        # The hit count should be 0 initially.
+        self.expect("watchpoint list -v",
+            substrs = ['hit_count = 0'])
+
+        self.runCmd("process continue")
+
+        # We should be stopped again due to the watchpoint (write type).
+        # The stop reason of the thread should be watchpoint.
+        self.expect("thread backtrace", STOPPED_DUE_TO_WATCHPOINT,
+            substrs = ['stop reason = watchpoint'])
+
+        # The watchpoint command "forced" our global variable to become 777.
+        self.expect("frame variable -g global",
+            substrs = ['(int32_t)', 'global = 777'])
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp?rev=161638&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp (added)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp Thu Aug  9 18:09:42 2012
@@ -0,0 +1,28 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+#include <stdint.h>
+
+int32_t global = 0; // Watchpoint variable declaration.
+
+static void modify(int32_t &var) {
+    ++var;
+}
+
+int main(int argc, char** argv) {
+    int local = 0;
+    printf("&global=%p\n", &global);
+    printf("about to write to 'global'...\n"); // Set break point at this line.
+                                               // When stopped, watch 'global',
+                                               // for the condition "global == 5".
+    for (int i = 0; i < 10; ++i)
+        modify(global);
+
+    printf("global=%d\n", global);
+}





More information about the lldb-commits mailing list