mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 21:55:39 +08:00
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
This commit is contained in:
@@ -63,6 +63,9 @@ public:
|
||||
|
||||
size_t
|
||||
GetStopDescription (char *dst, size_t dst_len);
|
||||
|
||||
SBValue
|
||||
GetStopReturnValue ();
|
||||
|
||||
lldb::tid_t
|
||||
GetThreadID () const;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
@@ -180,6 +186,11 @@ private:
|
||||
AddressType address_type,
|
||||
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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
//------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
@@ -613,6 +613,16 @@ public:
|
||||
lldb::ThreadPlanSP
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
@@ -82,6 +82,9 @@ public:
|
||||
size_t
|
||||
GetStopDescription (char *dst, size_t dst_len);
|
||||
|
||||
SBValue
|
||||
GetStopReturnValue ();
|
||||
|
||||
lldb::tid_t
|
||||
GetThreadID () const;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}"\
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user