diff options
author | Jim Ingham <jingham@apple.com> | 2012-09-14 02:14:15 +0000 |
---|---|---|
committer | Jim Ingham <jingham@apple.com> | 2012-09-14 02:14:15 +0000 |
commit | cb640dd8a0318b172c62859b45631353edad2811 (patch) | |
tree | a1b6a82d0c88dd90daa411787c91980c690e8f1b /lldb/source | |
parent | 00755e955469079e0a078bd5ce81e374ee419933 (diff) | |
download | bcm5719-llvm-cb640dd8a0318b172c62859b45631353edad2811.tar.gz bcm5719-llvm-cb640dd8a0318b172c62859b45631353edad2811.zip |
Make the unwinding of the stack part of "thread return" work, and add the thread return command.
llvm-svn: 163867
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/API/SBThread.cpp | 6 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectThread.cpp | 103 | ||||
-rw-r--r-- | lldb/source/Target/RegisterContext.cpp | 41 | ||||
-rw-r--r-- | lldb/source/Target/Thread.cpp | 21 |
4 files changed, 160 insertions, 11 deletions
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 74df380e357..223568a74f1 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -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; diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 93ecf36fdd2..f7f070e0e5c 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -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 ( diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp index 19e754d7edd..0d89db724ab 100644 --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -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 { diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 72c5261485a..c75b9c94349 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -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; - } } |