Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:

enum
{
    //----------------------------------------------------------------------
    // eFlagRequiresTarget
    //
    // Ensures a valid target is contained in m_exe_ctx prior to executing
    // the command. If a target doesn't exist or is invalid, the command
    // will fail and CommandObject::GetInvalidTargetDescription() will be
    // returned as the error. CommandObject subclasses can override the
    // virtual function for GetInvalidTargetDescription() to provide custom
    // strings when needed.
    //----------------------------------------------------------------------
    eFlagRequiresTarget         = (1u << 0),
    //----------------------------------------------------------------------
    // eFlagRequiresProcess
    //
    // Ensures a valid process is contained in m_exe_ctx prior to executing
    // the command. If a process doesn't exist or is invalid, the command
    // will fail and CommandObject::GetInvalidProcessDescription() will be
    // returned as the error. CommandObject subclasses can override the
    // virtual function for GetInvalidProcessDescription() to provide custom
    // strings when needed.
    //----------------------------------------------------------------------
    eFlagRequiresProcess        = (1u << 1),
    //----------------------------------------------------------------------
    // eFlagRequiresThread
    //
    // Ensures a valid thread is contained in m_exe_ctx prior to executing
    // the command. If a thread doesn't exist or is invalid, the command
    // will fail and CommandObject::GetInvalidThreadDescription() will be
    // returned as the error. CommandObject subclasses can override the
    // virtual function for GetInvalidThreadDescription() to provide custom
    // strings when needed.
    //----------------------------------------------------------------------
    eFlagRequiresThread         = (1u << 2),
    //----------------------------------------------------------------------
    // eFlagRequiresFrame
    //
    // Ensures a valid frame is contained in m_exe_ctx prior to executing
    // the command. If a frame doesn't exist or is invalid, the command
    // will fail and CommandObject::GetInvalidFrameDescription() will be
    // returned as the error. CommandObject subclasses can override the
    // virtual function for GetInvalidFrameDescription() to provide custom
    // strings when needed.
    //----------------------------------------------------------------------
    eFlagRequiresFrame          = (1u << 3),
    //----------------------------------------------------------------------
    // eFlagRequiresRegContext
    //
    // Ensures a valid register context (from the selected frame if there
    // is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
    // is availble from m_exe_ctx prior to executing the command. If a
    // target doesn't exist or is invalid, the command will fail and
    // CommandObject::GetInvalidRegContextDescription() will be returned as
    // the error. CommandObject subclasses can override the virtual function
    // for GetInvalidRegContextDescription() to provide custom strings when
    // needed.
    //----------------------------------------------------------------------
    eFlagRequiresRegContext     = (1u << 4),
    //----------------------------------------------------------------------
    // eFlagTryTargetAPILock
    //
    // Attempts to acquire the target lock if a target is selected in the
    // command interpreter. If the command object fails to acquire the API
    // lock, the command will fail with an appropriate error message.
    //----------------------------------------------------------------------
    eFlagTryTargetAPILock       = (1u << 5),
    //----------------------------------------------------------------------
    // eFlagProcessMustBeLaunched
    //
    // Verifies that there is a launched process in m_exe_ctx, if there
    // isn't, the command will fail with an appropriate error message.
    //----------------------------------------------------------------------
    eFlagProcessMustBeLaunched  = (1u << 6),
    //----------------------------------------------------------------------
    // eFlagProcessMustBePaused
    //
    // Verifies that there is a paused process in m_exe_ctx, if there
    // isn't, the command will fail with an appropriate error message.
    //----------------------------------------------------------------------
    eFlagProcessMustBePaused    = (1u << 7)
};

Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.




git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@171990 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp
index e90ae8f..784187f 100644
--- a/source/Interpreter/CommandObject.cpp
+++ b/source/Interpreter/CommandObject.cpp
@@ -208,8 +208,77 @@
 
 
 bool
-CommandObject::CheckFlags (CommandReturnObject &result)
+CommandObject::CheckRequirements (CommandReturnObject &result)
 {
+#ifdef LLDB_CONFIGURATION_DEBUG
+    // Nothing should be stored in m_exe_ctx between running commands as m_exe_ctx
+    // has shared pointers to the target, process, thread and frame and we don't
+    // want any CommandObject instances to keep any of these objects around
+    // longer than for a single command. Every command should call
+    // CommandObject::Cleanup() after it has completed
+    assert (m_exe_ctx.GetTargetPtr() == NULL);
+    assert (m_exe_ctx.GetProcessPtr() == NULL);
+    assert (m_exe_ctx.GetThreadPtr() == NULL);
+    assert (m_exe_ctx.GetFramePtr() == NULL);
+#endif
+
+    // Lock down the interpreter's execution context prior to running the
+    // command so we guarantee the selected target, process, thread and frame
+    // can't go away during the execution
+    m_exe_ctx = m_interpreter.GetExecutionContext();
+
+    const uint32_t flags = GetFlags().Get();
+    if (flags & (eFlagRequiresTarget   |
+                 eFlagRequiresProcess  |
+                 eFlagRequiresThread   |
+                 eFlagRequiresFrame    |
+                 eFlagTryTargetAPILock ))
+    {
+
+        if ((flags & eFlagRequiresTarget) && !m_exe_ctx.HasTargetScope())
+        {
+            result.AppendError (GetInvalidTargetDescription());
+            return false;
+        }
+
+        if ((flags & eFlagRequiresProcess) && !m_exe_ctx.HasProcessScope())
+        {
+            result.AppendError (GetInvalidProcessDescription());
+            return false;
+        }
+        
+        if ((flags & eFlagRequiresThread) && !m_exe_ctx.HasThreadScope())
+        {
+            result.AppendError (GetInvalidThreadDescription());
+            return false;
+        }
+        
+        if ((flags & eFlagRequiresFrame) && !m_exe_ctx.HasFrameScope())
+        {
+            result.AppendError (GetInvalidFrameDescription());
+            return false;
+        }
+        
+        if ((flags & eFlagRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == NULL))
+        {
+            result.AppendError (GetInvalidRegContextDescription());
+            return false;
+        }
+
+        if (flags & eFlagTryTargetAPILock)
+        {
+            Target *target = m_exe_ctx.GetTargetPtr();
+            if (target)
+            {
+                if (m_api_locker.TryLock (target->GetAPIMutex(), NULL) == false)
+                {
+                    result.AppendError ("failed to get API lock");
+                    return false;
+                }
+            }
+        }
+    }
+
     if (GetFlags().AnySet (CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused))
     {
         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
@@ -263,6 +332,14 @@
     return true;
 }
 
+void
+CommandObject::Cleanup ()
+{
+    m_exe_ctx.Clear();
+    m_api_locker.Unlock();
+}
+
+
 class CommandDictCommandPartialMatch
 {
     public:
@@ -888,14 +965,16 @@
                 cmd_args.ReplaceArgumentAtIndex (i, m_interpreter.ProcessEmbeddedScriptCommands (tmp_str));
         }
 
-        if (!CheckFlags(result))
-            return false;
-            
-        if (!ParseOptions (cmd_args, result))
-            return false;
+        if (CheckRequirements(result))
+        {
+            if (ParseOptions (cmd_args, result))
+            {
+                // Call the command-specific version of 'Execute', passing it the already processed arguments.
+                handled = DoExecute (cmd_args, result);
+            }
+        }
 
-        // Call the command-specific version of 'Execute', passing it the already processed arguments.
-        handled = DoExecute (cmd_args, result);
+        Cleanup();
     }
     return handled;
 }
@@ -916,10 +995,10 @@
     }
     if (!handled)
     {
-        if (!CheckFlags(result))
-            return false;
-        else
+        if (CheckRequirements(result))
             handled = DoExecute (args_string, result);
+        
+        Cleanup();
     }
     return handled;
 }