[Lldb-commits] [lldb] r216747 - Allow "breakpoint command add" to add commands to more than one breakpoint at a time.

Jim Ingham jingham at apple.com
Fri Aug 29 10:34:18 PDT 2014


Author: jingham
Date: Fri Aug 29 12:34:17 2014
New Revision: 216747

URL: http://llvm.org/viewvc/llvm-project?rev=216747&view=rev
Log:
Allow "breakpoint command add" to add commands to more than one breakpoint at a time.

<rdar://problem/13314462>

Modified:
    lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
    lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
    lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreter.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
    lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py

Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=216747&r1=216746&r2=216747&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Fri Aug 29 12:34:17 2014
@@ -372,7 +372,7 @@ public:
     }
 
     virtual void 
-    CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+    CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &options,
                                              CommandReturnObject &result);
 
     virtual void 
@@ -380,6 +380,10 @@ public:
                                              CommandReturnObject &result);
 
     /// Set the specified text as the callback for the breakpoint.
+    Error
+    SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
+                                  const char *callback_text);
+
     virtual Error
     SetBreakpointCommandCallback (BreakpointOptions *bp_options,
                                   const char *callback_text)
@@ -389,6 +393,10 @@ public:
         return error;
     }
     
+    void
+    SetBreakpointCommandCallbackFunction (std::vector<BreakpointOptions *> &bp_options_vec,
+                                  const char *function_name);
+
     /// Set a one-liner as the callback for the breakpoint.
     virtual void 
     SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options,

Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h?rev=216747&r1=216746&r2=216747&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h Fri Aug 29 12:34:17 2014
@@ -225,7 +225,7 @@ public:
     AcquireInterpreterLock ();
     
     void
-    CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+    CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
                                              CommandReturnObject &result);
 
     void 

Modified: lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp?rev=216747&r1=216746&r2=216747&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp Fri Aug 29 12:34:17 2014
@@ -47,7 +47,7 @@ public:
                              "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit."
                              "  If no breakpoint is specified, adds the commands to the last created breakpoint.",
                              NULL),
-    IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand),
+        IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand),
         m_options (interpreter)
     {
         SetHelpLong (
@@ -229,9 +229,12 @@ one command per line.\n" );
     {
         io_handler.SetIsDone(true);
         
-        BreakpointOptions *bp_options = (BreakpointOptions *) io_handler.GetUserData();
-        if (bp_options)
+        std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData();
+        for (BreakpointOptions *bp_options : *bp_options_vec)
         {
+            if (!bp_options)
+                continue;
+                    
             std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
             if (data_ap.get())
             {
@@ -240,36 +243,37 @@ one command per line.\n" );
                 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
             }
         }
-
     }
     
     void
-    CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, 
+    CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
                                              CommandReturnObject &result)
     {
         m_interpreter.GetLLDBCommandsFromIOHandler ("> ",           // Prompt
                                                     *this,          // IOHandlerDelegate
                                                     true,           // Run IOHandler in async mode
-                                                    bp_options);    // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
+                                                    &bp_options_vec);    // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
     }
     
     /// Set a one-liner as the callback for the breakpoint.
     void 
-    SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+    SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
                                   const char *oneliner)
     {
-        std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::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 breakpoint 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;
+        for (auto bp_options : bp_options_vec)
+        {
+            std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
 
-        BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
-        bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+            // It's necessary to set both user_source and script_source to the oneliner.
+            // The former is used to generate callback description (as in breakpoint 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 BreakpointOptions::CommandBaton (data_ap.release()));
+            bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+        }
         return;
     }
     
@@ -460,15 +464,11 @@ protected:
         BreakpointIDList valid_bp_ids;
         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
 
+        m_bp_options_vec.clear();
+        
         if (result.Succeeded())
         {
             const size_t count = valid_bp_ids.GetSize();
-            if (count > 1)
-            {
-                result.AppendError ("can only add commands to one breakpoint at a time.");
-                result.SetStatus (eReturnStatusFailed);
-                return false;
-            }
             
             for (size_t i = 0; i < count; ++i)
             {
@@ -490,44 +490,45 @@ protected:
                         if (bp_loc_sp)
                             bp_options = bp_loc_sp->GetLocationOptions();
                     }
+                    if (bp_options)
+                        m_bp_options_vec.push_back (bp_options);
+                }
+            }
 
-                    // Skip this breakpoint if bp_options is not good.
-                    if (bp_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()->SetBreakpointCommandCallback (bp_options,
-                                                                                                m_options.m_one_liner.c_str());
-                        }
-                        else if (m_options.m_function_name.size())
-                        {
-                            m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options,
-                                                                                                        m_options.m_function_name.c_str());
-                        }
-                        else
-                        {
-                            m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
-                                                                                                           result);
-                        }
-                    }
-                    else
-                    {
-                        // Special handling for one-liner specified inline.
-                        if (m_options.m_use_one_liner)
-                            SetBreakpointCommandCallback (bp_options,
-                                                          m_options.m_one_liner.c_str());
-                        else
-                            CollectDataForBreakpointCommandCallback (bp_options, 
-                                                                     result);
-                    }
+            // 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)
+            {
+                ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter();
+                // Special handling for one-liner specified inline.
+                if (m_options.m_use_one_liner)
+                {
+                    script_interp->SetBreakpointCommandCallback (m_bp_options_vec,
+                                                                 m_options.m_one_liner.c_str());
                 }
+                else if (m_options.m_function_name.size())
+                {
+                    script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec,
+                                                                         m_options.m_function_name.c_str());
+                }
+                else
+                {
+                    script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec,
+                                                                            result);
+                }
+            }
+            else
+            {
+                // Special handling for one-liner specified inline.
+                if (m_options.m_use_one_liner)
+                    SetBreakpointCommandCallback (m_bp_options_vec,
+                                                  m_options.m_one_liner.c_str());
+                else
+                    CollectDataForBreakpointCommandCallback (m_bp_options_vec,
+                                                             result);
             }
+
         }
 
         return result.Succeeded();
@@ -535,6 +536,17 @@ protected:
 
 private:
     CommandOptions m_options;
+    std::vector<BreakpointOptions *> m_bp_options_vec;  // This stores the breakpoint options that we are currently
+                                                        // collecting commands for.  In the CollectData... calls we need
+                                                        // to hand this off to the IOHandler, which may run asynchronously.
+                                                        // So we have to have some way to keep it alive, and not leak it.
+                                                        // Making it an ivar of the command object, which never goes away
+                                                        // achieves this.  Note that if we were able to run
+                                                        // the same command concurrently in one interpreter we'd have to
+                                                        // make this "per invocation".  But there are many more reasons
+                                                        // why it is not in general safe to do that in lldb at present,
+                                                        // so it isn't worthwhile to come up with a more complex mechanism
+                                                        // to address this particular weakness right now.
     static const char *g_reader_instructions;
 
 };

Modified: lldb/trunk/source/Interpreter/ScriptInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreter.cpp?rev=216747&r1=216746&r2=216747&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreter.cpp Fri Aug 29 12:34:17 2014
@@ -44,7 +44,7 @@ ScriptInterpreter::GetCommandInterpreter
 void 
 ScriptInterpreter::CollectDataForBreakpointCommandCallback 
 (
-    BreakpointOptions *bp_options,
+    std::vector<BreakpointOptions *> &bp_options_vec,
     CommandReturnObject &result
 )
 {
@@ -81,6 +81,30 @@ ScriptInterpreter::LanguageToString (lld
     return return_value;
 }
 
+Error
+ScriptInterpreter::SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
+                                                 const char *callback_text)
+{
+    Error return_error;
+    for (BreakpointOptions *bp_options : bp_options_vec)
+    {
+        return_error = SetBreakpointCommandCallback(bp_options, callback_text);
+        if (return_error.Success())
+            break;
+    }
+    return return_error;
+}
+
+void
+ScriptInterpreter::SetBreakpointCommandCallbackFunction (std::vector<BreakpointOptions *> &bp_options_vec,
+                                                         const char *function_name)
+{
+    for (BreakpointOptions *bp_options : bp_options_vec)
+    {
+        SetBreakpointCommandCallbackFunction(bp_options, function_name);
+    }
+}
+
 std::unique_ptr<ScriptInterpreterLocker>
 ScriptInterpreter::AcquireInterpreterLock ()
 {

Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=216747&r1=216746&r2=216747&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Fri Aug 29 12:34:17 2014
@@ -256,24 +256,30 @@ ScriptInterpreterPython::IOHandlerInputC
         break;
     case eIOHandlerBreakpoint:
         {
-            BreakpointOptions *bp_options = (BreakpointOptions *)io_handler.GetUserData();
-            std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
-            if (data_ap.get())
+            std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData();
+            for (auto bp_options : *bp_options_vec)
             {
-                data_ap->user_source.SplitIntoLines(data);
-                
-                if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source).Success())
-                {
-                    BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
-                    bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
-                }
-                else if (!batch_mode)
-                {
-                    StreamFileSP error_sp = io_handler.GetErrorStreamFile();
-                    if (error_sp)
+                if (!bp_options)
+                    continue;
+                    
+                std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+                if (data_ap.get())
+                {
+                    data_ap->user_source.SplitIntoLines(data);
+                    
+                    if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source).Success())
                     {
-                        error_sp->Printf ("Warning: No command attached to breakpoint.\n");
-                        error_sp->Flush();
+                        BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+                        bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
+                    }
+                    else if (!batch_mode)
+                    {
+                        StreamFileSP error_sp = io_handler.GetErrorStreamFile();
+                        if (error_sp)
+                        {
+                            error_sp->Printf ("Warning: No command attached to breakpoint.\n");
+                            error_sp->Flush();
+                        }
                     }
                 }
             }
@@ -307,8 +313,6 @@ ScriptInterpreterPython::IOHandlerInputC
         }
         break;
     }
-
-
 }
 
 
@@ -1087,11 +1091,11 @@ ScriptInterpreterPython::ExecuteMultiple
 
 
 void
-ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
                                                                   CommandReturnObject &result)
 {
     m_active_io_handler = eIOHandlerBreakpoint;
-    m_interpreter.GetPythonCommandsFromIOHandler ("    ", *this, true, bp_options);
+    m_interpreter.GetPythonCommandsFromIOHandler ("    ", *this, true, &bp_options_vec);
 }
 
 void

Modified: lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py?rev=216747&r1=216746&r2=216747&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py (original)
+++ lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py Fri Aug 29 12:34:17 2014
@@ -52,9 +52,11 @@ class BreakpointCommandTestCase(TestBase
         lldbutil.run_break_set_by_file_and_line (self, None, self.line, num_expected_locations=1, loc_exact=True)
         lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
         lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
+        # Breakpoint 4 - set at the same location as breakpoint 1 to test setting breakpoint commands on two breakpoints at a time
+        lldbutil.run_break_set_by_file_and_line (self, None, self.line, num_expected_locations=1, loc_exact=True)
 
         # Now add callbacks for the breakpoints just created.
-        self.runCmd("breakpoint command add -s command -o 'frame variable --show-types --scope' 1")
+        self.runCmd("breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4")
         self.runCmd("breakpoint command add -s python -o 'here = open(\"output.txt\", \"w\"); print >> here, \"lldb\"; here.close()' 2")
         self.runCmd("breakpoint command add --python-function bktptcmd.function 3")
 
@@ -83,6 +85,12 @@ class BreakpointCommandTestCase(TestBase
             substrs = ["Breakpoint commands:",
                           "bktptcmd.function(frame, bp_loc, internal_dict)"])
 
+        self.expect("breakpoint command list 4", "Breakpoint 4 command ok",
+            substrs = ["Breakpoint commands:",
+                          "frame variable --show-types --scope"])
+
+        self.runCmd("breakpoint delete 4")
+
         self.runCmd("command script import --allow-reload ./bktptcmd.py")
 
         # Next lets try some other breakpoint kinds.  First break with a regular expression





More information about the lldb-commits mailing list