[Lldb-commits] [lldb] r174095 - Add "thread return -x" to unwind the innermost user called expression (if you happen to have stopped in it due to a crash.)

Jim Ingham jingham at apple.com
Thu Jan 31 13:46:01 PST 2013


Author: jingham
Date: Thu Jan 31 15:46:01 2013
New Revision: 174095

URL: http://llvm.org/viewvc/llvm-project?rev=174095&view=rev
Log:
Add "thread return -x" to unwind the innermost user called expression (if you happen to have stopped in it due to a crash.)
Make the message when you hit an crash while evaluating an expression a little clearer, and mention "thread return -x".

rdar://problem/13110464

Modified:
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/source/Commands/CommandObjectFrame.cpp
    lldb/trunk/source/Commands/CommandObjectThread.cpp
    lldb/trunk/source/Expression/ClangUserExpression.cpp
    lldb/trunk/source/Target/Thread.cpp

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=174095&r1=174094&r2=174095&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Thu Jan 31 15:46:01 2013
@@ -394,9 +394,13 @@ public:
     uint32_t
     SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast = false);
 
+
     bool
     SetSelectedFrameByIndex (uint32_t frame_idx, bool broadcast = false);
 
+    bool
+    SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_stream);
+
     void
     SetDefaultFileAndLineToSelectedFrame()
     {
@@ -663,6 +667,17 @@ public:
     //------------------------------------------------------------------
     ThreadPlan *
     GetCurrentPlan ();
+    
+    //------------------------------------------------------------------
+    /// Unwinds the thread stack for the innermost expression plan currently
+    /// on the thread plan stack.
+    ///
+    /// @return
+    ///     An error if the thread plan could not be unwound.
+    //------------------------------------------------------------------
+
+    Error
+    UnwindInnermostExpression();
 
 private:
     bool

Modified: lldb/trunk/source/Commands/CommandObjectFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectFrame.cpp?rev=174095&r1=174094&r2=174095&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectFrame.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectFrame.cpp Thu Jan 31 15:46:01 2013
@@ -261,33 +261,19 @@ protected:
             }
         }
 
-        const bool broadcast = true;
-        bool success = thread->SetSelectedFrameByIndex (frame_idx, broadcast);
+        bool success = thread->SetSelectedFrameByIndexNoisily (frame_idx, result.GetOutputStream());
         if (success)
         {
             m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ());
-            StackFrame *frame = m_exe_ctx.GetFramePtr();
-            if (frame)
-            {
-                bool already_shown = false;
-                SymbolContext frame_sc(frame->GetSymbolContext(eSymbolContextLineEntry));
-                if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
-                {
-                    already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
-                }
-
-                bool show_frame_info = true;
-                bool show_source = !already_shown;
-                if (frame->GetStatus (result.GetOutputStream(), show_frame_info, show_source))
-                {
-                    result.SetStatus (eReturnStatusSuccessFinishResult);
-                    return result.Succeeded();
-                }
-            }
+            result.SetStatus (eReturnStatusSuccessFinishResult);
+        }
+        else
+        {
+            result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
+            result.SetStatus (eReturnStatusFailed);
         }
-        result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
-        result.SetStatus (eReturnStatusFailed);
-        return false;
+        
+        return result.Succeeded();
     }
 protected:
 

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=174095&r1=174094&r2=174095&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Thu Jan 31 15:46:01 2013
@@ -1248,25 +1248,104 @@ protected:
     }
 };
 
+//-------------------------------------------------------------------------
+// CommandObjectThreadReturn
+//-------------------------------------------------------------------------
+
 class CommandObjectThreadReturn : public CommandObjectRaw
 {
 public:
+    class CommandOptions : public Options
+    {
+    public:
+
+        CommandOptions (CommandInterpreter &interpreter) :
+            Options (interpreter),
+            m_from_expression (false)
+        {
+            // Keep default values of all options in one place: OptionParsingStarting ()
+            OptionParsingStarting ();
+        }
+
+        virtual
+        ~CommandOptions ()
+        {
+        }
+
+        virtual Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            Error error;
+            const int short_option = m_getopt_table[option_idx].val;
+
+            switch (short_option)
+            {
+                case 'x':
+                {
+                    bool success;
+                    bool tmp_value = Args::StringToBoolean (option_arg, false, &success);
+                    if (success)
+                        m_from_expression = tmp_value;
+                    else
+                    {
+                        error.SetErrorStringWithFormat ("invalid boolean value '%s' for 'x' option", option_arg);
+                    }
+                }
+                break;
+                default:
+                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+                    break;
+
+            }
+            return error;
+        }
+
+        void
+        OptionParsingStarting ()
+        {
+            m_from_expression = false;
+        }
+
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        bool m_from_expression;
+
+        // Options table: Required for subclasses of Options.
+
+        static OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+    };
+
+    virtual
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
     CommandObjectThreadReturn (CommandInterpreter &interpreter) :
         CommandObjectRaw (interpreter,
                           "thread return",
-                          "Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value.",
+                          "Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value,"
+                          " or with the -x option from the innermost function evaluation.",
                           "thread return",
                           eFlagRequiresFrame         |
                           eFlagTryTargetAPILock      |
                           eFlagProcessMustBeLaunched |
-                          eFlagProcessMustBePaused   )
+                          eFlagProcessMustBePaused   ),
+        m_options (interpreter)
     {
         CommandArgumentEntry arg;
         CommandArgumentData expression_arg;
 
         // Define the first (and only) variant of this arg.
         expression_arg.arg_type = eArgTypeExpression;
-        expression_arg.arg_repetition = eArgRepeatPlain;
+        expression_arg.arg_repetition = eArgRepeatOptional;
 
         // There is only one variant this argument could be; put it into the argument entry.
         arg.push_back (expression_arg);
@@ -1289,6 +1368,38 @@ protected:
         CommandReturnObject &result
     )
     {
+        // I am going to handle this by hand, because I don't want you to have to say:
+        // "thread return -- -5".
+        if (command[0] == '-' && command[1] == 'x')
+        {
+            if (command && command[2] != '\0')
+                result.AppendWarning("Return values ignored when returning from user called expressions");
+            
+            Thread *thread = m_exe_ctx.GetThreadPtr();
+            Error error;
+            error = thread->UnwindInnermostExpression();
+            if (!error.Success())
+            {
+                result.AppendErrorWithFormat ("Unwinding expression failed - %s.", error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+            else
+            {
+                bool success = thread->SetSelectedFrameByIndexNoisily (0, result.GetOutputStream());
+                if (success)
+                {
+                    m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ());
+                    result.SetStatus (eReturnStatusSuccessFinishResult);
+                }
+                else
+                {
+                    result.AppendErrorWithFormat ("Could not select 0th frame after unwinding expression.");
+                    result.SetStatus (eReturnStatusFailed);
+                }
+            }
+            return result.Succeeded();
+        }
+        
         ValueObjectSP return_valobj_sp;
         
         StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
@@ -1340,8 +1451,16 @@ protected:
         result.SetStatus (eReturnStatusSuccessFinishResult);
         return true;
     }
+    
+    CommandOptions m_options;
 
 };
+OptionDefinition
+CommandObjectThreadReturn::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "from-expression",  'x', no_argument, NULL,               0, eArgTypeNone,     "Return from the innermost expression evaluation."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
 
 //-------------------------------------------------------------------------
 // CommandObjectMultiwordThread

Modified: lldb/trunk/source/Expression/ClangUserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUserExpression.cpp?rev=174095&r1=174094&r2=174095&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangUserExpression.cpp (original)
+++ lldb/trunk/source/Expression/ClangUserExpression.cpp Thu Jan 31 15:46:01 2013
@@ -759,9 +759,9 @@ ClangUserExpression::Execute (Stream &er
                 
             if ((execution_result == eExecutionInterrupted && unwind_on_error)
                 || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints))
-                error_stream.Printf ("\nThe process has been returned to the state before execution.");
+                error_stream.Printf ("\nThe process has been returned to the state before expression evaluation.");
             else
-                error_stream.Printf ("\nThe process has been left at the point where it was interrupted.");
+                error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
 
             return execution_result;
         }

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=174095&r1=174094&r2=174095&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Thu Jan 31 15:46:01 2013
@@ -323,6 +323,33 @@ Thread::SetSelectedFrameByIndex (uint32_
         return false;
 }
 
+bool
+Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_stream)
+{
+    const bool broadcast = true;
+    bool success = SetSelectedFrameByIndex (frame_idx, broadcast);
+    if (success)
+    {
+        StackFrameSP frame_sp = GetSelectedFrame();
+        if (frame_sp)
+        {
+            bool already_shown = false;
+            SymbolContext frame_sc(frame_sp->GetSymbolContext(eSymbolContextLineEntry));
+            if (GetProcess()->GetTarget().GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
+            {
+                already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
+            }
+
+            bool show_frame_info = true;
+            bool show_source = !already_shown;
+            return frame_sp->GetStatus (output_stream, show_frame_info, show_source);
+        }
+        return false;
+    }
+    else
+        return false;
+}
+
 
 lldb::StopInfoSP
 Thread::GetStopInfo ()
@@ -1165,6 +1192,28 @@ Thread::PlanIsBasePlan (ThreadPlan *plan
        return m_plan_stack[0].get() == plan_ptr;
 }
 
+Error
+Thread::UnwindInnermostExpression()
+{
+    Error error;
+    int stack_size = m_plan_stack.size();
+    
+    // If the input plan is NULL, discard all plans.  Otherwise make sure this plan is in the
+    // stack, and if so discard up to and including it.
+    
+    for (int i = stack_size - 1; i > 0; i--)
+    {
+        if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction)
+        {
+            DiscardThreadPlansUpToPlan(m_plan_stack[i].get());
+            return error;
+        }
+    }
+    error.SetErrorString("No expressions currently active on this thread");
+    return error;
+}
+
+
 ThreadPlan *
 Thread::QueueFundamentalPlan (bool abort_other_plans)
 {
@@ -1478,6 +1527,11 @@ Thread::ReturnFromFrame (lldb::StackFram
     Thread *thread = frame_sp->GetThread().get();
     uint32_t older_frame_idx = frame_sp->GetFrameIndex() + 1;
     StackFrameSP older_frame_sp = thread->GetStackFrameAtIndex(older_frame_idx);
+    if (!older_frame_sp)
+    {
+        return_error.SetErrorString("No older frame to return to.");
+        return return_error;
+    }
     
     if (return_value_sp)
     {    
@@ -1519,20 +1573,29 @@ Thread::ReturnFromFrame (lldb::StackFram
     
     // Now write the return registers for the chosen frame:
     // Note, we can't use ReadAllRegisterValues->WriteAllRegisterValues, since the read & write
-    // cook their data 
-    bool copy_success = thread->GetStackFrameAtIndex(0)->GetRegisterContext()->CopyFromRegisterContext(older_frame_sp->GetRegisterContext());
-    if (copy_success)
-    {
-        thread->DiscardThreadPlans(true);
-        thread->ClearStackFrames();
-        if (broadcast && EventTypeHasListeners(eBroadcastBitStackChanged))
-            BroadcastEvent(eBroadcastBitStackChanged, new ThreadEventData (this->shared_from_this()));
-        return return_error;
+    // cook their data
+    
+    StackFrameSP youngest_frame_sp = thread->GetStackFrameAtIndex(0);
+    if (youngest_frame_sp)
+    {
+        bool copy_success = youngest_frame_sp->GetRegisterContext()->CopyFromRegisterContext(older_frame_sp->GetRegisterContext());
+        if (copy_success)
+        {
+            thread->DiscardThreadPlans(true);
+            thread->ClearStackFrames();
+            if (broadcast && EventTypeHasListeners(eBroadcastBitStackChanged))
+                BroadcastEvent(eBroadcastBitStackChanged, new ThreadEventData (this->shared_from_this()));
+            return return_error;
+        }
+        else
+        {
+            return_error.SetErrorString("Could not reset register values.");
+            return return_error;
+        }
     }
     else
     {
-        return_error.SetErrorString("Could not reset register values.");
-        return return_error;
+        return_error.SetErrorString("Returned past top frame.");
     }
 }
 





More information about the lldb-commits mailing list