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:
Jim Ingham 2012-09-14 02:14:15 +00:00
parent 00755e9554
commit cb640dd8a0
8 changed files with 167 additions and 15 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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", "
//--------------------------------------------------------------------------

View File

@ -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;

View File

@ -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 (

View File

@ -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
{

View File

@ -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;
}
}