forked from OSchip/llvm-project
Make the unwinding of the stack part of "thread return" work, and add the thread return command.
llvm-svn: 163867
This commit is contained in:
parent
00755e9554
commit
cb640dd8a0
|
@ -103,7 +103,7 @@ public:
|
|||
RunToAddress (lldb::addr_t addr);
|
||||
|
||||
SBError
|
||||
ReturnToFrame (SBFrame &frame, SBValue &return_value);
|
||||
ReturnFromFrame (SBFrame &frame, SBValue &return_value);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// LLDB currently supports process centric debugging which means when any
|
||||
|
|
|
@ -72,6 +72,9 @@ public:
|
|||
virtual bool
|
||||
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
|
||||
|
||||
bool
|
||||
CopyFromRegisterContext (lldb::RegisterContextSP context);
|
||||
|
||||
virtual uint32_t
|
||||
ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) = 0;
|
||||
|
||||
|
|
|
@ -286,10 +286,10 @@ public:
|
|||
}
|
||||
|
||||
Error
|
||||
ReturnToFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp);
|
||||
ReturnFromFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp);
|
||||
|
||||
Error
|
||||
ReturnToFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp);
|
||||
ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp);
|
||||
|
||||
virtual lldb::StackFrameSP
|
||||
GetFrameWithStackID (const StackID &stack_id)
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
RunToAddress (lldb::addr_t addr);
|
||||
|
||||
SBError
|
||||
ReturnToFrame (SBFrame &frame, SBValue &return_value);
|
||||
ReturnFromFrame (SBFrame &frame, SBValue &return_value);
|
||||
|
||||
%feature("docstring", "
|
||||
//--------------------------------------------------------------------------
|
||||
|
|
|
@ -878,7 +878,7 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
|
|||
}
|
||||
|
||||
SBError
|
||||
SBThread::ReturnToFrame (SBFrame &frame, SBValue &return_value)
|
||||
SBThread::ReturnFromFrame (SBFrame &frame, SBValue &return_value)
|
||||
{
|
||||
SBError sb_error;
|
||||
|
||||
|
@ -889,12 +889,12 @@ SBThread::ReturnToFrame (SBFrame &frame, SBValue &return_value)
|
|||
|
||||
|
||||
if (log)
|
||||
log->Printf ("SBThread(%p)::ReturnToFrame (frame=%d)", exe_ctx.GetThreadPtr(), frame.GetFrameID());
|
||||
log->Printf ("SBThread(%p)::ReturnFromFrame (frame=%d)", exe_ctx.GetThreadPtr(), frame.GetFrameID());
|
||||
|
||||
if (exe_ctx.HasThreadScope())
|
||||
{
|
||||
Thread *thread = exe_ctx.GetThreadPtr();
|
||||
sb_error.SetError (thread->ReturnToFrame(frame.GetFrameSP(), return_value.GetSP()));
|
||||
sb_error.SetError (thread->ReturnFromFrame(frame.GetFrameSP(), return_value.GetSP()));
|
||||
}
|
||||
|
||||
return sb_error;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Core/SourceManager.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
|
@ -1244,6 +1245,107 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
class CommandObjectThreadReturn : public CommandObjectRaw
|
||||
{
|
||||
public:
|
||||
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.",
|
||||
"thread return",
|
||||
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
|
||||
{
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData expression_arg;
|
||||
|
||||
// Define the first (and only) variant of this arg.
|
||||
expression_arg.arg_type = eArgTypeExpression;
|
||||
expression_arg.arg_repetition = eArgRepeatPlain;
|
||||
|
||||
// There is only one variant this argument could be; put it into the argument entry.
|
||||
arg.push_back (expression_arg);
|
||||
|
||||
// Push the data for the first argument into the m_arguments vector.
|
||||
m_arguments.push_back (arg);
|
||||
|
||||
|
||||
}
|
||||
|
||||
~CommandObjectThreadReturn()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool DoExecute
|
||||
(
|
||||
const char *command,
|
||||
CommandReturnObject &result
|
||||
)
|
||||
{
|
||||
// If there is a command string, pass it to the expression parser:
|
||||
ExecutionContext exe_ctx = m_interpreter.GetExecutionContext();
|
||||
if (!(exe_ctx.HasProcessScope() && exe_ctx.HasThreadScope() && exe_ctx.HasFrameScope()))
|
||||
{
|
||||
result.AppendError("Must have selected process, thread and frame for thread return.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
ValueObjectSP return_valobj_sp;
|
||||
|
||||
StackFrameSP frame_sp = exe_ctx.GetFrameSP();
|
||||
uint32_t frame_idx = frame_sp->GetFrameIndex();
|
||||
|
||||
if (frame_sp->IsInlined())
|
||||
{
|
||||
result.AppendError("Don't know how to return from inlined frames.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command && command[0] != '\0')
|
||||
{
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
Target::EvaluateExpressionOptions options;
|
||||
|
||||
options.SetUnwindOnError(true);
|
||||
options.SetUseDynamic(eNoDynamicValues);
|
||||
|
||||
ExecutionResults exe_results = eExecutionSetupError;
|
||||
exe_results = target->EvaluateExpression (command,
|
||||
frame_sp.get(),
|
||||
return_valobj_sp,
|
||||
options);
|
||||
if (exe_results != eExecutionCompleted)
|
||||
{
|
||||
if (return_valobj_sp)
|
||||
result.AppendErrorWithFormat("Error evaluating result expression: %s", return_valobj_sp->GetError().AsCString());
|
||||
else
|
||||
result.AppendErrorWithFormat("Unknown error evaluating result expression.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Error error;
|
||||
ThreadSP thread_sp = exe_ctx.GetThreadSP();
|
||||
error = thread_sp->ReturnFromFrame (frame_sp, return_valobj_sp);
|
||||
if (!error.Success())
|
||||
{
|
||||
result.AppendErrorWithFormat("Error returning from frame %d of thread %d: %s.", frame_idx, thread_sp->GetIndexID(), error.AsCString());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_sp->GetStatus(result.GetOutputStream(), 0, 1, 1);
|
||||
result.SetStatus (eReturnStatusSuccessFinishResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectMultiwordThread
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -1257,6 +1359,7 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &
|
|||
LoadSubCommand ("backtrace", CommandObjectSP (new CommandObjectThreadBacktrace (interpreter)));
|
||||
LoadSubCommand ("continue", CommandObjectSP (new CommandObjectThreadContinue (interpreter)));
|
||||
LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadList (interpreter)));
|
||||
LoadSubCommand ("return", CommandObjectSP (new CommandObjectThreadReturn (interpreter)));
|
||||
LoadSubCommand ("select", CommandObjectSP (new CommandObjectThreadSelect (interpreter)));
|
||||
LoadSubCommand ("until", CommandObjectSP (new CommandObjectThreadUntil (interpreter)));
|
||||
LoadSubCommand ("step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
|
||||
|
|
|
@ -196,6 +196,47 @@ RegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContext::CopyFromRegisterContext (lldb::RegisterContextSP context)
|
||||
{
|
||||
uint32_t num_register_sets = context->GetRegisterSetCount();
|
||||
// We don't know that two threads have the same register context, so require the threads to be the same.
|
||||
if (context->GetThreadID() != GetThreadID())
|
||||
return false;
|
||||
|
||||
if (num_register_sets != GetRegisterSetCount())
|
||||
return false;
|
||||
|
||||
RegisterContextSP frame_zero_context = m_thread.GetRegisterContext();
|
||||
|
||||
for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx)
|
||||
{
|
||||
const RegisterSet * const reg_set = GetRegisterSet(set_idx);
|
||||
|
||||
const uint32_t num_registers = reg_set->num_registers;
|
||||
for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
|
||||
{
|
||||
const uint32_t reg = reg_set->registers[reg_idx];
|
||||
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
|
||||
if (!reg_info || reg_info->value_regs)
|
||||
continue;
|
||||
RegisterValue reg_value;
|
||||
|
||||
// If we can reconstruct the register from the frame we are copying from, then do so, otherwise
|
||||
// use the value from frame 0.
|
||||
if (context->ReadRegister(reg_info, reg_value))
|
||||
{
|
||||
WriteRegister(reg_info, reg_value);
|
||||
}
|
||||
else if (frame_zero_context->ReadRegister(reg_info, reg_value))
|
||||
{
|
||||
WriteRegister(reg_info, reg_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
lldb::tid_t
|
||||
RegisterContext::GetThreadID() const
|
||||
{
|
||||
|
|
|
@ -1273,7 +1273,7 @@ Thread::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
|
|||
|
||||
|
||||
Error
|
||||
Thread::ReturnToFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp)
|
||||
Thread::ReturnFromFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp)
|
||||
{
|
||||
StackFrameSP frame_sp = GetStackFrameAtIndex (frame_idx);
|
||||
Error return_error;
|
||||
|
@ -1283,11 +1283,11 @@ Thread::ReturnToFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_v
|
|||
return_error.SetErrorStringWithFormat("Could not find frame with index %d in thread 0x%llx.", frame_idx, GetID());
|
||||
}
|
||||
|
||||
return ReturnToFrame(frame_sp, return_value_sp);
|
||||
return ReturnFromFrame(frame_sp, return_value_sp);
|
||||
}
|
||||
|
||||
Error
|
||||
Thread::ReturnToFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp)
|
||||
Thread::ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp)
|
||||
{
|
||||
Error return_error;
|
||||
|
||||
|
@ -1298,32 +1298,37 @@ Thread::ReturnToFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_v
|
|||
}
|
||||
|
||||
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 (return_value_sp)
|
||||
{
|
||||
// TODO: coerce the return_value_sp to the type of the function in frame_sp.
|
||||
|
||||
lldb::ABISP abi = thread->GetProcess()->GetABI();
|
||||
if (!abi)
|
||||
{
|
||||
return_error.SetErrorString("Could not find ABI to set return value.");
|
||||
}
|
||||
return_error = abi->SetReturnValueObject(frame_sp, return_value_sp);
|
||||
return_error = abi->SetReturnValueObject(older_frame_sp, return_value_sp);
|
||||
if (!return_error.Success())
|
||||
return return_error;
|
||||
}
|
||||
|
||||
// Now write the return registers for the chosen frame:
|
||||
lldb::DataBufferSP register_values_sp;
|
||||
frame_sp->GetRegisterContext()->ReadAllRegisterValues (register_values_sp);
|
||||
if (thread->ResetFrameZeroRegisters(register_values_sp))
|
||||
// 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();
|
||||
return return_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_error.SetErrorString("Could not reset register values.");
|
||||
return return_error;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue