2010-06-08 16:52:24 +00:00
//===-- CommandObjectThread.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "CommandObjectThread.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
2012-09-14 02:14:15 +00:00
# include "lldb/lldb-private.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/State.h"
# include "lldb/Core/SourceManager.h"
2011-02-01 01:31:41 +00:00
# include "lldb/Host/Host.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Interpreter/Options.h"
# include "lldb/Symbol/CompileUnit.h"
# include "lldb/Symbol/Function.h"
# include "lldb/Symbol/LineTable.h"
# include "lldb/Symbol/LineEntry.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Target/Process.h"
# include "lldb/Target/RegisterContext.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/ThreadPlan.h"
# include "lldb/Target/ThreadPlanStepInstruction.h"
# include "lldb/Target/ThreadPlanStepOut.h"
# include "lldb/Target/ThreadPlanStepRange.h"
# include "lldb/Target/ThreadPlanStepInRange.h"
2012-08-29 21:13:06 +00:00
2010-06-08 16:52:24 +00:00
using namespace lldb ;
using namespace lldb_private ;
//-------------------------------------------------------------------------
// CommandObjectThreadBacktrace
//-------------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectThreadBacktrace : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
2010-08-26 23:36:03 +00:00
class CommandOptions : public Options
{
public :
2011-04-07 22:46:35 +00:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2010-08-26 23:36:03 +00:00
{
2011-04-13 00:18:08 +00:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-08-26 23:36:03 +00:00
}
virtual
~ CommandOptions ( )
{
}
virtual Error
2011-04-13 00:18:08 +00:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-08-26 23:36:03 +00:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' c ' :
{
bool success ;
int32_t input_count = Args : : StringToSInt32 ( option_arg , - 1 , 0 , & success ) ;
if ( ! success )
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid integer value for option '%c' " , short_option ) ;
2010-08-26 23:36:03 +00:00
if ( input_count < - 1 )
m_count = UINT32_MAX ;
else
m_count = input_count ;
}
break ;
case ' s ' :
{
bool success ;
m_start = Args : : StringToUInt32 ( option_arg , 0 , 0 , & success ) ;
if ( ! success )
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid integer value for option '%c' " , short_option ) ;
2010-08-26 23:36:03 +00:00
}
break ;
default :
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
2010-08-26 23:36:03 +00:00
break ;
}
return error ;
}
void
2011-04-13 00:18:08 +00:00
OptionParsingStarting ( )
2010-08-26 23:36:03 +00:00
{
2011-04-18 08:33:37 +00:00
m_count = UINT32_MAX ;
2010-08-26 23:36:03 +00:00
m_start = 0 ;
}
2011-03-24 21:19:54 +00:00
const OptionDefinition *
2010-08-26 23:36:03 +00:00
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
2011-03-24 21:19:54 +00:00
static OptionDefinition g_option_table [ ] ;
2010-08-26 23:36:03 +00:00
// Instance variables to hold the values for command options.
uint32_t m_count ;
uint32_t m_start ;
} ;
2010-09-18 01:14:36 +00:00
CommandObjectThreadBacktrace ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" thread backtrace " ,
" Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \" all \" to see all threads. " ,
NULL ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ) ,
2011-04-07 22:46:35 +00:00
m_options ( interpreter )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg ;
CommandArgumentData thread_idx_arg ;
// Define the first (and only) variant of this arg.
thread_idx_arg . arg_type = eArgTypeThreadIndex ;
thread_idx_arg . arg_repetition = eArgRepeatStar ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( thread_idx_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-08 16:52:24 +00:00
}
~ CommandObjectThreadBacktrace ( )
{
}
2010-08-26 23:36:03 +00:00
virtual Options *
GetOptions ( )
{
return & m_options ;
}
2010-06-08 16:52:24 +00:00
2012-06-08 21:56:10 +00:00
protected :
2010-06-23 01:19:29 +00:00
virtual bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2011-04-18 08:33:37 +00:00
{
2010-08-27 00:58:05 +00:00
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
2011-04-18 08:33:37 +00:00
Stream & strm = result . GetOutputStream ( ) ;
// Don't show source context when doing backtraces.
const uint32_t num_frames_with_source = 0 ;
2010-06-08 16:52:24 +00:00
if ( command . GetArgumentCount ( ) = = 0 )
{
2011-04-12 05:54:46 +00:00
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
2011-09-22 04:58:26 +00:00
Thread * thread = exe_ctx . GetThreadPtr ( ) ;
if ( thread )
2010-06-08 16:52:24 +00:00
{
2011-06-02 18:02:15 +00:00
// Thread::GetStatus() returns the number of frames shown.
2011-09-22 04:58:26 +00:00
if ( thread - > GetStatus ( strm ,
m_options . m_start ,
m_options . m_count ,
num_frames_with_source ) )
2010-06-08 16:52:24 +00:00
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
}
else
{
result . AppendError ( " invalid thread " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
2010-08-27 00:58:05 +00:00
else if ( command . GetArgumentCount ( ) = = 1 & & : : strcmp ( command . GetArgumentAtIndex ( 0 ) , " all " ) = = 0 )
{
2011-09-22 04:58:26 +00:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2012-09-10 20:50:15 +00:00
Mutex : : Locker locker ( process - > GetThreadList ( ) . GetMutex ( ) ) ;
2010-08-27 00:58:05 +00:00
uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
for ( uint32_t i = 0 ; i < num_threads ; i + + )
{
ThreadSP thread_sp = process - > GetThreadList ( ) . GetThreadAtIndex ( i ) ;
2011-06-01 23:19:52 +00:00
if ( ! thread_sp - > GetStatus ( strm ,
m_options . m_start ,
m_options . m_count ,
num_frames_with_source ) )
2010-08-27 00:58:05 +00:00
{
2010-09-03 22:45:01 +00:00
result . AppendErrorWithFormat ( " error displaying backtrace for thread: \" 0x%4.4x \" \n " , i ) ;
2010-08-27 00:58:05 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-07-26 02:39:59 +00:00
if ( i < num_threads - 1 )
result . AppendMessage ( " " ) ;
2010-08-27 00:58:05 +00:00
}
}
2010-06-08 16:52:24 +00:00
else
{
2010-08-27 00:58:05 +00:00
uint32_t num_args = command . GetArgumentCount ( ) ;
2011-09-22 04:58:26 +00:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2012-09-10 20:50:15 +00:00
Mutex : : Locker locker ( process - > GetThreadList ( ) . GetMutex ( ) ) ;
2010-08-27 00:58:05 +00:00
std : : vector < ThreadSP > thread_sps ;
for ( uint32_t i = 0 ; i < num_args ; i + + )
{
bool success ;
uint32_t thread_idx = Args : : StringToUInt32 ( command . GetArgumentAtIndex ( i ) , 0 , 0 , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " invalid thread specification: \" %s \" \n " , command . GetArgumentAtIndex ( i ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
thread_sps . push_back ( process - > GetThreadList ( ) . FindThreadByIndexID ( thread_idx ) ) ;
if ( ! thread_sps [ i ] )
{
result . AppendErrorWithFormat ( " no thread with index: \" %s \" \n " , command . GetArgumentAtIndex ( i ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
for ( uint32_t i = 0 ; i < num_args ; i + + )
{
2011-04-18 08:33:37 +00:00
if ( ! thread_sps [ i ] - > GetStatus ( strm ,
m_options . m_start ,
m_options . m_count ,
num_frames_with_source ) )
2010-08-27 00:58:05 +00:00
{
result . AppendErrorWithFormat ( " error displaying backtrace for thread: \" %s \" \n " , command . GetArgumentAtIndex ( i ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( i < num_args - 1 )
result . AppendMessage ( " " ) ;
}
2010-06-08 16:52:24 +00:00
}
return result . Succeeded ( ) ;
}
2012-06-08 21:56:10 +00:00
2010-08-26 23:36:03 +00:00
CommandOptions m_options ;
2010-06-08 16:52:24 +00:00
} ;
2011-03-24 21:19:54 +00:00
OptionDefinition
2010-08-26 23:36:03 +00:00
CommandObjectThreadBacktrace : : CommandOptions : : g_option_table [ ] =
{
2010-10-01 19:59:14 +00:00
{ LLDB_OPT_SET_1 , false , " count " , ' c ' , required_argument , NULL , 0 , eArgTypeCount , " How many frames to display (-1 for all) " } ,
2010-10-04 22:28:36 +00:00
{ LLDB_OPT_SET_1 , false , " start " , ' s ' , required_argument , NULL , 0 , eArgTypeFrameIndex , " Frame in which to start the backtrace " } ,
2010-10-01 19:59:14 +00:00
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-08-26 23:36:03 +00:00
} ;
2010-06-08 16:52:24 +00:00
2010-07-07 17:07:17 +00:00
enum StepScope
2010-06-08 16:52:24 +00:00
{
eStepScopeSource ,
eStepScopeInstruction
} ;
2012-06-08 21:56:10 +00:00
class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
class CommandOptions : public Options
{
public :
2011-04-07 22:46:35 +00:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2010-06-08 16:52:24 +00:00
{
2011-04-13 00:18:08 +00:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandOptions ( )
{
}
virtual Error
2011-04-13 00:18:08 +00:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-06-08 16:52:24 +00:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
2010-10-08 04:20:14 +00:00
case ' a ' :
2010-06-08 16:52:24 +00:00
{
bool success ;
m_avoid_no_debug = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( ! success )
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid boolean value for option '%c' " , short_option ) ;
2010-06-08 16:52:24 +00:00
}
break ;
2010-10-08 04:20:14 +00:00
case ' m ' :
2010-06-08 16:52:24 +00:00
{
OptionEnumValueElement * enum_values = g_option_table [ option_idx ] . enum_values ;
2011-10-07 18:58:12 +00:00
m_run_mode = ( lldb : : RunMode ) Args : : StringToOptionEnum ( option_arg , enum_values , eOnlyDuringStepping , error ) ;
2010-06-08 16:52:24 +00:00
}
break ;
2010-10-08 04:20:14 +00:00
case ' r ' :
2010-07-10 02:27:39 +00:00
{
m_avoid_regexp . clear ( ) ;
m_avoid_regexp . assign ( option_arg ) ;
}
break ;
2010-10-08 04:20:14 +00:00
default :
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
2010-10-08 04:20:14 +00:00
break ;
2010-06-08 16:52:24 +00:00
}
return error ;
}
void
2011-04-13 00:18:08 +00:00
OptionParsingStarting ( )
2010-06-08 16:52:24 +00:00
{
m_avoid_no_debug = true ;
m_run_mode = eOnlyDuringStepping ;
2010-07-10 02:27:39 +00:00
m_avoid_regexp . clear ( ) ;
2010-06-08 16:52:24 +00:00
}
2011-03-24 21:19:54 +00:00
const OptionDefinition *
2010-06-08 16:52:24 +00:00
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
2011-03-24 21:19:54 +00:00
static OptionDefinition g_option_table [ ] ;
2010-06-08 16:52:24 +00:00
// Instance variables to hold the values for command options.
bool m_avoid_no_debug ;
RunMode m_run_mode ;
2010-07-10 02:27:39 +00:00
std : : string m_avoid_regexp ;
2010-06-08 16:52:24 +00:00
} ;
2010-09-18 01:14:36 +00:00
CommandObjectThreadStepWithTypeAndScope ( CommandInterpreter & interpreter ,
const char * name ,
const char * help ,
const char * syntax ,
uint32_t flags ,
StepType step_type ,
StepScope step_scope ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter , name , help , syntax , flags ) ,
2010-06-08 16:52:24 +00:00
m_step_type ( step_type ) ,
m_step_scope ( step_scope ) ,
2011-04-07 22:46:35 +00:00
m_options ( interpreter )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg ;
CommandArgumentData thread_id_arg ;
// Define the first (and only) variant of this arg.
thread_id_arg . arg_type = eArgTypeThreadID ;
thread_id_arg . arg_repetition = eArgRepeatOptional ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( thread_id_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandObjectThreadStepWithTypeAndScope ( )
{
}
virtual
Options *
GetOptions ( )
{
return & m_options ;
}
2012-06-08 21:56:10 +00:00
protected :
2010-06-08 16:52:24 +00:00
virtual bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-08 16:52:24 +00:00
{
2011-09-22 04:58:26 +00:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-09-18 01:14:36 +00:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-08 16:52:24 +00:00
if ( process = = NULL )
{
result . AppendError ( " need a valid process to step " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
else
{
const uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
Thread * thread = NULL ;
if ( command . GetArgumentCount ( ) = = 0 )
{
2010-08-26 21:32:51 +00:00
thread = process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) ;
2010-06-08 16:52:24 +00:00
if ( thread = = NULL )
{
2010-08-26 23:36:03 +00:00
result . AppendError ( " no selected thread in process " ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else
{
const char * thread_idx_cstr = command . GetArgumentAtIndex ( 0 ) ;
uint32_t step_thread_idx = Args : : StringToUInt32 ( thread_idx_cstr , LLDB_INVALID_INDEX32 ) ;
if ( step_thread_idx = = LLDB_INVALID_INDEX32 )
{
2011-10-26 00:56:27 +00:00
result . AppendErrorWithFormat ( " invalid thread index '%s'. \n " , thread_idx_cstr ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
thread = process - > GetThreadList ( ) . FindThreadByIndexID ( step_thread_idx ) . get ( ) ;
if ( thread = = NULL )
{
result . AppendErrorWithFormat ( " Thread index %u is out of range (valid values are 0 - %u). \n " ,
2011-09-20 21:44:10 +00:00
step_thread_idx , num_threads ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
const bool abort_other_plans = false ;
const lldb : : RunMode stop_other_threads = m_options . m_run_mode ;
// This is a bit unfortunate, but not all the commands in this command object support
// only while stepping, so I use the bool for them.
bool bool_stop_other_threads ;
if ( m_options . m_run_mode = = eAllThreads )
bool_stop_other_threads = false ;
else
bool_stop_other_threads = true ;
2012-05-03 21:19:36 +00:00
ThreadPlan * new_plan = NULL ;
2010-06-08 16:52:24 +00:00
if ( m_step_type = = eStepTypeInto )
{
StackFrame * frame = thread - > GetStackFrameAtIndex ( 0 ) . get ( ) ;
if ( frame - > HasDebugInformation ( ) )
{
new_plan = thread - > QueueThreadPlanForStepRange ( abort_other_plans , m_step_type ,
frame - > GetSymbolContext ( eSymbolContextEverything ) . line_entry . range ,
frame - > GetSymbolContext ( eSymbolContextEverything ) ,
2010-06-12 18:59:55 +00:00
stop_other_threads ,
m_options . m_avoid_no_debug ) ;
2010-07-10 02:27:39 +00:00
if ( new_plan & & ! m_options . m_avoid_regexp . empty ( ) )
{
ThreadPlanStepInRange * step_in_range_plan = static_cast < ThreadPlanStepInRange * > ( new_plan ) ;
step_in_range_plan - > SetAvoidRegexp ( m_options . m_avoid_regexp . c_str ( ) ) ;
}
2010-06-08 16:52:24 +00:00
}
else
new_plan = thread - > QueueThreadPlanForStepSingleInstruction ( false , abort_other_plans , bool_stop_other_threads ) ;
2012-05-03 21:19:36 +00:00
2010-06-08 16:52:24 +00:00
}
else if ( m_step_type = = eStepTypeOver )
{
StackFrame * frame = thread - > GetStackFrameAtIndex ( 0 ) . get ( ) ;
if ( frame - > HasDebugInformation ( ) )
new_plan = thread - > QueueThreadPlanForStepRange ( abort_other_plans ,
m_step_type ,
frame - > GetSymbolContext ( eSymbolContextEverything ) . line_entry . range ,
frame - > GetSymbolContext ( eSymbolContextEverything ) ,
2010-06-12 18:59:55 +00:00
stop_other_threads ,
false ) ;
2010-06-08 16:52:24 +00:00
else
new_plan = thread - > QueueThreadPlanForStepSingleInstruction ( true ,
abort_other_plans ,
bool_stop_other_threads ) ;
}
else if ( m_step_type = = eStepTypeTrace )
{
2012-05-03 21:19:36 +00:00
new_plan = thread - > QueueThreadPlanForStepSingleInstruction ( false , abort_other_plans , bool_stop_other_threads ) ;
2010-06-08 16:52:24 +00:00
}
else if ( m_step_type = = eStepTypeTraceOver )
{
2012-05-03 21:19:36 +00:00
new_plan = thread - > QueueThreadPlanForStepSingleInstruction ( true , abort_other_plans , bool_stop_other_threads ) ;
2010-06-08 16:52:24 +00:00
}
else if ( m_step_type = = eStepTypeOut )
{
2011-01-21 06:11:58 +00:00
new_plan = thread - > QueueThreadPlanForStepOut ( abort_other_plans ,
NULL ,
false ,
bool_stop_other_threads ,
eVoteYes ,
eVoteNoOpinion ,
thread - > GetSelectedFrameIndex ( ) ) ;
2010-06-08 16:52:24 +00:00
}
else
{
result . AppendError ( " step type is not supported " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2012-05-03 21:19:36 +00:00
return false ;
2010-06-08 16:52:24 +00:00
}
2012-05-03 21:19:36 +00:00
// If we got a new plan, then set it to be a master plan (User level Plans should be master plans
// so that they can be interruptible). Then resume the process.
if ( new_plan ! = NULL )
2010-06-08 16:52:24 +00:00
{
2012-05-03 21:19:36 +00:00
new_plan - > SetIsMasterPlan ( true ) ;
new_plan - > SetOkayToDiscard ( false ) ;
2010-08-26 21:32:51 +00:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2012-05-03 21:19:36 +00:00
process - > Resume ( ) ;
if ( synchronous_execution )
{
StateType state = process - > WaitForProcessToStop ( NULL ) ;
//EventSP event_sp;
//StateType state = process->WaitForStateChangedEvents (NULL, event_sp);
//while (! StateIsStoppedState (state))
// {
// state = process->WaitForStateChangedEvents (NULL, event_sp);
// }
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
result . SetDidChangeProcessState ( true ) ;
result . AppendMessageWithFormat ( " Process %llu %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
2012-05-16 00:37:40 +00:00
else
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
2012-05-03 21:19:36 +00:00
}
else
{
result . AppendError ( " Couldn't find thread plan to implement step type. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-06-08 16:52:24 +00:00
}
}
return result . Succeeded ( ) ;
}
protected :
StepType m_step_type ;
StepScope m_step_scope ;
CommandOptions m_options ;
} ;
2011-03-24 21:19:54 +00:00
static OptionEnumValueElement
2010-06-08 16:52:24 +00:00
g_tri_running_mode [ ] =
{
2010-09-18 03:37:20 +00:00
{ eOnlyThisThread , " this-thread " , " Run only this thread " } ,
{ eAllThreads , " all-threads " , " Run all threads " } ,
{ eOnlyDuringStepping , " while-stepping " , " Run only this thread while stepping " } ,
2010-06-08 16:52:24 +00:00
{ 0 , NULL , NULL }
} ;
2011-03-24 21:19:54 +00:00
static OptionEnumValueElement
2010-06-08 16:52:24 +00:00
g_duo_running_mode [ ] =
{
2010-09-18 03:37:20 +00:00
{ eOnlyThisThread , " this-thread " , " Run only this thread " } ,
{ eAllThreads , " all-threads " , " Run all threads " } ,
2010-06-08 16:52:24 +00:00
{ 0 , NULL , NULL }
} ;
2011-03-24 21:19:54 +00:00
OptionDefinition
2010-06-08 16:52:24 +00:00
CommandObjectThreadStepWithTypeAndScope : : CommandOptions : : g_option_table [ ] =
{
2010-10-01 19:59:14 +00:00
{ LLDB_OPT_SET_1 , false , " avoid-no-debug " , ' a ' , required_argument , NULL , 0 , eArgTypeBoolean , " A boolean value that sets whether step-in will step over functions with no debug information. " } ,
{ LLDB_OPT_SET_1 , false , " run-mode " , ' m ' , required_argument , g_tri_running_mode , 0 , eArgTypeRunMode , " Determine how to run other threads while stepping the current thread. " } ,
{ LLDB_OPT_SET_1 , false , " step-over-regexp " , ' r ' , required_argument , NULL , 0 , eArgTypeRegularExpression , " A regular expression that defines function names to step over. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-06-08 16:52:24 +00:00
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadContinue
//-------------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectThreadContinue : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
2010-09-18 01:14:36 +00:00
CommandObjectThreadContinue ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" thread continue " ,
" Continue execution of one or more threads in an active process. " ,
NULL ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg ;
CommandArgumentData thread_idx_arg ;
// Define the first (and only) variant of this arg.
thread_idx_arg . arg_type = eArgTypeThreadIndex ;
thread_idx_arg . arg_repetition = eArgRepeatPlus ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( thread_idx_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandObjectThreadContinue ( )
{
}
virtual bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-08 16:52:24 +00:00
{
2010-09-18 01:14:36 +00:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-08 16:52:24 +00:00
2010-09-18 01:14:36 +00:00
if ( ! m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) )
2010-06-08 16:52:24 +00:00
{
2011-05-03 22:09:39 +00:00
result . AppendError ( " invalid target, create a debug target using the 'target create' command " ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-09-22 04:58:26 +00:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-08 16:52:24 +00:00
if ( process = = NULL )
{
result . AppendError ( " no process exists. Cannot continue " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
StateType state = process - > GetState ( ) ;
if ( ( state = = eStateCrashed ) | | ( state = = eStateStopped ) | | ( state = = eStateSuspended ) )
{
2012-07-03 20:54:16 +00:00
Mutex : : Locker locker ( process - > GetThreadList ( ) . GetMutex ( ) ) ;
2010-06-08 16:52:24 +00:00
const uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc > 0 )
{
2012-07-03 20:54:16 +00:00
std : : vector < Thread * > resume_threads ;
2010-06-08 16:52:24 +00:00
for ( uint32_t i = 0 ; i < argc ; + + i )
{
2012-05-31 20:48:41 +00:00
bool success ;
const int base = 0 ;
2012-07-03 20:54:16 +00:00
uint32_t thread_idx = Args : : StringToUInt32 ( command . GetArgumentAtIndex ( i ) , LLDB_INVALID_INDEX32 , base , & success ) ;
if ( success )
2012-05-31 20:48:41 +00:00
{
2012-07-03 20:54:16 +00:00
Thread * thread = process - > GetThreadList ( ) . FindThreadByIndexID ( thread_idx ) . get ( ) ;
if ( thread )
{
resume_threads . push_back ( thread ) ;
}
else
{
result . AppendErrorWithFormat ( " invalid thread index %u. \n " , thread_idx ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2012-05-31 20:48:41 +00:00
}
2010-06-08 16:52:24 +00:00
else
2012-05-31 20:48:41 +00:00
{
2012-07-03 20:54:16 +00:00
result . AppendErrorWithFormat ( " invalid thread index argument: \" %s \" . \n " , command . GetArgumentAtIndex ( i ) ) ;
2012-05-31 20:48:41 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-06-08 16:52:24 +00:00
}
2012-07-03 20:54:16 +00:00
if ( resume_threads . empty ( ) )
2010-06-08 16:52:24 +00:00
{
result . AppendError ( " no valid thread indexes were specified " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
{
2012-07-03 20:54:16 +00:00
if ( resume_threads . size ( ) = = 1 )
2012-05-31 20:48:41 +00:00
result . AppendMessageWithFormat ( " Resuming thread: " ) ;
else
result . AppendMessageWithFormat ( " Resuming threads: " ) ;
2012-07-03 20:54:16 +00:00
for ( uint32_t idx = 0 ; idx < num_threads ; + + idx )
2010-06-08 16:52:24 +00:00
{
2012-07-03 20:54:16 +00:00
Thread * thread = process - > GetThreadList ( ) . GetThreadAtIndex ( idx ) . get ( ) ;
std : : vector < Thread * > : : iterator this_thread_pos = find ( resume_threads . begin ( ) , resume_threads . end ( ) , thread ) ;
2012-05-31 20:48:41 +00:00
2012-07-03 20:54:16 +00:00
if ( this_thread_pos ! = resume_threads . end ( ) )
2010-06-08 16:52:24 +00:00
{
2012-07-03 20:54:16 +00:00
resume_threads . erase ( this_thread_pos ) ;
if ( resume_threads . size ( ) > 0 )
2012-05-31 20:48:41 +00:00
result . AppendMessageWithFormat ( " %u, " , thread - > GetIndexID ( ) ) ;
else
result . AppendMessageWithFormat ( " %u " , thread - > GetIndexID ( ) ) ;
2010-06-08 16:52:24 +00:00
thread - > SetResumeState ( eStateRunning ) ;
}
else
{
thread - > SetResumeState ( eStateSuspended ) ;
}
}
2011-10-19 18:09:39 +00:00
result . AppendMessageWithFormat ( " in process %llu \n " , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
}
}
else
{
2010-08-26 21:32:51 +00:00
Thread * current_thread = process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) ;
2010-06-08 16:52:24 +00:00
if ( current_thread = = NULL )
{
result . AppendError ( " the process doesn't have a current thread " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
// Set the actions that the threads should each take when resuming
2012-07-03 20:54:16 +00:00
for ( uint32_t idx = 0 ; idx < num_threads ; + + idx )
2010-06-08 16:52:24 +00:00
{
2012-07-03 20:54:16 +00:00
Thread * thread = process - > GetThreadList ( ) . GetThreadAtIndex ( idx ) . get ( ) ;
2010-06-08 16:52:24 +00:00
if ( thread = = current_thread )
{
2011-10-19 18:09:39 +00:00
result . AppendMessageWithFormat ( " Resuming thread 0x%4.4llx in process %llu \n " , thread - > GetID ( ) , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
thread - > SetResumeState ( eStateRunning ) ;
}
else
{
thread - > SetResumeState ( eStateSuspended ) ;
}
}
}
2012-07-03 20:54:16 +00:00
2010-06-08 16:52:24 +00:00
Error error ( process - > Resume ( ) ) ;
if ( error . Success ( ) )
{
2011-10-19 18:09:39 +00:00
result . AppendMessageWithFormat ( " Process %llu resuming \n " , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( synchronous_execution )
{
2010-07-14 00:18:15 +00:00
state = process - > WaitForProcessToStop ( NULL ) ;
2012-07-03 20:54:16 +00:00
2010-06-08 16:52:24 +00:00
result . SetDidChangeProcessState ( true ) ;
2011-10-19 18:09:39 +00:00
result . AppendMessageWithFormat ( " Process %llu %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Failed to resume process: %s \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Process cannot be continued from its current state (%s). \n " ,
StateAsCString ( state ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadUntil
//-------------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectThreadUntil : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
class CommandOptions : public Options
{
public :
uint32_t m_thread_idx ;
uint32_t m_frame_idx ;
2011-04-07 22:46:35 +00:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter ) ,
2010-06-08 16:52:24 +00:00
m_thread_idx ( LLDB_INVALID_THREAD_ID ) ,
m_frame_idx ( LLDB_INVALID_FRAME_ID )
{
2011-04-13 00:18:08 +00:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandOptions ( )
{
}
virtual Error
2011-04-13 00:18:08 +00:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-06-08 16:52:24 +00:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' t ' :
{
2010-07-14 00:18:15 +00:00
m_thread_idx = Args : : StringToUInt32 ( option_arg , LLDB_INVALID_INDEX32 ) ;
2010-06-08 16:52:24 +00:00
if ( m_thread_idx = = LLDB_INVALID_INDEX32 )
{
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid thread index '%s' " , option_arg ) ;
2010-06-08 16:52:24 +00:00
}
}
break ;
case ' f ' :
{
m_frame_idx = Args : : StringToUInt32 ( option_arg , LLDB_INVALID_FRAME_ID ) ;
if ( m_frame_idx = = LLDB_INVALID_FRAME_ID )
{
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid frame index '%s' " , option_arg ) ;
2010-06-08 16:52:24 +00:00
}
}
break ;
case ' m ' :
{
OptionEnumValueElement * enum_values = g_option_table [ option_idx ] . enum_values ;
2011-10-07 18:58:12 +00:00
lldb : : RunMode run_mode = ( lldb : : RunMode ) Args : : StringToOptionEnum ( option_arg , enum_values , eOnlyDuringStepping , error ) ;
2010-06-08 16:52:24 +00:00
2011-10-07 18:58:12 +00:00
if ( error . Success ( ) )
{
if ( run_mode = = eAllThreads )
m_stop_others = false ;
else
m_stop_others = true ;
}
2010-06-08 16:52:24 +00:00
}
break ;
default :
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
2010-06-08 16:52:24 +00:00
break ;
}
return error ;
}
void
2011-04-13 00:18:08 +00:00
OptionParsingStarting ( )
2010-06-08 16:52:24 +00:00
{
m_thread_idx = LLDB_INVALID_THREAD_ID ;
m_frame_idx = 0 ;
m_stop_others = false ;
}
2011-03-24 21:19:54 +00:00
const OptionDefinition *
2010-06-08 16:52:24 +00:00
GetDefinitions ( )
{
return g_option_table ;
}
uint32_t m_step_thread_idx ;
bool m_stop_others ;
// Options table: Required for subclasses of Options.
2011-03-24 21:19:54 +00:00
static OptionDefinition g_option_table [ ] ;
2010-06-08 16:52:24 +00:00
// Instance variables to hold the values for command options.
} ;
2010-09-18 01:14:36 +00:00
CommandObjectThreadUntil ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" thread until " ,
" Run the current or specified thread until it reaches a given line number or leaves the current function. " ,
NULL ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ) ,
2011-04-07 22:46:35 +00:00
m_options ( interpreter )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg ;
CommandArgumentData line_num_arg ;
// Define the first (and only) variant of this arg.
line_num_arg . arg_type = eArgTypeLineNum ;
line_num_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( line_num_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandObjectThreadUntil ( )
{
}
virtual
Options *
GetOptions ( )
{
return & m_options ;
}
2012-06-08 21:56:10 +00:00
protected :
2010-06-08 16:52:24 +00:00
virtual bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-08 16:52:24 +00:00
{
2010-09-18 01:14:36 +00:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-08 16:52:24 +00:00
2010-09-18 01:14:36 +00:00
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
2010-09-14 23:36:40 +00:00
if ( target = = NULL )
2010-06-08 16:52:24 +00:00
{
2011-05-03 22:09:39 +00:00
result . AppendError ( " invalid target, create a debug target using the 'target create' command " ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-09-22 04:58:26 +00:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-08 16:52:24 +00:00
if ( process = = NULL )
{
result . AppendError ( " need a valid process to step " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
else
{
Thread * thread = NULL ;
uint32_t line_number ;
if ( command . GetArgumentCount ( ) ! = 1 )
{
result . AppendErrorWithFormat ( " No line number provided: \n %s " , GetSyntax ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
line_number = Args : : StringToUInt32 ( command . GetArgumentAtIndex ( 0 ) , UINT32_MAX ) ;
if ( line_number = = UINT32_MAX )
{
2011-10-26 00:56:27 +00:00
result . AppendErrorWithFormat ( " invalid line number: '%s'. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( m_options . m_thread_idx = = LLDB_INVALID_THREAD_ID )
{
2010-08-26 21:32:51 +00:00
thread = process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) ;
2010-06-08 16:52:24 +00:00
}
else
{
2012-05-31 00:29:20 +00:00
thread = process - > GetThreadList ( ) . FindThreadByIndexID ( m_options . m_thread_idx ) . get ( ) ;
2010-06-08 16:52:24 +00:00
}
if ( thread = = NULL )
{
const uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
2011-05-08 00:56:32 +00:00
result . AppendErrorWithFormat ( " Thread index %u is out of range (valid values are 0 - %u). \n " ,
m_options . m_thread_idx ,
num_threads ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2012-05-11 23:47:32 +00:00
const bool abort_other_plans = false ;
2010-06-08 16:52:24 +00:00
StackFrame * frame = thread - > GetStackFrameAtIndex ( m_options . m_frame_idx ) . get ( ) ;
if ( frame = = NULL )
{
2011-05-08 00:56:32 +00:00
result . AppendErrorWithFormat ( " Frame index %u is out of range for thread %u. \n " ,
m_options . m_frame_idx ,
m_options . m_thread_idx ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2012-05-03 21:19:36 +00:00
ThreadPlan * new_plan = NULL ;
2010-06-08 16:52:24 +00:00
if ( frame - > HasDebugInformation ( ) )
{
// Finally we got here... Translate the given line number to a bunch of addresses:
SymbolContext sc ( frame - > GetSymbolContext ( eSymbolContextCompUnit ) ) ;
LineTable * line_table = NULL ;
if ( sc . comp_unit )
line_table = sc . comp_unit - > GetLineTable ( ) ;
if ( line_table = = NULL )
{
result . AppendErrorWithFormat ( " Failed to resolve the line table for frame %u of thread index %u. \n " ,
m_options . m_frame_idx , m_options . m_thread_idx ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
LineEntry function_start ;
uint32_t index_ptr = 0 , end_ptr ;
std : : vector < addr_t > address_list ;
// Find the beginning & end index of the
AddressRange fun_addr_range = sc . function - > GetAddressRange ( ) ;
Address fun_start_addr = fun_addr_range . GetBaseAddress ( ) ;
line_table - > FindLineEntryByAddress ( fun_start_addr , function_start , & index_ptr ) ;
2011-05-08 00:56:32 +00:00
Address fun_end_addr ( fun_start_addr . GetSection ( ) ,
fun_start_addr . GetOffset ( ) + fun_addr_range . GetByteSize ( ) ) ;
2010-06-08 16:52:24 +00:00
line_table - > FindLineEntryByAddress ( fun_end_addr , function_start , & end_ptr ) ;
2011-05-08 00:56:32 +00:00
bool all_in_function = true ;
2010-06-08 16:52:24 +00:00
while ( index_ptr < = end_ptr )
{
LineEntry line_entry ;
2011-09-23 00:54:11 +00:00
const bool exact = false ;
index_ptr = sc . comp_unit - > FindLineEntry ( index_ptr , line_number , sc . comp_unit , exact , & line_entry ) ;
2010-06-08 16:52:24 +00:00
if ( index_ptr = = UINT32_MAX )
break ;
2010-09-14 23:36:40 +00:00
addr_t address = line_entry . range . GetBaseAddress ( ) . GetLoadAddress ( target ) ;
2010-06-08 16:52:24 +00:00
if ( address ! = LLDB_INVALID_ADDRESS )
2011-05-08 00:56:32 +00:00
{
if ( fun_addr_range . ContainsLoadAddress ( address , target ) )
address_list . push_back ( address ) ;
else
all_in_function = false ;
}
2010-06-08 16:52:24 +00:00
index_ptr + + ;
}
2011-05-08 00:56:32 +00:00
if ( address_list . size ( ) = = 0 )
{
if ( all_in_function )
result . AppendErrorWithFormat ( " No line entries matching until target. \n " ) ;
else
result . AppendErrorWithFormat ( " Until target outside of the current function. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
new_plan = thread - > QueueThreadPlanForStepUntil ( abort_other_plans ,
& address_list . front ( ) ,
address_list . size ( ) ,
m_options . m_stop_others ,
thread - > GetSelectedFrameIndex ( ) ) ;
2012-05-03 21:19:36 +00:00
// User level plans should be master plans so they can be interrupted (e.g. by hitting a breakpoint)
// and other plans executed by the user (stepping around the breakpoint) and then a "continue"
// will resume the original plan.
new_plan - > SetIsMasterPlan ( true ) ;
2010-06-08 16:52:24 +00:00
new_plan - > SetOkayToDiscard ( false ) ;
}
else
{
2011-05-08 00:56:32 +00:00
result . AppendErrorWithFormat ( " Frame index %u of thread %u has no debug information. \n " ,
m_options . m_frame_idx ,
m_options . m_thread_idx ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-08-26 21:32:51 +00:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( m_options . m_thread_idx ) ;
2010-06-08 16:52:24 +00:00
Error error ( process - > Resume ( ) ) ;
if ( error . Success ( ) )
{
2011-10-19 18:09:39 +00:00
result . AppendMessageWithFormat ( " Process %llu resuming \n " , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( synchronous_execution )
{
StateType state = process - > WaitForProcessToStop ( NULL ) ;
result . SetDidChangeProcessState ( true ) ;
2011-10-19 18:09:39 +00:00
result . AppendMessageWithFormat ( " Process %llu %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Failed to resume process: %s. \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
return result . Succeeded ( ) ;
}
2012-06-08 21:56:10 +00:00
2010-06-08 16:52:24 +00:00
CommandOptions m_options ;
} ;
2011-03-24 21:19:54 +00:00
OptionDefinition
2010-06-08 16:52:24 +00:00
CommandObjectThreadUntil : : CommandOptions : : g_option_table [ ] =
{
2010-10-04 22:28:36 +00:00
{ LLDB_OPT_SET_1 , false , " frame " , ' f ' , required_argument , NULL , 0 , eArgTypeFrameIndex , " Frame index for until operation - defaults to 0 " } ,
2010-10-01 19:59:14 +00:00
{ LLDB_OPT_SET_1 , false , " thread " , ' t ' , required_argument , NULL , 0 , eArgTypeThreadIndex , " Thread index for the thread for until operation " } ,
{ LLDB_OPT_SET_1 , false , " run-mode " , ' m ' , required_argument , g_duo_running_mode , 0 , eArgTypeRunMode , " Determine how to run other threads while stepping this one " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-06-08 16:52:24 +00:00
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadSelect
//-------------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectThreadSelect : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
2010-09-18 01:14:36 +00:00
CommandObjectThreadSelect ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" thread select " ,
" Select a thread as the currently active thread. " ,
NULL ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg ;
CommandArgumentData thread_idx_arg ;
// Define the first (and only) variant of this arg.
thread_idx_arg . arg_type = eArgTypeThreadIndex ;
thread_idx_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( thread_idx_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandObjectThreadSelect ( )
{
}
2012-06-08 21:56:10 +00:00
protected :
2010-06-08 16:52:24 +00:00
virtual bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-08 16:52:24 +00:00
{
2011-09-22 04:58:26 +00:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-08 16:52:24 +00:00
if ( process = = NULL )
{
result . AppendError ( " no process " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( command . GetArgumentCount ( ) ! = 1 )
{
2011-09-20 21:44:10 +00:00
result . AppendErrorWithFormat ( " '%s' takes exactly one thread index argument: \n Usage: %s \n " , m_cmd_name . c_str ( ) , m_cmd_syntax . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
uint32_t index_id = Args : : StringToUInt32 ( command . GetArgumentAtIndex ( 0 ) , 0 , 0 ) ;
Thread * new_thread = process - > GetThreadList ( ) . FindThreadByIndexID ( index_id ) . get ( ) ;
if ( new_thread = = NULL )
{
2011-10-26 00:56:27 +00:00
result . AppendErrorWithFormat ( " invalid thread #%s. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-08-26 21:32:51 +00:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( new_thread - > GetID ( ) ) ;
2010-09-14 00:53:53 +00:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2010-06-08 16:52:24 +00:00
2011-04-18 08:33:37 +00:00
const uint32_t start_frame = 0 ;
const uint32_t num_frames = 1 ;
const uint32_t num_frames_with_source = 1 ;
new_thread - > GetStatus ( result . GetOutputStream ( ) ,
start_frame ,
num_frames ,
num_frames_with_source ) ;
2010-06-08 16:52:24 +00:00
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadList
//-------------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectThreadList : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
2010-06-23 01:19:29 +00:00
public :
2010-06-08 16:52:24 +00:00
2010-09-18 01:14:36 +00:00
CommandObjectThreadList ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" thread list " ,
" Show a summary of all current threads in a process. " ,
" thread list " ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
2010-06-08 16:52:24 +00:00
{
2010-06-23 01:19:29 +00:00
}
2010-06-08 16:52:24 +00:00
2010-06-23 01:19:29 +00:00
~ CommandObjectThreadList ( )
{
}
2012-06-08 21:56:10 +00:00
protected :
2010-06-23 01:19:29 +00:00
bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-23 01:19:29 +00:00
{
2011-02-19 02:53:09 +00:00
Stream & strm = result . GetOutputStream ( ) ;
2010-06-23 01:19:29 +00:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2011-04-12 05:54:46 +00:00
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
2011-09-22 04:58:26 +00:00
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
2010-06-08 16:52:24 +00:00
{
2011-04-18 08:33:37 +00:00
const bool only_threads_with_stop_reason = false ;
const uint32_t start_frame = 0 ;
const uint32_t num_frames = 0 ;
const uint32_t num_frames_with_source = 0 ;
2011-09-22 04:58:26 +00:00
process - > GetStatus ( strm ) ;
process - > GetThreadStatus ( strm ,
only_threads_with_stop_reason ,
start_frame ,
num_frames ,
num_frames_with_source ) ;
2010-06-08 16:52:24 +00:00
}
else
{
2010-06-23 01:19:29 +00:00
result . AppendError ( " no current location or status available " ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-23 01:19:29 +00:00
return result . Succeeded ( ) ;
2010-06-08 16:52:24 +00:00
}
2010-06-23 01:19:29 +00:00
} ;
2010-06-08 16:52:24 +00:00
2012-09-14 02:14:15 +00:00
class CommandObjectThreadReturn : public CommandObjectRaw
{
public :
CommandObjectThreadReturn ( CommandInterpreter & interpreter ) :
CommandObjectRaw ( interpreter ,
" thread return " ,
" Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value. " ,
" thread return " ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
{
CommandArgumentEntry arg ;
CommandArgumentData expression_arg ;
// Define the first (and only) variant of this arg.
expression_arg . arg_type = eArgTypeExpression ;
expression_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( expression_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
}
~ CommandObjectThreadReturn ( )
{
}
protected :
bool DoExecute
(
const char * command ,
CommandReturnObject & result
)
{
// If there is a command string, pass it to the expression parser:
ExecutionContext exe_ctx = m_interpreter . GetExecutionContext ( ) ;
if ( ! ( exe_ctx . HasProcessScope ( ) & & exe_ctx . HasThreadScope ( ) & & exe_ctx . HasFrameScope ( ) ) )
{
result . AppendError ( " Must have selected process, thread and frame for thread return. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ValueObjectSP return_valobj_sp ;
StackFrameSP frame_sp = exe_ctx . GetFrameSP ( ) ;
uint32_t frame_idx = frame_sp - > GetFrameIndex ( ) ;
if ( frame_sp - > IsInlined ( ) )
{
result . AppendError ( " Don't know how to return from inlined frames. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command & & command [ 0 ] ! = ' \0 ' )
{
Target * target = exe_ctx . GetTargetPtr ( ) ;
Target : : EvaluateExpressionOptions options ;
options . SetUnwindOnError ( true ) ;
options . SetUseDynamic ( eNoDynamicValues ) ;
ExecutionResults exe_results = eExecutionSetupError ;
exe_results = target - > EvaluateExpression ( command ,
frame_sp . get ( ) ,
return_valobj_sp ,
options ) ;
if ( exe_results ! = eExecutionCompleted )
{
if ( return_valobj_sp )
result . AppendErrorWithFormat ( " Error evaluating result expression: %s " , return_valobj_sp - > GetError ( ) . AsCString ( ) ) ;
else
result . AppendErrorWithFormat ( " Unknown error evaluating result expression. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
Error error ;
ThreadSP thread_sp = exe_ctx . GetThreadSP ( ) ;
error = thread_sp - > ReturnFromFrame ( frame_sp , return_valobj_sp ) ;
if ( ! error . Success ( ) )
{
result . AppendErrorWithFormat ( " Error returning from frame %d of thread %d: %s. " , frame_idx , thread_sp - > GetIndexID ( ) , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
thread_sp - > GetStatus ( result . GetOutputStream ( ) , 0 , 1 , 1 ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return true ;
}
} ;
2010-06-08 16:52:24 +00:00
//-------------------------------------------------------------------------
// CommandObjectMultiwordThread
//-------------------------------------------------------------------------
2010-06-23 01:19:29 +00:00
CommandObjectMultiwordThread : : CommandObjectMultiwordThread ( CommandInterpreter & interpreter ) :
2010-09-18 01:14:36 +00:00
CommandObjectMultiword ( interpreter ,
" thread " ,
2010-09-07 22:38:08 +00:00
" A set of commands for operating on one or more threads within a running process. " ,
2010-06-08 16:52:24 +00:00
" thread <subcommand> [<subcommand-options>] " )
{
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " backtrace " , CommandObjectSP ( new CommandObjectThreadBacktrace ( interpreter ) ) ) ;
LoadSubCommand ( " continue " , CommandObjectSP ( new CommandObjectThreadContinue ( interpreter ) ) ) ;
LoadSubCommand ( " list " , CommandObjectSP ( new CommandObjectThreadList ( interpreter ) ) ) ;
2012-09-14 02:14:15 +00:00
LoadSubCommand ( " return " , CommandObjectSP ( new CommandObjectThreadReturn ( interpreter ) ) ) ;
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " select " , CommandObjectSP ( new CommandObjectThreadSelect ( interpreter ) ) ) ;
LoadSubCommand ( " until " , CommandObjectSP ( new CommandObjectThreadUntil ( interpreter ) ) ) ;
LoadSubCommand ( " step-in " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
2010-06-23 01:19:29 +00:00
" thread step-in " ,
2010-09-18 01:14:36 +00:00
" Source level single step in specified thread (current thread, if none specified). " ,
2010-10-04 22:28:36 +00:00
NULL ,
2010-09-18 01:14:36 +00:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeInto ,
eStepScopeSource ) ) ) ;
2010-06-23 01:19:29 +00:00
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " step-out " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
" thread step-out " ,
2011-12-17 01:35:57 +00:00
" Finish executing the function of the currently selected frame and return to its call site in specified thread (current thread, if none specified). " ,
2010-10-04 22:28:36 +00:00
NULL ,
2010-09-18 01:14:36 +00:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeOut ,
eStepScopeSource ) ) ) ;
2010-06-08 16:52:24 +00:00
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " step-over " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
" thread step-over " ,
" Source level single step in specified thread (current thread, if none specified), stepping over calls. " ,
2010-10-04 22:28:36 +00:00
NULL ,
2010-09-18 01:14:36 +00:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeOver ,
eStepScopeSource ) ) ) ;
2010-06-08 16:52:24 +00:00
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " step-inst " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
" thread step-inst " ,
" Single step one instruction in specified thread (current thread, if none specified). " ,
2010-10-04 22:28:36 +00:00
NULL ,
2010-09-18 01:14:36 +00:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeTrace ,
eStepScopeInstruction ) ) ) ;
2010-06-23 01:19:29 +00:00
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " step-inst-over " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
" thread step-inst-over " ,
" Single step one instruction in specified thread (current thread, if none specified), stepping over calls. " ,
2010-10-04 22:28:36 +00:00
NULL ,
2010-09-18 01:14:36 +00:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeTraceOver ,
eStepScopeInstruction ) ) ) ;
2010-06-08 16:52:24 +00:00
}
CommandObjectMultiwordThread : : ~ CommandObjectMultiwordThread ( )
{
}