2010-06-09 00:52:24 +08: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
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Options.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/State.h"
# include "lldb/Core/SourceManager.h"
2011-02-01 09:31:41 +08:00
# include "lldb/Host/Host.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
# 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"
# include "lldb/Symbol/LineTable.h"
# include "lldb/Symbol/LineEntry.h"
using namespace lldb ;
using namespace lldb_private ;
bool
lldb_private : : DisplayThreadInfo
(
2010-06-23 09:19:29 +08:00
CommandInterpreter & interpreter ,
2010-06-09 00:52:24 +08:00
Stream & strm ,
Thread * thread ,
bool only_threads_with_stop_reason ,
bool show_source
)
{
if ( thread )
{
if ( only_threads_with_stop_reason )
{
2010-08-04 09:40:35 +08:00
if ( thread - > GetStopInfo ( ) = = NULL )
return false ;
2010-06-09 00:52:24 +08:00
}
strm . Indent ( ) ;
2010-08-27 05:32:51 +08:00
strm . Printf ( " %c " , thread - > GetProcess ( ) . GetThreadList ( ) . GetSelectedThread ( ) . get ( ) = = thread ? ' * ' : ' ' ) ;
2010-06-09 00:52:24 +08:00
// Show one frame with only the first showing source
if ( show_source )
{
2010-08-31 03:44:40 +08:00
bool already_shown = false ;
StackFrameSP frame_sp = thread - > GetStackFrameAtIndex ( 0 ) ;
SymbolContext frame_sc ( frame_sp - > GetSymbolContext ( eSymbolContextLineEntry ) ) ;
2010-09-21 04:44:43 +08:00
if ( interpreter . GetDebugger ( ) . GetUseExternalEditor ( ) & & frame_sc . line_entry . file & & frame_sc . line_entry . line ! = 0 )
2010-08-31 03:44:40 +08:00
{
already_shown = Host : : OpenFileInExternalEditor ( frame_sc . line_entry . file , frame_sc . line_entry . line ) ;
}
2010-06-09 00:52:24 +08:00
DisplayFramesForExecutionContext ( thread ,
interpreter ,
strm ,
0 , // Start at first frame
1 , // Number of frames to show
false , // Don't show the frame info since we already displayed most of it above...
2010-08-31 03:44:40 +08:00
! already_shown , // Show source for the first frame
2010-06-09 00:52:24 +08:00
3 , // lines of source context before
3 ) ; // lines of source context after
}
else
{
2010-10-04 09:05:56 +08:00
thread - > DumpUsingSettingsFormat ( strm , 0 ) ;
2010-06-09 00:52:24 +08:00
}
return true ;
}
return false ;
}
size_t
lldb_private : : DisplayThreadsInfo
(
2010-06-23 09:19:29 +08:00
CommandInterpreter & interpreter ,
2010-06-09 00:52:24 +08:00
ExecutionContext * exe_ctx ,
CommandReturnObject & result ,
bool only_threads_with_stop_reason ,
bool show_source
)
{
StreamString strm ;
size_t num_thread_infos_dumped = 0 ;
if ( ! exe_ctx - > process )
return 0 ;
const size_t num_threads = exe_ctx - > process - > GetThreadList ( ) . GetSize ( ) ;
if ( num_threads > 0 )
{
for ( uint32_t i = 0 ; i < num_threads ; i + + )
{
Thread * thread = exe_ctx - > process - > GetThreadList ( ) . GetThreadAtIndex ( i ) . get ( ) ;
if ( thread )
{
if ( DisplayThreadInfo ( interpreter ,
strm ,
thread ,
only_threads_with_stop_reason ,
show_source ) )
+ + num_thread_infos_dumped ;
}
}
}
if ( num_thread_infos_dumped > 0 )
{
if ( num_thread_infos_dumped < num_threads )
result . GetOutputStream ( ) . Printf ( " %u of %u threads stopped with reasons: \n " , num_thread_infos_dumped , num_threads ) ;
2011-02-19 10:53:09 +08:00
result . AppendMessage ( strm . GetString ( ) . c_str ( ) ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
return num_thread_infos_dumped ;
}
size_t
lldb_private : : DisplayFramesForExecutionContext
(
Thread * thread ,
2010-06-23 09:19:29 +08:00
CommandInterpreter & interpreter ,
2010-06-09 00:52:24 +08:00
Stream & strm ,
uint32_t first_frame ,
uint32_t num_frames ,
bool show_frame_info ,
uint32_t num_frames_with_source ,
uint32_t source_lines_before ,
uint32_t source_lines_after
)
{
if ( thread = = NULL )
return 0 ;
size_t num_frames_displayed = 0 ;
if ( num_frames = = 0 )
return 0 ;
2010-10-04 09:05:56 +08:00
thread - > DumpUsingSettingsFormat ( strm , num_frames > 1 ? UINT32_MAX : first_frame ) ;
2010-06-09 00:52:24 +08:00
strm . IndentMore ( ) ;
StackFrameSP frame_sp ;
2010-07-10 04:39:50 +08:00
uint32_t frame_idx = 0 ;
2010-08-27 07:36:03 +08:00
uint32_t last_frame ;
// Don't let the last frame wrap around...
if ( num_frames = = UINT32_MAX )
last_frame = UINT32_MAX ;
2010-06-09 00:52:24 +08:00
else
2010-08-27 07:36:03 +08:00
last_frame = first_frame + num_frames ;
for ( frame_idx = first_frame ; frame_idx < last_frame ; + + frame_idx )
2010-06-09 00:52:24 +08:00
{
2010-08-27 07:36:03 +08:00
frame_sp = thread - > GetStackFrameAtIndex ( frame_idx ) ;
if ( frame_sp . get ( ) = = NULL )
break ;
if ( DisplayFrameForExecutionContext ( thread ,
frame_sp . get ( ) ,
interpreter ,
strm ,
show_frame_info ,
num_frames_with_source > first_frame - frame_idx ,
source_lines_before ,
source_lines_after ) = = false )
break ;
+ + num_frames_displayed ;
2010-06-09 00:52:24 +08:00
}
2010-08-27 07:36:03 +08:00
2010-06-09 00:52:24 +08:00
strm . IndentLess ( ) ;
return num_frames_displayed ;
}
bool
lldb_private : : DisplayFrameForExecutionContext
(
Thread * thread ,
StackFrame * frame ,
2010-06-23 09:19:29 +08:00
CommandInterpreter & interpreter ,
2010-06-09 00:52:24 +08:00
Stream & strm ,
bool show_frame_info ,
bool show_source ,
uint32_t source_lines_before ,
uint32_t source_lines_after
)
{
// thread and frame must be filled in prior to calling this function
if ( thread & & frame )
{
if ( show_frame_info )
{
strm . Indent ( ) ;
2010-10-04 09:05:56 +08:00
frame - > DumpUsingSettingsFormat ( & strm ) ;
2010-06-09 00:52:24 +08:00
}
SymbolContext sc ( frame - > GetSymbolContext ( eSymbolContextCompUnit | eSymbolContextLineEntry ) ) ;
if ( show_source & & sc . comp_unit & & sc . line_entry . IsValid ( ) )
{
2010-06-23 09:19:29 +08:00
interpreter . GetDebugger ( ) . GetSourceManager ( ) . DisplaySourceLinesWithLineNumbers (
2010-06-09 00:52:24 +08:00
sc . line_entry . file ,
sc . line_entry . line ,
3 ,
3 ,
" -> " ,
& strm ) ;
}
return true ;
}
return false ;
}
//-------------------------------------------------------------------------
// CommandObjectThreadBacktrace
//-------------------------------------------------------------------------
class CommandObjectThreadBacktrace : public CommandObject
{
public :
2010-08-27 07:36:03 +08:00
class CommandOptions : public Options
{
public :
2011-04-08 06:46:35 +08:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2010-08-27 07:36:03 +08:00
{
2011-04-13 08:18:08 +08:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-08-27 07:36:03 +08:00
}
virtual
~ CommandOptions ( )
{
}
virtual Error
2011-04-13 08:18:08 +08:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-08-27 07:36:03 +08: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 )
error . SetErrorStringWithFormat ( " Invalid integer value for option '%c'. \n " , short_option ) ;
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 )
error . SetErrorStringWithFormat ( " Invalid integer value for option '%c'. \n " , short_option ) ;
}
break ;
default :
error . SetErrorStringWithFormat ( " Invalid short option character '%c'. \n " , short_option ) ;
break ;
}
return error ;
}
void
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( )
2010-08-27 07:36:03 +08:00
{
m_count = - 1 ;
m_start = 0 ;
}
2011-03-25 05:19:54 +08:00
const OptionDefinition *
2010-08-27 07:36:03 +08:00
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
2011-03-25 05:19:54 +08:00
static OptionDefinition g_option_table [ ] ;
2010-08-27 07:36:03 +08:00
// Instance variables to hold the values for command options.
uint32_t m_count ;
uint32_t m_start ;
} ;
2010-09-18 09:14:36 +08:00
CommandObjectThreadBacktrace ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" thread backtrace " ,
2010-09-09 06:08:58 +08:00
" 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. " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-06-09 00:52:24 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ) ,
2011-04-08 06:46:35 +08:00
m_options ( interpreter )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08: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-09 00:52:24 +08:00
}
~ CommandObjectThreadBacktrace ( )
{
}
2010-08-27 07:36:03 +08:00
virtual Options *
GetOptions ( )
{
return & m_options ;
}
2010-06-09 00:52:24 +08:00
2010-06-23 09:19:29 +08:00
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command , CommandReturnObject & result )
2010-06-09 00:52:24 +08:00
{
2010-08-27 08:58:05 +08:00
bool show_frame_info = true ;
uint32_t num_frames_with_source = 0 ; // Don't show any frames with source when backtracing
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
2010-06-09 00:52:24 +08:00
if ( command . GetArgumentCount ( ) = = 0 )
{
2011-04-12 13:54:46 +08:00
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
2010-06-09 00:52:24 +08:00
if ( exe_ctx . thread )
{
if ( DisplayFramesForExecutionContext ( exe_ctx . thread ,
2010-09-18 09:14:36 +08:00
m_interpreter ,
2010-06-09 00:52:24 +08:00
result . GetOutputStream ( ) ,
2010-08-27 07:36:03 +08:00
m_options . m_start ,
m_options . m_count ,
2010-06-09 00:52:24 +08:00
show_frame_info ,
num_frames_with_source ,
3 ,
3 ) )
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
}
else
{
result . AppendError ( " invalid thread " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
2010-08-27 08:58:05 +08:00
else if ( command . GetArgumentCount ( ) = = 1 & & : : strcmp ( command . GetArgumentAtIndex ( 0 ) , " all " ) = = 0 )
{
2011-04-12 13:54:46 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . process ;
2010-08-27 08:58:05 +08:00
uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
for ( uint32_t i = 0 ; i < num_threads ; i + + )
{
ThreadSP thread_sp = process - > GetThreadList ( ) . GetThreadAtIndex ( i ) ;
if ( ! DisplayFramesForExecutionContext ( thread_sp . get ( ) ,
2010-09-18 09:14:36 +08:00
m_interpreter ,
2010-08-27 08:58:05 +08:00
result . GetOutputStream ( ) ,
m_options . m_start ,
m_options . m_count ,
show_frame_info ,
num_frames_with_source ,
3 ,
3 ) )
{
2010-09-04 06:45:01 +08:00
result . AppendErrorWithFormat ( " error displaying backtrace for thread: \" 0x%4.4x \" \n " , i ) ;
2010-08-27 08:58:05 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( i < num_threads - 1 )
result . AppendMessage ( " " ) ;
}
}
2010-06-09 00:52:24 +08:00
else
{
2010-08-27 08:58:05 +08:00
uint32_t num_args = command . GetArgumentCount ( ) ;
2011-04-12 13:54:46 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . process ;
2010-08-27 08:58:05 +08: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 + + )
{
if ( ! DisplayFramesForExecutionContext ( thread_sps [ i ] . get ( ) ,
2010-09-18 09:14:36 +08:00
m_interpreter ,
2010-08-27 08:58:05 +08:00
result . GetOutputStream ( ) ,
m_options . m_start ,
m_options . m_count ,
show_frame_info ,
num_frames_with_source ,
3 ,
3 ) )
{
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-09 00:52:24 +08:00
}
return result . Succeeded ( ) ;
}
protected :
2010-08-27 07:36:03 +08:00
CommandOptions m_options ;
2010-06-09 00:52:24 +08:00
} ;
2011-03-25 05:19:54 +08:00
OptionDefinition
2010-08-27 07:36:03 +08:00
CommandObjectThreadBacktrace : : CommandOptions : : g_option_table [ ] =
{
2010-10-02 03:59:14 +08:00
{ LLDB_OPT_SET_1 , false , " count " , ' c ' , required_argument , NULL , 0 , eArgTypeCount , " How many frames to display (-1 for all) " } ,
2010-10-05 06:28:36 +08:00
{ LLDB_OPT_SET_1 , false , " start " , ' s ' , required_argument , NULL , 0 , eArgTypeFrameIndex , " Frame in which to start the backtrace " } ,
2010-10-02 03:59:14 +08:00
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-08-27 07:36:03 +08:00
} ;
2010-06-09 00:52:24 +08:00
2010-07-08 01:07:17 +08:00
enum StepScope
2010-06-09 00:52:24 +08:00
{
eStepScopeSource ,
eStepScopeInstruction
} ;
class CommandObjectThreadStepWithTypeAndScope : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
2011-04-08 06:46:35 +08:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2010-06-09 00:52:24 +08:00
{
2011-04-13 08:18:08 +08:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandOptions ( )
{
}
virtual Error
2011-04-13 08:18:08 +08:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-06-09 00:52:24 +08:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
2010-10-08 12:20:14 +08:00
case ' a ' :
2010-06-09 00:52:24 +08:00
{
bool success ;
m_avoid_no_debug = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( ! success )
error . SetErrorStringWithFormat ( " Invalid boolean value for option '%c'. \n " , short_option ) ;
}
break ;
2010-10-08 12:20:14 +08:00
case ' m ' :
2010-06-09 00:52:24 +08:00
{
bool found_one = false ;
OptionEnumValueElement * enum_values = g_option_table [ option_idx ] . enum_values ;
m_run_mode = ( lldb : : RunMode ) Args : : StringToOptionEnum ( option_arg , enum_values , eOnlyDuringStepping , & found_one ) ;
if ( ! found_one )
error . SetErrorStringWithFormat ( " Invalid enumeration value for option '%c'. \n " , short_option ) ;
}
break ;
2010-10-08 12:20:14 +08:00
case ' r ' :
2010-07-10 10:27:39 +08:00
{
m_avoid_regexp . clear ( ) ;
m_avoid_regexp . assign ( option_arg ) ;
}
break ;
2010-10-08 12:20:14 +08:00
default :
error . SetErrorStringWithFormat ( " Invalid short option character '%c'. \n " , short_option ) ;
break ;
2010-06-09 00:52:24 +08:00
}
return error ;
}
void
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( )
2010-06-09 00:52:24 +08:00
{
m_avoid_no_debug = true ;
m_run_mode = eOnlyDuringStepping ;
2010-07-10 10:27:39 +08:00
m_avoid_regexp . clear ( ) ;
2010-06-09 00:52:24 +08:00
}
2011-03-25 05:19:54 +08:00
const OptionDefinition *
2010-06-09 00:52:24 +08:00
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
2011-03-25 05:19:54 +08:00
static OptionDefinition g_option_table [ ] ;
2010-06-09 00:52:24 +08:00
// Instance variables to hold the values for command options.
bool m_avoid_no_debug ;
RunMode m_run_mode ;
2010-07-10 10:27:39 +08:00
std : : string m_avoid_regexp ;
2010-06-09 00:52:24 +08:00
} ;
2010-09-18 09:14:36 +08:00
CommandObjectThreadStepWithTypeAndScope ( CommandInterpreter & interpreter ,
const char * name ,
const char * help ,
const char * syntax ,
uint32_t flags ,
StepType step_type ,
StepScope step_scope ) :
CommandObject ( interpreter , name , help , syntax , flags ) ,
2010-06-09 00:52:24 +08:00
m_step_type ( step_type ) ,
m_step_scope ( step_scope ) ,
2011-04-08 06:46:35 +08:00
m_options ( interpreter )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08: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-09 00:52:24 +08:00
}
virtual
~ CommandObjectThreadStepWithTypeAndScope ( )
{
}
virtual
Options *
GetOptions ( )
{
return & m_options ;
}
virtual bool
2010-06-23 09:19:29 +08:00
Execute
(
Args & command ,
CommandReturnObject & result
)
2010-06-09 00:52:24 +08:00
{
2011-04-12 13:54:46 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . process ;
2010-09-18 09:14:36 +08:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-09 00:52:24 +08: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-27 05:32:51 +08:00
thread = process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) ;
2010-06-09 00:52:24 +08:00
if ( thread = = NULL )
{
2010-08-27 07:36:03 +08:00
result . AppendError ( " no selected thread in process " ) ;
2010-06-09 00:52:24 +08: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 )
{
result . AppendErrorWithFormat ( " Invalid thread index '%s'. \n " , thread_idx_cstr ) ;
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 " ,
step_thread_idx , 0 , num_threads ) ;
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 ;
if ( m_step_type = = eStepTypeInto )
{
StackFrame * frame = thread - > GetStackFrameAtIndex ( 0 ) . get ( ) ;
ThreadPlan * new_plan ;
if ( frame - > HasDebugInformation ( ) )
{
new_plan = thread - > QueueThreadPlanForStepRange ( abort_other_plans , m_step_type ,
frame - > GetSymbolContext ( eSymbolContextEverything ) . line_entry . range ,
frame - > GetSymbolContext ( eSymbolContextEverything ) ,
2010-06-13 02:59:55 +08:00
stop_other_threads ,
m_options . m_avoid_no_debug ) ;
2010-07-10 10:27:39 +08: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-09 00:52:24 +08:00
}
else
new_plan = thread - > QueueThreadPlanForStepSingleInstruction ( false , abort_other_plans , bool_stop_other_threads ) ;
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
process - > Resume ( ) ;
}
else if ( m_step_type = = eStepTypeOver )
{
StackFrame * frame = thread - > GetStackFrameAtIndex ( 0 ) . get ( ) ;
ThreadPlan * new_plan ;
if ( frame - > HasDebugInformation ( ) )
new_plan = thread - > QueueThreadPlanForStepRange ( abort_other_plans ,
m_step_type ,
frame - > GetSymbolContext ( eSymbolContextEverything ) . line_entry . range ,
frame - > GetSymbolContext ( eSymbolContextEverything ) ,
2010-06-13 02:59:55 +08:00
stop_other_threads ,
false ) ;
2010-06-09 00:52:24 +08:00
else
new_plan = thread - > QueueThreadPlanForStepSingleInstruction ( true ,
abort_other_plans ,
bool_stop_other_threads ) ;
// FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
// Maybe there should be a parameter to control this.
new_plan - > SetOkayToDiscard ( false ) ;
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
process - > Resume ( ) ;
}
else if ( m_step_type = = eStepTypeTrace )
{
thread - > QueueThreadPlanForStepSingleInstruction ( false , abort_other_plans , bool_stop_other_threads ) ;
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
process - > Resume ( ) ;
}
else if ( m_step_type = = eStepTypeTraceOver )
{
thread - > QueueThreadPlanForStepSingleInstruction ( true , abort_other_plans , bool_stop_other_threads ) ;
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
process - > Resume ( ) ;
}
else if ( m_step_type = = eStepTypeOut )
{
ThreadPlan * new_plan ;
2011-01-21 14:11:58 +08:00
new_plan = thread - > QueueThreadPlanForStepOut ( abort_other_plans ,
NULL ,
false ,
bool_stop_other_threads ,
eVoteYes ,
eVoteNoOpinion ,
thread - > GetSelectedFrameIndex ( ) ) ;
2010-06-09 00:52:24 +08:00
// FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
// Maybe there should be a parameter to control this.
new_plan - > SetOkayToDiscard ( false ) ;
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
process - > Resume ( ) ;
}
else
{
result . AppendError ( " step type is not supported " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
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);
// }
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
result . SetDidChangeProcessState ( true ) ;
result . AppendMessageWithFormat ( " Process %i %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
}
return result . Succeeded ( ) ;
}
protected :
StepType m_step_type ;
StepScope m_step_scope ;
CommandOptions m_options ;
} ;
2011-03-25 05:19:54 +08:00
static OptionEnumValueElement
2010-06-09 00:52:24 +08:00
g_tri_running_mode [ ] =
{
2010-09-18 11:37:20 +08: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-09 00:52:24 +08:00
{ 0 , NULL , NULL }
} ;
2011-03-25 05:19:54 +08:00
static OptionEnumValueElement
2010-06-09 00:52:24 +08:00
g_duo_running_mode [ ] =
{
2010-09-18 11:37:20 +08:00
{ eOnlyThisThread , " this-thread " , " Run only this thread " } ,
{ eAllThreads , " all-threads " , " Run all threads " } ,
2010-06-09 00:52:24 +08:00
{ 0 , NULL , NULL }
} ;
2011-03-25 05:19:54 +08:00
OptionDefinition
2010-06-09 00:52:24 +08:00
CommandObjectThreadStepWithTypeAndScope : : CommandOptions : : g_option_table [ ] =
{
2010-10-02 03:59:14 +08: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-09 00:52:24 +08:00
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadContinue
//-------------------------------------------------------------------------
class CommandObjectThreadContinue : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectThreadContinue ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" thread continue " ,
2010-09-09 05:06:11 +08:00
" Continue execution of one or more threads in an active process. " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-06-09 00:52:24 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
{
2010-10-05 06:28:36 +08: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-09 00:52:24 +08:00
}
virtual
~ CommandObjectThreadContinue ( )
{
}
virtual bool
2010-06-23 09:19:29 +08:00
Execute
(
Args & command ,
CommandReturnObject & result
)
2010-06-09 00:52:24 +08:00
{
2010-09-18 09:14:36 +08:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-09 00:52:24 +08:00
2010-09-18 09:14:36 +08:00
if ( ! m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) )
2010-06-09 00:52:24 +08:00
{
result . AppendError ( " invalid target, set executable file using 'file' command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-04-12 13:54:46 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . process ;
2010-06-09 00:52:24 +08: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 ) )
{
const uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
uint32_t idx ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc > 0 )
{
std : : vector < uint32_t > resume_thread_indexes ;
for ( uint32_t i = 0 ; i < argc ; + + i )
{
idx = Args : : StringToUInt32 ( command . GetArgumentAtIndex ( 0 ) , LLDB_INVALID_INDEX32 ) ;
if ( idx < num_threads )
resume_thread_indexes . push_back ( idx ) ;
else
result . AppendWarningWithFormat ( " Thread index %u out of range. \n " , idx ) ;
}
if ( resume_thread_indexes . empty ( ) )
{
result . AppendError ( " no valid thread indexes were specified " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
{
result . AppendMessage ( " Resuming thread " ) ;
for ( idx = 0 ; idx < num_threads ; + + idx )
{
Thread * thread = process - > GetThreadList ( ) . GetThreadAtIndex ( idx ) . get ( ) ;
if ( find ( resume_thread_indexes . begin ( ) , resume_thread_indexes . end ( ) , idx ) ! = resume_thread_indexes . end ( ) )
{
result . AppendMessageWithFormat ( " %u " , idx ) ;
thread - > SetResumeState ( eStateRunning ) ;
}
else
{
thread - > SetResumeState ( eStateSuspended ) ;
}
}
result . AppendMessageWithFormat ( " in process %i \n " , process - > GetID ( ) ) ;
}
}
else
{
2010-08-27 05:32:51 +08:00
Thread * current_thread = process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) ;
2010-06-09 00:52:24 +08: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
for ( idx = 0 ; idx < num_threads ; + + idx )
{
Thread * thread = process - > GetThreadList ( ) . GetThreadAtIndex ( idx ) . get ( ) ;
if ( thread = = current_thread )
{
result . AppendMessageWithFormat ( " Resuming thread 0x%4.4x in process %i \n " , thread - > GetID ( ) , process - > GetID ( ) ) ;
thread - > SetResumeState ( eStateRunning ) ;
}
else
{
thread - > SetResumeState ( eStateSuspended ) ;
}
}
}
Error error ( process - > Resume ( ) ) ;
if ( error . Success ( ) )
{
2010-10-18 09:45:30 +08:00
result . AppendMessageWithFormat ( " Process %i resuming \n " , process - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
if ( synchronous_execution )
{
2010-07-14 08:18:15 +08:00
state = process - > WaitForProcessToStop ( NULL ) ;
2010-06-09 00:52:24 +08:00
result . SetDidChangeProcessState ( true ) ;
result . AppendMessageWithFormat ( " Process %i %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
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
//-------------------------------------------------------------------------
class CommandObjectThreadUntil : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
uint32_t m_thread_idx ;
uint32_t m_frame_idx ;
2011-04-08 06:46:35 +08:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter ) ,
2010-06-09 00:52:24 +08:00
m_thread_idx ( LLDB_INVALID_THREAD_ID ) ,
m_frame_idx ( LLDB_INVALID_FRAME_ID )
{
2011-04-13 08:18:08 +08:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandOptions ( )
{
}
virtual Error
2011-04-13 08:18:08 +08:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-06-09 00:52:24 +08:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' t ' :
{
2010-07-14 08:18:15 +08:00
m_thread_idx = Args : : StringToUInt32 ( option_arg , LLDB_INVALID_INDEX32 ) ;
2010-06-09 00:52:24 +08:00
if ( m_thread_idx = = LLDB_INVALID_INDEX32 )
{
error . SetErrorStringWithFormat ( " Invalid thread index '%s'. \n " , option_arg ) ;
}
}
break ;
case ' f ' :
{
m_frame_idx = Args : : StringToUInt32 ( option_arg , LLDB_INVALID_FRAME_ID ) ;
if ( m_frame_idx = = LLDB_INVALID_FRAME_ID )
{
error . SetErrorStringWithFormat ( " Invalid frame index '%s'. \n " , option_arg ) ;
}
}
break ;
case ' m ' :
{
bool found_one = false ;
OptionEnumValueElement * enum_values = g_option_table [ option_idx ] . enum_values ;
lldb : : RunMode run_mode = ( lldb : : RunMode ) Args : : StringToOptionEnum ( option_arg , enum_values , eOnlyDuringStepping , & found_one ) ;
if ( ! found_one )
error . SetErrorStringWithFormat ( " Invalid enumeration value for option '%c'. \n " , short_option ) ;
else if ( run_mode = = eAllThreads )
m_stop_others = false ;
else
m_stop_others = true ;
}
break ;
default :
error . SetErrorStringWithFormat ( " Invalid short option character '%c'. \n " , short_option ) ;
break ;
}
return error ;
}
void
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( )
2010-06-09 00:52:24 +08:00
{
m_thread_idx = LLDB_INVALID_THREAD_ID ;
m_frame_idx = 0 ;
m_stop_others = false ;
}
2011-03-25 05:19:54 +08:00
const OptionDefinition *
2010-06-09 00:52:24 +08: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-25 05:19:54 +08:00
static OptionDefinition g_option_table [ ] ;
2010-06-09 00:52:24 +08:00
// Instance variables to hold the values for command options.
} ;
2010-09-18 09:14:36 +08:00
CommandObjectThreadUntil ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" thread until " ,
2010-09-09 05:06:11 +08:00
" Run the current or specified thread until it reaches a given line number or leaves the current function. " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-06-09 00:52:24 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ) ,
2011-04-08 06:46:35 +08:00
m_options ( interpreter )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08: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-09 00:52:24 +08:00
}
virtual
~ CommandObjectThreadUntil ( )
{
}
virtual
Options *
GetOptions ( )
{
return & m_options ;
}
virtual bool
2010-06-23 09:19:29 +08:00
Execute
(
Args & command ,
CommandReturnObject & result
)
2010-06-09 00:52:24 +08:00
{
2010-09-18 09:14:36 +08:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-09 00:52:24 +08:00
2010-09-18 09:14:36 +08:00
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
2010-09-15 07:36:40 +08:00
if ( target = = NULL )
2010-06-09 00:52:24 +08:00
{
result . AppendError ( " invalid target, set executable file using 'file' command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-04-12 13:54:46 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . process ;
2010-06-09 00:52:24 +08: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 )
{
result . AppendErrorWithFormat ( " Invalid line number: '%s'. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( m_options . m_thread_idx = = LLDB_INVALID_THREAD_ID )
{
2010-08-27 05:32:51 +08:00
thread = process - > GetThreadList ( ) . GetSelectedThread ( ) . get ( ) ;
2010-06-09 00:52:24 +08:00
}
else
{
thread = process - > GetThreadList ( ) . GetThreadAtIndex ( m_options . m_thread_idx ) . get ( ) ;
}
if ( thread = = NULL )
{
const uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
result . AppendErrorWithFormat ( " Thread index %u is out of range (valid values are 0 - %u). \n " , m_options . m_thread_idx , 0 , num_threads ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const bool abort_other_plans = true ;
StackFrame * frame = thread - > GetStackFrameAtIndex ( m_options . m_frame_idx ) . get ( ) ;
if ( frame = = NULL )
{
result . AppendErrorWithFormat ( " Frame index %u is out of range for thread %u. \n " , m_options . m_frame_idx , m_options . m_thread_idx ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ThreadPlan * new_plan ;
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 ) ;
Address fun_end_addr ( fun_start_addr . GetSection ( ) , fun_start_addr . GetOffset ( ) + fun_addr_range . GetByteSize ( ) ) ;
line_table - > FindLineEntryByAddress ( fun_end_addr , function_start , & end_ptr ) ;
while ( index_ptr < = end_ptr )
{
LineEntry line_entry ;
index_ptr = sc . comp_unit - > FindLineEntry ( index_ptr , line_number , sc . comp_unit , & line_entry ) ;
if ( index_ptr = = UINT32_MAX )
break ;
2010-09-15 07:36:40 +08:00
addr_t address = line_entry . range . GetBaseAddress ( ) . GetLoadAddress ( target ) ;
2010-06-09 00:52:24 +08:00
if ( address ! = LLDB_INVALID_ADDRESS )
address_list . push_back ( address ) ;
index_ptr + + ;
}
2011-01-21 14:11:58 +08:00
new_plan = thread - > QueueThreadPlanForStepUntil ( abort_other_plans , & address_list . front ( ) , address_list . size ( ) , m_options . m_stop_others , thread - > GetSelectedFrameIndex ( ) ) ;
2010-06-09 00:52:24 +08:00
new_plan - > SetOkayToDiscard ( false ) ;
}
else
{
result . AppendErrorWithFormat ( " Frame index %u of thread %u has no debug information. \n " , m_options . m_frame_idx , m_options . m_thread_idx ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( m_options . m_thread_idx ) ;
2010-06-09 00:52:24 +08:00
Error error ( process - > Resume ( ) ) ;
if ( error . Success ( ) )
{
2010-10-18 09:45:30 +08:00
result . AppendMessageWithFormat ( " Process %i resuming \n " , process - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
if ( synchronous_execution )
{
StateType state = process - > WaitForProcessToStop ( NULL ) ;
result . SetDidChangeProcessState ( true ) ;
result . AppendMessageWithFormat ( " Process %i %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Failed to resume process: %s. \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
return result . Succeeded ( ) ;
}
protected :
CommandOptions m_options ;
} ;
2011-03-25 05:19:54 +08:00
OptionDefinition
2010-06-09 00:52:24 +08:00
CommandObjectThreadUntil : : CommandOptions : : g_option_table [ ] =
{
2010-10-05 06:28:36 +08:00
{ LLDB_OPT_SET_1 , false , " frame " , ' f ' , required_argument , NULL , 0 , eArgTypeFrameIndex , " Frame index for until operation - defaults to 0 " } ,
2010-10-02 03:59:14 +08: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-09 00:52:24 +08:00
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadSelect
//-------------------------------------------------------------------------
class CommandObjectThreadSelect : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectThreadSelect ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" thread select " ,
" Select a thread as the currently active thread. " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08: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-09 00:52:24 +08:00
}
virtual
~ CommandObjectThreadSelect ( )
{
}
virtual bool
2010-06-23 09:19:29 +08:00
Execute
(
Args & command ,
CommandReturnObject & result
)
2010-06-09 00:52:24 +08:00
{
2011-04-12 13:54:46 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . process ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " no process " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( command . GetArgumentCount ( ) ! = 1 )
{
result . AppendErrorWithFormat ( " '%s' takes exactly one thread index argument: \n Usage: \n " , m_cmd_name . c_str ( ) , m_cmd_syntax . c_str ( ) ) ;
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 )
{
result . AppendErrorWithFormat ( " Invalid thread #%s. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-08-27 05:32:51 +08:00
process - > GetThreadList ( ) . SetSelectedThreadByID ( new_thread - > GetID ( ) ) ;
2010-09-14 08:53:53 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2010-06-09 00:52:24 +08:00
2010-09-18 09:14:36 +08:00
DisplayThreadInfo ( m_interpreter ,
2010-06-09 00:52:24 +08:00
result . GetOutputStream ( ) ,
new_thread ,
false ,
true ) ;
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectThreadList
//-------------------------------------------------------------------------
2010-06-23 09:19:29 +08:00
class CommandObjectThreadList : public CommandObject
2010-06-09 00:52:24 +08:00
{
2010-06-23 09:19:29 +08:00
public :
2010-06-09 00:52:24 +08:00
2010-09-18 09:14:36 +08:00
CommandObjectThreadList ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" thread list " ,
2010-09-09 05:06:11 +08:00
" Show a summary of all current threads in a process. " ,
2010-06-23 09:19:29 +08:00
" thread list " ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
{
}
~ CommandObjectThreadList ( )
2010-06-09 00:52:24 +08:00
{
2010-06-23 09:19:29 +08:00
}
2010-06-09 00:52:24 +08:00
2010-06-23 09:19:29 +08:00
bool
Execute
(
Args & command ,
CommandReturnObject & result
)
{
2011-02-19 10:53:09 +08:00
Stream & strm = result . GetOutputStream ( ) ;
2010-06-23 09:19:29 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2011-04-12 13:54:46 +08:00
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
2010-06-23 09:19:29 +08:00
if ( exe_ctx . process )
2010-06-09 00:52:24 +08:00
{
2010-06-23 09:19:29 +08:00
const StateType state = exe_ctx . process - > GetState ( ) ;
if ( StateIsStoppedState ( state ) )
2010-06-09 00:52:24 +08:00
{
2010-06-23 09:19:29 +08:00
if ( state = = eStateExited )
2010-06-09 00:52:24 +08:00
{
2010-06-23 09:19:29 +08:00
int exit_status = exe_ctx . process - > GetExitStatus ( ) ;
const char * exit_description = exe_ctx . process - > GetExitDescription ( ) ;
strm . Printf ( " Process %d exited with status = %i (0x%8.8x) %s \n " ,
exe_ctx . process - > GetID ( ) ,
exit_status ,
exit_status ,
exit_description ? exit_description : " " ) ;
2010-06-09 00:52:24 +08:00
}
else
{
2010-06-23 09:19:29 +08:00
strm . Printf ( " Process %d state is %s \n " , exe_ctx . process - > GetID ( ) , StateAsCString ( state ) ) ;
if ( exe_ctx . thread = = NULL )
exe_ctx . thread = exe_ctx . process - > GetThreadList ( ) . GetThreadAtIndex ( 0 ) . get ( ) ;
if ( exe_ctx . thread ! = NULL )
{
2010-09-18 09:14:36 +08:00
DisplayThreadsInfo ( m_interpreter , & exe_ctx , result , false , false ) ;
2010-06-23 09:19:29 +08:00
}
else
{
result . AppendError ( " no valid thread found in current process " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-09 00:52:24 +08:00
}
}
2010-06-23 09:19:29 +08:00
else
{
result . AppendError ( " process is currently running " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-09 00:52:24 +08:00
}
else
{
2010-06-23 09:19:29 +08:00
result . AppendError ( " no current location or status available " ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-23 09:19:29 +08:00
return result . Succeeded ( ) ;
2010-06-09 00:52:24 +08:00
}
2010-06-23 09:19:29 +08:00
} ;
2010-06-09 00:52:24 +08:00
//-------------------------------------------------------------------------
// CommandObjectMultiwordThread
//-------------------------------------------------------------------------
2010-06-23 09:19:29 +08:00
CommandObjectMultiwordThread : : CommandObjectMultiwordThread ( CommandInterpreter & interpreter ) :
2010-09-18 09:14:36 +08:00
CommandObjectMultiword ( interpreter ,
" thread " ,
2010-09-08 06:38:08 +08:00
" A set of commands for operating on one or more threads within a running process. " ,
2010-06-09 00:52:24 +08:00
" thread <subcommand> [<subcommand-options>] " )
{
2010-09-18 09:14:36 +08:00
LoadSubCommand ( " backtrace " , CommandObjectSP ( new CommandObjectThreadBacktrace ( interpreter ) ) ) ;
LoadSubCommand ( " continue " , CommandObjectSP ( new CommandObjectThreadContinue ( interpreter ) ) ) ;
LoadSubCommand ( " list " , CommandObjectSP ( new CommandObjectThreadList ( interpreter ) ) ) ;
LoadSubCommand ( " select " , CommandObjectSP ( new CommandObjectThreadSelect ( interpreter ) ) ) ;
LoadSubCommand ( " until " , CommandObjectSP ( new CommandObjectThreadUntil ( interpreter ) ) ) ;
LoadSubCommand ( " step-in " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
2010-06-23 09:19:29 +08:00
" thread step-in " ,
2010-09-18 09:14:36 +08:00
" Source level single step in specified thread (current thread, if none specified). " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeInto ,
eStepScopeSource ) ) ) ;
2010-06-23 09:19:29 +08:00
2010-09-18 09:14:36 +08:00
LoadSubCommand ( " step-out " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
" thread step-out " ,
" Finish executing the current fucntion and return to its call site in specified thread (current thread, if none specified). " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeOut ,
eStepScopeSource ) ) ) ;
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-05 06:28:36 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeOver ,
eStepScopeSource ) ) ) ;
LoadSubCommand ( " step-inst " , CommandObjectSP ( new CommandObjectThreadStepWithTypeAndScope (
interpreter ,
" thread step-inst " ,
" Single step one instruction in specified thread (current thread, if none specified). " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeTrace ,
eStepScopeInstruction ) ) ) ;
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-05 06:28:36 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused ,
eStepTypeTraceOver ,
eStepScopeInstruction ) ) ) ;
2010-06-09 00:52:24 +08:00
}
CommandObjectMultiwordThread : : ~ CommandObjectMultiwordThread ( )
{
}