diff options
author | Jim Ingham <jingham@apple.com> | 2011-12-17 01:35:57 +0000 |
---|---|---|
committer | Jim Ingham <jingham@apple.com> | 2011-12-17 01:35:57 +0000 |
commit | 73ca05a2a0c6ce957f9679e76b35ee06dc1559d4 (patch) | |
tree | 20b0f08ba2a6812f994fdea521bf436ea25453ce | |
parent | 903231bc58b27bbd1b74622b013fa277ceaeb16f (diff) | |
download | bcm5719-llvm-73ca05a2a0c6ce957f9679e76b35ee06dc1559d4.tar.gz bcm5719-llvm-73ca05a2a0c6ce957f9679e76b35ee06dc1559d4.zip |
Add the ability to capture the return value in a thread's stop info, and print it
as part of the thread format output.
Currently this is only done for the ThreadPlanStepOut.
Add a convenience API ABI::GetReturnValueObject.
Change the ValueObject::EvaluationPoint to BE an ExecutionContextScope, rather than
trying to hand out one of its subsidiary object's pointers. That way this will always
be good.
llvm-svn: 146806
22 files changed, 316 insertions, 40 deletions
diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h index 57a62e1fafa..fb721fe7e1d 100644 --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -63,6 +63,9 @@ public: size_t GetStopDescription (char *dst, size_t dst_len); + + SBValue + GetStopReturnValue (); lldb::tid_t GetThreadID () const; diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 1472ca3b435..d119a65481c 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -336,7 +336,7 @@ public: }; - class EvaluationPoint + class EvaluationPoint : public ExecutionContextScope { public: @@ -348,9 +348,6 @@ public: ~EvaluationPoint (); - ExecutionContextScope * - GetExecutionContextScope (); - const lldb::TargetSP & GetTargetSP () const { @@ -443,6 +440,20 @@ public: } + // If this EvaluationPoint is created without a target, then we could have it + // hand out a NULL ExecutionContextScope. But then everybody would have to check that before + // calling through it, which is annoying. So instead, we make the EvaluationPoint BE an + // ExecutionContextScope, and it hands out the right things. + virtual Target *CalculateTarget (); + + virtual Process *CalculateProcess (); + + virtual Thread *CalculateThread (); + + virtual StackFrame *CalculateStackFrame (); + + virtual void CalculateExecutionContext (ExecutionContext &exe_ctx); + private: bool SyncWithProcessState () @@ -479,7 +490,7 @@ public: ExecutionContextScope * GetExecutionContextScope () { - return m_update_point.GetExecutionContextScope(); + return &m_update_point; } void diff --git a/lldb/include/lldb/Core/ValueObjectConstResult.h b/lldb/include/lldb/Core/ValueObjectConstResult.h index ebba0619e4f..54c017c1824 100644 --- a/lldb/include/lldb/Core/ValueObjectConstResult.h +++ b/lldb/include/lldb/Core/ValueObjectConstResult.h @@ -59,6 +59,12 @@ public: AddressType address_type, uint8_t addr_byte_size); + static lldb::ValueObjectSP + Create (ExecutionContextScope *exe_scope, + clang::ASTContext *clang_ast, + Value &value, + const ConstString &name); + // When an expression fails to evaluate, we return an error static lldb::ValueObjectSP Create (ExecutionContextScope *exe_scope, @@ -181,6 +187,11 @@ private: uint8_t addr_byte_size); ValueObjectConstResult (ExecutionContextScope *exe_scope, + clang::ASTContext *clang_ast, + const Value &value, + const ConstString &name); + + ValueObjectConstResult (ExecutionContextScope *exe_scope, const Error& error); DISALLOW_COPY_AND_ASSIGN (ValueObjectConstResult); diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 76ad8ba6a22..a98ab2a1915 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -48,6 +48,10 @@ public: virtual bool GetReturnValue (Thread &thread, Value &value) const = 0; + + virtual lldb::ValueObjectSP + GetReturnValueObject (Thread &thread, + ClangASTType &type) const; virtual bool CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) = 0; diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h index 6fedf52831f..6711e2329d8 100644 --- a/lldb/include/lldb/Target/StopInfo.h +++ b/lldb/include/lldb/Target/StopInfo.h @@ -126,10 +126,13 @@ public: CreateStopReasonToTrace (Thread &thread); static lldb::StopInfoSP - CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan); + CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan, lldb::ValueObjectSP return_valobj_sp); static lldb::StopInfoSP CreateStopReasonWithException (Thread &thread, const char *description); + + static lldb::ValueObjectSP + GetReturnValueObject (lldb::StopInfoSP &stop_info_sp); protected: //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 28a8ed4b3a8..ab416ca2ab1 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -604,7 +604,7 @@ private: public: //------------------------------------------------------------------ - /// Gets the inner-most plan that was popped off the plan stack in the + /// Gets the outer-most plan that was popped off the plan stack in the /// most recent stop. Useful for printing the stop reason accurately. /// /// @return @@ -614,6 +614,16 @@ public: GetCompletedPlan (); //------------------------------------------------------------------ + /// Gets the outer-most return value from the completed plans + /// + /// @return + /// A ValueObjectSP, either empty if there is no return value, + /// or containing the return value. + //------------------------------------------------------------------ + lldb::ValueObjectSP + GetReturnValueObject (); + + //------------------------------------------------------------------ /// Checks whether the given plan is in the completed plans for this /// stop. /// diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index d848e54fa40..e31071bc9b9 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -387,6 +387,12 @@ public: return m_thread.GetStopInfo (); } + virtual lldb::ValueObjectSP + GetReturnValueObject () + { + return lldb::ValueObjectSP(); + } + protected: //------------------------------------------------------------------ // Classes that inherit from ThreadPlan can see and modify these diff --git a/lldb/include/lldb/Target/ThreadPlanStepOut.h b/lldb/include/lldb/Target/ThreadPlanStepOut.h index c2273db81e7..b96be5d29a3 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepOut.h +++ b/lldb/include/lldb/Target/ThreadPlanStepOut.h @@ -42,6 +42,11 @@ public: virtual bool WillStop (); virtual bool MischiefManaged (); virtual void DidPush(); + + virtual lldb::ValueObjectSP GetReturnValueObject() + { + return m_return_valobj_sp; + } protected: bool QueueInlinedStepPlan (bool queue_now); @@ -56,6 +61,8 @@ private: bool m_stop_others; lldb::ThreadPlanSP m_step_through_inline_plan_sp; lldb::ThreadPlanSP m_step_out_plan_sp; + Function *m_immediate_step_from_function; + lldb::ValueObjectSP m_return_valobj_sp; friend ThreadPlan * Thread::QueueThreadPlanForStepOut (bool abort_other_plans, @@ -69,6 +76,9 @@ private: // Need an appropriate marker for the current stack so we can tell step out // from step in. + void + CalculateReturnValue(); + DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOut); }; diff --git a/lldb/scripts/Python/interface/SBThread.i b/lldb/scripts/Python/interface/SBThread.i index 67170908954..413d16c1f3f 100644 --- a/lldb/scripts/Python/interface/SBThread.i +++ b/lldb/scripts/Python/interface/SBThread.i @@ -82,6 +82,9 @@ public: size_t GetStopDescription (char *dst, size_t dst_len); + SBValue + GetStopReturnValue (); + lldb::tid_t GetThreadID () const; diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 69924ad6ad0..9ea28772978 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -31,10 +31,10 @@ #include "lldb/API/SBAddress.h" -#include "lldb/API/SBFrame.h" -// DONT THINK THIS IS NECESSARY: #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBDebugger.h" +#include "lldb/API/SBFrame.h" #include "lldb/API/SBProcess.h" +#include "lldb/API/SBValue.h" using namespace lldb; using namespace lldb_private; @@ -316,6 +316,30 @@ SBThread::GetStopDescription (char *dst, size_t dst_len) return 0; } +SBValue +SBThread::GetStopReturnValue () +{ + ValueObjectSP return_valobj_sp; + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex()); + StopInfoSP stop_info_sp = m_opaque_sp->GetStopInfo (); + if (stop_info_sp) + { + return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); + } + } + + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + log->Printf ("SBThread(%p)::GetStopReturnValue () => %s", m_opaque_sp.get(), + return_valobj_sp.get() + ? return_valobj_sp->GetValueAsCString() + : "<no return value>"); + + return SBValue (return_valobj_sp); +} + void SBThread::SetThread (const ThreadSP& lldb_object_sp) { diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index c9f78e2cf1f..daaeea089ca 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -380,7 +380,7 @@ SBValue::CreateValueFromExpression (const char *name, const char* expression) { ValueObjectSP result_valobj_sp; m_opaque_sp->GetUpdatePoint().GetTargetSP()->EvaluateExpression (expression, - m_opaque_sp->GetUpdatePoint().GetExecutionContextScope()->CalculateStackFrame(), + m_opaque_sp->GetExecutionContextScope()->CalculateStackFrame(), eExecutionPolicyOnlyWhenNeeded, true, // unwind on error true, // keep in memory @@ -410,7 +410,7 @@ SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType t lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t))); - ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (m_opaque_sp->GetUpdatePoint().GetExecutionContextScope(), + ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (m_opaque_sp->GetExecutionContextScope(), real_type.m_opaque_sp->GetASTContext(), real_type.m_opaque_sp->GetOpaqueQualType(), ConstString(name), @@ -871,9 +871,9 @@ SBValue::GetThread() SBThread result; if (m_opaque_sp) { - if (m_opaque_sp->GetUpdatePoint().GetExecutionContextScope()) + if (m_opaque_sp->GetExecutionContextScope()) { - result = SBThread(m_opaque_sp->GetUpdatePoint().GetExecutionContextScope()->CalculateThread()->GetSP()); + result = SBThread(m_opaque_sp->GetExecutionContextScope()->CalculateThread()->GetSP()); } } LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); @@ -893,9 +893,9 @@ SBValue::GetFrame() SBFrame result; if (m_opaque_sp) { - if (m_opaque_sp->GetUpdatePoint().GetExecutionContextScope()) + if (m_opaque_sp->GetExecutionContextScope()) { - result.SetFrame (m_opaque_sp->GetUpdatePoint().GetExecutionContextScope()->CalculateStackFrame()->GetSP()); + result.SetFrame (m_opaque_sp->GetExecutionContextScope()->CalculateStackFrame()->GetSP()); } } LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 658222e19d8..d6a9670fe0f 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1246,7 +1246,7 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter & LoadSubCommand ("step-out", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ( interpreter, "thread step-out", - "Finish executing the current function and return to its call site in specified thread (current thread, if none specified).", + "Finish executing the function of the currently selected frame and return to its call site in specified thread (current thread, if none specified).", NULL, eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, eStepTypeOut, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index cd86698661a..e33e9412c91 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1701,6 +1701,23 @@ Debugger::FormatPrompt } } } + else if (::strncmp (var_name_begin, "return-value}", strlen("return-value}")) == 0) + { + StopInfoSP stop_info_sp = thread->GetStopInfo (); + if (stop_info_sp) + { + ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); + if (return_valobj_sp) + { + cstr = return_valobj_sp->GetValueAsCString (); + if (cstr && cstr[0]) + { + s.PutCString(cstr); + var_success = true; + } + } + } + } } } } @@ -2562,6 +2579,7 @@ Debugger::SettingsController::global_settings_table[] = MODULE_WITH_FUNC\ FILE_AND_LINE\ "{, stop reason = ${thread.stop-reason}}"\ + "{, return value = ${thread.return-value}}"\ "\\n" //#define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id}"\ diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 657faf36f85..e1c25becbc7 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -707,7 +707,7 @@ ValueObject::GetPointeeData (DataExtractor& data, AddressType addr_type; lldb::addr_t addr = IsPointerType() ? GetPointerValue(&addr_type) : GetAddressOf(true, &addr_type); - ExecutionContextScope *exe_scope = m_update_point.GetExecutionContextScope(); + ExecutionContextScope *exe_scope = GetExecutionContextScope(); switch (addr_type) @@ -3428,12 +3428,14 @@ ValueObject::CastPointerType (const char *name, TypeSP &type_sp) } ValueObject::EvaluationPoint::EvaluationPoint () : + ExecutionContextScope(), m_thread_id (LLDB_INVALID_UID), m_mod_id () { } ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected): + ExecutionContextScope (), m_needs_update (true), m_first_update (true), m_thread_id (LLDB_INVALID_THREAD_ID), @@ -3500,14 +3502,47 @@ ValueObject::EvaluationPoint::~EvaluationPoint () { } -ExecutionContextScope * -ValueObject::EvaluationPoint::GetExecutionContextScope () +Target * +ValueObject::EvaluationPoint::CalculateTarget () { - // We have to update before giving out the scope, or we could be handing out stale pointers. - ExecutionContextScope *exe_scope; + return m_target_sp.get(); +} + +Process * +ValueObject::EvaluationPoint::CalculateProcess () +{ + return m_process_sp.get(); +} + +Thread * +ValueObject::EvaluationPoint::CalculateThread () +{ + ExecutionContextScope *exe_scope; SyncWithProcessState(exe_scope); - - return exe_scope; + if (exe_scope) + return exe_scope->CalculateThread(); + else + return NULL; +} + +StackFrame * +ValueObject::EvaluationPoint::CalculateStackFrame () +{ + ExecutionContextScope *exe_scope; + SyncWithProcessState(exe_scope); + if (exe_scope) + return exe_scope->CalculateStackFrame(); + else + return NULL; +} + +void +ValueObject::EvaluationPoint::CalculateExecutionContext (ExecutionContext &exe_ctx) +{ + ExecutionContextScope *exe_scope; + SyncWithProcessState(exe_scope); + if (exe_scope) + return exe_scope->CalculateExecutionContext (exe_ctx); } // This function checks the EvaluationPoint against the current process state. If the current @@ -3520,12 +3555,18 @@ ValueObject::EvaluationPoint::GetExecutionContextScope () bool ValueObject::EvaluationPoint::SyncWithProcessState(ExecutionContextScope *&exe_scope) { + + // Start with the target, if it is NULL, then we're obviously not going to get any further: + exe_scope = m_target_sp.get(); + + if (exe_scope == NULL) + return false; + // If we don't have a process nothing can change. if (!m_process_sp) - { - exe_scope = m_target_sp.get(); return false; - } + + exe_scope = m_process_sp.get(); // If our stop id is the current stop ID, nothing has changed: ProcessModID current_mod_id = m_process_sp->GetModID(); @@ -3533,10 +3574,7 @@ ValueObject::EvaluationPoint::SyncWithProcessState(ExecutionContextScope *&exe_s // If the current stop id is 0, either we haven't run yet, or the process state has been cleared. // In either case, we aren't going to be able to sync with the process state. if (current_mod_id.GetStopID() == 0) - { - exe_scope = m_target_sp.get(); return false; - } bool changed; @@ -3555,10 +3593,10 @@ ValueObject::EvaluationPoint::SyncWithProcessState(ExecutionContextScope *&exe_s changed = true; } } - exe_scope = m_process_sp.get(); - // Something has changed, so we will return true. Now make sure the thread & frame still exist, and if either - // doesn't, mark ourselves as invalid. + // Now re-look up the thread and frame in case the underlying objects have gone away & been recreated. + // That way we'll be sure to return a valid exe_scope. + // If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid. if (m_thread_id != LLDB_INVALID_THREAD_ID) { diff --git a/lldb/source/Core/ValueObjectConstResult.cpp b/lldb/source/Core/ValueObjectConstResult.cpp index fa1503f3217..950d33405af 100644 --- a/lldb/source/Core/ValueObjectConstResult.cpp +++ b/lldb/source/Core/ValueObjectConstResult.cpp @@ -130,6 +130,15 @@ ValueObjectConstResult::Create address))->GetSP(); } +ValueObjectSP +ValueObjectConstResult::Create (ExecutionContextScope *exe_scope, + clang::ASTContext *clang_ast, + Value &value, + const ConstString &name) +{ + return (new ValueObjectConstResult (exe_scope, clang_ast, value, name))->GetSP(); +} + ValueObjectConstResult::ValueObjectConstResult ( ExecutionContextScope *exe_scope, @@ -239,6 +248,21 @@ ValueObjectConstResult::ValueObjectConstResult ( SetIsConstant (); } +ValueObjectConstResult::ValueObjectConstResult ( + ExecutionContextScope *exe_scope, + clang::ASTContext *clang_ast, + const Value &value, + const ConstString &name) : + ValueObject (exe_scope), + m_type_name (), + m_byte_size (0), + m_clang_ast (clang_ast), + m_impl(this) +{ + m_value = value; + m_value.GetData(m_data); +} + ValueObjectConstResult::~ValueObjectConstResult() { } diff --git a/lldb/source/Core/ValueObjectConstResultImpl.cpp b/lldb/source/Core/ValueObjectConstResultImpl.cpp index afe050291b0..31646b4ca0b 100644 --- a/lldb/source/Core/ValueObjectConstResultImpl.cpp +++ b/lldb/source/Core/ValueObjectConstResultImpl.cpp @@ -185,7 +185,7 @@ ValueObjectConstResultImpl::AddressOf (Error &error) std::string new_name("&"); new_name.append(m_impl_backend->GetName().AsCString("")); - m_address_of_backend = ValueObjectConstResult::Create(m_impl_backend->GetUpdatePoint().GetExecutionContextScope(), + m_address_of_backend = ValueObjectConstResult::Create(m_impl_backend->GetExecutionContextScope(), type.GetASTContext(), type.GetPointerType(), ConstString(new_name.c_str()), diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 4119c6e5273..1094dc1e34c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -309,7 +309,7 @@ AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value, // If the class address didn't point into the binary, or // it points into the right section but there wasn't a symbol // there, try to look it up by calling the class method in the target. - ExecutionContextScope *exe_scope = in_value.GetUpdatePoint().GetExecutionContextScope(); + ExecutionContextScope *exe_scope = in_value.GetExecutionContextScope(); Thread *thread_to_use; if (exe_scope) thread_to_use = exe_scope->CalculateThread(); diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index fc55ccac6fc..f3a5404aa10 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -9,6 +9,10 @@ #include "lldb/Target/ABI.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/ClangASTType.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; @@ -97,3 +101,28 @@ ABI::GetRegisterInfoByKind (RegisterKind reg_kind, uint32_t reg_num, RegisterInf } return false; } + +ValueObjectSP +ABI::GetReturnValueObject (Thread &thread, + ClangASTType &ast_type) const +{ + if (!ast_type.IsValid()) + return ValueObjectSP(); + + Value ret_value; + ret_value.SetContext(Value::eContextTypeClangType, + ast_type.GetOpaqueQualType()); + if (GetReturnValue (thread, ret_value)) + { + return ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), + ast_type.GetASTContext(), + ret_value, + ConstString("FunctionReturn")); + + } + else + return ValueObjectSP(); +} + + diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 4e089d42c05..f90968fdad7 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -722,9 +722,10 @@ class StopInfoThreadPlan : public StopInfo { public: - StopInfoThreadPlan (ThreadPlanSP &plan_sp) : + StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp) : StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID), - m_plan_sp (plan_sp) + m_plan_sp (plan_sp), + m_return_valobj_sp (return_valobj_sp) { } @@ -749,9 +750,16 @@ public: } return m_description.c_str(); } + + ValueObjectSP + GetReturnValueObject() + { + return m_return_valobj_sp; + } private: ThreadPlanSP m_plan_sp; + ValueObjectSP m_return_valobj_sp; }; } // namespace lldb_private @@ -786,9 +794,9 @@ StopInfo::CreateStopReasonToTrace (Thread &thread) } StopInfoSP -StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp) +StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp) { - return StopInfoSP (new StopInfoThreadPlan (plan_sp)); + return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp)); } StopInfoSP @@ -796,3 +804,15 @@ StopInfo::CreateStopReasonWithException (Thread &thread, const char *description { return StopInfoSP (new StopInfoException (thread, description)); } + +ValueObjectSP +StopInfo::GetReturnValueObject(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->GetReturnValueObject(); + } + else + return ValueObjectSP(); +} diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index e4415b7b73e..6fe6ec7df5b 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -95,7 +95,7 @@ Thread::GetStopInfo () { ThreadPlanSP plan_sp (GetCompletedPlan()); if (plan_sp) - return StopInfo::CreateStopReasonWithPlan (plan_sp); + return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject()); else { if (m_actual_stop_info_sp @@ -551,6 +551,22 @@ Thread::GetCompletedPlan () return empty_plan_sp; } +ValueObjectSP +Thread::GetReturnValueObject () +{ + if (!m_completed_plan_stack.empty()) + { + for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) + { + ValueObjectSP return_valobj_sp; + return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject(); + if (return_valobj_sp) + return return_valobj_sp; + } + } + return ValueObjectSP(); +} + bool Thread::IsThreadPlanDone (ThreadPlan *plan) { diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index d78411ee936..485db25dd8d 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -16,6 +16,8 @@ #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/lldb-private-log.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" @@ -47,7 +49,8 @@ ThreadPlanStepOut::ThreadPlanStepOut m_first_insn (first_insn), m_stop_others (stop_others), m_step_through_inline_plan_sp(), - m_step_out_plan_sp () + m_step_out_plan_sp (), + m_immediate_step_from_function(NULL) { m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); @@ -88,6 +91,15 @@ ThreadPlanStepOut::ThreadPlanStepOut return_bp->SetThreadID(m_thread.GetID()); m_return_bp_id = return_bp->GetID(); } + + if (immediate_return_from_sp) + { + const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction); + if (sc.function) + { + m_immediate_step_from_function = sc.function; + } + } } } @@ -152,6 +164,7 @@ ThreadPlanStepOut::PlanExplainsStop () if (m_step_out_plan_sp->MischiefManaged()) { // If this one is done, then we are all done. + CalculateReturnValue(); SetPlanComplete(); return true; } @@ -183,7 +196,10 @@ ThreadPlanStepOut::PlanExplainsStop () { const uint32_t num_frames = m_thread.GetStackFrameCount(); if (m_stack_depth > num_frames) + { + CalculateReturnValue(); SetPlanComplete(); + } // If there was only one owner, then we're done. But if we also hit some // user breakpoint on our way out, we should mark ourselves as done, but @@ -217,6 +233,7 @@ ThreadPlanStepOut::ShouldStop (Event *event_ptr) } else if (m_stack_depth > m_thread.GetStackFrameCount()) { + CalculateReturnValue(); SetPlanComplete(); return true; } @@ -233,6 +250,7 @@ ThreadPlanStepOut::ShouldStop (Event *event_ptr) } else { + CalculateReturnValue(); SetPlanComplete (); return true; } @@ -244,6 +262,10 @@ ThreadPlanStepOut::ShouldStop (Event *event_ptr) { if (m_step_through_inline_plan_sp->MischiefManaged()) { + // We don't calculate the return value here because we don't know how to. + // But in case we had a return value sitting around from our process in + // getting here, let's clear it out. + m_return_valobj_sp.reset(); SetPlanComplete(); return true; } @@ -387,3 +409,26 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now) return false; } + +void +ThreadPlanStepOut::CalculateReturnValue () +{ + if (m_return_valobj_sp) + return; + + if (m_immediate_step_from_function != NULL) + { + Type *return_type = m_immediate_step_from_function->GetType(); + lldb::clang_type_t return_clang_type = m_immediate_step_from_function->GetReturnClangType(); + if (return_type && return_clang_type) + { + ClangASTType ast_type (return_type->GetClangAST(), return_clang_type); + + lldb::ABISP abi_sp = m_thread.GetProcess().GetABI(); + if (abi_sp) + { + m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, ast_type); + } + } + } +} diff --git a/lldb/www/formats.html b/lldb/www/formats.html index ff5dc8dd396..7c81359cf3c 100755 --- a/lldb/www/formats.html +++ b/lldb/www/formats.html @@ -97,6 +97,7 @@ <tr valign=top><td><b>thread.name</b></td><td>The name of the thread if the target OS supports naming threads</td></tr>
<tr valign=top><td><b>thread.queue</b></td><td>The queue name of the thread if the target OS supports dispatch queues</td></tr>
<tr valign=top><td><b>thread.stop-reason</b></td><td>A textual reason each thread stopped</td></tr>
+ <tr valign=top><td><b>thread.return-value</b></td><td>The return value of the latest step operation (currently only for step-out.)</td></tr>
<tr valign=top><td><b>target.arch</b></td><td>The architecture of the current target</td></tr>
</table>
|