Author: jingham
Date: Mon Jul  7 20:07:32 2014
New Revision: 212506

URL: http://llvm.org/viewvc/llvm-project?rev=212506&view=rev
Log:
If a hand-called function is interrupted by hitting a breakpoint, then 
when you continue to finish off the function call, the expression result
will be included as part of the thread stop info.

Added:
    lldb/trunk/test/expression_command/call-function/TestCallStopAndContinue.py
Modified:
    lldb/trunk/include/lldb/Target/StopInfo.h
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/include/lldb/Target/ThreadPlan.h
    lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h
    lldb/trunk/source/Core/Debugger.cpp
    lldb/trunk/source/Expression/ClangUserExpression.cpp
    lldb/trunk/source/Target/StopInfo.cpp
    lldb/trunk/source/Target/Thread.cpp
    lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp
    lldb/trunk/test/expression_command/call-function/main.cpp

Modified: lldb/trunk/include/lldb/Target/StopInfo.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StopInfo.h?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/StopInfo.h (original)
+++ lldb/trunk/include/lldb/Target/StopInfo.h Mon Jul  7 20:07:32 2014
@@ -157,7 +157,9 @@ public:
     CreateStopReasonToTrace (Thread &thread);
 
     static lldb::StopInfoSP
-    CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan, lldb::ValueObjectSP 
return_valobj_sp);
+    CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan,
+                              lldb::ValueObjectSP return_valobj_sp,
+                              lldb::ClangExpressionVariableSP 
expression_variable_sp);
 
     static lldb::StopInfoSP
     CreateStopReasonWithException (Thread &thread, const char *description);
@@ -168,6 +170,9 @@ public:
     static lldb::ValueObjectSP
     GetReturnValueObject (lldb::StopInfoSP &stop_info_sp);
 
+    static lldb::ClangExpressionVariableSP
+    GetExpressionVariable (lldb::StopInfoSP &stop_info_sp);
+
 protected:
     // Perform any action that is associated with this stop.  This is done as 
the
     // Event is removed from the event queue.  ProcessEventData::DoOnRemoval 
does the job.

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Mon Jul  7 20:07:32 2014
@@ -966,6 +966,17 @@ public:
     GetReturnValueObject ();
 
     //------------------------------------------------------------------
+    /// Gets the outer-most expression variable from the completed plans
+    ///
+    /// @return
+    ///     A ClangExpressionVariableSP, either empty if there is no
+    ///     plan completed an expression during the current stop
+    ///     or the expression variable that was made for the completed 
expression.
+    //------------------------------------------------------------------
+    lldb::ClangExpressionVariableSP
+    GetExpressionVariable ();
+
+    //------------------------------------------------------------------
     ///  Checks whether the given plan is in the completed plans for this
     ///  stop.
     ///

Modified: lldb/trunk/include/lldb/Target/ThreadPlan.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlan.h?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlan.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlan.h Mon Jul  7 20:07:32 2014
@@ -501,11 +501,26 @@ public:
         return m_thread.GetStopInfo ();
     }
     
+    // If the completion of the thread plan stepped out of a function, the 
return value of the function
+    // might have been captured by the thread plan (currently only 
ThreadPlanStepOut does this.)
+    // If so, the ReturnValueObject can be retrieved from here.
+    
     virtual lldb::ValueObjectSP
     GetReturnValueObject ()
     {
         return lldb::ValueObjectSP();
     }
+
+    // If the thread plan managing the evaluation of a user expression lives 
longer than the command
+    // that instigated the expression (generally because the expression 
evaluation hit a breakpoint, and
+    // the user regained control at that point) a subsequent process control 
command step/continue/etc. might
+    // complete the expression evaluations.  If so, the result of the 
expression evaluation will show up here.
+    
+    virtual lldb::ClangExpressionVariableSP
+    GetExpressionVariable ()
+    {
+        return lldb::ClangExpressionVariableSP();
+    }
     
     // If a thread plan stores the state before it was run, then you might
     // want to restore the state when it is done.  This will do that job.

Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h Mon Jul  7 
20:07:32 2014
@@ -40,21 +40,35 @@ public:
     GetDescription (Stream *s, lldb::DescriptionLevel level);
     
     virtual void
-    WillPop ()
-    {
-        ThreadPlanCallFunction::WillPop();
-        if (m_user_expression_sp)
-            m_user_expression_sp.reset();
-    }
+    WillPop ();
 
     virtual lldb::StopInfoSP
     GetRealStopInfo();
     
+    virtual bool
+    MischiefManaged ();
+    
+    void
+    TransferExpressionOwnership ()
+    {
+        m_manage_materialization = true;
+    }
+    
+    virtual lldb::ClangExpressionVariableSP
+    GetExpressionVariable ()
+    {
+        return m_result_var_sp;
+    }
+    
 protected:
 private:
     ClangUserExpression::ClangUserExpressionSP m_user_expression_sp;    // 
This is currently just used to ensure the
                                                                         // 
User expression the initiated this ThreadPlan
                                                                         // 
lives as long as the thread plan does.
+    bool m_manage_materialization = false;
+    lldb::ClangExpressionVariableSP m_result_var_sp;                 // If we 
are left to manage the materialization,
+                                                                        // 
then stuff the result expression variable here.
+
     DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallUserExpression);
 };
 

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Mon Jul  7 20:07:32 2014
@@ -111,6 +111,7 @@ g_language_enumerators[] =
     "{, ${thread.info.trace_messages} messages}" \
     "{, stop reason = ${thread.stop-reason}}"\
     "{\\nReturn value: ${thread.return-value}}"\
+    "{\\nCompleted expression: ${thread.completed-expression}}"\
     "\\n"
 
 #define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
@@ -2074,6 +2075,19 @@ FormatPromptRecurse
                                                     var_success = true;
                                                 }
                                             }
+                                        }
+                                        else if (IsToken (var_name_begin, 
"completed-expression}"))
+                                        {
+                                            StopInfoSP stop_info_sp = 
thread->GetStopInfo ();
+                                            if (stop_info_sp && 
stop_info_sp->IsValid())
+                                            {
+                                                ClangExpressionVariableSP 
expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp);
+                                                if (expression_var_sp && 
expression_var_sp->GetValueObject())
+                                                {
+                                                    
expression_var_sp->GetValueObject()->Dump(s);
+                                                    var_success = true;
+                                                }
+                                            }
                                         }
                                         else if (IsToken (var_name_begin, 
"script:"))
                                         {

Modified: lldb/trunk/source/Expression/ClangUserExpression.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUserExpression.cpp?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangUserExpression.cpp (original)
+++ lldb/trunk/source/Expression/ClangUserExpression.cpp Mon Jul  7 20:07:32 
2014
@@ -884,17 +884,19 @@ ClangUserExpression::Execute (Stream &er
             }
 
             args.push_back(struct_address);
-
-            lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression 
(exe_ctx.GetThreadRef(),
-                                                                              
wrapper_address,
-                                                                              
args,
-                                                                              
options,
-                                                                              
shared_ptr_to_me));
+         
+            ThreadPlanCallUserExpression *user_expression_plan = 
+                    new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
+                                                      wrapper_address, 
+                                                      args,
+                                                      options,
+                                                      shared_ptr_to_me);
+            lldb::ThreadPlanSP call_plan_sp(user_expression_plan);
 
             if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
                 return lldb::eExpressionSetupError;
 
-            lldb::addr_t function_stack_pointer = 
static_cast<ThreadPlanCallFunction 
*>(call_plan_sp.get())->GetFunctionStackPointer();
+            lldb::addr_t function_stack_pointer = 
user_expression_plan->GetFunctionStackPointer();
 
             function_stack_bottom = function_stack_pointer - 
Host::GetPageSize();
             function_stack_top = function_stack_pointer;
@@ -935,8 +937,12 @@ ClangUserExpression::Execute (Stream &er
                     || (execution_result == lldb::eExpressionHitBreakpoint && 
options.DoesIgnoreBreakpoints()))
                     error_stream.PutCString ("\nThe process has been returned 
to the state before expression evaluation.");
                 else
+                {
+                    if (execution_result == lldb::eExpressionHitBreakpoint)
+                        user_expression_plan->TransferExpressionOwnership();
                     error_stream.PutCString ("\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/StopInfo.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Mon Jul  7 20:07:32 2014
@@ -997,10 +997,11 @@ class StopInfoThreadPlan : public StopIn
 {
 public:
 
-    StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP 
&return_valobj_sp) :
+    StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP 
&return_valobj_sp, ClangExpressionVariableSP &expression_variable_sp) :
         StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),
         m_plan_sp (plan_sp),
-        m_return_valobj_sp (return_valobj_sp)
+        m_return_valobj_sp (return_valobj_sp),
+        m_expression_variable_sp (expression_variable_sp)
     {
     }
     
@@ -1032,6 +1033,12 @@ public:
         return m_return_valobj_sp;
     }
     
+    ClangExpressionVariableSP
+    GetExpressionVariable()
+    {
+        return m_expression_variable_sp;
+    }
+    
 protected:
     virtual bool
     ShouldStop (Event *event_ptr)
@@ -1045,6 +1052,7 @@ protected:
 private:
     ThreadPlanSP m_plan_sp;
     ValueObjectSP m_return_valobj_sp;
+    ClangExpressionVariableSP m_expression_variable_sp;
 };
     
 class StopInfoExec : public StopInfo
@@ -1123,9 +1131,11 @@ StopInfo::CreateStopReasonToTrace (Threa
 }
 
 StopInfoSP
-StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, ValueObjectSP 
return_valobj_sp)
+StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp,
+                                    ValueObjectSP return_valobj_sp,
+                                    ClangExpressionVariableSP 
expression_variable_sp)
 {
-    return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp));
+    return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp, 
expression_variable_sp));
 }
 
 StopInfoSP
@@ -1151,3 +1161,15 @@ StopInfo::GetReturnValueObject(StopInfoS
     else
         return ValueObjectSP();
 }
+
+ClangExpressionVariableSP
+StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp)
+{
+    if (stop_info_sp && stop_info_sp->GetStopReason() == 
eStopReasonPlanComplete)
+    {
+        StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan 
*>(stop_info_sp.get());
+        return plan_stop_info->GetExpressionVariable();
+    }
+    else
+        return ClangExpressionVariableSP();
+}

Modified: lldb/trunk/source/Target/Thread.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Mon Jul  7 20:07:32 2014
@@ -420,7 +420,7 @@ Thread::GetStopInfo ()
     const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
     if (plan_sp && plan_sp->PlanSucceeded())
     {
-        return StopInfo::CreateStopReasonWithPlan (plan_sp, 
GetReturnValueObject());
+        return StopInfo::CreateStopReasonWithPlan (plan_sp, 
GetReturnValueObject(), GetExpressionVariable());
     }
     else
     {
@@ -1184,6 +1184,22 @@ Thread::GetReturnValueObject ()
     return ValueObjectSP();
 }
 
+ClangExpressionVariableSP
+Thread::GetExpressionVariable ()
+{
+    if (!m_completed_plan_stack.empty())
+    {
+        for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+        {
+            ClangExpressionVariableSP expression_variable_sp;
+            expression_variable_sp = 
m_completed_plan_stack[i]->GetExpressionVariable();
+            if (expression_variable_sp)
+            return expression_variable_sp;
+        }
+    }
+    return ClangExpressionVariableSP();
+}
+
 bool
 Thread::IsThreadPlanDone (ThreadPlan *plan)
 {

Modified: lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp Mon Jul  7 
20:07:32 2014
@@ -56,7 +56,54 @@ ThreadPlanCallUserExpression::~ThreadPla
 void
 ThreadPlanCallUserExpression::GetDescription (Stream *s, 
lldb::DescriptionLevel level)
 {        
-    ThreadPlanCallFunction::GetDescription (s, level);
+    if (level == eDescriptionLevelBrief)
+        s->Printf("User Expression thread plan");
+    else
+        ThreadPlanCallFunction::GetDescription (s, level);
+}
+
+void
+ThreadPlanCallUserExpression::WillPop ()
+{
+    ThreadPlanCallFunction::WillPop();
+    if (m_user_expression_sp)
+        m_user_expression_sp.reset();
+}
+
+bool
+ThreadPlanCallUserExpression::MischiefManaged ()
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+    if (IsPlanComplete())
+    {
+        if (log)
+            log->Printf("ThreadPlanCallFunction(%p): Completed call function 
plan.",
+                        static_cast<void*>(this));
+
+        if (m_manage_materialization && PlanSucceeded() && 
m_user_expression_sp)
+        {
+            lldb::addr_t function_stack_top;
+            lldb::addr_t function_stack_bottom;
+            lldb::addr_t function_stack_pointer = GetFunctionStackPointer();
+
+            function_stack_bottom = function_stack_pointer - 
Host::GetPageSize();
+            function_stack_top = function_stack_pointer;
+            
+            StreamString  error_stream;
+            
+            ExecutionContext exe_ctx(GetThread());
+
+            m_user_expression_sp->FinalizeJITExecution(error_stream, exe_ctx, 
m_result_var_sp, function_stack_bottom, function_stack_top);
+        }
+        
+        ThreadPlan::MischiefManaged ();
+        return true;
+    }
+    else
+    {
+        return false;
+    }
 }
 
 StopInfoSP

Added: 
lldb/trunk/test/expression_command/call-function/TestCallStopAndContinue.py
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/test/expression_command/call-function/TestCallStopAndContinue.py?rev=212506&view=auto
==============================================================================
--- lldb/trunk/test/expression_command/call-function/TestCallStopAndContinue.py 
(added)
+++ lldb/trunk/test/expression_command/call-function/TestCallStopAndContinue.py 
Mon Jul  7 20:07:32 2014
@@ -0,0 +1,59 @@
+"""
+Test calling a function, stopping in the call, continue and gather the result 
on stop.
+"""
+
+import unittest2
+import lldb
+import lldbutil
+from lldbtest import *
+
+class ExprCommandCallStopContinueTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break for main.c.
+        self.line = line_number('main.cpp',
+                                '// Please test these expressions while 
stopped at this line:')
+        self.func_line = line_number ('main.cpp', 
+                                '{ 5, "five" }')
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_with_dsym(self):
+        """Test gathering result from interrupted function call."""
+        self.buildDsym()
+        self.call_function()
+
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test gathering result from interrupted function call."""
+        self.buildDwarf()
+        self.call_function()
+
+    def call_function(self):
+        """Test gathering result from interrupted function call."""
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        # Some versions of GCC encode two locations for the 'return' statement 
in main.cpp
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, 
num_expected_locations=-1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", 
self.func_line, num_expected_locations=-1, loc_exact=True)
+        
+        self.expect("expr -i false -- returnsFive()", error=True,
+            substrs = ['Execution was interrupted, reason: breakpoint'])
+
+        self.runCmd("continue", "Continue completed")
+        self.expect ("thread list",
+                     substrs = ['stop reason = User Expression thread plan',
+                                r'Completed expression: (Five) $0 = (number = 
5, name = "five")'])
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Modified: lldb/trunk/test/expression_command/call-function/main.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/test/expression_command/call-function/main.cpp?rev=212506&r1=212505&r2=212506&view=diff
==============================================================================
--- lldb/trunk/test/expression_command/call-function/main.cpp (original)
+++ lldb/trunk/test/expression_command/call-function/main.cpp Mon Jul  7 
20:07:32 2014
@@ -1,11 +1,25 @@
 #include <iostream>
 #include <string>
 
+struct Five
+{
+    int number;
+    const char *name;
+};
+
+Five
+returnsFive()
+{
+    Five my_five = { 5, "five" };
+    return my_five;
+}
+
 int main (int argc, char const *argv[])
 {
     std::string str = "Hello world";
     std::cout << str << std::endl;
     std::cout << str.c_str() << std::endl;
+    Five main_five = returnsFive();
 #if 0
     print str
     print str.c_str()


_______________________________________________
lldb-commits mailing list
lldb-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to