2013-08-23 13:46:38 -04:00
//===-- Thread.cpp ----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/lldb-python.h"
# include "lldb/lldb-private-log.h"
# include "lldb/Breakpoint/BreakpointLocation.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Core/Log.h"
2015-02-08 20:44:09 -05:00
# include "lldb/Core/FormatEntity.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/State.h"
# include "lldb/Core/Stream.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Core/RegularExpression.h"
# include "lldb/Host/Host.h"
2014-02-18 11:23:10 -05:00
# include "lldb/Interpreter/OptionValueFileSpecList.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Symbol/Function.h"
# include "lldb/Target/DynamicLoader.h"
# include "lldb/Target/ExecutionContext.h"
# include "lldb/Target/ObjCLanguageRuntime.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/RegisterContext.h"
# include "lldb/Target/StopInfo.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Target/SystemRuntime.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/ThreadPlan.h"
# include "lldb/Target/ThreadPlanCallFunction.h"
# include "lldb/Target/ThreadPlanBase.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Target/ThreadPlanPython.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/ThreadPlanStepInstruction.h"
# include "lldb/Target/ThreadPlanStepOut.h"
# include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
# include "lldb/Target/ThreadPlanStepThrough.h"
# include "lldb/Target/ThreadPlanStepInRange.h"
# include "lldb/Target/ThreadPlanStepOverRange.h"
# include "lldb/Target/ThreadPlanRunToAddress.h"
# include "lldb/Target/ThreadPlanStepUntil.h"
# include "lldb/Target/ThreadSpec.h"
# include "lldb/Target/Unwind.h"
# include "Plugins/Process/Utility/UnwindLLDB.h"
2015-02-06 16:38:51 -05:00
# include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h"
2013-08-23 13:46:38 -04:00
using namespace lldb ;
using namespace lldb_private ;
const ThreadPropertiesSP &
Thread : : GetGlobalProperties ( )
{
static ThreadPropertiesSP g_settings_sp ;
if ( ! g_settings_sp )
g_settings_sp . reset ( new ThreadProperties ( true ) ) ;
return g_settings_sp ;
}
static PropertyDefinition
g_properties [ ] =
{
2014-11-25 16:00:58 -05:00
{ " step-in-avoid-nodebug " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " If true, step-in will not stop in functions with no debug information. " } ,
{ " step-out-avoid-nodebug " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " If true, when step-in/step-out/step-over leave the current frame, they will continue to step out till they come to a function with "
" debug information. Passing a frame argument to step-out will override this option. " } ,
2015-02-08 20:44:09 -05:00
{ " step-avoid-regexp " , OptionValue : : eTypeRegex , true , 0 , " ^std:: " , NULL , " A regular expression defining functions step-in won't stop in. " } ,
{ " step-avoid-libraries " , OptionValue : : eTypeFileSpecList , true , 0 , NULL , NULL , " A list of libraries that source stepping won't stop in. " } ,
2013-08-23 13:46:38 -04:00
{ " trace-thread " , OptionValue : : eTypeBoolean , false , false , NULL , NULL , " If true, this thread will single-step and log execution. " } ,
{ NULL , OptionValue : : eTypeInvalid , false , 0 , NULL , NULL , NULL }
} ;
enum {
2014-11-25 16:00:58 -05:00
ePropertyStepInAvoidsNoDebug ,
ePropertyStepOutAvoidsNoDebug ,
2013-08-23 13:46:38 -04:00
ePropertyStepAvoidRegex ,
2014-02-18 11:23:10 -05:00
ePropertyStepAvoidLibraries ,
2013-08-23 13:46:38 -04:00
ePropertyEnableThreadTrace
} ;
class ThreadOptionValueProperties : public OptionValueProperties
{
public :
ThreadOptionValueProperties ( const ConstString & name ) :
OptionValueProperties ( name )
{
}
// This constructor is used when creating ThreadOptionValueProperties when it
// is part of a new lldb_private::Thread instance. It will copy all current
// global property values as needed
ThreadOptionValueProperties ( ThreadProperties * global_properties ) :
OptionValueProperties ( * global_properties - > GetValueProperties ( ) )
{
}
virtual const Property *
GetPropertyAtIndex ( const ExecutionContext * exe_ctx , bool will_modify , uint32_t idx ) const
{
2014-11-25 16:00:58 -05:00
// When getting the value for a key from the thread options, we will always
2013-08-23 13:46:38 -04:00
// try and grab the setting from the current thread if there is one. Else we just
// use the one from this instance.
if ( exe_ctx )
{
Thread * thread = exe_ctx - > GetThreadPtr ( ) ;
if ( thread )
{
ThreadOptionValueProperties * instance_properties = static_cast < ThreadOptionValueProperties * > ( thread - > GetValueProperties ( ) . get ( ) ) ;
if ( this ! = instance_properties )
return instance_properties - > ProtectedGetPropertyAtIndex ( idx ) ;
}
}
return ProtectedGetPropertyAtIndex ( idx ) ;
}
} ;
ThreadProperties : : ThreadProperties ( bool is_global ) :
Properties ( )
{
if ( is_global )
{
m_collection_sp . reset ( new ThreadOptionValueProperties ( ConstString ( " thread " ) ) ) ;
m_collection_sp - > Initialize ( g_properties ) ;
}
else
m_collection_sp . reset ( new ThreadOptionValueProperties ( Thread : : GetGlobalProperties ( ) . get ( ) ) ) ;
}
ThreadProperties : : ~ ThreadProperties ( )
{
}
const RegularExpression *
ThreadProperties : : GetSymbolsToAvoidRegexp ( )
{
const uint32_t idx = ePropertyStepAvoidRegex ;
return m_collection_sp - > GetPropertyAtIndexAsOptionValueRegex ( NULL , idx ) ;
}
2014-02-18 11:23:10 -05:00
FileSpecList &
ThreadProperties : : GetLibrariesToAvoid ( ) const
{
const uint32_t idx = ePropertyStepAvoidLibraries ;
OptionValueFileSpecList * option_value = m_collection_sp - > GetPropertyAtIndexAsOptionValueFileSpecList ( NULL , false , idx ) ;
assert ( option_value ) ;
return option_value - > GetCurrentValue ( ) ;
}
2013-08-23 13:46:38 -04:00
bool
ThreadProperties : : GetTraceEnabledState ( ) const
{
const uint32_t idx = ePropertyEnableThreadTrace ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
2014-11-25 16:00:58 -05:00
bool
ThreadProperties : : GetStepInAvoidsNoDebug ( ) const
{
const uint32_t idx = ePropertyStepInAvoidsNoDebug ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
bool
ThreadProperties : : GetStepOutAvoidsNoDebug ( ) const
{
const uint32_t idx = ePropertyStepOutAvoidsNoDebug ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
2013-08-23 13:46:38 -04:00
//------------------------------------------------------------------
// Thread Event Data
//------------------------------------------------------------------
const ConstString &
Thread : : ThreadEventData : : GetFlavorString ( )
{
static ConstString g_flavor ( " Thread::ThreadEventData " ) ;
return g_flavor ;
}
Thread : : ThreadEventData : : ThreadEventData ( const lldb : : ThreadSP thread_sp ) :
m_thread_sp ( thread_sp ) ,
m_stack_id ( )
{
}
Thread : : ThreadEventData : : ThreadEventData ( const lldb : : ThreadSP thread_sp , const StackID & stack_id ) :
m_thread_sp ( thread_sp ) ,
m_stack_id ( stack_id )
{
}
Thread : : ThreadEventData : : ThreadEventData ( ) :
m_thread_sp ( ) ,
m_stack_id ( )
{
}
Thread : : ThreadEventData : : ~ ThreadEventData ( )
{
}
void
Thread : : ThreadEventData : : Dump ( Stream * s ) const
{
}
const Thread : : ThreadEventData *
Thread : : ThreadEventData : : GetEventDataFromEvent ( const Event * event_ptr )
{
if ( event_ptr )
{
const EventData * event_data = event_ptr - > GetData ( ) ;
if ( event_data & & event_data - > GetFlavor ( ) = = ThreadEventData : : GetFlavorString ( ) )
return static_cast < const ThreadEventData * > ( event_ptr - > GetData ( ) ) ;
}
return NULL ;
}
ThreadSP
Thread : : ThreadEventData : : GetThreadFromEvent ( const Event * event_ptr )
{
ThreadSP thread_sp ;
const ThreadEventData * event_data = GetEventDataFromEvent ( event_ptr ) ;
if ( event_data )
thread_sp = event_data - > GetThread ( ) ;
return thread_sp ;
}
StackID
Thread : : ThreadEventData : : GetStackIDFromEvent ( const Event * event_ptr )
{
StackID stack_id ;
const ThreadEventData * event_data = GetEventDataFromEvent ( event_ptr ) ;
if ( event_data )
stack_id = event_data - > GetStackID ( ) ;
return stack_id ;
}
StackFrameSP
Thread : : ThreadEventData : : GetStackFrameFromEvent ( const Event * event_ptr )
{
const ThreadEventData * event_data = GetEventDataFromEvent ( event_ptr ) ;
StackFrameSP frame_sp ;
if ( event_data )
{
ThreadSP thread_sp = event_data - > GetThread ( ) ;
if ( thread_sp )
{
frame_sp = thread_sp - > GetStackFrameList ( ) - > GetFrameWithStackID ( event_data - > GetStackID ( ) ) ;
}
}
return frame_sp ;
}
//------------------------------------------------------------------
// Thread class
//------------------------------------------------------------------
ConstString &
Thread : : GetStaticBroadcasterClass ( )
{
static ConstString class_name ( " lldb.thread " ) ;
return class_name ;
}
2014-11-25 16:00:58 -05:00
Thread : : Thread ( Process & process , lldb : : tid_t tid , bool use_invalid_index_id ) :
2013-08-23 13:46:38 -04:00
ThreadProperties ( false ) ,
UserID ( tid ) ,
Broadcaster ( & process . GetTarget ( ) . GetDebugger ( ) , Thread : : GetStaticBroadcasterClass ( ) . AsCString ( ) ) ,
m_process_wp ( process . shared_from_this ( ) ) ,
m_stop_info_sp ( ) ,
m_stop_info_stop_id ( 0 ) ,
2015-02-06 16:38:51 -05:00
m_stop_info_override_stop_id ( 0 ) ,
2014-11-25 16:00:58 -05:00
m_index_id ( use_invalid_index_id ? LLDB_INVALID_INDEX32 : process . GetNextThreadIndexID ( tid ) ) ,
2013-08-23 13:46:38 -04:00
m_reg_context_sp ( ) ,
m_state ( eStateUnloaded ) ,
m_state_mutex ( Mutex : : eMutexTypeRecursive ) ,
m_plan_stack ( ) ,
m_completed_plan_stack ( ) ,
m_frame_mutex ( Mutex : : eMutexTypeRecursive ) ,
m_curr_frames_sp ( ) ,
m_prev_frames_sp ( ) ,
m_resume_signal ( LLDB_INVALID_SIGNAL_NUMBER ) ,
m_resume_state ( eStateRunning ) ,
m_temporary_resume_state ( eStateRunning ) ,
m_unwinder_ap ( ) ,
m_destroy_called ( false ) ,
2014-11-25 16:00:58 -05:00
m_override_should_notify ( eLazyBoolCalculate ) ,
m_extended_info_fetched ( false ) ,
m_extended_info ( )
2013-08-23 13:46:38 -04:00
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_OBJECT ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " %p Thread::Thread(tid = 0x%4.4 " PRIx64 " ) " ,
static_cast < void * > ( this ) , GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
CheckInWithManager ( ) ;
QueueFundamentalPlan ( true ) ;
}
Thread : : ~ Thread ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_OBJECT ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " %p Thread::~Thread(tid = 0x%4.4 " PRIx64 " ) " ,
static_cast < void * > ( this ) , GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
/// If you hit this assert, it means your derived class forgot to call DoDestroy in its destructor.
assert ( m_destroy_called ) ;
}
void
Thread : : DestroyThread ( )
{
2013-11-06 11:48:53 -05:00
// Tell any plans on the plan stacks that the thread is being destroyed since
// any plans that have a thread go away in the middle of might need
// to do cleanup, or in some cases NOT do cleanup...
2013-08-23 13:46:38 -04:00
for ( auto plan : m_plan_stack )
plan - > ThreadDestroyed ( ) ;
2013-11-06 11:48:53 -05:00
for ( auto plan : m_discarded_plan_stack )
plan - > ThreadDestroyed ( ) ;
for ( auto plan : m_completed_plan_stack )
plan - > ThreadDestroyed ( ) ;
2013-08-23 13:46:38 -04:00
m_destroy_called = true ;
m_plan_stack . clear ( ) ;
m_discarded_plan_stack . clear ( ) ;
m_completed_plan_stack . clear ( ) ;
// Push a ThreadPlanNull on the plan stack. That way we can continue assuming that the
// plan stack is never empty, but if somebody errantly asks questions of a destroyed thread
// without checking first whether it is destroyed, they won't crash.
ThreadPlanSP null_plan_sp ( new ThreadPlanNull ( * this ) ) ;
m_plan_stack . push_back ( null_plan_sp ) ;
m_stop_info_sp . reset ( ) ;
m_reg_context_sp . reset ( ) ;
m_unwinder_ap . reset ( ) ;
Mutex : : Locker locker ( m_frame_mutex ) ;
m_curr_frames_sp . reset ( ) ;
m_prev_frames_sp . reset ( ) ;
}
void
Thread : : BroadcastSelectedFrameChange ( StackID & new_frame_id )
{
if ( EventTypeHasListeners ( eBroadcastBitSelectedFrameChanged ) )
BroadcastEvent ( eBroadcastBitSelectedFrameChanged , new ThreadEventData ( this - > shared_from_this ( ) , new_frame_id ) ) ;
}
uint32_t
Thread : : SetSelectedFrame ( lldb_private : : StackFrame * frame , bool broadcast )
{
uint32_t ret_value = GetStackFrameList ( ) - > SetSelectedFrame ( frame ) ;
if ( broadcast )
BroadcastSelectedFrameChange ( frame - > GetStackID ( ) ) ;
return ret_value ;
}
bool
Thread : : SetSelectedFrameByIndex ( uint32_t frame_idx , bool broadcast )
{
StackFrameSP frame_sp ( GetStackFrameList ( ) - > GetFrameAtIndex ( frame_idx ) ) ;
if ( frame_sp )
{
GetStackFrameList ( ) - > SetSelectedFrame ( frame_sp . get ( ) ) ;
if ( broadcast )
BroadcastSelectedFrameChange ( frame_sp - > GetStackID ( ) ) ;
return true ;
}
else
return false ;
}
bool
Thread : : SetSelectedFrameByIndexNoisily ( uint32_t frame_idx , Stream & output_stream )
{
const bool broadcast = true ;
bool success = SetSelectedFrameByIndex ( frame_idx , broadcast ) ;
if ( success )
{
StackFrameSP frame_sp = GetSelectedFrame ( ) ;
if ( frame_sp )
{
bool already_shown = false ;
SymbolContext frame_sc ( frame_sp - > GetSymbolContext ( eSymbolContextLineEntry ) ) ;
if ( GetProcess ( ) - > GetTarget ( ) . GetDebugger ( ) . GetUseExternalEditor ( ) & & frame_sc . line_entry . file & & frame_sc . line_entry . line ! = 0 )
{
already_shown = Host : : OpenFileInExternalEditor ( frame_sc . line_entry . file , frame_sc . line_entry . line ) ;
}
bool show_frame_info = true ;
bool show_source = ! already_shown ;
return frame_sp - > GetStatus ( output_stream , show_frame_info , show_source ) ;
}
return false ;
}
else
return false ;
}
lldb : : StopInfoSP
Thread : : GetStopInfo ( )
{
if ( m_destroy_called )
return m_stop_info_sp ;
ThreadPlanSP plan_sp ( GetCompletedPlan ( ) ) ;
ProcessSP process_sp ( GetProcess ( ) ) ;
const uint32_t stop_id = process_sp ? process_sp - > GetStopID ( ) : UINT32_MAX ;
if ( plan_sp & & plan_sp - > PlanSucceeded ( ) )
{
2014-11-25 16:00:58 -05:00
return StopInfo : : CreateStopReasonWithPlan ( plan_sp , GetReturnValueObject ( ) , GetExpressionVariable ( ) ) ;
2013-08-23 13:46:38 -04:00
}
else
{
if ( ( m_stop_info_stop_id = = stop_id ) | | // Stop info is valid, just return what we have (even if empty)
( m_stop_info_sp & & m_stop_info_sp - > IsValid ( ) ) ) // Stop info is valid, just return what we have
{
return m_stop_info_sp ;
}
else
{
GetPrivateStopInfo ( ) ;
return m_stop_info_sp ;
}
}
}
lldb : : StopInfoSP
Thread : : GetPrivateStopInfo ( )
{
if ( m_destroy_called )
return m_stop_info_sp ;
ProcessSP process_sp ( GetProcess ( ) ) ;
if ( process_sp )
{
const uint32_t process_stop_id = process_sp - > GetStopID ( ) ;
if ( m_stop_info_stop_id ! = process_stop_id )
{
if ( m_stop_info_sp )
{
if ( m_stop_info_sp - > IsValid ( )
| | IsStillAtLastBreakpointHit ( )
| | GetCurrentPlan ( ) - > IsVirtualStep ( ) )
SetStopInfo ( m_stop_info_sp ) ;
else
m_stop_info_sp . reset ( ) ;
}
if ( ! m_stop_info_sp )
{
if ( CalculateStopInfo ( ) = = false )
SetStopInfo ( StopInfoSP ( ) ) ;
}
}
2015-02-06 16:38:51 -05:00
// The stop info can be manually set by calling Thread::SetStopInfo()
// prior to this function ever getting called, so we can't rely on
// "m_stop_info_stop_id != process_stop_id" as the condition for
// the if statement below, we must also check the stop info to see
// if we need to override it. See the header documentation in
// Process::GetStopInfoOverrideCallback() for more information on
// the stop info override callback.
if ( m_stop_info_override_stop_id ! = process_stop_id )
{
m_stop_info_override_stop_id = process_stop_id ;
if ( m_stop_info_sp )
{
ArchSpec : : StopInfoOverrideCallbackType callback = GetProcess ( ) - > GetStopInfoOverrideCallback ( ) ;
if ( callback )
callback ( * this ) ;
}
}
2013-08-23 13:46:38 -04:00
}
return m_stop_info_sp ;
}
lldb : : StopReason
Thread : : GetStopReason ( )
{
lldb : : StopInfoSP stop_info_sp ( GetStopInfo ( ) ) ;
if ( stop_info_sp )
return stop_info_sp - > GetStopReason ( ) ;
return eStopReasonNone ;
}
void
Thread : : SetStopInfo ( const lldb : : StopInfoSP & stop_info_sp )
{
m_stop_info_sp = stop_info_sp ;
if ( m_stop_info_sp )
{
m_stop_info_sp - > MakeStopInfoValid ( ) ;
// If we are overriding the ShouldReportStop, do that here:
if ( m_override_should_notify ! = eLazyBoolCalculate )
m_stop_info_sp - > OverrideShouldNotify ( m_override_should_notify = = eLazyBoolYes ) ;
}
ProcessSP process_sp ( GetProcess ( ) ) ;
if ( process_sp )
m_stop_info_stop_id = process_sp - > GetStopID ( ) ;
else
m_stop_info_stop_id = UINT32_MAX ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " %p: tid = 0x% " PRIx64 " : stop info = %s (stop_id = %u) " ,
static_cast < void * > ( this ) , GetID ( ) ,
stop_info_sp ? stop_info_sp - > GetDescription ( ) : " <NULL> " ,
m_stop_info_stop_id ) ;
2013-08-23 13:46:38 -04:00
}
void
Thread : : SetShouldReportStop ( Vote vote )
{
if ( vote = = eVoteNoOpinion )
return ;
else
{
m_override_should_notify = ( vote = = eVoteYes ? eLazyBoolYes : eLazyBoolNo ) ;
if ( m_stop_info_sp )
m_stop_info_sp - > OverrideShouldNotify ( m_override_should_notify = = eLazyBoolYes ) ;
}
}
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 ( bool ) GetPrivateStopInfo ( ) ;
}
bool
Thread : : CheckpointThreadState ( ThreadStateCheckpoint & saved_state )
{
2013-12-03 13:51:59 -05:00
saved_state . register_backup_sp . reset ( ) ;
lldb : : StackFrameSP frame_sp ( GetStackFrameAtIndex ( 0 ) ) ;
if ( frame_sp )
{
lldb : : RegisterCheckpointSP reg_checkpoint_sp ( new RegisterCheckpoint ( RegisterCheckpoint : : Reason : : eExpression ) ) ;
if ( reg_checkpoint_sp )
{
lldb : : RegisterContextSP reg_ctx_sp ( frame_sp - > GetRegisterContext ( ) ) ;
if ( reg_ctx_sp & & reg_ctx_sp - > ReadAllRegisterValues ( * reg_checkpoint_sp ) )
saved_state . register_backup_sp = reg_checkpoint_sp ;
}
}
if ( ! saved_state . register_backup_sp )
2013-08-23 13:46:38 -04:00
return false ;
saved_state . stop_info_sp = GetStopInfo ( ) ;
ProcessSP process_sp ( GetProcess ( ) ) ;
if ( process_sp )
saved_state . orig_stop_id = process_sp - > GetStopID ( ) ;
saved_state . current_inlined_depth = GetCurrentInlinedDepth ( ) ;
return true ;
}
bool
Thread : : RestoreRegisterStateFromCheckpoint ( ThreadStateCheckpoint & saved_state )
{
2013-12-03 13:51:59 -05:00
if ( saved_state . register_backup_sp )
{
lldb : : StackFrameSP frame_sp ( GetStackFrameAtIndex ( 0 ) ) ;
if ( frame_sp )
{
lldb : : RegisterContextSP reg_ctx_sp ( frame_sp - > GetRegisterContext ( ) ) ;
if ( reg_ctx_sp )
{
bool ret = reg_ctx_sp - > WriteAllRegisterValues ( * saved_state . register_backup_sp ) ;
// Clear out all stack frames as our world just changed.
ClearStackFrames ( ) ;
reg_ctx_sp - > InvalidateIfNeeded ( true ) ;
if ( m_unwinder_ap . get ( ) )
m_unwinder_ap - > Clear ( ) ;
return ret ;
}
}
}
return false ;
2013-08-23 13:46:38 -04:00
}
bool
Thread : : RestoreThreadStateFromCheckpoint ( ThreadStateCheckpoint & saved_state )
{
if ( saved_state . stop_info_sp )
saved_state . stop_info_sp - > MakeStopInfoValid ( ) ;
SetStopInfo ( saved_state . stop_info_sp ) ;
GetStackFrameList ( ) - > SetCurrentInlinedDepth ( saved_state . current_inlined_depth ) ;
return true ;
}
StateType
Thread : : GetState ( ) const
{
// If any other threads access this we will need a mutex for it
Mutex : : Locker locker ( m_state_mutex ) ;
return m_state ;
}
void
Thread : : SetState ( StateType state )
{
Mutex : : Locker locker ( m_state_mutex ) ;
m_state = state ;
}
void
Thread : : WillStop ( )
{
ThreadPlan * current_plan = GetCurrentPlan ( ) ;
// FIXME: I may decide to disallow threads with no plans. In which
// case this should go to an assert.
if ( ! current_plan )
return ;
current_plan - > WillStop ( ) ;
}
void
Thread : : SetupForResume ( )
{
if ( GetResumeState ( ) ! = eStateSuspended )
{
// If we're at a breakpoint push the step-over breakpoint plan. Do this before
// telling the current plan it will resume, since we might change what the current
// plan is.
// StopReason stop_reason = lldb::eStopReasonInvalid;
// StopInfoSP stop_info_sp = GetStopInfo();
// if (stop_info_sp.get())
// stop_reason = stop_info_sp->GetStopReason();
// if (stop_reason == lldb::eStopReasonBreakpoint)
lldb : : RegisterContextSP reg_ctx_sp ( GetRegisterContext ( ) ) ;
if ( reg_ctx_sp )
{
2015-02-06 16:38:51 -05:00
const addr_t thread_pc = reg_ctx_sp - > GetPC ( ) ;
BreakpointSiteSP bp_site_sp = GetProcess ( ) - > GetBreakpointSiteList ( ) . FindByAddress ( thread_pc ) ;
2013-08-23 13:46:38 -04:00
if ( bp_site_sp )
{
// Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything
// special to step over a breakpoint.
ThreadPlan * cur_plan = GetCurrentPlan ( ) ;
2015-02-06 16:38:51 -05:00
bool push_step_over_bp_plan = false ;
if ( cur_plan - > GetKind ( ) = = ThreadPlan : : eKindStepOverBreakpoint )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
ThreadPlanStepOverBreakpoint * bp_plan = ( ThreadPlanStepOverBreakpoint * ) cur_plan ;
if ( bp_plan - > GetBreakpointLoadAddress ( ) ! = thread_pc )
push_step_over_bp_plan = true ;
}
else
push_step_over_bp_plan = true ;
if ( push_step_over_bp_plan )
{
ThreadPlanSP step_bp_plan_sp ( new ThreadPlanStepOverBreakpoint ( * this ) ) ;
if ( step_bp_plan_sp )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
;
step_bp_plan_sp - > SetPrivate ( true ) ;
2013-08-23 13:46:38 -04:00
if ( GetCurrentPlan ( ) - > RunState ( ) ! = eStateStepping )
{
2015-02-06 16:38:51 -05:00
ThreadPlanStepOverBreakpoint * step_bp_plan
= static_cast < ThreadPlanStepOverBreakpoint * > ( step_bp_plan_sp . get ( ) ) ;
2013-08-23 13:46:38 -04:00
step_bp_plan - > SetAutoContinue ( true ) ;
}
QueueThreadPlan ( step_bp_plan_sp , false ) ;
}
}
}
}
}
}
bool
Thread : : ShouldResume ( StateType resume_state )
{
// At this point clear the completed plan stack.
m_completed_plan_stack . clear ( ) ;
m_discarded_plan_stack . clear ( ) ;
m_override_should_notify = eLazyBoolCalculate ;
m_temporary_resume_state = resume_state ;
lldb : : ThreadSP backing_thread_sp ( GetBackingThread ( ) ) ;
if ( backing_thread_sp )
backing_thread_sp - > m_temporary_resume_state = resume_state ;
// Make sure m_stop_info_sp is valid
GetPrivateStopInfo ( ) ;
// This is a little dubious, but we are trying to limit how often we actually fetch stop info from
// the target, 'cause that slows down single stepping. So assume that if we got to the point where
// we're about to resume, and we haven't yet had to fetch the stop reason, then it doesn't need to know
// about the fact that we are resuming...
const uint32_t process_stop_id = GetProcess ( ) - > GetStopID ( ) ;
if ( m_stop_info_stop_id = = process_stop_id & &
( m_stop_info_sp & & m_stop_info_sp - > IsValid ( ) ) )
{
StopInfo * stop_info = GetPrivateStopInfo ( ) . get ( ) ;
if ( stop_info )
stop_info - > WillResume ( resume_state ) ;
}
// Tell all the plans that we are about to resume in case they need to clear any state.
// We distinguish between the plan on the top of the stack and the lower
// plans in case a plan needs to do any special business before it runs.
bool need_to_resume = false ;
ThreadPlan * plan_ptr = GetCurrentPlan ( ) ;
if ( plan_ptr )
{
need_to_resume = plan_ptr - > WillResume ( resume_state , true ) ;
while ( ( plan_ptr = GetPreviousPlan ( plan_ptr ) ) ! = NULL )
{
plan_ptr - > WillResume ( resume_state , false ) ;
}
// If the WillResume for the plan says we are faking a resume, then it will have set an appropriate stop info.
// In that case, don't reset it here.
if ( need_to_resume & & resume_state ! = eStateSuspended )
{
m_stop_info_sp . reset ( ) ;
}
}
if ( need_to_resume )
{
ClearStackFrames ( ) ;
// Let Thread subclasses do any special work they need to prior to resuming
WillResume ( resume_state ) ;
}
return need_to_resume ;
}
void
Thread : : DidResume ( )
{
SetResumeSignal ( LLDB_INVALID_SIGNAL_NUMBER ) ;
}
void
Thread : : DidStop ( )
{
SetState ( eStateStopped ) ;
}
bool
Thread : : ShouldStop ( Event * event_ptr )
{
ThreadPlan * current_plan = GetCurrentPlan ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
bool should_stop = true ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( GetResumeState ( ) = = eStateSuspended )
{
if ( log )
log - > Printf ( " Thread::%s for tid = 0x%4.4 " PRIx64 " 0x%4.4 " PRIx64 " , should_stop = 0 (ignore since thread was suspended) " ,
2014-11-25 16:00:58 -05:00
__FUNCTION__ , GetID ( ) , GetProtocolID ( ) ) ;
2013-08-23 13:46:38 -04:00
return false ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( GetTemporaryResumeState ( ) = = eStateSuspended )
{
if ( log )
log - > Printf ( " Thread::%s for tid = 0x%4.4 " PRIx64 " 0x%4.4 " PRIx64 " , should_stop = 0 (ignore since thread was suspended) " ,
2014-11-25 16:00:58 -05:00
__FUNCTION__ , GetID ( ) , GetProtocolID ( ) ) ;
2013-08-23 13:46:38 -04:00
return false ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Based on the current thread plan and process stop info, check if this
// thread caused the process to stop. NOTE: this must take place before
// the plan is moved from the current plan stack to the completed plan
// stack.
if ( ThreadStoppedForAReason ( ) = = false )
{
if ( log )
log - > Printf ( " Thread::%s for tid = 0x%4.4 " PRIx64 " 0x%4.4 " PRIx64 " , pc = 0x%16.16 " PRIx64 " , should_stop = 0 (ignore since no stop reason) " ,
2014-11-25 16:00:58 -05:00
__FUNCTION__ , GetID ( ) , GetProtocolID ( ) ,
2013-08-23 13:46:38 -04:00
GetRegisterContext ( ) ? GetRegisterContext ( ) - > GetPC ( ) : LLDB_INVALID_ADDRESS ) ;
return false ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( log )
{
log - > Printf ( " Thread::%s(%p) for tid = 0x%4.4 " PRIx64 " 0x%4.4 " PRIx64 " , pc = 0x%16.16 " PRIx64 ,
2014-11-25 16:00:58 -05:00
__FUNCTION__ , static_cast < void * > ( this ) , GetID ( ) ,
2013-08-23 13:46:38 -04:00
GetProtocolID ( ) ,
2014-11-25 16:00:58 -05:00
GetRegisterContext ( )
? GetRegisterContext ( ) - > GetPC ( )
: LLDB_INVALID_ADDRESS ) ;
2013-08-23 13:46:38 -04:00
log - > Printf ( " ^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^ " ) ;
StreamString s ;
s . IndentMore ( ) ;
DumpThreadPlans ( & s ) ;
log - > Printf ( " Plan stack initial state: \n %s " , s . GetData ( ) ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// The top most plan always gets to do the trace log...
current_plan - > DoTraceLog ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// First query the stop info's ShouldStopSynchronous. This handles "synchronous" stop reasons, for example the breakpoint
// command on internal breakpoints. If a synchronous stop reason says we should not stop, then we don't have to
// do any more work on this stop.
StopInfoSP private_stop_info ( GetPrivateStopInfo ( ) ) ;
if ( private_stop_info & & private_stop_info - > ShouldStopSynchronous ( event_ptr ) = = false )
{
if ( log )
log - > Printf ( " StopInfo::ShouldStop async callback says we should not stop, returning ShouldStop of false. " ) ;
return false ;
}
// If we've already been restarted, don't query the plans since the state they would examine is not current.
if ( Process : : ProcessEventData : : GetRestartedFromEvent ( event_ptr ) )
return false ;
// Before the plans see the state of the world, calculate the current inlined depth.
GetStackFrameList ( ) - > CalculateCurrentInlinedDepth ( ) ;
// If the base plan doesn't understand why we stopped, then we have to find a plan that does.
// If that plan is still working, then we don't need to do any more work. If the plan that explains
// the stop is done, then we should pop all the plans below it, and pop it, and then let the plans above it decide
// whether they still need to do more work.
bool done_processing_current_plan = false ;
if ( ! current_plan - > PlanExplainsStop ( event_ptr ) )
{
if ( current_plan - > TracerExplainsStop ( ) )
{
done_processing_current_plan = true ;
should_stop = false ;
}
else
{
// If the current plan doesn't explain the stop, then find one that
// does and let it handle the situation.
ThreadPlan * plan_ptr = current_plan ;
while ( ( plan_ptr = GetPreviousPlan ( plan_ptr ) ) ! = NULL )
{
if ( plan_ptr - > PlanExplainsStop ( event_ptr ) )
{
should_stop = plan_ptr - > ShouldStop ( event_ptr ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// plan_ptr explains the stop, next check whether plan_ptr is done, if so, then we should take it
// and all the plans below it off the stack.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( plan_ptr - > MischiefManaged ( ) )
{
// We're going to pop the plans up to and including the plan that explains the stop.
ThreadPlan * prev_plan_ptr = GetPreviousPlan ( plan_ptr ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
do
{
if ( should_stop )
current_plan - > WillStop ( ) ;
PopPlan ( ) ;
}
while ( ( current_plan = GetCurrentPlan ( ) ) ! = prev_plan_ptr ) ;
// Now, if the responsible plan was not "Okay to discard" then we're done,
// otherwise we forward this to the next plan in the stack below.
if ( plan_ptr - > IsMasterPlan ( ) & & ! plan_ptr - > OkayToDiscard ( ) )
done_processing_current_plan = true ;
else
done_processing_current_plan = false ;
}
else
done_processing_current_plan = true ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
break ;
}
}
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ! done_processing_current_plan )
{
bool over_ride_stop = current_plan - > ShouldAutoContinue ( event_ptr ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Plan %s explains stop, auto-continue %i. " ,
current_plan - > GetName ( ) , over_ride_stop ) ;
2013-08-23 13:46:38 -04:00
// We're starting from the base plan, so just let it decide;
if ( PlanIsBasePlan ( current_plan ) )
{
should_stop = current_plan - > ShouldStop ( event_ptr ) ;
if ( log )
log - > Printf ( " Base plan says should stop: %i. " , should_stop ) ;
}
else
{
// Otherwise, don't let the base plan override what the other plans say to do, since
// presumably if there were other plans they would know what to do...
while ( 1 )
{
if ( PlanIsBasePlan ( current_plan ) )
break ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
should_stop = current_plan - > ShouldStop ( event_ptr ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Plan %s should stop: %d. " ,
current_plan - > GetName ( ) , should_stop ) ;
2013-08-23 13:46:38 -04:00
if ( current_plan - > MischiefManaged ( ) )
{
if ( should_stop )
current_plan - > WillStop ( ) ;
// If a Master Plan wants to stop, and wants to stick on the stack, we let it.
// Otherwise, see if the plan's parent wants to stop.
if ( should_stop & & current_plan - > IsMasterPlan ( ) & & ! current_plan - > OkayToDiscard ( ) )
{
PopPlan ( ) ;
break ;
}
else
{
PopPlan ( ) ;
current_plan = GetCurrentPlan ( ) ;
if ( current_plan = = NULL )
{
break ;
}
}
}
else
{
break ;
}
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( over_ride_stop )
should_stop = false ;
2015-02-06 16:38:51 -05:00
}
// One other potential problem is that we set up a master plan, then stop in before it is complete - for instance
// by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up
// past the end point condition of the initial plan. We don't want to strand the original plan on the stack,
// This code clears stale plans off the stack.
2014-11-25 16:00:58 -05:00
2015-02-06 16:38:51 -05:00
if ( should_stop )
{
ThreadPlan * plan_ptr = GetCurrentPlan ( ) ;
while ( ! PlanIsBasePlan ( plan_ptr ) )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
bool stale = plan_ptr - > IsPlanStale ( ) ;
ThreadPlan * examined_plan = plan_ptr ;
plan_ptr = GetPreviousPlan ( examined_plan ) ;
2014-11-25 16:00:58 -05:00
2015-02-06 16:38:51 -05:00
if ( stale )
{
if ( log )
log - > Printf ( " Plan %s being discarded in cleanup, it says it is already done. " ,
examined_plan - > GetName ( ) ) ;
DiscardThreadPlansUpToPlan ( examined_plan ) ;
2013-08-23 13:46:38 -04:00
}
}
}
if ( log )
{
StreamString s ;
s . IndentMore ( ) ;
DumpThreadPlans ( & s ) ;
log - > Printf ( " Plan stack final state: \n %s " , s . GetData ( ) ) ;
log - > Printf ( " vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv " , should_stop ) ;
}
return should_stop ;
}
Vote
Thread : : ShouldReportStop ( Event * event_ptr )
{
StateType thread_state = GetResumeState ( ) ;
StateType temp_thread_state = GetTemporaryResumeState ( ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( thread_state = = eStateSuspended | | thread_state = = eStateInvalid )
{
if ( log )
log - > Printf ( " Thread::ShouldReportStop() tid = 0x%4.4 " PRIx64 " : returning vote %i (state was suspended or invalid) " , GetID ( ) , eVoteNoOpinion ) ;
return eVoteNoOpinion ;
}
if ( temp_thread_state = = eStateSuspended | | temp_thread_state = = eStateInvalid )
{
if ( log )
log - > Printf ( " Thread::ShouldReportStop() tid = 0x%4.4 " PRIx64 " : returning vote %i (temporary state was suspended or invalid) " , GetID ( ) , eVoteNoOpinion ) ;
return eVoteNoOpinion ;
}
if ( ! ThreadStoppedForAReason ( ) )
{
if ( log )
log - > Printf ( " Thread::ShouldReportStop() tid = 0x%4.4 " PRIx64 " : returning vote %i (thread didn't stop for a reason.) " , GetID ( ) , eVoteNoOpinion ) ;
return eVoteNoOpinion ;
}
if ( m_completed_plan_stack . size ( ) > 0 )
{
// Don't use GetCompletedPlan here, since that suppresses private plans.
if ( log )
log - > Printf ( " Thread::ShouldReportStop() tid = 0x%4.4 " PRIx64 " : returning vote for complete stack's back plan " , GetID ( ) ) ;
return m_completed_plan_stack . back ( ) - > ShouldReportStop ( event_ptr ) ;
}
else
{
Vote thread_vote = eVoteNoOpinion ;
ThreadPlan * plan_ptr = GetCurrentPlan ( ) ;
while ( 1 )
{
if ( plan_ptr - > PlanExplainsStop ( event_ptr ) )
{
thread_vote = plan_ptr - > ShouldReportStop ( event_ptr ) ;
break ;
}
if ( PlanIsBasePlan ( plan_ptr ) )
break ;
else
plan_ptr = GetPreviousPlan ( plan_ptr ) ;
}
if ( log )
log - > Printf ( " Thread::ShouldReportStop() tid = 0x%4.4 " PRIx64 " : returning vote %i for current plan " , GetID ( ) , thread_vote ) ;
return thread_vote ;
}
}
Vote
Thread : : ShouldReportRun ( Event * event_ptr )
{
StateType thread_state = GetResumeState ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( thread_state = = eStateSuspended
| | thread_state = = eStateInvalid )
{
return eVoteNoOpinion ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( m_completed_plan_stack . size ( ) > 0 )
{
// Don't use GetCompletedPlan here, since that suppresses private plans.
if ( log )
log - > Printf ( " Current Plan for thread %d(%p) (0x%4.4 " PRIx64 " , %s): %s being asked whether we should report run. " ,
2014-11-25 16:00:58 -05:00
GetIndexID ( ) , static_cast < void * > ( this ) , GetID ( ) ,
2013-08-23 13:46:38 -04:00
StateAsCString ( GetTemporaryResumeState ( ) ) ,
m_completed_plan_stack . back ( ) - > GetName ( ) ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
return m_completed_plan_stack . back ( ) - > ShouldReportRun ( event_ptr ) ;
}
else
{
if ( log )
log - > Printf ( " Current Plan for thread %d(%p) (0x%4.4 " PRIx64 " , %s): %s being asked whether we should report run. " ,
2014-11-25 16:00:58 -05:00
GetIndexID ( ) , static_cast < void * > ( this ) , GetID ( ) ,
2013-08-23 13:46:38 -04:00
StateAsCString ( GetTemporaryResumeState ( ) ) ,
GetCurrentPlan ( ) - > GetName ( ) ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
return GetCurrentPlan ( ) - > ShouldReportRun ( event_ptr ) ;
}
}
bool
Thread : : MatchesSpec ( const ThreadSpec * spec )
{
if ( spec = = NULL )
return true ;
return spec - > ThreadPassesBasicTests ( * this ) ;
}
void
Thread : : PushPlan ( ThreadPlanSP & thread_plan_sp )
{
if ( thread_plan_sp )
{
// If the thread plan doesn't already have a tracer, give it its parent's tracer:
if ( ! thread_plan_sp - > GetThreadPlanTracer ( ) )
thread_plan_sp - > SetThreadPlanTracer ( m_plan_stack . back ( ) - > GetThreadPlanTracer ( ) ) ;
m_plan_stack . push_back ( thread_plan_sp ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
thread_plan_sp - > DidPush ( ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( log )
{
StreamString s ;
thread_plan_sp - > GetDescription ( & s , lldb : : eDescriptionLevelFull ) ;
log - > Printf ( " Thread::PushPlan(0x%p): \" %s \" , tid = 0x%4.4 " PRIx64 " . " ,
2014-11-25 16:00:58 -05:00
static_cast < void * > ( this ) , s . GetData ( ) ,
2013-08-23 13:46:38 -04:00
thread_plan_sp - > GetThread ( ) . GetID ( ) ) ;
}
}
}
void
Thread : : PopPlan ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( m_plan_stack . size ( ) < = 1 )
return ;
else
{
ThreadPlanSP & plan = m_plan_stack . back ( ) ;
if ( log )
{
log - > Printf ( " Popping plan: \" %s \" , tid = 0x%4.4 " PRIx64 " . " , plan - > GetName ( ) , plan - > GetThread ( ) . GetID ( ) ) ;
}
m_completed_plan_stack . push_back ( plan ) ;
plan - > WillPop ( ) ;
m_plan_stack . pop_back ( ) ;
}
}
void
Thread : : DiscardPlan ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( m_plan_stack . size ( ) > 1 )
{
ThreadPlanSP & plan = m_plan_stack . back ( ) ;
if ( log )
log - > Printf ( " Discarding plan: \" %s \" , tid = 0x%4.4 " PRIx64 " . " , plan - > GetName ( ) , plan - > GetThread ( ) . GetID ( ) ) ;
m_discarded_plan_stack . push_back ( plan ) ;
plan - > WillPop ( ) ;
m_plan_stack . pop_back ( ) ;
}
}
ThreadPlan *
Thread : : GetCurrentPlan ( )
{
// There will always be at least the base plan. If somebody is mucking with a
// thread with an empty plan stack, we should assert right away.
if ( m_plan_stack . empty ( ) )
return NULL ;
return m_plan_stack . back ( ) . get ( ) ;
}
ThreadPlanSP
Thread : : GetCompletedPlan ( )
{
ThreadPlanSP empty_plan_sp ;
if ( ! m_completed_plan_stack . empty ( ) )
{
for ( int i = m_completed_plan_stack . size ( ) - 1 ; i > = 0 ; i - - )
{
ThreadPlanSP completed_plan_sp ;
completed_plan_sp = m_completed_plan_stack [ i ] ;
if ( ! completed_plan_sp - > GetPrivate ( ) )
return completed_plan_sp ;
}
}
return empty_plan_sp ;
}
ValueObjectSP
Thread : : GetReturnValueObject ( )
{
if ( ! m_completed_plan_stack . empty ( ) )
{
for ( int i = m_completed_plan_stack . size ( ) - 1 ; i > = 0 ; i - - )
{
ValueObjectSP return_valobj_sp ;
return_valobj_sp = m_completed_plan_stack [ i ] - > GetReturnValueObject ( ) ;
if ( return_valobj_sp )
return return_valobj_sp ;
}
}
return ValueObjectSP ( ) ;
}
2014-11-25 16:00:58 -05:00
ClangExpressionVariableSP
Thread : : GetExpressionVariable ( )
{
if ( ! m_completed_plan_stack . empty ( ) )
{
for ( int i = m_completed_plan_stack . size ( ) - 1 ; i > = 0 ; i - - )
{
ClangExpressionVariableSP expression_variable_sp ;
expression_variable_sp = m_completed_plan_stack [ i ] - > GetExpressionVariable ( ) ;
if ( expression_variable_sp )
return expression_variable_sp ;
}
}
return ClangExpressionVariableSP ( ) ;
}
2013-08-23 13:46:38 -04:00
bool
Thread : : IsThreadPlanDone ( ThreadPlan * plan )
{
if ( ! m_completed_plan_stack . empty ( ) )
{
for ( int i = m_completed_plan_stack . size ( ) - 1 ; i > = 0 ; i - - )
{
if ( m_completed_plan_stack [ i ] . get ( ) = = plan )
return true ;
}
}
return false ;
}
bool
Thread : : WasThreadPlanDiscarded ( ThreadPlan * plan )
{
if ( ! m_discarded_plan_stack . empty ( ) )
{
for ( int i = m_discarded_plan_stack . size ( ) - 1 ; i > = 0 ; i - - )
{
if ( m_discarded_plan_stack [ i ] . get ( ) = = plan )
return true ;
}
}
return false ;
}
ThreadPlan *
Thread : : GetPreviousPlan ( ThreadPlan * current_plan )
{
if ( current_plan = = NULL )
return NULL ;
int stack_size = m_completed_plan_stack . size ( ) ;
for ( int i = stack_size - 1 ; i > 0 ; i - - )
{
if ( current_plan = = m_completed_plan_stack [ i ] . get ( ) )
return m_completed_plan_stack [ i - 1 ] . get ( ) ;
}
if ( stack_size > 0 & & m_completed_plan_stack [ 0 ] . get ( ) = = current_plan )
{
if ( m_plan_stack . size ( ) > 0 )
return m_plan_stack . back ( ) . get ( ) ;
else
return NULL ;
}
stack_size = m_plan_stack . size ( ) ;
for ( int i = stack_size - 1 ; i > 0 ; i - - )
{
if ( current_plan = = m_plan_stack [ i ] . get ( ) )
return m_plan_stack [ i - 1 ] . get ( ) ;
}
return NULL ;
}
void
Thread : : QueueThreadPlan ( ThreadPlanSP & thread_plan_sp , bool abort_other_plans )
{
if ( abort_other_plans )
DiscardThreadPlans ( true ) ;
PushPlan ( thread_plan_sp ) ;
}
void
Thread : : EnableTracer ( bool value , bool single_stepping )
{
int stack_size = m_plan_stack . size ( ) ;
for ( int i = 0 ; i < stack_size ; i + + )
{
if ( m_plan_stack [ i ] - > GetThreadPlanTracer ( ) )
{
m_plan_stack [ i ] - > GetThreadPlanTracer ( ) - > EnableTracing ( value ) ;
m_plan_stack [ i ] - > GetThreadPlanTracer ( ) - > EnableSingleStep ( single_stepping ) ;
}
}
}
void
Thread : : SetTracer ( lldb : : ThreadPlanTracerSP & tracer_sp )
{
int stack_size = m_plan_stack . size ( ) ;
for ( int i = 0 ; i < stack_size ; i + + )
m_plan_stack [ i ] - > SetThreadPlanTracer ( tracer_sp ) ;
}
2015-02-06 16:38:51 -05:00
bool
Thread : : DiscardUserThreadPlansUpToIndex ( uint32_t thread_index )
{
// Count the user thread plans from the back end to get the number of the one we want
// to discard:
uint32_t idx = 0 ;
ThreadPlan * up_to_plan_ptr = nullptr ;
for ( ThreadPlanSP plan_sp : m_plan_stack )
{
if ( plan_sp - > GetPrivate ( ) )
continue ;
if ( idx = = thread_index )
{
up_to_plan_ptr = plan_sp . get ( ) ;
break ;
}
else
idx + + ;
}
if ( up_to_plan_ptr = = nullptr )
return false ;
DiscardThreadPlansUpToPlan ( up_to_plan_ptr ) ;
return true ;
}
2013-08-23 13:46:38 -04:00
void
Thread : : DiscardThreadPlansUpToPlan ( lldb : : ThreadPlanSP & up_to_plan_sp )
{
DiscardThreadPlansUpToPlan ( up_to_plan_sp . get ( ) ) ;
}
void
Thread : : DiscardThreadPlansUpToPlan ( ThreadPlan * up_to_plan_ptr )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Discarding thread plans for thread tid = 0x%4.4 " PRIx64 " , up to %p " ,
GetID ( ) , static_cast < void * > ( up_to_plan_ptr ) ) ;
2013-08-23 13:46:38 -04:00
int stack_size = m_plan_stack . size ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the
// stack, and if so discard up to and including it.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( up_to_plan_ptr = = NULL )
{
for ( int i = stack_size - 1 ; i > 0 ; i - - )
DiscardPlan ( ) ;
}
else
{
bool found_it = false ;
for ( int i = stack_size - 1 ; i > 0 ; i - - )
{
if ( m_plan_stack [ i ] . get ( ) = = up_to_plan_ptr )
found_it = true ;
}
if ( found_it )
{
bool last_one = false ;
for ( int i = stack_size - 1 ; i > 0 & & ! last_one ; i - - )
{
if ( GetCurrentPlan ( ) = = up_to_plan_ptr )
last_one = true ;
DiscardPlan ( ) ;
}
}
}
return ;
}
void
Thread : : DiscardThreadPlans ( bool force )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
if ( log )
{
log - > Printf ( " Discarding thread plans for thread (tid = 0x%4.4 " PRIx64 " , force %d) " , GetID ( ) , force ) ;
}
if ( force )
{
int stack_size = m_plan_stack . size ( ) ;
for ( int i = stack_size - 1 ; i > 0 ; i - - )
{
DiscardPlan ( ) ;
}
return ;
}
while ( 1 )
{
int master_plan_idx ;
bool discard = true ;
// Find the first master plan, see if it wants discarding, and if yes discard up to it.
for ( master_plan_idx = m_plan_stack . size ( ) - 1 ; master_plan_idx > = 0 ; master_plan_idx - - )
{
if ( m_plan_stack [ master_plan_idx ] - > IsMasterPlan ( ) )
{
discard = m_plan_stack [ master_plan_idx ] - > OkayToDiscard ( ) ;
break ;
}
}
if ( discard )
{
// First pop all the dependent plans:
for ( int i = m_plan_stack . size ( ) - 1 ; i > master_plan_idx ; i - - )
{
// FIXME: Do we need a finalize here, or is the rule that "PrepareForStop"
// for the plan leaves it in a state that it is safe to pop the plan
// with no more notice?
DiscardPlan ( ) ;
}
// Now discard the master plan itself.
// The bottom-most plan never gets discarded. "OkayToDiscard" for it means
// discard it's dependent plans, but not it...
if ( master_plan_idx > 0 )
{
DiscardPlan ( ) ;
}
}
else
{
// If the master plan doesn't want to get discarded, then we're done.
break ;
}
}
}
bool
Thread : : PlanIsBasePlan ( ThreadPlan * plan_ptr )
{
if ( plan_ptr - > IsBasePlan ( ) )
return true ;
else if ( m_plan_stack . size ( ) = = 0 )
return false ;
else
return m_plan_stack [ 0 ] . get ( ) = = plan_ptr ;
}
Error
Thread : : UnwindInnermostExpression ( )
{
Error error ;
int stack_size = m_plan_stack . size ( ) ;
// If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the
// stack, and if so discard up to and including it.
for ( int i = stack_size - 1 ; i > 0 ; i - - )
{
if ( m_plan_stack [ i ] - > GetKind ( ) = = ThreadPlan : : eKindCallFunction )
{
DiscardThreadPlansUpToPlan ( m_plan_stack [ i ] . get ( ) ) ;
return error ;
}
}
error . SetErrorString ( " No expressions currently active on this thread " ) ;
return error ;
}
ThreadPlanSP
Thread : : QueueFundamentalPlan ( bool abort_other_plans )
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanBase ( * this ) ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepSingleInstruction
(
bool step_over ,
bool abort_other_plans ,
bool stop_other_threads
)
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanStepInstruction ( * this , step_over , stop_other_threads , eVoteNoOpinion , eVoteNoOpinion ) ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepOverRange
(
bool abort_other_plans ,
const AddressRange & range ,
const SymbolContext & addr_context ,
2014-11-25 16:00:58 -05:00
lldb : : RunMode stop_other_threads ,
LazyBool step_out_avoids_code_withoug_debug_info
2013-08-23 13:46:38 -04:00
)
{
ThreadPlanSP thread_plan_sp ;
2014-11-25 16:00:58 -05:00
thread_plan_sp . reset ( new ThreadPlanStepOverRange ( * this , range , addr_context , stop_other_threads , step_out_avoids_code_withoug_debug_info ) ) ;
2013-08-23 13:46:38 -04:00
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepInRange
(
bool abort_other_plans ,
const AddressRange & range ,
const SymbolContext & addr_context ,
const char * step_in_target ,
lldb : : RunMode stop_other_threads ,
2014-11-25 16:00:58 -05:00
LazyBool step_in_avoids_code_without_debug_info ,
LazyBool step_out_avoids_code_without_debug_info
2013-08-23 13:46:38 -04:00
)
{
2015-02-06 16:38:51 -05:00
ThreadPlanSP thread_plan_sp ( new ThreadPlanStepInRange ( * this ,
2014-11-25 16:00:58 -05:00
range ,
addr_context ,
stop_other_threads ,
step_in_avoids_code_without_debug_info ,
2015-02-06 16:38:51 -05:00
step_out_avoids_code_without_debug_info ) ) ;
ThreadPlanStepInRange * plan = static_cast < ThreadPlanStepInRange * > ( thread_plan_sp . get ( ) ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( step_in_target )
plan - > SetStepInTarget ( step_in_target ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepOut
(
bool abort_other_plans ,
SymbolContext * addr_context ,
bool first_insn ,
bool stop_other_threads ,
Vote stop_vote ,
Vote run_vote ,
2014-11-25 16:00:58 -05:00
uint32_t frame_idx ,
LazyBool step_out_avoids_code_withoug_debug_info
2013-08-23 13:46:38 -04:00
)
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanStepOut ( * this ,
addr_context ,
first_insn ,
stop_other_threads ,
stop_vote ,
run_vote ,
2014-11-25 16:00:58 -05:00
frame_idx ,
step_out_avoids_code_withoug_debug_info ) ) ;
if ( thread_plan_sp - > ValidatePlan ( NULL ) )
{
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
else
{
return ThreadPlanSP ( ) ;
}
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepOutNoShouldStop
(
bool abort_other_plans ,
SymbolContext * addr_context ,
bool first_insn ,
bool stop_other_threads ,
Vote stop_vote ,
Vote run_vote ,
uint32_t frame_idx
)
{
2015-02-06 16:38:51 -05:00
ThreadPlanSP thread_plan_sp ( new ThreadPlanStepOut ( * this ,
2014-11-25 16:00:58 -05:00
addr_context ,
first_insn ,
stop_other_threads ,
stop_vote ,
run_vote ,
frame_idx ,
2015-02-06 16:38:51 -05:00
eLazyBoolNo ) ) ;
ThreadPlanStepOut * new_plan = static_cast < ThreadPlanStepOut * > ( thread_plan_sp . get ( ) ) ;
2014-11-25 16:00:58 -05:00
new_plan - > ClearShouldStopHereCallbacks ( ) ;
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
if ( thread_plan_sp - > ValidatePlan ( NULL ) )
{
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
else
{
return ThreadPlanSP ( ) ;
}
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepThrough ( StackID & return_stack_id , bool abort_other_plans , bool stop_other_threads )
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanStepThrough ( * this , return_stack_id , stop_other_threads ) ) ;
if ( ! thread_plan_sp | | ! thread_plan_sp - > ValidatePlan ( NULL ) )
return ThreadPlanSP ( ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
ThreadPlanSP
Thread : : QueueThreadPlanForRunToAddress ( bool abort_other_plans ,
Address & target_addr ,
bool stop_other_threads )
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanRunToAddress ( * this , target_addr , stop_other_threads ) ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
ThreadPlanSP
Thread : : QueueThreadPlanForStepUntil ( bool abort_other_plans ,
lldb : : addr_t * address_list ,
size_t num_addresses ,
bool stop_other_threads ,
uint32_t frame_idx )
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanStepUntil ( * this , address_list , num_addresses , stop_other_threads , frame_idx ) ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
return thread_plan_sp ;
}
2015-02-06 16:38:51 -05:00
lldb : : ThreadPlanSP
Thread : : QueueThreadPlanForStepScripted ( bool abort_other_plans ,
const char * class_name ,
bool stop_other_threads )
{
ThreadPlanSP thread_plan_sp ( new ThreadPlanPython ( * this , class_name ) ) ;
QueueThreadPlan ( thread_plan_sp , abort_other_plans ) ;
// This seems a little funny, but I don't want to have to split up the constructor and the
// DidPush in the scripted plan, that seems annoying.
// That means the constructor has to be in DidPush.
// So I have to validate the plan AFTER pushing it, and then take it off again...
if ( ! thread_plan_sp - > ValidatePlan ( nullptr ) )
{
DiscardThreadPlansUpToPlan ( thread_plan_sp ) ;
return ThreadPlanSP ( ) ;
}
else
return thread_plan_sp ;
}
2013-08-23 13:46:38 -04:00
uint32_t
Thread : : GetIndexID ( ) const
{
return m_index_id ;
}
2015-02-06 16:38:51 -05:00
static void
PrintPlanElement ( Stream * s , const ThreadPlanSP & plan , lldb : : DescriptionLevel desc_level , int32_t elem_idx )
2013-08-23 13:46:38 -04:00
{
s - > IndentMore ( ) ;
s - > Indent ( ) ;
2015-02-06 16:38:51 -05:00
s - > Printf ( " Element %d: " , elem_idx ) ;
plan - > GetDescription ( s , desc_level ) ;
2013-08-23 13:46:38 -04:00
s - > EOL ( ) ;
s - > IndentLess ( ) ;
2015-02-06 16:38:51 -05:00
}
static void
PrintPlanStack ( Stream * s , const std : : vector < lldb : : ThreadPlanSP > & plan_stack , lldb : : DescriptionLevel desc_level , bool include_internal )
{
int32_t print_idx = 0 ;
for ( ThreadPlanSP plan_sp : plan_stack )
{
if ( include_internal | | ! plan_sp - > GetPrivate ( ) )
{
PrintPlanElement ( s , plan_sp , desc_level , print_idx + + ) ;
}
2013-08-23 13:46:38 -04:00
}
2015-02-06 16:38:51 -05:00
}
2013-08-23 13:46:38 -04:00
2015-02-06 16:38:51 -05:00
void
Thread : : DumpThreadPlans ( Stream * s ,
lldb : : DescriptionLevel desc_level ,
bool include_internal ,
bool ignore_boring_threads ) const
{
uint32_t stack_size ;
if ( ignore_boring_threads )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
uint32_t stack_size = m_plan_stack . size ( ) ;
uint32_t completed_stack_size = m_completed_plan_stack . size ( ) ;
uint32_t discarded_stack_size = m_discarded_plan_stack . size ( ) ;
if ( stack_size = = 1 & & completed_stack_size = = 0 & & discarded_stack_size = = 0 )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
s - > Printf ( " thread #%u: tid = 0x%4.4 " PRIx64 " \n " , GetIndexID ( ) , GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
s - > IndentMore ( ) ;
s - > Indent ( ) ;
2015-02-06 16:38:51 -05:00
s - > Printf ( " No active thread plans \n " ) ;
2013-08-23 13:46:38 -04:00
s - > IndentLess ( ) ;
2015-02-06 16:38:51 -05:00
return ;
2013-08-23 13:46:38 -04:00
}
}
2015-02-06 16:38:51 -05:00
s - > Indent ( ) ;
s - > Printf ( " thread #%u: tid = 0x%4.4 " PRIx64 " : \n " , GetIndexID ( ) , GetID ( ) ) ;
s - > IndentMore ( ) ;
s - > Indent ( ) ;
s - > Printf ( " Active plan stack: \n " ) ;
PrintPlanStack ( s , m_plan_stack , desc_level , include_internal ) ;
stack_size = m_completed_plan_stack . size ( ) ;
if ( stack_size > 0 )
{
s - > Indent ( ) ;
s - > Printf ( " Completed Plan Stack: \n " ) ;
PrintPlanStack ( s , m_completed_plan_stack , desc_level , include_internal ) ;
}
2013-08-23 13:46:38 -04:00
stack_size = m_discarded_plan_stack . size ( ) ;
if ( stack_size > 0 )
{
s - > Indent ( ) ;
2015-02-06 16:38:51 -05:00
s - > Printf ( " Discarded Plan Stack: \n " ) ;
PrintPlanStack ( s , m_discarded_plan_stack , desc_level , include_internal ) ;
2013-08-23 13:46:38 -04:00
}
2015-02-06 16:38:51 -05:00
s - > IndentLess ( ) ;
2013-08-23 13:46:38 -04:00
}
TargetSP
Thread : : CalculateTarget ( )
{
TargetSP target_sp ;
ProcessSP process_sp ( GetProcess ( ) ) ;
if ( process_sp )
target_sp = process_sp - > CalculateTarget ( ) ;
return target_sp ;
}
ProcessSP
Thread : : CalculateProcess ( )
{
return GetProcess ( ) ;
}
ThreadSP
Thread : : CalculateThread ( )
{
return shared_from_this ( ) ;
}
StackFrameSP
Thread : : CalculateStackFrame ( )
{
return StackFrameSP ( ) ;
}
void
Thread : : CalculateExecutionContext ( ExecutionContext & exe_ctx )
{
exe_ctx . SetContext ( shared_from_this ( ) ) ;
}
StackFrameListSP
Thread : : GetStackFrameList ( )
{
StackFrameListSP frame_list_sp ;
Mutex : : Locker locker ( m_frame_mutex ) ;
if ( m_curr_frames_sp )
{
frame_list_sp = m_curr_frames_sp ;
}
else
{
frame_list_sp . reset ( new StackFrameList ( * this , m_prev_frames_sp , true ) ) ;
m_curr_frames_sp = frame_list_sp ;
}
return frame_list_sp ;
}
void
Thread : : ClearStackFrames ( )
{
Mutex : : Locker locker ( m_frame_mutex ) ;
Unwind * unwinder = GetUnwinder ( ) ;
if ( unwinder )
unwinder - > Clear ( ) ;
// Only store away the old "reference" StackFrameList if we got all its frames:
// FIXME: At some point we can try to splice in the frames we have fetched into
// the new frame as we make it, but let's not try that now.
if ( m_curr_frames_sp & & m_curr_frames_sp - > GetAllFramesFetched ( ) )
m_prev_frames_sp . swap ( m_curr_frames_sp ) ;
m_curr_frames_sp . reset ( ) ;
2014-11-25 16:00:58 -05:00
m_extended_info . reset ( ) ;
m_extended_info_fetched = false ;
2013-08-23 13:46:38 -04:00
}
lldb : : StackFrameSP
Thread : : GetFrameWithConcreteFrameIndex ( uint32_t unwind_idx )
{
return GetStackFrameList ( ) - > GetFrameWithConcreteFrameIndex ( unwind_idx ) ;
}
Error
Thread : : ReturnFromFrameWithIndex ( uint32_t frame_idx , lldb : : ValueObjectSP return_value_sp , bool broadcast )
{
StackFrameSP frame_sp = GetStackFrameAtIndex ( frame_idx ) ;
Error return_error ;
if ( ! frame_sp )
{
return_error . SetErrorStringWithFormat ( " Could not find frame with index %d in thread 0x% " PRIx64 " . " , frame_idx , GetID ( ) ) ;
}
return ReturnFromFrame ( frame_sp , return_value_sp , broadcast ) ;
}
Error
Thread : : ReturnFromFrame ( lldb : : StackFrameSP frame_sp , lldb : : ValueObjectSP return_value_sp , bool broadcast )
{
Error return_error ;
if ( ! frame_sp )
{
return_error . SetErrorString ( " Can't return to a null frame. " ) ;
return return_error ;
}
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 ( ! older_frame_sp )
{
return_error . SetErrorString ( " No older frame to return to. " ) ;
return return_error ;
}
if ( return_value_sp )
{
lldb : : ABISP abi = thread - > GetProcess ( ) - > GetABI ( ) ;
if ( ! abi )
{
return_error . SetErrorString ( " Could not find ABI to set return value. " ) ;
return return_error ;
}
SymbolContext sc = frame_sp - > GetSymbolContext ( eSymbolContextFunction ) ;
// FIXME: ValueObject::Cast doesn't currently work correctly, at least not for scalars.
// Turn that back on when that works.
2015-02-06 16:38:51 -05:00
if ( /* DISABLES CODE */ ( 0 ) & & sc . function ! = NULL )
2013-08-23 13:46:38 -04:00
{
Type * function_type = sc . function - > GetType ( ) ;
if ( function_type )
{
ClangASTType return_type = sc . function - > GetClangType ( ) . GetFunctionReturnType ( ) ;
if ( return_type )
{
StreamString s ;
return_type . DumpTypeDescription ( & s ) ;
ValueObjectSP cast_value_sp = return_value_sp - > Cast ( return_type ) ;
if ( cast_value_sp )
{
cast_value_sp - > SetFormat ( eFormatHex ) ;
return_value_sp = cast_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:
// Note, we can't use ReadAllRegisterValues->WriteAllRegisterValues, since the read & write
// cook their data
StackFrameSP youngest_frame_sp = thread - > GetStackFrameAtIndex ( 0 ) ;
if ( youngest_frame_sp )
{
lldb : : RegisterContextSP reg_ctx_sp ( youngest_frame_sp - > GetRegisterContext ( ) ) ;
if ( reg_ctx_sp )
{
bool copy_success = reg_ctx_sp - > CopyFromRegisterContext ( older_frame_sp - > GetRegisterContext ( ) ) ;
if ( copy_success )
{
thread - > DiscardThreadPlans ( true ) ;
thread - > ClearStackFrames ( ) ;
if ( broadcast & & EventTypeHasListeners ( eBroadcastBitStackChanged ) )
BroadcastEvent ( eBroadcastBitStackChanged , new ThreadEventData ( this - > shared_from_this ( ) ) ) ;
}
else
{
return_error . SetErrorString ( " Could not reset register values. " ) ;
}
}
else
{
return_error . SetErrorString ( " Frame has no register context. " ) ;
}
}
else
{
return_error . SetErrorString ( " Returned past top frame. " ) ;
}
return return_error ;
}
2013-11-06 11:48:53 -05:00
static void DumpAddressList ( Stream & s , const std : : vector < Address > & list , ExecutionContextScope * exe_scope )
{
for ( size_t n = 0 ; n < list . size ( ) ; n + + )
{
s < < " \t " ;
list [ n ] . Dump ( & s , exe_scope , Address : : DumpStyleResolvedDescription , Address : : DumpStyleSectionNameOffset ) ;
s < < " \n " ;
}
}
Error
Thread : : JumpToLine ( const FileSpec & file , uint32_t line , bool can_leave_function , std : : string * warnings )
{
ExecutionContext exe_ctx ( GetStackFrameAtIndex ( 0 ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
TargetSP target_sp = exe_ctx . GetTargetSP ( ) ;
RegisterContext * reg_ctx = exe_ctx . GetRegisterContext ( ) ;
StackFrame * frame = exe_ctx . GetFramePtr ( ) ;
const SymbolContext & sc = frame - > GetSymbolContext ( eSymbolContextFunction ) ;
// Find candidate locations.
std : : vector < Address > candidates , within_function , outside_function ;
target - > GetImages ( ) . FindAddressesForLine ( target_sp , file , line , sc . function , within_function , outside_function ) ;
// If possible, we try and stay within the current function.
// Within a function, we accept multiple locations (optimized code may do this,
// there's no solution here so we do the best we can).
// However if we're trying to leave the function, we don't know how to pick the
// right location, so if there's more than one then we bail.
if ( ! within_function . empty ( ) )
candidates = within_function ;
else if ( outside_function . size ( ) = = 1 & & can_leave_function )
candidates = outside_function ;
// Check if we got anything.
if ( candidates . empty ( ) )
{
if ( outside_function . empty ( ) )
{
return Error ( " Cannot locate an address for %s:%i. " ,
file . GetFilename ( ) . AsCString ( ) , line ) ;
}
else if ( outside_function . size ( ) = = 1 )
{
return Error ( " %s:%i is outside the current function. " ,
file . GetFilename ( ) . AsCString ( ) , line ) ;
}
else
{
StreamString sstr ;
DumpAddressList ( sstr , outside_function , target ) ;
return Error ( " %s:%i has multiple candidate locations: \n %s " ,
file . GetFilename ( ) . AsCString ( ) , line , sstr . GetString ( ) . c_str ( ) ) ;
}
}
// Accept the first location, warn about any others.
Address dest = candidates [ 0 ] ;
if ( warnings & & candidates . size ( ) > 1 )
{
StreamString sstr ;
sstr . Printf ( " %s:%i appears multiple times in this function, selecting the first location: \n " ,
file . GetFilename ( ) . AsCString ( ) , line ) ;
DumpAddressList ( sstr , candidates , target ) ;
* warnings = sstr . GetString ( ) ;
}
if ( ! reg_ctx - > SetPC ( dest ) )
return Error ( " Cannot change PC to target address. " ) ;
return Error ( ) ;
}
2013-08-23 13:46:38 -04:00
void
Thread : : DumpUsingSettingsFormat ( Stream & strm , uint32_t frame_idx )
{
ExecutionContext exe_ctx ( shared_from_this ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process = = NULL )
return ;
StackFrameSP frame_sp ;
SymbolContext frame_sc ;
2015-02-08 20:44:09 -05:00
if ( frame_idx ! = LLDB_INVALID_FRAME_ID )
2013-08-23 13:46:38 -04:00
{
frame_sp = GetStackFrameAtIndex ( frame_idx ) ;
if ( frame_sp )
{
exe_ctx . SetFrameSP ( frame_sp ) ;
frame_sc = frame_sp - > GetSymbolContext ( eSymbolContextEverything ) ;
}
}
2015-02-08 20:44:09 -05:00
const FormatEntity : : Entry * thread_format = exe_ctx . GetTargetRef ( ) . GetDebugger ( ) . GetThreadFormat ( ) ;
2013-08-23 13:46:38 -04:00
assert ( thread_format ) ;
2015-02-08 20:44:09 -05:00
FormatEntity : : Format ( * thread_format ,
strm ,
frame_sp ? & frame_sc : NULL ,
& exe_ctx ,
NULL ,
NULL ,
false ,
false ) ;
2013-08-23 13:46:38 -04:00
}
void
Thread : : SettingsInitialize ( )
{
}
void
Thread : : SettingsTerminate ( )
{
}
2013-11-06 11:48:53 -05:00
lldb : : addr_t
Thread : : GetThreadPointer ( )
{
return LLDB_INVALID_ADDRESS ;
}
addr_t
Thread : : GetThreadLocalData ( const ModuleSP module )
{
// The default implementation is to ask the dynamic loader for it.
// This can be overridden for specific platforms.
DynamicLoader * loader = GetProcess ( ) - > GetDynamicLoader ( ) ;
if ( loader )
return loader - > GetThreadLocalData ( module , shared_from_this ( ) ) ;
else
return LLDB_INVALID_ADDRESS ;
}
2014-11-25 16:00:58 -05:00
bool
Thread : : SafeToCallFunctions ( )
{
Process * process = GetProcess ( ) . get ( ) ;
if ( process )
{
SystemRuntime * runtime = process - > GetSystemRuntime ( ) ;
if ( runtime )
{
return runtime - > SafeToCallFunctionsOnThisThread ( shared_from_this ( ) ) ;
}
}
return true ;
}
2013-08-23 13:46:38 -04:00
lldb : : StackFrameSP
Thread : : GetStackFrameSPForStackFramePtr ( StackFrame * stack_frame_ptr )
{
return GetStackFrameList ( ) - > GetStackFrameSPForStackFramePtr ( stack_frame_ptr ) ;
}
const char *
Thread : : StopReasonAsCString ( lldb : : StopReason reason )
{
switch ( reason )
{
case eStopReasonInvalid : return " invalid " ;
case eStopReasonNone : return " none " ;
case eStopReasonTrace : return " trace " ;
case eStopReasonBreakpoint : return " breakpoint " ;
case eStopReasonWatchpoint : return " watchpoint " ;
case eStopReasonSignal : return " signal " ;
case eStopReasonException : return " exception " ;
case eStopReasonExec : return " exec " ;
case eStopReasonPlanComplete : return " plan complete " ;
case eStopReasonThreadExiting : return " thread exiting " ;
2015-02-06 16:38:51 -05:00
case eStopReasonInstrumentation : return " instrumentation break " ;
2013-08-23 13:46:38 -04:00
}
static char unknown_state_string [ 64 ] ;
snprintf ( unknown_state_string , sizeof ( unknown_state_string ) , " StopReason = %i " , reason ) ;
return unknown_state_string ;
}
const char *
Thread : : RunModeAsCString ( lldb : : RunMode mode )
{
switch ( mode )
{
case eOnlyThisThread : return " only this thread " ;
case eAllThreads : return " all threads " ;
case eOnlyDuringStepping : return " only during stepping " ;
}
static char unknown_state_string [ 64 ] ;
snprintf ( unknown_state_string , sizeof ( unknown_state_string ) , " RunMode = %i " , mode ) ;
return unknown_state_string ;
}
size_t
Thread : : GetStatus ( Stream & strm , uint32_t start_frame , uint32_t num_frames , uint32_t num_frames_with_source )
{
ExecutionContext exe_ctx ( shared_from_this ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
size_t num_frames_shown = 0 ;
strm . Indent ( ) ;
bool is_selected = false ;
if ( process )
{
if ( process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) = = this )
is_selected = true ;
}
strm . Printf ( " %c " , is_selected ? ' * ' : ' ' ) ;
if ( target & & target - > GetDebugger ( ) . GetUseExternalEditor ( ) )
{
StackFrameSP frame_sp = GetStackFrameAtIndex ( start_frame ) ;
if ( frame_sp )
{
SymbolContext frame_sc ( frame_sp - > GetSymbolContext ( eSymbolContextLineEntry ) ) ;
if ( frame_sc . line_entry . line ! = 0 & & frame_sc . line_entry . file )
{
Host : : OpenFileInExternalEditor ( frame_sc . line_entry . file , frame_sc . line_entry . line ) ;
}
}
}
DumpUsingSettingsFormat ( strm , start_frame ) ;
if ( num_frames > 0 )
{
strm . IndentMore ( ) ;
const bool show_frame_info = true ;
2013-11-06 11:48:53 -05:00
const char * selected_frame_marker = NULL ;
if ( num_frames = = 1 | | ( GetID ( ) ! = GetProcess ( ) - > GetThreadList ( ) . GetSelectedThread ( ) - > GetID ( ) ) )
strm . IndentMore ( ) ;
else
selected_frame_marker = " * " ;
2013-08-23 13:46:38 -04:00
num_frames_shown = GetStackFrameList ( ) - > GetStatus ( strm ,
start_frame ,
num_frames ,
show_frame_info ,
2013-11-06 11:48:53 -05:00
num_frames_with_source ,
selected_frame_marker ) ;
if ( num_frames = = 1 )
strm . IndentLess ( ) ;
2013-08-23 13:46:38 -04:00
strm . IndentLess ( ) ;
}
return num_frames_shown ;
}
2014-11-25 16:00:58 -05:00
bool
2015-02-06 16:38:51 -05:00
Thread : : GetDescription ( Stream & strm , lldb : : DescriptionLevel level , bool print_json_thread , bool print_json_stopinfo )
2014-11-25 16:00:58 -05:00
{
DumpUsingSettingsFormat ( strm , 0 ) ;
strm . Printf ( " \n " ) ;
StructuredData : : ObjectSP thread_info = GetExtendedInfo ( ) ;
2015-02-06 16:38:51 -05:00
StructuredData : : ObjectSP stop_info = m_stop_info_sp - > GetExtendedInfo ( ) ;
if ( print_json_thread | | print_json_stopinfo )
2014-11-25 16:00:58 -05:00
{
2015-02-06 16:38:51 -05:00
if ( thread_info & & print_json_thread )
{
thread_info - > Dump ( strm ) ;
strm . Printf ( " \n " ) ;
}
if ( stop_info & & print_json_stopinfo )
{
stop_info - > Dump ( strm ) ;
strm . Printf ( " \n " ) ;
}
2014-11-25 16:00:58 -05:00
return true ;
}
if ( thread_info )
{
StructuredData : : ObjectSP activity = thread_info - > GetObjectForDotSeparatedPath ( " activity " ) ;
StructuredData : : ObjectSP breadcrumb = thread_info - > GetObjectForDotSeparatedPath ( " breadcrumb " ) ;
StructuredData : : ObjectSP messages = thread_info - > GetObjectForDotSeparatedPath ( " trace_messages " ) ;
bool printed_activity = false ;
if ( activity & & activity - > GetType ( ) = = StructuredData : : Type : : eTypeDictionary )
{
StructuredData : : Dictionary * activity_dict = activity - > GetAsDictionary ( ) ;
StructuredData : : ObjectSP id = activity_dict - > GetValueForKey ( " id " ) ;
StructuredData : : ObjectSP name = activity_dict - > GetValueForKey ( " name " ) ;
if ( name & & name - > GetType ( ) = = StructuredData : : Type : : eTypeString
& & id & & id - > GetType ( ) = = StructuredData : : Type : : eTypeInteger )
{
strm . Printf ( " Activity '%s', 0x% " PRIx64 " \n " , name - > GetAsString ( ) - > GetValue ( ) . c_str ( ) , id - > GetAsInteger ( ) - > GetValue ( ) ) ;
}
printed_activity = true ;
}
bool printed_breadcrumb = false ;
if ( breadcrumb & & breadcrumb - > GetType ( ) = = StructuredData : : Type : : eTypeDictionary )
{
if ( printed_activity )
strm . Printf ( " \n " ) ;
StructuredData : : Dictionary * breadcrumb_dict = breadcrumb - > GetAsDictionary ( ) ;
StructuredData : : ObjectSP breadcrumb_text = breadcrumb_dict - > GetValueForKey ( " name " ) ;
if ( breadcrumb_text & & breadcrumb_text - > GetType ( ) = = StructuredData : : Type : : eTypeString )
{
strm . Printf ( " Current Breadcrumb: %s \n " , breadcrumb_text - > GetAsString ( ) - > GetValue ( ) . c_str ( ) ) ;
}
printed_breadcrumb = true ;
}
if ( messages & & messages - > GetType ( ) = = StructuredData : : Type : : eTypeArray )
{
if ( printed_breadcrumb )
strm . Printf ( " \n " ) ;
StructuredData : : Array * messages_array = messages - > GetAsArray ( ) ;
const size_t msg_count = messages_array - > GetSize ( ) ;
if ( msg_count > 0 )
{
strm . Printf ( " %zu trace messages: \n " , msg_count ) ;
for ( size_t i = 0 ; i < msg_count ; i + + )
{
StructuredData : : ObjectSP message = messages_array - > GetItemAtIndex ( i ) ;
if ( message & & message - > GetType ( ) = = StructuredData : : Type : : eTypeDictionary )
{
StructuredData : : Dictionary * message_dict = message - > GetAsDictionary ( ) ;
StructuredData : : ObjectSP message_text = message_dict - > GetValueForKey ( " message " ) ;
if ( message_text & & message_text - > GetType ( ) = = StructuredData : : Type : : eTypeString )
{
strm . Printf ( " %s \n " , message_text - > GetAsString ( ) - > GetValue ( ) . c_str ( ) ) ;
}
}
}
}
}
}
return true ;
}
2013-08-23 13:46:38 -04:00
size_t
Thread : : GetStackFrameStatus ( Stream & strm ,
uint32_t first_frame ,
uint32_t num_frames ,
bool show_frame_info ,
uint32_t num_frames_with_source )
{
return GetStackFrameList ( ) - > GetStatus ( strm ,
first_frame ,
num_frames ,
show_frame_info ,
num_frames_with_source ) ;
}
Unwind *
Thread : : GetUnwinder ( )
{
if ( m_unwinder_ap . get ( ) = = NULL )
{
const ArchSpec target_arch ( CalculateTarget ( ) - > GetArchitecture ( ) ) ;
const llvm : : Triple : : ArchType machine = target_arch . GetMachine ( ) ;
switch ( machine )
{
case llvm : : Triple : : x86_64 :
case llvm : : Triple : : x86 :
case llvm : : Triple : : arm :
2014-11-25 16:00:58 -05:00
case llvm : : Triple : : aarch64 :
2013-08-23 13:46:38 -04:00
case llvm : : Triple : : thumb :
2013-11-06 11:48:53 -05:00
case llvm : : Triple : : mips64 :
2015-02-06 16:38:51 -05:00
case llvm : : Triple : : ppc :
case llvm : : Triple : : ppc64 :
2014-02-25 16:42:16 -05:00
case llvm : : Triple : : hexagon :
2013-08-23 13:46:38 -04:00
m_unwinder_ap . reset ( new UnwindLLDB ( * this ) ) ;
break ;
default :
if ( target_arch . GetTriple ( ) . getVendor ( ) = = llvm : : Triple : : Apple )
m_unwinder_ap . reset ( new UnwindMacOSXFrameBackchain ( * this ) ) ;
break ;
}
}
return m_unwinder_ap . get ( ) ;
}
void
Thread : : Flush ( )
{
ClearStackFrames ( ) ;
m_reg_context_sp . reset ( ) ;
}
bool
Thread : : IsStillAtLastBreakpointHit ( )
{
// If we are currently stopped at a breakpoint, always return that stopinfo and don't reset it.
// This allows threads to maintain their breakpoint stopinfo, such as when thread-stepping in
// multithreaded programs.
if ( m_stop_info_sp ) {
StopReason stop_reason = m_stop_info_sp - > GetStopReason ( ) ;
if ( stop_reason = = lldb : : eStopReasonBreakpoint ) {
uint64_t value = m_stop_info_sp - > GetValue ( ) ;
lldb : : RegisterContextSP reg_ctx_sp ( GetRegisterContext ( ) ) ;
if ( reg_ctx_sp )
{
lldb : : addr_t pc = reg_ctx_sp - > GetPC ( ) ;
BreakpointSiteSP bp_site_sp = GetProcess ( ) - > GetBreakpointSiteList ( ) . FindByAddress ( pc ) ;
2014-11-25 16:00:58 -05:00
if ( bp_site_sp & &
static_cast < break_id_t > ( value ) = = bp_site_sp - > GetID ( ) )
2013-08-23 13:46:38 -04:00
return true ;
}
}
}
return false ;
}
2014-02-18 11:23:10 -05:00
Error
Thread : : StepIn ( bool source_step ,
2014-11-25 16:00:58 -05:00
LazyBool step_in_avoids_code_without_debug_info ,
LazyBool step_out_avoids_code_without_debug_info )
2014-02-18 11:23:10 -05:00
{
Error error ;
Process * process = GetProcess ( ) . get ( ) ;
if ( StateIsStoppedState ( process - > GetState ( ) , true ) )
{
StackFrameSP frame_sp = GetStackFrameAtIndex ( 0 ) ;
ThreadPlanSP new_plan_sp ;
const lldb : : RunMode run_mode = eOnlyThisThread ;
const bool abort_other_plans = false ;
if ( source_step & & frame_sp & & frame_sp - > HasDebugInformation ( ) )
{
SymbolContext sc ( frame_sp - > GetSymbolContext ( eSymbolContextEverything ) ) ;
new_plan_sp = QueueThreadPlanForStepInRange ( abort_other_plans ,
sc . line_entry . range ,
sc ,
NULL ,
run_mode ,
2014-11-25 16:00:58 -05:00
step_in_avoids_code_without_debug_info ,
step_out_avoids_code_without_debug_info ) ;
2014-02-18 11:23:10 -05:00
}
else
{
new_plan_sp = QueueThreadPlanForStepSingleInstruction ( false ,
abort_other_plans ,
run_mode ) ;
}
new_plan_sp - > SetIsMasterPlan ( true ) ;
new_plan_sp - > SetOkayToDiscard ( false ) ;
// Why do we need to set the current thread by ID here???
process - > GetThreadList ( ) . SetSelectedThreadByID ( GetID ( ) ) ;
error = process - > Resume ( ) ;
}
else
{
error . SetErrorString ( " process not stopped " ) ;
}
return error ;
}
Error
2014-11-25 16:00:58 -05:00
Thread : : StepOver ( bool source_step ,
LazyBool step_out_avoids_code_without_debug_info )
2014-02-18 11:23:10 -05:00
{
Error error ;
Process * process = GetProcess ( ) . get ( ) ;
if ( StateIsStoppedState ( process - > GetState ( ) , true ) )
{
StackFrameSP frame_sp = GetStackFrameAtIndex ( 0 ) ;
ThreadPlanSP new_plan_sp ;
const lldb : : RunMode run_mode = eOnlyThisThread ;
const bool abort_other_plans = false ;
if ( source_step & & frame_sp & & frame_sp - > HasDebugInformation ( ) )
{
SymbolContext sc ( frame_sp - > GetSymbolContext ( eSymbolContextEverything ) ) ;
new_plan_sp = QueueThreadPlanForStepOverRange ( abort_other_plans ,
sc . line_entry . range ,
sc ,
2014-11-25 16:00:58 -05:00
run_mode ,
step_out_avoids_code_without_debug_info ) ;
2014-02-18 11:23:10 -05:00
}
else
{
new_plan_sp = QueueThreadPlanForStepSingleInstruction ( true ,
abort_other_plans ,
run_mode ) ;
}
new_plan_sp - > SetIsMasterPlan ( true ) ;
new_plan_sp - > SetOkayToDiscard ( false ) ;
// Why do we need to set the current thread by ID here???
process - > GetThreadList ( ) . SetSelectedThreadByID ( GetID ( ) ) ;
error = process - > Resume ( ) ;
}
else
{
error . SetErrorString ( " process not stopped " ) ;
}
return error ;
}
Error
Thread : : StepOut ( )
{
Error error ;
Process * process = GetProcess ( ) . get ( ) ;
if ( StateIsStoppedState ( process - > GetState ( ) , true ) )
{
const bool first_instruction = false ;
const bool stop_other_threads = false ;
const bool abort_other_plans = false ;
ThreadPlanSP new_plan_sp ( QueueThreadPlanForStepOut ( abort_other_plans ,
NULL ,
first_instruction ,
stop_other_threads ,
eVoteYes ,
eVoteNoOpinion ,
0 ) ) ;
new_plan_sp - > SetIsMasterPlan ( true ) ;
new_plan_sp - > SetOkayToDiscard ( false ) ;
// Why do we need to set the current thread by ID here???
process - > GetThreadList ( ) . SetSelectedThreadByID ( GetID ( ) ) ;
error = process - > Resume ( ) ;
}
else
{
error . SetErrorString ( " process not stopped " ) ;
}
return error ;
2014-11-25 16:00:58 -05:00
}