forked from OSchip/llvm-project
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:
parent
7d381c48fe
commit
77787033b9
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -2370,7 +2370,6 @@
|
|||
isa = PBXProject;
|
||||
buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
en,
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue