2013-08-23 17:46:38 +00:00
//===-- CommandObjectBreakpoint.cpp -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/lldb-python.h"
# include "CommandObjectBreakpoint.h"
# include "CommandObjectBreakpointCommand.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
# include "lldb/Breakpoint/Breakpoint.h"
# include "lldb/Breakpoint/BreakpointIDList.h"
# include "lldb/Breakpoint/BreakpointLocation.h"
# include "lldb/Interpreter/Options.h"
# include "lldb/Core/RegularExpression.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
# include "lldb/Target/Target.h"
# include "lldb/Interpreter/CommandCompletions.h"
# include "lldb/Target/StackFrame.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/ThreadSpec.h"
# include <vector>
using namespace lldb ;
using namespace lldb_private ;
static void
AddBreakpointDescription ( Stream * s , Breakpoint * bp , lldb : : DescriptionLevel level )
{
s - > IndentMore ( ) ;
bp - > GetDescription ( s , level , true ) ;
s - > IndentLess ( ) ;
s - > EOL ( ) ;
}
//-------------------------------------------------------------------------
// CommandObjectBreakpointSet
//-------------------------------------------------------------------------
class CommandObjectBreakpointSet : public CommandObjectParsed
{
public :
typedef enum BreakpointSetType
{
eSetTypeInvalid ,
eSetTypeFileAndLine ,
eSetTypeAddress ,
eSetTypeFunctionName ,
eSetTypeFunctionRegexp ,
eSetTypeSourceRegexp ,
eSetTypeException
} BreakpointSetType ;
CommandObjectBreakpointSet ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" breakpoint set " ,
" Sets a breakpoint or set of breakpoints in the executable. " ,
" breakpoint set <cmd-options> " ) ,
m_options ( interpreter )
{
}
virtual
~ CommandObjectBreakpointSet ( ) { }
virtual Options *
GetOptions ( )
{
return & m_options ;
}
class CommandOptions : public Options
{
public :
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter ) ,
m_condition ( ) ,
m_filenames ( ) ,
m_line_num ( 0 ) ,
m_column ( 0 ) ,
m_func_names ( ) ,
m_func_name_type_mask ( eFunctionNameTypeNone ) ,
m_func_regexp ( ) ,
m_source_text_regexp ( ) ,
m_modules ( ) ,
m_load_addr ( ) ,
m_ignore_count ( 0 ) ,
m_thread_id ( LLDB_INVALID_THREAD_ID ) ,
m_thread_index ( UINT32_MAX ) ,
m_thread_name ( ) ,
m_queue_name ( ) ,
m_catch_bp ( false ) ,
m_throw_bp ( true ) ,
2013-11-06 16:48:53 +00:00
m_hardware ( false ) ,
2013-08-23 17:46:38 +00:00
m_language ( eLanguageTypeUnknown ) ,
m_skip_prologue ( eLazyBoolCalculate ) ,
m_one_shot ( false )
{
}
virtual
~ CommandOptions ( ) { }
virtual Error
SetOptionValue ( uint32_t option_idx , const char * option_arg )
{
Error error ;
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' a ' :
{
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
m_load_addr = Args : : StringToAddress ( & exe_ctx , option_arg , LLDB_INVALID_ADDRESS , & error ) ;
}
break ;
case ' b ' :
m_func_names . push_back ( option_arg ) ;
m_func_name_type_mask | = eFunctionNameTypeBase ;
break ;
case ' C ' :
m_column = Args : : StringToUInt32 ( option_arg , 0 ) ;
break ;
case ' c ' :
m_condition . assign ( option_arg ) ;
break ;
case ' E ' :
{
LanguageType language = LanguageRuntime : : GetLanguageTypeFromString ( option_arg ) ;
switch ( language )
{
case eLanguageTypeC89 :
case eLanguageTypeC :
case eLanguageTypeC99 :
2014-11-25 21:00:58 +00:00
case eLanguageTypeC11 :
2013-08-23 17:46:38 +00:00
m_language = eLanguageTypeC ;
break ;
case eLanguageTypeC_plus_plus :
2014-11-25 21:00:58 +00:00
case eLanguageTypeC_plus_plus_03 :
case eLanguageTypeC_plus_plus_11 :
2013-08-23 17:46:38 +00:00
m_language = eLanguageTypeC_plus_plus ;
break ;
case eLanguageTypeObjC :
m_language = eLanguageTypeObjC ;
break ;
case eLanguageTypeObjC_plus_plus :
error . SetErrorStringWithFormat ( " Set exception breakpoints separately for c++ and objective-c " ) ;
break ;
case eLanguageTypeUnknown :
error . SetErrorStringWithFormat ( " Unknown language type: '%s' for exception breakpoint " , option_arg ) ;
break ;
default :
error . SetErrorStringWithFormat ( " Unsupported language type: '%s' for exception breakpoint " , option_arg ) ;
}
}
break ;
case ' f ' :
m_filenames . AppendIfUnique ( FileSpec ( option_arg , false ) ) ;
break ;
case ' F ' :
m_func_names . push_back ( option_arg ) ;
m_func_name_type_mask | = eFunctionNameTypeFull ;
break ;
case ' h ' :
2013-11-06 16:48:53 +00:00
{
bool success ;
m_catch_bp = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( ! success )
error . SetErrorStringWithFormat ( " Invalid boolean value for on-catch option: '%s' " , option_arg ) ;
}
break ;
case ' H ' :
m_hardware = true ;
break ;
2013-08-23 17:46:38 +00:00
case ' i ' :
{
m_ignore_count = Args : : StringToUInt32 ( option_arg , UINT32_MAX , 0 ) ;
if ( m_ignore_count = = UINT32_MAX )
error . SetErrorStringWithFormat ( " invalid ignore count '%s' " , option_arg ) ;
break ;
}
case ' K ' :
{
bool success ;
bool value ;
value = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( value )
m_skip_prologue = eLazyBoolYes ;
else
m_skip_prologue = eLazyBoolNo ;
if ( ! success )
error . SetErrorStringWithFormat ( " Invalid boolean value for skip prologue option: '%s' " , option_arg ) ;
}
break ;
case ' l ' :
m_line_num = Args : : StringToUInt32 ( option_arg , 0 ) ;
break ;
case ' M ' :
m_func_names . push_back ( option_arg ) ;
m_func_name_type_mask | = eFunctionNameTypeMethod ;
break ;
case ' n ' :
m_func_names . push_back ( option_arg ) ;
m_func_name_type_mask | = eFunctionNameTypeAuto ;
break ;
case ' o ' :
m_one_shot = true ;
break ;
case ' p ' :
m_source_text_regexp . assign ( option_arg ) ;
break ;
case ' q ' :
m_queue_name . assign ( option_arg ) ;
break ;
case ' r ' :
m_func_regexp . assign ( option_arg ) ;
break ;
case ' s ' :
{
m_modules . AppendIfUnique ( FileSpec ( option_arg , false ) ) ;
break ;
}
case ' S ' :
m_func_names . push_back ( option_arg ) ;
m_func_name_type_mask | = eFunctionNameTypeSelector ;
break ;
case ' t ' :
{
m_thread_id = Args : : StringToUInt64 ( option_arg , LLDB_INVALID_THREAD_ID , 0 ) ;
if ( m_thread_id = = LLDB_INVALID_THREAD_ID )
error . SetErrorStringWithFormat ( " invalid thread id string '%s' " , option_arg ) ;
}
break ;
case ' T ' :
m_thread_name . assign ( option_arg ) ;
break ;
case ' w ' :
{
bool success ;
m_throw_bp = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( ! success )
error . SetErrorStringWithFormat ( " Invalid boolean value for on-throw option: '%s' " , option_arg ) ;
}
break ;
case ' x ' :
{
m_thread_index = Args : : StringToUInt32 ( option_arg , UINT32_MAX , 0 ) ;
if ( m_thread_id = = UINT32_MAX )
error . SetErrorStringWithFormat ( " invalid thread index string '%s' " , option_arg ) ;
}
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " , short_option ) ;
break ;
}
return error ;
}
void
OptionParsingStarting ( )
{
m_condition . clear ( ) ;
m_filenames . Clear ( ) ;
m_line_num = 0 ;
m_column = 0 ;
m_func_names . clear ( ) ;
m_func_name_type_mask = eFunctionNameTypeNone ;
m_func_regexp . clear ( ) ;
m_source_text_regexp . clear ( ) ;
m_modules . Clear ( ) ;
m_load_addr = LLDB_INVALID_ADDRESS ;
m_ignore_count = 0 ;
m_thread_id = LLDB_INVALID_THREAD_ID ;
m_thread_index = UINT32_MAX ;
m_thread_name . clear ( ) ;
m_queue_name . clear ( ) ;
m_catch_bp = false ;
m_throw_bp = true ;
2013-11-06 16:48:53 +00:00
m_hardware = false ;
2013-08-23 17:46:38 +00:00
m_language = eLanguageTypeUnknown ;
m_skip_prologue = eLazyBoolCalculate ;
m_one_shot = false ;
}
const OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
std : : string m_condition ;
FileSpecList m_filenames ;
uint32_t m_line_num ;
uint32_t m_column ;
std : : vector < std : : string > m_func_names ;
uint32_t m_func_name_type_mask ;
std : : string m_func_regexp ;
std : : string m_source_text_regexp ;
FileSpecList m_modules ;
lldb : : addr_t m_load_addr ;
uint32_t m_ignore_count ;
lldb : : tid_t m_thread_id ;
uint32_t m_thread_index ;
std : : string m_thread_name ;
std : : string m_queue_name ;
bool m_catch_bp ;
bool m_throw_bp ;
2013-11-06 16:48:53 +00:00
bool m_hardware ; // Request to use hardware breakpoints
2013-08-23 17:46:38 +00:00
lldb : : LanguageType m_language ;
LazyBool m_skip_prologue ;
bool m_one_shot ;
} ;
protected :
virtual bool
DoExecute ( Args & command ,
CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. Must set target before setting breakpoints (see 'target create' command). " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
// The following are the various types of breakpoints that could be set:
// 1). -f -l -p [-s -g] (setting breakpoint by source location)
// 2). -a [-s -g] (setting breakpoint by address)
// 3). -n [-s -g] (setting breakpoint by function name)
// 4). -r [-s -g] (setting breakpoint by function name regular expression)
// 5). -p -f (setting a breakpoint by comparing a reg-exp to source text)
// 6). -E [-w -h] (setting a breakpoint for exceptions for a given language.)
BreakpointSetType break_type = eSetTypeInvalid ;
if ( m_options . m_line_num ! = 0 )
break_type = eSetTypeFileAndLine ;
else if ( m_options . m_load_addr ! = LLDB_INVALID_ADDRESS )
break_type = eSetTypeAddress ;
else if ( ! m_options . m_func_names . empty ( ) )
break_type = eSetTypeFunctionName ;
else if ( ! m_options . m_func_regexp . empty ( ) )
break_type = eSetTypeFunctionRegexp ;
else if ( ! m_options . m_source_text_regexp . empty ( ) )
break_type = eSetTypeSourceRegexp ;
else if ( m_options . m_language ! = eLanguageTypeUnknown )
break_type = eSetTypeException ;
Breakpoint * bp = NULL ;
FileSpec module_spec ;
const bool internal = false ;
switch ( break_type )
{
case eSetTypeFileAndLine : // Breakpoint by source position
{
FileSpec file ;
const size_t num_files = m_options . m_filenames . GetSize ( ) ;
if ( num_files = = 0 )
{
if ( ! GetDefaultFile ( target , file , result ) )
{
result . AppendError ( " No file supplied and no default file available. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else if ( num_files > 1 )
{
result . AppendError ( " Only one file at a time is allowed for file and line breakpoints. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
file = m_options . m_filenames . GetFileSpecAtIndex ( 0 ) ;
// Only check for inline functions if
LazyBool check_inlines = eLazyBoolCalculate ;
bp = target - > CreateBreakpoint ( & ( m_options . m_modules ) ,
file ,
m_options . m_line_num ,
check_inlines ,
m_options . m_skip_prologue ,
2013-11-06 16:48:53 +00:00
internal ,
m_options . m_hardware ) . get ( ) ;
2013-08-23 17:46:38 +00:00
}
break ;
case eSetTypeAddress : // Breakpoint by address
2013-11-06 16:48:53 +00:00
bp = target - > CreateBreakpoint ( m_options . m_load_addr ,
internal ,
m_options . m_hardware ) . get ( ) ;
2013-08-23 17:46:38 +00:00
break ;
case eSetTypeFunctionName : // Breakpoint by function name
{
uint32_t name_type_mask = m_options . m_func_name_type_mask ;
if ( name_type_mask = = 0 )
name_type_mask = eFunctionNameTypeAuto ;
bp = target - > CreateBreakpoint ( & ( m_options . m_modules ) ,
& ( m_options . m_filenames ) ,
m_options . m_func_names ,
name_type_mask ,
m_options . m_skip_prologue ,
2013-11-06 16:48:53 +00:00
internal ,
m_options . m_hardware ) . get ( ) ;
2013-08-23 17:46:38 +00:00
}
break ;
case eSetTypeFunctionRegexp : // Breakpoint by regular expression function name
{
RegularExpression regexp ( m_options . m_func_regexp . c_str ( ) ) ;
if ( ! regexp . IsValid ( ) )
{
char err_str [ 1024 ] ;
regexp . GetErrorAsCString ( err_str , sizeof ( err_str ) ) ;
result . AppendErrorWithFormat ( " Function name regular expression could not be compiled: \" %s \" " ,
err_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
bp = target - > CreateFuncRegexBreakpoint ( & ( m_options . m_modules ) ,
& ( m_options . m_filenames ) ,
regexp ,
m_options . m_skip_prologue ,
2013-11-06 16:48:53 +00:00
internal ,
m_options . m_hardware ) . get ( ) ;
2013-08-23 17:46:38 +00:00
}
break ;
case eSetTypeSourceRegexp : // Breakpoint by regexp on source text.
{
const size_t num_files = m_options . m_filenames . GetSize ( ) ;
if ( num_files = = 0 )
{
FileSpec file ;
if ( ! GetDefaultFile ( target , file , result ) )
{
result . AppendError ( " No files provided and could not find default file. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
{
m_options . m_filenames . Append ( file ) ;
}
}
RegularExpression regexp ( m_options . m_source_text_regexp . c_str ( ) ) ;
if ( ! regexp . IsValid ( ) )
{
char err_str [ 1024 ] ;
regexp . GetErrorAsCString ( err_str , sizeof ( err_str ) ) ;
result . AppendErrorWithFormat ( " Source text regular expression could not be compiled: \" %s \" " ,
err_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-11-06 16:48:53 +00:00
bp = target - > CreateSourceRegexBreakpoint ( & ( m_options . m_modules ) ,
& ( m_options . m_filenames ) ,
regexp ,
internal ,
m_options . m_hardware ) . get ( ) ;
2013-08-23 17:46:38 +00:00
}
break ;
case eSetTypeException :
{
2013-11-06 16:48:53 +00:00
bp = target - > CreateExceptionBreakpoint ( m_options . m_language ,
m_options . m_catch_bp ,
m_options . m_throw_bp ,
m_options . m_hardware ) . get ( ) ;
2013-08-23 17:46:38 +00:00
}
break ;
default :
break ;
}
// Now set the various options that were passed in:
if ( bp )
{
if ( m_options . m_thread_id ! = LLDB_INVALID_THREAD_ID )
bp - > SetThreadID ( m_options . m_thread_id ) ;
if ( m_options . m_thread_index ! = UINT32_MAX )
bp - > GetOptions ( ) - > GetThreadSpec ( ) - > SetIndex ( m_options . m_thread_index ) ;
if ( ! m_options . m_thread_name . empty ( ) )
bp - > GetOptions ( ) - > GetThreadSpec ( ) - > SetName ( m_options . m_thread_name . c_str ( ) ) ;
if ( ! m_options . m_queue_name . empty ( ) )
bp - > GetOptions ( ) - > GetThreadSpec ( ) - > SetQueueName ( m_options . m_queue_name . c_str ( ) ) ;
if ( m_options . m_ignore_count ! = 0 )
bp - > GetOptions ( ) - > SetIgnoreCount ( m_options . m_ignore_count ) ;
if ( ! m_options . m_condition . empty ( ) )
bp - > GetOptions ( ) - > SetCondition ( m_options . m_condition . c_str ( ) ) ;
bp - > SetOneShot ( m_options . m_one_shot ) ;
}
if ( bp )
{
Stream & output_stream = result . GetOutputStream ( ) ;
const bool show_locations = false ;
bp - > GetDescription ( & output_stream , lldb : : eDescriptionLevelInitial , show_locations ) ;
// Don't print out this warning for exception breakpoints. They can get set before the target
// is set, but we won't know how to actually set the breakpoint till we run.
if ( bp - > GetNumLocations ( ) = = 0 & & break_type ! = eSetTypeException )
output_stream . Printf ( " WARNING: Unable to resolve breakpoint to any actual locations. \n " ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else if ( ! bp )
{
result . AppendError ( " Breakpoint creation failed: No breakpoint created. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
private :
bool
GetDefaultFile ( Target * target , FileSpec & file , CommandReturnObject & result )
{
uint32_t default_line ;
// First use the Source Manager's default file.
// Then use the current stack frame's file.
if ( ! target - > GetSourceManager ( ) . GetDefaultFileAndLine ( file , default_line ) )
{
StackFrame * cur_frame = m_exe_ctx . GetFramePtr ( ) ;
if ( cur_frame = = NULL )
{
result . AppendError ( " No selected frame to use to find the default file. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( ! cur_frame - > HasDebugInformation ( ) )
{
result . AppendError ( " Cannot use the selected frame to find the default file, it has no debug info. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
{
const SymbolContext & sc = cur_frame - > GetSymbolContext ( eSymbolContextLineEntry ) ;
if ( sc . line_entry . file )
{
file = sc . line_entry . file ;
}
else
{
result . AppendError ( " Can't find the file for the selected frame to use as the default file. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
}
return true ;
}
CommandOptions m_options ;
} ;
// If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
// update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
# define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 )
# define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 )
# define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) )
OptionDefinition
CommandObjectBreakpointSet : : CommandOptions : : g_option_table [ ] =
{
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_NOT_10 , false , " shlib " , ' s ' , OptionParser : : eRequiredArgument , NULL , NULL , CommandCompletions : : eModuleCompletion , eArgTypeShlibName ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint only in this shared library. "
" Can repeat this option multiple times to specify multiple shared libraries. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " ignore-count " , ' i ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeCount ,
2013-08-23 17:46:38 +00:00
" Set the number of times this breakpoint is skipped before stopping. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " one-shot " , ' o ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone ,
2013-08-23 17:46:38 +00:00
" The breakpoint is deleted the first time it causes a stop. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " condition " , ' c ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeExpression ,
2013-08-23 17:46:38 +00:00
" The breakpoint stops only if this condition expression evaluates to true. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " thread-index " , ' x ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeThreadIndex ,
2013-08-23 17:46:38 +00:00
" The breakpoint stops only for the thread whose indeX matches this argument. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " thread-id " , ' t ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeThreadID ,
2013-08-23 17:46:38 +00:00
" The breakpoint stops only for the thread whose TID matches this argument. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " thread-name " , ' T ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeThreadName ,
2013-08-23 17:46:38 +00:00
" The breakpoint stops only for the thread whose thread name matches this argument. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " hardware " , ' H ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone ,
2013-11-06 16:48:53 +00:00
" Require the breakpoint to use hardware breakpoints. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " queue-name " , ' q ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeQueueName ,
2013-08-23 17:46:38 +00:00
" The breakpoint stops only for threads in the queue whose name is given by this argument. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_FILE , false , " file " , ' f ' , OptionParser : : eRequiredArgument , NULL , NULL , CommandCompletions : : eSourceFileCompletion , eArgTypeFilename ,
2013-08-23 17:46:38 +00:00
" Specifies the source file in which to set this breakpoint. "
" Note, by default lldb only looks for files that are #included if they use the standard include file extensions. "
" To set breakpoints on .c/.cpp/.m/.mm files that are #included, set target.inline-breakpoint-strategy "
" to \" always \" . " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_1 , true , " line " , ' l ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeLineNum ,
2013-08-23 17:46:38 +00:00
" Specifies the line number on which to set this breakpoint. " } ,
// Comment out this option for the moment, as we don't actually use it, but will in the future.
// This way users won't see it, but the infrastructure is left in place.
2013-11-06 16:48:53 +00:00
// { 0, false, "column", 'C', OptionParser::eRequiredArgument, NULL, "<column>",
2013-08-23 17:46:38 +00:00
// "Set the breakpoint by source location at this particular column."},
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_2 , true , " address " , ' a ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeAddressOrExpression ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by address, at the specified address. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_3 , true , " name " , ' n ' , OptionParser : : eRequiredArgument , NULL , NULL , CommandCompletions : : eSymbolCompletion , eArgTypeFunctionName ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_4 , true , " fullname " , ' F ' , OptionParser : : eRequiredArgument , NULL , NULL , CommandCompletions : : eSymbolCompletion , eArgTypeFullName ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by fully qualified function names. For C++ this means namespaces and all arguments, and "
" for Objective C this means a full function prototype with class and selector. "
" Can be repeated multiple times to make one breakpoint for multiple names. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_5 , true , " selector " , ' S ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeSelector ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by ObjC selector name. Can be repeated multiple times to make one breakpoint for multiple Selectors. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_6 , true , " method " , ' M ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeMethod ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by C++ method names. Can be repeated multiple times to make one breakpoint for multiple methods. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_7 , true , " func-regex " , ' r ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeRegularExpression ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by function name, evaluating a regular-expression to find the function name(s). " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_8 , true , " basename " , ' b ' , OptionParser : : eRequiredArgument , NULL , NULL , CommandCompletions : : eSymbolCompletion , eArgTypeFunctionName ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by function basename (C++ namespaces and arguments will be ignored). "
" Can be repeated multiple times to make one breakpoint for multiple symbols. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_9 , true , " source-pattern-regexp " , ' p ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeRegularExpression ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint by specifying a regular expression which is matched against the source text in a source file or files "
" specified with the -f option. The -f option can be specified more than once. "
" If no source files are specified, uses the current \" default source file \" " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_10 , true , " language-exception " , ' E ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeLanguage ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint on exceptions thrown by the specified language (without options, on throw but not catch.) " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_10 , false , " on-throw " , ' w ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint on exception throW. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_10 , false , " on-catch " , ' h ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean ,
2013-08-23 17:46:38 +00:00
" Set the breakpoint on exception catcH. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SKIP_PROLOGUE , false , " skip-prologue " , ' K ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean ,
2013-08-23 17:46:38 +00:00
" sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used. " } ,
2014-11-25 21:00:58 +00:00
{ 0 , false , NULL , 0 , 0 , NULL , NULL , 0 , eArgTypeNone , NULL }
2013-08-23 17:46:38 +00:00
} ;
//-------------------------------------------------------------------------
// CommandObjectBreakpointModify
//-------------------------------------------------------------------------
# pragma mark Modify
class CommandObjectBreakpointModify : public CommandObjectParsed
{
public :
CommandObjectBreakpointModify ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" breakpoint modify " ,
" Modify the options on a breakpoint or set of breakpoints in the executable. "
" If no breakpoint is specified, acts on the last created breakpoint. "
" With the exception of -e, -d and -i, passing an empty argument clears the modification. " ,
NULL ) ,
m_options ( interpreter )
{
CommandArgumentEntry arg ;
CommandObject : : AddIDsArgumentData ( arg , eArgTypeBreakpointID , eArgTypeBreakpointIDRange ) ;
// Add the entry for the first argument for this command to the object's arguments vector.
m_arguments . push_back ( arg ) ;
}
virtual
~ CommandObjectBreakpointModify ( ) { }
virtual Options *
GetOptions ( )
{
return & m_options ;
}
class CommandOptions : public Options
{
public :
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter ) ,
m_ignore_count ( 0 ) ,
m_thread_id ( LLDB_INVALID_THREAD_ID ) ,
m_thread_id_passed ( false ) ,
m_thread_index ( UINT32_MAX ) ,
m_thread_index_passed ( false ) ,
m_thread_name ( ) ,
m_queue_name ( ) ,
m_condition ( ) ,
m_one_shot ( false ) ,
m_enable_passed ( false ) ,
m_enable_value ( false ) ,
m_name_passed ( false ) ,
m_queue_passed ( false ) ,
m_condition_passed ( false ) ,
m_one_shot_passed ( false )
{
}
virtual
~ CommandOptions ( ) { }
virtual Error
SetOptionValue ( uint32_t option_idx , const char * option_arg )
{
Error error ;
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' c ' :
if ( option_arg ! = NULL )
m_condition . assign ( option_arg ) ;
else
m_condition . clear ( ) ;
m_condition_passed = true ;
break ;
case ' d ' :
m_enable_passed = true ;
m_enable_value = false ;
break ;
case ' e ' :
m_enable_passed = true ;
m_enable_value = true ;
break ;
case ' i ' :
{
m_ignore_count = Args : : StringToUInt32 ( option_arg , UINT32_MAX , 0 ) ;
if ( m_ignore_count = = UINT32_MAX )
error . SetErrorStringWithFormat ( " invalid ignore count '%s' " , option_arg ) ;
}
break ;
case ' o ' :
{
bool value , success ;
value = Args : : StringToBoolean ( option_arg , false , & success ) ;
if ( success )
{
m_one_shot_passed = true ;
m_one_shot = value ;
}
else
error . SetErrorStringWithFormat ( " invalid boolean value '%s' passed for -o option " , option_arg ) ;
}
break ;
case ' t ' :
{
if ( option_arg [ 0 ] = = ' \0 ' )
{
m_thread_id = LLDB_INVALID_THREAD_ID ;
m_thread_id_passed = true ;
}
else
{
m_thread_id = Args : : StringToUInt64 ( option_arg , LLDB_INVALID_THREAD_ID , 0 ) ;
if ( m_thread_id = = LLDB_INVALID_THREAD_ID )
error . SetErrorStringWithFormat ( " invalid thread id string '%s' " , option_arg ) ;
else
m_thread_id_passed = true ;
}
}
break ;
case ' T ' :
if ( option_arg ! = NULL )
m_thread_name . assign ( option_arg ) ;
else
m_thread_name . clear ( ) ;
m_name_passed = true ;
break ;
case ' q ' :
if ( option_arg ! = NULL )
m_queue_name . assign ( option_arg ) ;
else
m_queue_name . clear ( ) ;
m_queue_passed = true ;
break ;
case ' x ' :
{
if ( option_arg [ 0 ] = = ' \n ' )
{
m_thread_index = UINT32_MAX ;
m_thread_index_passed = true ;
}
else
{
m_thread_index = Args : : StringToUInt32 ( option_arg , UINT32_MAX , 0 ) ;
if ( m_thread_id = = UINT32_MAX )
error . SetErrorStringWithFormat ( " invalid thread index string '%s' " , option_arg ) ;
else
m_thread_index_passed = true ;
}
}
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " , short_option ) ;
break ;
}
return error ;
}
void
OptionParsingStarting ( )
{
m_ignore_count = 0 ;
m_thread_id = LLDB_INVALID_THREAD_ID ;
m_thread_id_passed = false ;
m_thread_index = UINT32_MAX ;
m_thread_index_passed = false ;
m_thread_name . clear ( ) ;
m_queue_name . clear ( ) ;
m_condition . clear ( ) ;
m_one_shot = false ;
m_enable_passed = false ;
m_queue_passed = false ;
m_name_passed = false ;
m_condition_passed = false ;
m_one_shot_passed = false ;
}
const OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
uint32_t m_ignore_count ;
lldb : : tid_t m_thread_id ;
bool m_thread_id_passed ;
uint32_t m_thread_index ;
bool m_thread_index_passed ;
std : : string m_thread_name ;
std : : string m_queue_name ;
std : : string m_condition ;
bool m_one_shot ;
bool m_enable_passed ;
bool m_enable_value ;
bool m_name_passed ;
bool m_queue_passed ;
bool m_condition_passed ;
bool m_one_shot_passed ;
} ;
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. No existing target or breakpoints. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Mutex : : Locker locker ;
target - > GetBreakpointList ( ) . GetListMutex ( locker ) ;
BreakpointIDList valid_bp_ids ;
CommandObjectMultiwordBreakpoint : : VerifyBreakpointIDs ( command , target , result , & valid_bp_ids ) ;
if ( result . Succeeded ( ) )
{
const size_t count = valid_bp_ids . GetSize ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
BreakpointID cur_bp_id = valid_bp_ids . GetBreakpointIDAtIndex ( i ) ;
if ( cur_bp_id . GetBreakpointID ( ) ! = LLDB_INVALID_BREAK_ID )
{
Breakpoint * bp = target - > GetBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) . get ( ) ;
if ( cur_bp_id . GetLocationID ( ) ! = LLDB_INVALID_BREAK_ID )
{
BreakpointLocation * location = bp - > FindLocationByID ( cur_bp_id . GetLocationID ( ) ) . get ( ) ;
if ( location )
{
if ( m_options . m_thread_id_passed )
location - > SetThreadID ( m_options . m_thread_id ) ;
if ( m_options . m_thread_index_passed )
location - > SetThreadIndex ( m_options . m_thread_index ) ;
if ( m_options . m_name_passed )
location - > SetThreadName ( m_options . m_thread_name . c_str ( ) ) ;
if ( m_options . m_queue_passed )
location - > SetQueueName ( m_options . m_queue_name . c_str ( ) ) ;
if ( m_options . m_ignore_count ! = 0 )
location - > SetIgnoreCount ( m_options . m_ignore_count ) ;
if ( m_options . m_enable_passed )
location - > SetEnabled ( m_options . m_enable_value ) ;
if ( m_options . m_condition_passed )
location - > SetCondition ( m_options . m_condition . c_str ( ) ) ;
}
}
else
{
if ( m_options . m_thread_id_passed )
bp - > SetThreadID ( m_options . m_thread_id ) ;
if ( m_options . m_thread_index_passed )
bp - > SetThreadIndex ( m_options . m_thread_index ) ;
if ( m_options . m_name_passed )
bp - > SetThreadName ( m_options . m_thread_name . c_str ( ) ) ;
if ( m_options . m_queue_passed )
bp - > SetQueueName ( m_options . m_queue_name . c_str ( ) ) ;
if ( m_options . m_ignore_count ! = 0 )
bp - > SetIgnoreCount ( m_options . m_ignore_count ) ;
if ( m_options . m_enable_passed )
bp - > SetEnabled ( m_options . m_enable_value ) ;
if ( m_options . m_condition_passed )
bp - > SetCondition ( m_options . m_condition . c_str ( ) ) ;
}
}
}
}
return result . Succeeded ( ) ;
}
private :
CommandOptions m_options ;
} ;
# pragma mark Modify::CommandOptions
OptionDefinition
CommandObjectBreakpointModify : : CommandOptions : : g_option_table [ ] =
{
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " ignore-count " , ' i ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeCount , " Set the number of times this breakpoint is skipped before stopping. " } ,
{ LLDB_OPT_SET_ALL , false , " one-shot " , ' o ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean , " The breakpoint is deleted the first time it stop causes a stop. " } ,
{ LLDB_OPT_SET_ALL , false , " thread-index " , ' x ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeThreadIndex , " The breakpoint stops only for the thread whose index matches this argument. " } ,
{ LLDB_OPT_SET_ALL , false , " thread-id " , ' t ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeThreadID , " The breakpoint stops only for the thread whose TID matches this argument. " } ,
{ LLDB_OPT_SET_ALL , false , " thread-name " , ' T ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeThreadName , " The breakpoint stops only for the thread whose thread name matches this argument. " } ,
{ LLDB_OPT_SET_ALL , false , " queue-name " , ' q ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeQueueName , " The breakpoint stops only for threads in the queue whose name is given by this argument. " } ,
{ LLDB_OPT_SET_ALL , false , " condition " , ' c ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeExpression , " The breakpoint stops only if this condition expression evaluates to true. " } ,
{ LLDB_OPT_SET_1 , false , " enable " , ' e ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " Enable the breakpoint. " } ,
{ LLDB_OPT_SET_2 , false , " disable " , ' d ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " Disable the breakpoint. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , NULL , 0 , eArgTypeNone , NULL }
2013-08-23 17:46:38 +00:00
} ;
//-------------------------------------------------------------------------
// CommandObjectBreakpointEnable
//-------------------------------------------------------------------------
# pragma mark Enable
class CommandObjectBreakpointEnable : public CommandObjectParsed
{
public :
CommandObjectBreakpointEnable ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" enable " ,
" Enable the specified disabled breakpoint(s). If no breakpoints are specified, enable all of them. " ,
NULL )
{
CommandArgumentEntry arg ;
CommandObject : : AddIDsArgumentData ( arg , eArgTypeBreakpointID , eArgTypeBreakpointIDRange ) ;
// Add the entry for the first argument for this command to the object's arguments vector.
m_arguments . push_back ( arg ) ;
}
virtual
~ CommandObjectBreakpointEnable ( ) { }
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. No existing target or breakpoints. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Mutex : : Locker locker ;
target - > GetBreakpointList ( ) . GetListMutex ( locker ) ;
const BreakpointList & breakpoints = target - > GetBreakpointList ( ) ;
size_t num_breakpoints = breakpoints . GetSize ( ) ;
if ( num_breakpoints = = 0 )
{
result . AppendError ( " No breakpoints exist to be enabled. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command . GetArgumentCount ( ) = = 0 )
{
// No breakpoint selected; enable all currently set breakpoints.
target - > EnableAllBreakpoints ( ) ;
2014-11-25 21:00:58 +00:00
result . AppendMessageWithFormat ( " All breakpoints enabled. (% " PRIu64 " breakpoints) \n " , ( uint64_t ) num_breakpoints ) ;
2013-08-23 17:46:38 +00:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
// Particular breakpoint selected; enable that breakpoint.
BreakpointIDList valid_bp_ids ;
CommandObjectMultiwordBreakpoint : : VerifyBreakpointIDs ( command , target , result , & valid_bp_ids ) ;
if ( result . Succeeded ( ) )
{
int enable_count = 0 ;
int loc_count = 0 ;
const size_t count = valid_bp_ids . GetSize ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
BreakpointID cur_bp_id = valid_bp_ids . GetBreakpointIDAtIndex ( i ) ;
if ( cur_bp_id . GetBreakpointID ( ) ! = LLDB_INVALID_BREAK_ID )
{
Breakpoint * breakpoint = target - > GetBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) . get ( ) ;
if ( cur_bp_id . GetLocationID ( ) ! = LLDB_INVALID_BREAK_ID )
{
BreakpointLocation * location = breakpoint - > FindLocationByID ( cur_bp_id . GetLocationID ( ) ) . get ( ) ;
if ( location )
{
location - > SetEnabled ( true ) ;
+ + loc_count ;
}
}
else
{
breakpoint - > SetEnabled ( true ) ;
+ + enable_count ;
}
}
}
result . AppendMessageWithFormat ( " %d breakpoints enabled. \n " , enable_count + loc_count ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectBreakpointDisable
//-------------------------------------------------------------------------
# pragma mark Disable
class CommandObjectBreakpointDisable : public CommandObjectParsed
{
public :
CommandObjectBreakpointDisable ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" breakpoint disable " ,
" Disable the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disable them all. " ,
NULL )
{
SetHelpLong (
" Disable the specified breakpoint(s) without removing it/them. \n \
If no breakpoints are specified , disable them all . \ n \
\ n \
Note : disabling a breakpoint will cause none of its locations to be hit \ n \
regardless of whether they are enabled or disabled . So the sequence : \ n \
\ n \
( lldb ) break disable 1 \ n \
( lldb ) break enable 1.1 \ n \
\ n \
will NOT cause location 1.1 to get hit . To achieve that , do : \ n \
\ n \
( lldb ) break disable 1. * \ n \
( lldb ) break enable 1.1 \ n \
\ n \
The first command disables all the locations of breakpoint 1 , \ n \
the second re - enables the first location . "
) ;
CommandArgumentEntry arg ;
CommandObject : : AddIDsArgumentData ( arg , eArgTypeBreakpointID , eArgTypeBreakpointIDRange ) ;
// Add the entry for the first argument for this command to the object's arguments vector.
m_arguments . push_back ( arg ) ;
}
virtual
~ CommandObjectBreakpointDisable ( ) { }
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. No existing target or breakpoints. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Mutex : : Locker locker ;
target - > GetBreakpointList ( ) . GetListMutex ( locker ) ;
const BreakpointList & breakpoints = target - > GetBreakpointList ( ) ;
size_t num_breakpoints = breakpoints . GetSize ( ) ;
if ( num_breakpoints = = 0 )
{
result . AppendError ( " No breakpoints exist to be disabled. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command . GetArgumentCount ( ) = = 0 )
{
// No breakpoint selected; disable all currently set breakpoints.
target - > DisableAllBreakpoints ( ) ;
2014-11-25 21:00:58 +00:00
result . AppendMessageWithFormat ( " All breakpoints disabled. (% " PRIu64 " breakpoints) \n " , ( uint64_t ) num_breakpoints ) ;
2013-08-23 17:46:38 +00:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
// Particular breakpoint selected; disable that breakpoint.
BreakpointIDList valid_bp_ids ;
CommandObjectMultiwordBreakpoint : : VerifyBreakpointIDs ( command , target , result , & valid_bp_ids ) ;
if ( result . Succeeded ( ) )
{
int disable_count = 0 ;
int loc_count = 0 ;
const size_t count = valid_bp_ids . GetSize ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
BreakpointID cur_bp_id = valid_bp_ids . GetBreakpointIDAtIndex ( i ) ;
if ( cur_bp_id . GetBreakpointID ( ) ! = LLDB_INVALID_BREAK_ID )
{
Breakpoint * breakpoint = target - > GetBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) . get ( ) ;
if ( cur_bp_id . GetLocationID ( ) ! = LLDB_INVALID_BREAK_ID )
{
BreakpointLocation * location = breakpoint - > FindLocationByID ( cur_bp_id . GetLocationID ( ) ) . get ( ) ;
if ( location )
{
location - > SetEnabled ( false ) ;
+ + loc_count ;
}
}
else
{
breakpoint - > SetEnabled ( false ) ;
+ + disable_count ;
}
}
}
result . AppendMessageWithFormat ( " %d breakpoints disabled. \n " , disable_count + loc_count ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectBreakpointList
//-------------------------------------------------------------------------
# pragma mark List
class CommandObjectBreakpointList : public CommandObjectParsed
{
public :
CommandObjectBreakpointList ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" breakpoint list " ,
" List some or all breakpoints at configurable levels of detail. " ,
NULL ) ,
m_options ( interpreter )
{
CommandArgumentEntry arg ;
CommandArgumentData bp_id_arg ;
// Define the first (and only) variant of this arg.
bp_id_arg . arg_type = eArgTypeBreakpointID ;
bp_id_arg . arg_repetition = eArgRepeatOptional ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( bp_id_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
}
virtual
~ CommandObjectBreakpointList ( ) { }
virtual Options *
GetOptions ( )
{
return & m_options ;
}
class CommandOptions : public Options
{
public :
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter ) ,
m_level ( lldb : : eDescriptionLevelBrief ) // Breakpoint List defaults to brief descriptions
{
}
virtual
~ CommandOptions ( ) { }
virtual Error
SetOptionValue ( uint32_t option_idx , const char * option_arg )
{
Error error ;
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' b ' :
m_level = lldb : : eDescriptionLevelBrief ;
break ;
case ' f ' :
m_level = lldb : : eDescriptionLevelFull ;
break ;
case ' v ' :
m_level = lldb : : eDescriptionLevelVerbose ;
break ;
case ' i ' :
m_internal = true ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " , short_option ) ;
break ;
}
return error ;
}
void
OptionParsingStarting ( )
{
m_level = lldb : : eDescriptionLevelFull ;
m_internal = false ;
}
const OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
lldb : : DescriptionLevel m_level ;
bool m_internal ;
} ;
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. No current target or breakpoints. " ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
return true ;
}
const BreakpointList & breakpoints = target - > GetBreakpointList ( m_options . m_internal ) ;
Mutex : : Locker locker ;
target - > GetBreakpointList ( m_options . m_internal ) . GetListMutex ( locker ) ;
size_t num_breakpoints = breakpoints . GetSize ( ) ;
if ( num_breakpoints = = 0 )
{
result . AppendMessage ( " No breakpoints currently set. " ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
return true ;
}
Stream & output_stream = result . GetOutputStream ( ) ;
if ( command . GetArgumentCount ( ) = = 0 )
{
// No breakpoint selected; show info about all currently set breakpoints.
result . AppendMessage ( " Current breakpoints: " ) ;
for ( size_t i = 0 ; i < num_breakpoints ; + + i )
{
Breakpoint * breakpoint = breakpoints . GetBreakpointAtIndex ( i ) . get ( ) ;
AddBreakpointDescription ( & output_stream , breakpoint , m_options . m_level ) ;
}
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
// Particular breakpoints selected; show info about that breakpoint.
BreakpointIDList valid_bp_ids ;
CommandObjectMultiwordBreakpoint : : VerifyBreakpointIDs ( command , target , result , & valid_bp_ids ) ;
if ( result . Succeeded ( ) )
{
for ( size_t i = 0 ; i < valid_bp_ids . GetSize ( ) ; + + i )
{
BreakpointID cur_bp_id = valid_bp_ids . GetBreakpointIDAtIndex ( i ) ;
Breakpoint * breakpoint = target - > GetBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) . get ( ) ;
AddBreakpointDescription ( & output_stream , breakpoint , m_options . m_level ) ;
}
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . AppendError ( " Invalid breakpoint id. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
return result . Succeeded ( ) ;
}
private :
CommandOptions m_options ;
} ;
# pragma mark List::CommandOptions
OptionDefinition
CommandObjectBreakpointList : : CommandOptions : : g_option_table [ ] =
{
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_ALL , false , " internal " , ' i ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone ,
2013-08-23 17:46:38 +00:00
" Show debugger internal breakpoints " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_1 , false , " brief " , ' b ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone ,
2013-08-23 17:46:38 +00:00
" Give a brief description of the breakpoint (no location info). " } ,
// FIXME: We need to add an "internal" command, and then add this sort of thing to it.
// But I need to see it for now, and don't want to wait.
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_2 , false , " full " , ' f ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone ,
2013-08-23 17:46:38 +00:00
" Give a full description of the breakpoint and its locations. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_3 , false , " verbose " , ' v ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone ,
2013-08-23 17:46:38 +00:00
" Explain everything we know about the breakpoint (for debugging debugger bugs). " } ,
2014-11-25 21:00:58 +00:00
{ 0 , false , NULL , 0 , 0 , NULL , NULL , 0 , eArgTypeNone , NULL }
2013-08-23 17:46:38 +00:00
} ;
//-------------------------------------------------------------------------
// CommandObjectBreakpointClear
//-------------------------------------------------------------------------
# pragma mark Clear
class CommandObjectBreakpointClear : public CommandObjectParsed
{
public :
typedef enum BreakpointClearType
{
eClearTypeInvalid ,
eClearTypeFileAndLine
} BreakpointClearType ;
CommandObjectBreakpointClear ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" breakpoint clear " ,
" Clears a breakpoint or set of breakpoints in the executable. " ,
" breakpoint clear <cmd-options> " ) ,
m_options ( interpreter )
{
}
virtual
~ CommandObjectBreakpointClear ( ) { }
virtual Options *
GetOptions ( )
{
return & m_options ;
}
class CommandOptions : public Options
{
public :
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter ) ,
m_filename ( ) ,
m_line_num ( 0 )
{
}
virtual
~ CommandOptions ( ) { }
virtual Error
SetOptionValue ( uint32_t option_idx , const char * option_arg )
{
Error error ;
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' f ' :
m_filename . assign ( option_arg ) ;
break ;
case ' l ' :
m_line_num = Args : : StringToUInt32 ( option_arg , 0 ) ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " , short_option ) ;
break ;
}
return error ;
}
void
OptionParsingStarting ( )
{
m_filename . clear ( ) ;
m_line_num = 0 ;
}
const OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
std : : string m_filename ;
uint32_t m_line_num ;
} ;
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. No existing target or breakpoints. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
// The following are the various types of breakpoints that could be cleared:
// 1). -f -l (clearing breakpoint by source location)
BreakpointClearType break_type = eClearTypeInvalid ;
if ( m_options . m_line_num ! = 0 )
break_type = eClearTypeFileAndLine ;
Mutex : : Locker locker ;
target - > GetBreakpointList ( ) . GetListMutex ( locker ) ;
BreakpointList & breakpoints = target - > GetBreakpointList ( ) ;
size_t num_breakpoints = breakpoints . GetSize ( ) ;
// Early return if there's no breakpoint at all.
if ( num_breakpoints = = 0 )
{
result . AppendError ( " Breakpoint clear: No breakpoint cleared. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return result . Succeeded ( ) ;
}
// Find matching breakpoints and delete them.
// First create a copy of all the IDs.
std : : vector < break_id_t > BreakIDs ;
for ( size_t i = 0 ; i < num_breakpoints ; + + i )
BreakIDs . push_back ( breakpoints . GetBreakpointAtIndex ( i ) . get ( ) - > GetID ( ) ) ;
int num_cleared = 0 ;
StreamString ss ;
switch ( break_type )
{
case eClearTypeFileAndLine : // Breakpoint by source position
{
const ConstString filename ( m_options . m_filename . c_str ( ) ) ;
BreakpointLocationCollection loc_coll ;
for ( size_t i = 0 ; i < num_breakpoints ; + + i )
{
Breakpoint * bp = breakpoints . FindBreakpointByID ( BreakIDs [ i ] ) . get ( ) ;
if ( bp - > GetMatchingFileLine ( filename , m_options . m_line_num , loc_coll ) )
{
// If the collection size is 0, it's a full match and we can just remove the breakpoint.
if ( loc_coll . GetSize ( ) = = 0 )
{
bp - > GetDescription ( & ss , lldb : : eDescriptionLevelBrief ) ;
ss . EOL ( ) ;
target - > RemoveBreakpointByID ( bp - > GetID ( ) ) ;
+ + num_cleared ;
}
}
}
}
break ;
default :
break ;
}
if ( num_cleared > 0 )
{
Stream & output_stream = result . GetOutputStream ( ) ;
output_stream . Printf ( " %d breakpoints cleared: \n " , num_cleared ) ;
output_stream < < ss . GetData ( ) ;
output_stream . EOL ( ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . AppendError ( " Breakpoint clear: No breakpoint cleared. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
private :
CommandOptions m_options ;
} ;
# pragma mark Clear::CommandOptions
OptionDefinition
CommandObjectBreakpointClear : : CommandOptions : : g_option_table [ ] =
{
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_1 , false , " file " , ' f ' , OptionParser : : eRequiredArgument , NULL , NULL , CommandCompletions : : eSourceFileCompletion , eArgTypeFilename ,
2013-08-23 17:46:38 +00:00
" Specify the breakpoint by source location in this particular file. " } ,
2014-11-25 21:00:58 +00:00
{ LLDB_OPT_SET_1 , true , " line " , ' l ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeLineNum ,
2013-08-23 17:46:38 +00:00
" Specify the breakpoint by source location at this particular line. " } ,
2014-11-25 21:00:58 +00:00
{ 0 , false , NULL , 0 , 0 , NULL , NULL , 0 , eArgTypeNone , NULL }
2013-08-23 17:46:38 +00:00
} ;
//-------------------------------------------------------------------------
// CommandObjectBreakpointDelete
//-------------------------------------------------------------------------
# pragma mark Delete
class CommandObjectBreakpointDelete : public CommandObjectParsed
{
public :
CommandObjectBreakpointDelete ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" breakpoint delete " ,
" Delete the specified breakpoint(s). If no breakpoints are specified, delete them all. " ,
NULL )
{
CommandArgumentEntry arg ;
CommandObject : : AddIDsArgumentData ( arg , eArgTypeBreakpointID , eArgTypeBreakpointIDRange ) ;
// Add the entry for the first argument for this command to the object's arguments vector.
m_arguments . push_back ( arg ) ;
}
virtual
~ CommandObjectBreakpointDelete ( ) { }
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = NULL )
{
result . AppendError ( " Invalid target. No existing target or breakpoints. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Mutex : : Locker locker ;
target - > GetBreakpointList ( ) . GetListMutex ( locker ) ;
const BreakpointList & breakpoints = target - > GetBreakpointList ( ) ;
size_t num_breakpoints = breakpoints . GetSize ( ) ;
if ( num_breakpoints = = 0 )
{
result . AppendError ( " No breakpoints exist to be deleted. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command . GetArgumentCount ( ) = = 0 )
{
if ( ! m_interpreter . Confirm ( " About to delete all breakpoints, do you want to do that? " , true ) )
{
result . AppendMessage ( " Operation cancelled... " ) ;
}
else
{
target - > RemoveAllBreakpoints ( ) ;
2014-11-25 21:00:58 +00:00
result . AppendMessageWithFormat ( " All breakpoints removed. (% " PRIu64 " breakpoint%s) \n " , ( uint64_t ) num_breakpoints , num_breakpoints > 1 ? " s " : " " ) ;
2013-08-23 17:46:38 +00:00
}
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
// Particular breakpoint selected; disable that breakpoint.
BreakpointIDList valid_bp_ids ;
CommandObjectMultiwordBreakpoint : : VerifyBreakpointIDs ( command , target , result , & valid_bp_ids ) ;
if ( result . Succeeded ( ) )
{
int delete_count = 0 ;
int disable_count = 0 ;
const size_t count = valid_bp_ids . GetSize ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
BreakpointID cur_bp_id = valid_bp_ids . GetBreakpointIDAtIndex ( i ) ;
if ( cur_bp_id . GetBreakpointID ( ) ! = LLDB_INVALID_BREAK_ID )
{
if ( cur_bp_id . GetLocationID ( ) ! = LLDB_INVALID_BREAK_ID )
{
Breakpoint * breakpoint = target - > GetBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) . get ( ) ;
BreakpointLocation * location = breakpoint - > FindLocationByID ( cur_bp_id . GetLocationID ( ) ) . get ( ) ;
// It makes no sense to try to delete individual locations, so we disable them instead.
if ( location )
{
location - > SetEnabled ( false ) ;
+ + disable_count ;
}
}
else
{
target - > RemoveBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) ;
+ + delete_count ;
}
}
}
result . AppendMessageWithFormat ( " %d breakpoints deleted; %d breakpoint locations disabled. \n " ,
delete_count , disable_count ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectMultiwordBreakpoint
//-------------------------------------------------------------------------
# pragma mark MultiwordBreakpoint
CommandObjectMultiwordBreakpoint : : CommandObjectMultiwordBreakpoint ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( interpreter ,
" breakpoint " ,
" A set of commands for operating on breakpoints. Also see _regexp-break. " ,
" breakpoint <command> [<command-options>] " )
{
CommandObjectSP list_command_object ( new CommandObjectBreakpointList ( interpreter ) ) ;
CommandObjectSP enable_command_object ( new CommandObjectBreakpointEnable ( interpreter ) ) ;
CommandObjectSP disable_command_object ( new CommandObjectBreakpointDisable ( interpreter ) ) ;
CommandObjectSP clear_command_object ( new CommandObjectBreakpointClear ( interpreter ) ) ;
CommandObjectSP delete_command_object ( new CommandObjectBreakpointDelete ( interpreter ) ) ;
CommandObjectSP set_command_object ( new CommandObjectBreakpointSet ( interpreter ) ) ;
CommandObjectSP command_command_object ( new CommandObjectBreakpointCommand ( interpreter ) ) ;
CommandObjectSP modify_command_object ( new CommandObjectBreakpointModify ( interpreter ) ) ;
list_command_object - > SetCommandName ( " breakpoint list " ) ;
enable_command_object - > SetCommandName ( " breakpoint enable " ) ;
disable_command_object - > SetCommandName ( " breakpoint disable " ) ;
clear_command_object - > SetCommandName ( " breakpoint clear " ) ;
delete_command_object - > SetCommandName ( " breakpoint delete " ) ;
set_command_object - > SetCommandName ( " breakpoint set " ) ;
command_command_object - > SetCommandName ( " breakpoint command " ) ;
modify_command_object - > SetCommandName ( " breakpoint modify " ) ;
LoadSubCommand ( " list " , list_command_object ) ;
LoadSubCommand ( " enable " , enable_command_object ) ;
LoadSubCommand ( " disable " , disable_command_object ) ;
LoadSubCommand ( " clear " , clear_command_object ) ;
LoadSubCommand ( " delete " , delete_command_object ) ;
LoadSubCommand ( " set " , set_command_object ) ;
LoadSubCommand ( " command " , command_command_object ) ;
LoadSubCommand ( " modify " , modify_command_object ) ;
}
CommandObjectMultiwordBreakpoint : : ~ CommandObjectMultiwordBreakpoint ( )
{
}
void
CommandObjectMultiwordBreakpoint : : VerifyBreakpointIDs ( Args & args , Target * target , CommandReturnObject & result ,
BreakpointIDList * valid_ids )
{
// args can be strings representing 1). integers (for breakpoint ids)
// 2). the full breakpoint & location canonical representation
// 3). the word "to" or a hyphen, representing a range (in which case there
// had *better* be an entry both before & after of one of the first two types.
// If args is empty, we will use the last created breakpoint (if there is one.)
Args temp_args ;
if ( args . GetArgumentCount ( ) = = 0 )
{
if ( target - > GetLastCreatedBreakpoint ( ) )
{
valid_ids - > AddBreakpointID ( BreakpointID ( target - > GetLastCreatedBreakpoint ( ) - > GetID ( ) , LLDB_INVALID_BREAK_ID ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . AppendError ( " No breakpoint specified and no last created breakpoint. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return ;
}
// Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff directly from the old ARGS to
// the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for
// all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS.
BreakpointIDList : : FindAndReplaceIDRanges ( args , target , result , temp_args ) ;
// NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList:
valid_ids - > InsertStringArray ( temp_args . GetConstArgumentVector ( ) , temp_args . GetArgumentCount ( ) , result ) ;
// At this point, all of the breakpoint ids that the user passed in have been converted to breakpoint IDs
// and put into valid_ids.
if ( result . Succeeded ( ) )
{
// Now that we've converted everything from args into a list of breakpoint ids, go through our tentative list
// of breakpoint id's and verify that they correspond to valid/currently set breakpoints.
const size_t count = valid_ids - > GetSize ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
BreakpointID cur_bp_id = valid_ids - > GetBreakpointIDAtIndex ( i ) ;
Breakpoint * breakpoint = target - > GetBreakpointByID ( cur_bp_id . GetBreakpointID ( ) ) . get ( ) ;
if ( breakpoint ! = NULL )
{
const size_t num_locations = breakpoint - > GetNumLocations ( ) ;
2014-11-25 21:00:58 +00:00
if ( static_cast < size_t > ( cur_bp_id . GetLocationID ( ) ) > num_locations )
2013-08-23 17:46:38 +00:00
{
StreamString id_str ;
BreakpointID : : GetCanonicalReference ( & id_str ,
cur_bp_id . GetBreakpointID ( ) ,
cur_bp_id . GetLocationID ( ) ) ;
i = valid_ids - > GetSize ( ) + 1 ;
result . AppendErrorWithFormat ( " '%s' is not a currently valid breakpoint/location id. \n " ,
id_str . GetData ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
i = valid_ids - > GetSize ( ) + 1 ;
result . AppendErrorWithFormat ( " '%d' is not a currently valid breakpoint id. \n " , cur_bp_id . GetBreakpointID ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
}
}