Back up both the register AND the stop state when calling functions.

Set the thread state to "bland" before calling functions so they don't 
  inherit the pending signals and die.

llvm-svn: 123869
This commit is contained in:
Jim Ingham 2011-01-20 02:03:18 +00:00
parent 7d381c48fe
commit 77787033b9
14 changed files with 181 additions and 57 deletions

View File

@ -119,9 +119,16 @@ protected:
// Classes that inherit from StackID can see and modify these
//------------------------------------------------------------------
Thread & m_thread; // The thread corresponding to the stop reason.
const uint32_t m_stop_id; // The process stop ID for which this stop info is valid
uint32_t m_stop_id; // The process stop ID for which this stop info is valid
uint64_t m_value; // A generic value that can be used for things pertaining to this stop info
private:
friend class Thread;
// MakeStopInfoValid is necessary to allow saved stop infos to resurrect themselves as valid. It should
// only need to be called by Thread::RestoreThreadStateFromCheckpoint.
void
MakeStopInfoValid ();
DISALLOW_COPY_AND_ASSIGN (StopInfo);
};

View File

@ -115,6 +115,8 @@ public:
DISALLOW_COPY_AND_ASSIGN (SettingsController);
};
// TODO: You shouldn't just checkpoint the register state alone, so this should get
// moved to protected. To do that ThreadStateCheckpoint needs to be returned as a token...
class RegisterCheckpoint
{
public:
@ -135,6 +137,23 @@ public:
{
}
const RegisterCheckpoint&
operator= (const RegisterCheckpoint &rhs)
{
if (this != &rhs)
{
this->m_stack_id = rhs.m_stack_id;
this->m_data_sp = rhs.m_data_sp;
}
return *this;
}
RegisterCheckpoint (const RegisterCheckpoint &rhs) :
m_stack_id (rhs.m_stack_id),
m_data_sp (rhs.m_data_sp)
{
}
const StackID &
GetStackID()
{
@ -164,6 +183,13 @@ public:
lldb::DataBufferSP m_data_sp;
};
struct ThreadStateCheckpoint
{
uint32_t orig_stop_id; // Dunno if I need this yet but it is an interesting bit of data.
lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you might continue with the wrong signals.
RegisterCheckpoint register_backup; // You need to restore the registers, of course...
};
void
UpdateInstanceName ();
@ -261,6 +287,11 @@ public:
lldb::StopInfoSP
GetStopInfo ();
// This sets the stop reason to a "blank" stop reason, so you can call functions on the thread
// without having the called function run with whatever stop reason you stopped with.
void
SetStopInfoToNothing();
bool
ThreadStoppedForAReason ();
@ -309,12 +340,6 @@ public:
virtual lldb::RegisterContextSP
GetRegisterContext () = 0;
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint) = 0;
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) = 0;
virtual lldb::RegisterContextSP
CreateRegisterContextForFrame (StackFrame *frame) = 0;
@ -609,6 +634,12 @@ public:
void
DumpThreadPlans (Stream *s) const;
virtual bool
CheckpointThreadState (ThreadStateCheckpoint &saved_state);
virtual bool
RestoreThreadStateFromCheckpoint (ThreadStateCheckpoint &saved_state);
void
EnableTracer (bool value, bool single_step);
@ -678,22 +709,35 @@ protected:
ThreadPlan *GetPreviousPlan (ThreadPlan *plan);
// When you implement this method, make sure you don't overwrite the m_actual_stop_info if it claims to be
// valid. The stop info may be a "checkpointed and restored" stop info, so if it is still around it is right
// even if you have not calculated this yourself, or if it disagrees with what you might have calculated.
virtual lldb::StopInfoSP
GetPrivateStopReason () = 0;
typedef std::vector<lldb::ThreadPlanSP> plan_stack;
void
SetStopInfo (const lldb::StopInfoSP &stop_info_sp);
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint) = 0;
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) = 0;
virtual lldb_private::Unwind *
GetUnwinder () = 0;
StackFrameList &
GetStackFrameList ();
void
SetStopInfo (lldb::StopInfoSP stop_info_sp)
struct ThreadState
{
m_actual_stop_info_sp = stop_info_sp;
}
uint32_t orig_stop_id;
lldb::StopInfoSP stop_info_sp;
RegisterCheckpoint register_backup;
};
//------------------------------------------------------------------
// Classes that inherit from Process can see and modify these
@ -713,10 +757,14 @@ protected:
lldb::StateType m_resume_state; ///< The state that indicates what this thread should do when the process is resumed.
std::auto_ptr<lldb_private::Unwind> m_unwinder_ap;
bool m_destroy_called; // This is used internally to make sure derived Thread classes call DestroyThread.
uint32_t m_thread_stop_reason_stop_id; // This is the stop id for which the StopInfo is valid. Can use this so you know that
// the thread's m_actual_stop_info_sp is current and you don't have to fetch it again
private:
//------------------------------------------------------------------
// For Thread only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN (Thread);
};

View File

@ -66,9 +66,21 @@ namespace lldb_private {
// its job, but it doesn't want that sub-plan to be the one that sets the StopInfo, then call SetPrivate on the
// sub-plan when you create it, and the Thread will pass over that plan in reporting the reason for the stop.
//
// When the plan is moved from the plan stack to the completed plan stack its DidPop method is called. You should
// undo anything that affects target state in this method so the target state is clear for new plans.
// But be sure to leave whatever state might be needed to correctly fill the StopInfo.
// Discarded plans:
//
// Your plan may also get discarded, i.e. moved from the plan stack to the "discarded plan stack". This can
// happen, for instance, if the plan is calling a function and the function call crashes and you want
// to unwind the attempt to call. So don't assume that your plan will always successfully stop. Which leads to:
//
// Cleaning up after your plans:
//
// When the plan is moved from the plan stack its WillPop method is always called, no matter why. Once it is
// moved off the plan stack it is done, and won't get a chance to run again. So you should
// undo anything that affects target state in this method. But be sure to leave the plan able to correctly
// fill the StopInfo, however.
// N.B. Don't wait to do clean up target state till the destructor, since that will usually get called when
// the target resumes, and you want to leave the target state correct for new plans in the time between when
// your plan gets unshipped and the next resume.
//
// Over the lifetime of the plan, various methods of the ThreadPlan are then called in response to changes of state in
// the process we are debugging as follows:

View File

@ -103,6 +103,7 @@ private:
lldb::ThreadPlanSP m_subplan_sp;
LanguageRuntime *m_cxx_language_runtime;
LanguageRuntime *m_objc_language_runtime;
Thread::ThreadStateCheckpoint m_stored_thread_state;
DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
};

View File

@ -2370,7 +2370,6 @@
isa = PBXProject;
buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
en,

View File

@ -43,12 +43,6 @@ public:
virtual lldb::RegisterContextSP
GetRegisterContext();
virtual bool
SaveFrameZeroState(RegisterCheckpoint &checkpoint);
virtual bool
RestoreSaveFrameZero(const RegisterCheckpoint &checkpoint);
virtual lldb::RegisterContextSP
CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
@ -61,6 +55,13 @@ public:
void TraceNotify();
void ExitNotify();
protected:
virtual bool
SaveFrameZeroState(RegisterCheckpoint &checkpoint);
virtual bool
RestoreSaveFrameZero(const RegisterCheckpoint &checkpoint);
private:
RegisterContextLinux *

View File

@ -45,12 +45,6 @@ public:
virtual lldb::RegisterContextSP
CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint);
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
virtual void
ClearStackFrames ();
@ -124,6 +118,12 @@ public:
GetPrivateStopReason ();
protected:
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint);
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
bool
GetIdentifierInfo ();

View File

@ -37,8 +37,7 @@ ThreadGDBRemote::ThreadGDBRemote (ProcessGDBRemote &process, lldb::tid_t tid) :
Thread(process, tid),
m_thread_name (),
m_dispatch_queue_name (),
m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
m_thread_stop_reason_stop_id (0)
m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS)
{
// ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD | GDBR_LOG_VERBOSE, "ThreadGDBRemote::ThreadGDBRemote ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());

View File

@ -47,12 +47,6 @@ public:
virtual lldb::RegisterContextSP
CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint);
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
virtual void
ClearStackFrames ();
@ -80,12 +74,6 @@ public:
const char *
GetBasicInfoAsString ();
void
SetStopInfo (const lldb::StopInfoSP &stop_info)
{
m_actual_stop_info_sp = stop_info;
}
void
SetName (const char *name)
{
@ -111,6 +99,12 @@ protected:
friend class ProcessGDBRemote;
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint);
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
void
PrivateSetRegisterValue (uint32_t reg,
StringExtractor &response);
@ -121,7 +115,6 @@ protected:
std::string m_thread_name;
std::string m_dispatch_queue_name;
lldb::addr_t m_thread_dispatch_qaddr;
uint32_t m_thread_stop_reason_stop_id;
//------------------------------------------------------------------
// Member variables.
//------------------------------------------------------------------

View File

@ -2567,6 +2567,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
ExecutionResults return_value = eExecutionSetupError;
if (thread_plan_sp.get() == NULL)
{
errors.Printf("RunThreadPlan called with empty thread plan.");
return lldb::eExecutionSetupError;
}
// Save this value for restoration of the execution context after we run
uint32_t tid = exe_ctx.thread->GetIndexID();
@ -2592,6 +2598,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
Listener listener("ClangFunction temporary listener");
exe_ctx.process->HijackProcessEvents(&listener);
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
{
StreamString s;
thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
log->Printf ("Resuming thread 0x%x to run thread plan \"%s\".", tid, s.GetData());
}
Error resume_error = exe_ctx.process->Resume ();
if (!resume_error.Success())
{
@ -2616,7 +2630,6 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
timeout_ptr = &real_timeout;
}
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
while (1)
{
lldb::EventSP event_sp;

View File

@ -41,6 +41,12 @@ StopInfo::IsValid () const
return m_thread.GetProcess().GetStopID() == m_stop_id;
}
void
StopInfo::MakeStopInfoValid ()
{
m_stop_id = m_thread.GetProcess().GetStopID();
}
//----------------------------------------------------------------------
// StopInfoBreakpoint
//----------------------------------------------------------------------

View File

@ -55,7 +55,8 @@ Thread::Thread (Process &process, lldb::tid_t tid) :
m_resume_signal (LLDB_INVALID_SIGNAL_NUMBER),
m_resume_state (eStateRunning),
m_unwinder_ap (),
m_destroy_called (false)
m_destroy_called (false),
m_thread_stop_reason_stop_id (0)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
@ -95,12 +96,48 @@ Thread::GetStopInfo ()
return GetPrivateStopReason ();
}
void
Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp)
{
m_actual_stop_info_sp = stop_info_sp;
m_thread_stop_reason_stop_id = GetProcess().GetStopID();
}
void
Thread::SetStopInfoToNothing()
{
// Note, we can't just NULL out the private reason, or the native thread implementation will try to
// go calculate it again. For now, just set it to a Unix Signal with an invalid signal number.
SetStopInfo (StopInfo::CreateStopReasonWithSignal (*this, LLDB_INVALID_SIGNAL_NUMBER));
}
bool
Thread::ThreadStoppedForAReason (void)
{
return GetPrivateStopReason () != NULL;
}
bool
Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state)
{
if (!SaveFrameZeroState(saved_state.register_backup))
return false;
saved_state.stop_info_sp = GetStopInfo();
saved_state.orig_stop_id = GetProcess().GetStopID();
return true;
}
bool
Thread::RestoreThreadStateFromCheckpoint (ThreadStateCheckpoint &saved_state)
{
RestoreSaveFrameZero(saved_state.register_backup);
saved_state.stop_info_sp->MakeStopInfoValid();
SetStopInfo(saved_state.stop_info_sp);
return true;
}
StateType
Thread::GetState() const
{

View File

@ -59,6 +59,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
if (!abi)
return;
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
SetBreakpoints();
lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
@ -76,9 +78,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
m_start_addr = context.symbol->GetValue();
lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
if (!thread.SaveFrameZeroState(m_register_backup))
// Checkpoint the thread state so we can restore it later.
if (!thread.CheckpointThreadState (m_stored_thread_state))
{
if (log)
log->Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
return;
}
// Now set the thread state to "no reason" so we don't run with whatever signal was outstanding...
thread.SetStopInfoToNothing();
m_function_addr = function;
lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
@ -91,8 +100,6 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
cmd_arg))
return;
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
{
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
@ -115,24 +122,24 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
ThreadPlanCallFunction::~ThreadPlanCallFunction ()
{
if (m_valid && !IsPlanComplete())
DoTakedown();
}
void
ThreadPlanCallFunction::DoTakedown ()
{
m_thread.RestoreSaveFrameZero(m_register_backup);
m_thread.ClearStackFrames();
SetPlanComplete();
ClearBreakpoints();
if (m_valid && !IsPlanComplete())
{
m_thread.RestoreThreadStateFromCheckpoint(m_stored_thread_state);
SetPlanComplete();
ClearBreakpoints();
}
}
void
ThreadPlanCallFunction::WillPop ()
{
if (m_valid && !IsPlanComplete())
DoTakedown();
DoTakedown();
}
void
@ -278,6 +285,7 @@ ThreadPlanCallFunction::DidPush ()
m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
m_thread.QueueThreadPlan(m_subplan_sp, false);
m_subplan_sp->SetPrivate (true);
#endif
}

View File

@ -66,7 +66,7 @@ UnixSignals::Reset ()
AddSignal (3, "SIGQUIT", "QUIT", false, true, true, "quit");
AddSignal (4, "SIGILL", "ILL", false, true, true, "illegal instruction");
AddSignal (5, "SIGTRAP", "TRAP", true, true, true, "trace trap (not reset when caught)");
AddSignal (6, "SIGABRT", "ABRT", true, true, true, "abort()");
AddSignal (6, "SIGABRT", "ABRT", false, true, true, "abort()");
AddSignal (7, "SIGEMT", "EMT", false, true, true, "pollable event");
AddSignal (8, "SIGFPE", "FPE", false, true, true, "floating point exception");
AddSignal (9, "SIGKILL", "KILL", false, true, true, "kill");