Add an option to "process continue" to ignore the next <N> crossings of the breakpoint under
the currently selected thread.

<rdar://problem/10458225>


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@161723 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index a940d3b..ab5b806 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -13,14 +13,18 @@
 // C++ Includes
 // Other libraries and framework includes
 // Project includes
-#include "lldb/Interpreter/Args.h"
-#include "lldb/Interpreter/Options.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
 #include "lldb/Core/State.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 
@@ -670,7 +674,8 @@
                              "process continue",
                              "Continue execution of all threads in the current process.",
                              "process continue",
-                             eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+                             eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
+        m_options(interpreter)
     {
     }
 
@@ -680,6 +685,62 @@
     }
 
 protected:
+
+    class CommandOptions : public Options
+    {
+    public:
+
+        CommandOptions (CommandInterpreter &interpreter) :
+            Options(interpreter)
+        {
+            // Keep default values of all options in one place: OptionParsingStarting ()
+            OptionParsingStarting ();
+        }
+
+        ~CommandOptions ()
+        {
+        }
+
+        Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+            bool success = false;
+            switch (short_option)
+            {
+                case 'i':
+                    m_ignore = Args::StringToUInt32 (option_arg, 0, 0, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat ("invalid value for ignore option: \"%s\", should be a number.", option_arg);
+                    break;
+
+                default:
+                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+                    break;
+            }
+            return error;
+        }
+
+        void
+        OptionParsingStarting ()
+        {
+            m_ignore = 0;
+        }
+
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        // Options table: Required for subclasses of Options.
+
+        static OptionDefinition g_option_table[];
+
+        uint32_t m_ignore;
+    };
+    
     bool
     DoExecute (Args& command,
              CommandReturnObject &result)
@@ -704,6 +765,32 @@
                 return false;
             }
 
+            if (m_options.m_ignore > 0)
+            {
+                ThreadSP sel_thread_sp(process->GetThreadList().GetSelectedThread());
+                if (sel_thread_sp)
+                {
+                    StopInfoSP stop_info_sp = sel_thread_sp->GetStopInfo();
+                    if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
+                    {
+                        uint64_t bp_site_id = stop_info_sp->GetValue();
+                        BreakpointSiteSP bp_site_sp(process->GetBreakpointSiteList().FindByID(bp_site_id));
+                        if (bp_site_sp)
+                        {
+                            uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
+                            for (uint32_t i = 0; i < num_owners; i++)
+                            {
+                                Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+                                if (!bp_ref.IsInternal())
+                                {
+                                    bp_ref.SetIgnoreCount(m_options.m_ignore);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            
             const uint32_t num_threads = process->GetThreadList().GetSize();
 
             // Set the actions that the threads should each take when resuming
@@ -743,6 +830,23 @@
         }
         return result.Succeeded();
     }
+
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+    
+    CommandOptions m_options;
+
+};
+
+OptionDefinition
+CommandObjectProcessContinue::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "ignore-count",'i', required_argument,         NULL, 0, eArgTypeUnsignedInteger,
+                           "Ignore <N> crossings of the breakpoint (if it exists) for the currently selected thread."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
 };
 
 //-------------------------------------------------------------------------