2010-06-09 00:52:24 +08:00
//===-- CommandInterpreter.cpp ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include <string>
2010-10-13 05:57:09 +08:00
# include <vector>
2010-06-09 00:52:24 +08:00
# include <stdlib.h>
2011-06-24 01:59:56 +08:00
# include "CommandObjectScript.h"
2011-06-24 04:37:26 +08:00
# include "lldb/Interpreter/CommandObjectRegexCommand.h"
2011-06-24 01:59:56 +08:00
2010-06-13 10:17:17 +08:00
# include "../Commands/CommandObjectApropos.h"
# include "../Commands/CommandObjectArgs.h"
# include "../Commands/CommandObjectBreakpoint.h"
2015-07-02 18:03:37 +08:00
# include "../Commands/CommandObjectBugreport.h"
2010-06-13 10:17:17 +08:00
# include "../Commands/CommandObjectDisassemble.h"
# include "../Commands/CommandObjectExpression.h"
# include "../Commands/CommandObjectFrame.h"
2014-01-28 07:43:24 +08:00
# include "../Commands/CommandObjectGUI.h"
2010-06-13 10:17:17 +08:00
# include "../Commands/CommandObjectHelp.h"
# include "../Commands/CommandObjectLog.h"
# include "../Commands/CommandObjectMemory.h"
2011-03-19 09:12:21 +08:00
# include "../Commands/CommandObjectPlatform.h"
2012-09-29 07:57:51 +08:00
# include "../Commands/CommandObjectPlugin.h"
2010-06-13 10:17:17 +08:00
# include "../Commands/CommandObjectProcess.h"
# include "../Commands/CommandObjectQuit.h"
# include "../Commands/CommandObjectRegister.h"
# include "../Commands/CommandObjectSettings.h"
# include "../Commands/CommandObjectSource.h"
2010-07-07 11:36:20 +08:00
# include "../Commands/CommandObjectCommands.h"
2010-06-13 10:17:17 +08:00
# include "../Commands/CommandObjectSyntax.h"
# include "../Commands/CommandObjectTarget.h"
# include "../Commands/CommandObjectThread.h"
2011-06-24 01:59:56 +08:00
# include "../Commands/CommandObjectType.h"
2010-12-24 04:21:44 +08:00
# include "../Commands/CommandObjectVersion.h"
2011-09-23 02:04:58 +08:00
# include "../Commands/CommandObjectWatchpoint.h"
2015-05-05 02:39:38 +08:00
# include "../Commands/CommandObjectLanguage.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Debugger.h"
2012-10-30 05:18:03 +08:00
# include "lldb/Core/Log.h"
2015-07-31 04:28:07 +08:00
# include "lldb/Core/PluginManager.h"
2014-05-02 08:45:31 +08:00
# include "lldb/Core/State.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Stream.h"
2014-01-28 07:43:24 +08:00
# include "lldb/Core/StreamFile.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Timer.h"
2012-10-30 05:18:03 +08:00
2014-09-28 00:54:22 +08:00
# ifndef LLDB_DISABLE_LIBEDIT
2014-01-28 07:43:24 +08:00
# include "lldb/Host/Editline.h"
2014-09-28 00:54:22 +08:00
# endif
2011-02-01 09:31:41 +08:00
# include "lldb/Host/Host.h"
2014-08-22 05:49:24 +08:00
# include "lldb/Host/HostInfo.h"
2010-06-09 00:52:24 +08:00
2012-10-30 05:18:03 +08:00
# include "lldb/Interpreter/Args.h"
2013-03-30 01:03:23 +08:00
# include "lldb/Interpreter/CommandCompletions.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
2013-03-30 01:03:23 +08:00
# include "lldb/Interpreter/CommandReturnObject.h"
2012-10-30 05:18:03 +08:00
# include "lldb/Interpreter/Options.h"
2015-03-04 09:58:01 +08:00
# include "lldb/Interpreter/OptionValueProperties.h"
# include "lldb/Interpreter/Property.h"
2010-06-09 00:52:24 +08:00
2012-10-30 05:18:03 +08:00
# include "lldb/Target/Process.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/TargetList.h"
# include "lldb/Utility/CleanUp.h"
2014-08-22 05:49:24 +08:00
# include "llvm/ADT/SmallString.h"
2014-06-27 13:17:41 +08:00
# include "llvm/ADT/STLExtras.h"
2014-08-22 05:49:24 +08:00
# include "llvm/Support/Path.h"
2014-06-27 13:17:41 +08:00
2010-06-09 00:52:24 +08:00
using namespace lldb ;
using namespace lldb_private ;
2015-04-24 04:00:25 +08:00
static const char * k_white_space = " \t \v " ;
2012-08-23 08:22:02 +08:00
static PropertyDefinition
g_properties [ ] =
{
2014-04-20 08:31:37 +08:00
{ " expand-regex-aliases " , OptionValue : : eTypeBoolean , true , false , nullptr , nullptr , " If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands. " } ,
{ " prompt-on-quit " , OptionValue : : eTypeBoolean , true , true , nullptr , nullptr , " If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case. " } ,
{ " stop-command-source-on-error " , OptionValue : : eTypeBoolean , true , true , nullptr , nullptr , " If true, LLDB will stop running a 'command source' script upon encountering an error. " } ,
2015-10-20 07:11:07 +08:00
{ " space-repl-prompts " , OptionValue : : eTypeBoolean , true , false , nullptr , nullptr , " If true, blank lines will be printed between between REPL submissions. " } ,
2014-04-20 08:31:37 +08:00
{ nullptr , OptionValue : : eTypeInvalid , true , 0 , nullptr , nullptr , nullptr }
2012-08-23 08:22:02 +08:00
} ;
enum
{
2013-01-18 05:36:19 +08:00
ePropertyExpandRegexAliases = 0 ,
2013-06-11 09:26:35 +08:00
ePropertyPromptOnQuit = 1 ,
2015-10-20 07:11:07 +08:00
ePropertyStopCmdSourceOnError = 2 ,
eSpaceReplPrompts = 3
2012-08-23 08:22:02 +08:00
} ;
2012-02-16 14:50:00 +08:00
ConstString &
CommandInterpreter : : GetStaticBroadcasterClass ( )
{
static ConstString class_name ( " lldb.commandInterpreter " ) ;
return class_name ;
}
2015-07-31 04:28:07 +08:00
CommandInterpreter : : CommandInterpreter ( Debugger & debugger , ScriptLanguage script_language , bool synchronous_execution )
2016-03-08 05:50:25 +08:00
: Broadcaster ( debugger . GetBroadcasterManager ( ) , CommandInterpreter : : GetStaticBroadcasterClass ( ) . AsCString ( ) ) ,
2015-07-31 04:28:07 +08:00
Properties ( OptionValuePropertiesSP ( new OptionValueProperties ( ConstString ( " interpreter " ) ) ) ) ,
IOHandlerDelegate ( IOHandlerDelegate : : Completion : : LLDBCommand ) ,
m_debugger ( debugger ) ,
m_synchronous_execution ( synchronous_execution ) ,
m_skip_lldbinit_files ( false ) ,
m_skip_app_init_files ( false ) ,
m_script_interpreter_sp ( ) ,
m_command_io_handler_sp ( ) ,
m_comment_char ( ' # ' ) ,
m_batch_command_mode ( false ) ,
m_truncation_warning ( eNoTruncation ) ,
m_command_source_depth ( 0 ) ,
m_num_errors ( 0 ) ,
m_quit_requested ( false ) ,
m_stopped_for_crash ( false )
2010-06-09 00:52:24 +08:00
{
2012-08-23 01:17:09 +08:00
debugger . SetScriptLanguage ( script_language ) ;
2010-10-31 11:01:06 +08:00
SetEventName ( eBroadcastBitThreadShouldExit , " thread-should-exit " ) ;
SetEventName ( eBroadcastBitResetPrompt , " reset-prompt " ) ;
2012-08-23 01:17:09 +08:00
SetEventName ( eBroadcastBitQuitCommandReceived , " quit " ) ;
2012-02-16 14:50:00 +08:00
CheckInWithManager ( ) ;
2012-08-23 08:22:02 +08:00
m_collection_sp - > Initialize ( g_properties ) ;
2010-06-09 00:52:24 +08:00
}
2012-08-23 08:22:02 +08:00
bool
CommandInterpreter : : GetExpandRegexAliases ( ) const
{
const uint32_t idx = ePropertyExpandRegexAliases ;
2014-04-20 08:31:37 +08:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( nullptr , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
2012-08-23 08:22:02 +08:00
}
2013-01-18 05:36:19 +08:00
bool
CommandInterpreter : : GetPromptOnQuit ( ) const
{
const uint32_t idx = ePropertyPromptOnQuit ;
2014-04-20 08:31:37 +08:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( nullptr , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
2013-01-18 05:36:19 +08:00
}
2012-08-23 08:22:02 +08:00
2015-03-24 06:45:13 +08:00
void
CommandInterpreter : : SetPromptOnQuit ( bool b )
{
const uint32_t idx = ePropertyPromptOnQuit ;
m_collection_sp - > SetPropertyAtIndexAsBoolean ( nullptr , idx , b ) ;
}
2015-04-24 04:00:25 +08:00
void
CommandInterpreter : : ResolveCommand ( const char * command_line , CommandReturnObject & result )
{
std : : string command = command_line ;
if ( ResolveCommandImpl ( command , result ) ! = nullptr ) {
result . AppendMessageWithFormat ( " %s " , command . c_str ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
}
2013-06-11 09:26:35 +08:00
bool
CommandInterpreter : : GetStopCmdSourceOnError ( ) const
{
const uint32_t idx = ePropertyStopCmdSourceOnError ;
2014-04-20 08:31:37 +08:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( nullptr , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
2013-06-11 09:26:35 +08:00
}
2015-10-20 07:11:07 +08:00
bool
CommandInterpreter : : GetSpaceReplPrompts ( ) const
{
const uint32_t idx = eSpaceReplPrompts ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( nullptr , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
2010-06-09 00:52:24 +08:00
void
CommandInterpreter : : Initialize ( )
{
Timer scoped_timer ( __PRETTY_FUNCTION__ , __PRETTY_FUNCTION__ ) ;
CommandReturnObject result ;
LoadCommandDictionary ( ) ;
2016-02-26 09:37:30 +08:00
// An alias arguments vector to reuse - reset it before use...
OptionArgVectorSP alias_arguments_vector_sp ( new OptionArgVector ) ;
2010-06-09 00:52:24 +08:00
// Set up some initial aliases.
2011-05-07 05:37:15 +08:00
CommandObjectSP cmd_obj_sp = GetCommandSPExact ( " quit " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " q " , cmd_obj_sp ) ;
AddAlias ( " exit " , cmd_obj_sp ) ;
}
2012-05-05 07:15:02 +08:00
2012-08-25 02:15:45 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-attach " , false ) ;
2012-05-05 07:15:02 +08:00
if ( cmd_obj_sp )
{
AddAlias ( " attach " , cmd_obj_sp ) ;
}
2011-05-07 05:37:15 +08:00
2012-08-25 02:15:45 +08:00
cmd_obj_sp = GetCommandSPExact ( " process detach " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " detach " , cmd_obj_sp ) ;
}
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " process continue " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " c " , cmd_obj_sp ) ;
AddAlias ( " continue " , cmd_obj_sp ) ;
}
cmd_obj_sp = GetCommandSPExact ( " _regexp-break " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " b " , cmd_obj_sp ) ;
2012-10-06 03:16:31 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-tbreak " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " tbreak " , cmd_obj_sp ) ;
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " thread step-inst " , false ) ;
if ( cmd_obj_sp )
2011-10-22 08:47:41 +08:00
{
AddAlias ( " stepi " , cmd_obj_sp ) ;
2011-05-07 05:37:15 +08:00
AddAlias ( " si " , cmd_obj_sp ) ;
2011-10-22 08:47:41 +08:00
}
cmd_obj_sp = GetCommandSPExact ( " thread step-inst-over " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " nexti " , cmd_obj_sp ) ;
AddAlias ( " ni " , cmd_obj_sp ) ;
}
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " thread step-in " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " s " , cmd_obj_sp ) ;
AddAlias ( " step " , cmd_obj_sp ) ;
2016-02-26 09:37:30 +08:00
alias_arguments_vector_sp . reset ( new OptionArgVector ) ;
ProcessAliasOptionsArgs ( cmd_obj_sp , " --end-linenumber block --step-in-target %1 " , alias_arguments_vector_sp ) ;
AddAlias ( " sif " , cmd_obj_sp ) ;
AddOrReplaceAliasOptions ( " sif " , alias_arguments_vector_sp ) ;
2011-05-07 05:37:15 +08:00
}
cmd_obj_sp = GetCommandSPExact ( " thread step-over " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " n " , cmd_obj_sp ) ;
AddAlias ( " next " , cmd_obj_sp ) ;
}
cmd_obj_sp = GetCommandSPExact ( " thread step-out " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " finish " , cmd_obj_sp ) ;
}
2011-12-02 09:12:59 +08:00
cmd_obj_sp = GetCommandSPExact ( " frame select " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " f " , cmd_obj_sp ) ;
}
2012-10-06 03:16:31 +08:00
cmd_obj_sp = GetCommandSPExact ( " thread select " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " t " , cmd_obj_sp ) ;
}
2013-09-12 10:20:34 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-jump " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " j " , cmd_obj_sp ) ;
AddAlias ( " jump " , cmd_obj_sp ) ;
}
2013-02-02 07:33:03 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-list " , false ) ;
2011-05-07 05:37:15 +08:00
if ( cmd_obj_sp )
{
AddAlias ( " l " , cmd_obj_sp ) ;
AddAlias ( " list " , cmd_obj_sp ) ;
}
2013-02-13 02:52:24 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-env " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " env " , cmd_obj_sp ) ;
}
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " memory read " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " x " , cmd_obj_sp ) ;
cmd_obj_sp = GetCommandSPExact ( " _regexp-up " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " up " , cmd_obj_sp ) ;
cmd_obj_sp = GetCommandSPExact ( " _regexp-down " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " down " , cmd_obj_sp ) ;
2011-10-25 10:11:20 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-display " , false ) ;
2011-10-22 09:30:52 +08:00
if ( cmd_obj_sp )
AddAlias ( " display " , cmd_obj_sp ) ;
2011-10-25 02:37:00 +08:00
cmd_obj_sp = GetCommandSPExact ( " disassemble " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " dis " , cmd_obj_sp ) ;
cmd_obj_sp = GetCommandSPExact ( " disassemble " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " di " , cmd_obj_sp ) ;
2011-10-22 09:30:52 +08:00
2011-10-25 10:11:20 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-undisplay " , false ) ;
2011-10-22 09:30:52 +08:00
if ( cmd_obj_sp )
AddAlias ( " undisplay " , cmd_obj_sp ) ;
2012-10-11 00:51:31 +08:00
cmd_obj_sp = GetCommandSPExact ( " _regexp-bt " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " bt " , cmd_obj_sp ) ;
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " target create " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " file " , cmd_obj_sp ) ;
cmd_obj_sp = GetCommandSPExact ( " target modules " , false ) ;
if ( cmd_obj_sp )
AddAlias ( " image " , cmd_obj_sp ) ;
2016-02-26 11:36:27 +08:00
alias_arguments_vector_sp . reset ( new OptionArgVector ) ;
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " expression " , false ) ;
if ( cmd_obj_sp )
2013-04-18 01:23:58 +08:00
{
2011-05-07 05:37:15 +08:00
ProcessAliasOptionsArgs ( cmd_obj_sp , " -- " , alias_arguments_vector_sp ) ;
AddAlias ( " p " , cmd_obj_sp ) ;
AddAlias ( " print " , cmd_obj_sp ) ;
2012-08-08 09:30:34 +08:00
AddAlias ( " call " , cmd_obj_sp ) ;
2011-05-07 05:37:15 +08:00
AddOrReplaceAliasOptions ( " p " , alias_arguments_vector_sp ) ;
AddOrReplaceAliasOptions ( " print " , alias_arguments_vector_sp ) ;
2012-08-08 09:30:34 +08:00
AddOrReplaceAliasOptions ( " call " , alias_arguments_vector_sp ) ;
2011-05-07 05:37:15 +08:00
alias_arguments_vector_sp . reset ( new OptionArgVector ) ;
2013-05-15 09:03:08 +08:00
ProcessAliasOptionsArgs ( cmd_obj_sp , " -O -- " , alias_arguments_vector_sp ) ;
2011-05-07 05:37:15 +08:00
AddAlias ( " po " , cmd_obj_sp ) ;
AddOrReplaceAliasOptions ( " po " , alias_arguments_vector_sp ) ;
}
2012-06-02 07:29:32 +08:00
cmd_obj_sp = GetCommandSPExact ( " process kill " , false ) ;
if ( cmd_obj_sp )
2012-09-27 08:02:27 +08:00
{
2012-06-02 07:29:32 +08:00
AddAlias ( " kill " , cmd_obj_sp ) ;
2012-09-27 08:02:27 +08:00
}
2012-06-02 07:29:32 +08:00
2011-05-07 05:37:15 +08:00
cmd_obj_sp = GetCommandSPExact ( " process launch " , false ) ;
if ( cmd_obj_sp )
{
alias_arguments_vector_sp . reset ( new OptionArgVector ) ;
2014-07-09 09:29:05 +08:00
# if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
2012-07-06 10:46:23 +08:00
ProcessAliasOptionsArgs ( cmd_obj_sp , " -- " , alias_arguments_vector_sp ) ;
# else
2015-09-23 06:57:12 +08:00
# if defined(__APPLE__)
std : : string shell_option ;
shell_option . append ( " --shell-expand-args " ) ;
shell_option . append ( " true " ) ;
shell_option . append ( " -- " ) ;
ProcessAliasOptionsArgs ( cmd_obj_sp , shell_option . c_str ( ) , alias_arguments_vector_sp ) ;
# else
2014-10-21 01:46:43 +08:00
std : : string shell_option ;
shell_option . append ( " --shell= " ) ;
shell_option . append ( HostInfo : : GetDefaultShell ( ) . GetPath ( ) ) ;
shell_option . append ( " -- " ) ;
ProcessAliasOptionsArgs ( cmd_obj_sp , shell_option . c_str ( ) , alias_arguments_vector_sp ) ;
2015-09-23 06:57:12 +08:00
# endif
2012-07-06 10:46:23 +08:00
# endif
2011-05-07 05:37:15 +08:00
AddAlias ( " r " , cmd_obj_sp ) ;
AddAlias ( " run " , cmd_obj_sp ) ;
AddOrReplaceAliasOptions ( " r " , alias_arguments_vector_sp ) ;
AddOrReplaceAliasOptions ( " run " , alias_arguments_vector_sp ) ;
}
2012-03-30 05:47:51 +08:00
cmd_obj_sp = GetCommandSPExact ( " target symbols add " , false ) ;
if ( cmd_obj_sp )
{
AddAlias ( " add-dsym " , cmd_obj_sp ) ;
}
2012-05-22 02:25:19 +08:00
cmd_obj_sp = GetCommandSPExact ( " breakpoint set " , false ) ;
if ( cmd_obj_sp )
{
alias_arguments_vector_sp . reset ( new OptionArgVector ) ;
ProcessAliasOptionsArgs ( cmd_obj_sp , " --func-regex %1 " , alias_arguments_vector_sp ) ;
2012-10-19 07:24:12 +08:00
AddAlias ( " rbreak " , cmd_obj_sp ) ;
AddOrReplaceAliasOptions ( " rbreak " , alias_arguments_vector_sp ) ;
2012-05-22 02:25:19 +08:00
}
2010-06-09 00:52:24 +08:00
}
2014-04-25 08:35:14 +08:00
void
CommandInterpreter : : Clear ( )
{
m_command_io_handler_sp . reset ( ) ;
2015-07-31 04:28:07 +08:00
if ( m_script_interpreter_sp )
m_script_interpreter_sp - > Clear ( ) ;
2014-04-25 08:35:14 +08:00
}
2010-06-09 00:52:24 +08:00
const char *
CommandInterpreter : : ProcessEmbeddedScriptCommands ( const char * arg )
{
// This function has not yet been implemented.
// Look for any embedded script command
// If found,
// get interpreter object from the command dictionary,
// call execute_one_command on it,
// get the results as a string,
// substitute that string for current stuff.
return arg ;
}
void
CommandInterpreter : : LoadCommandDictionary ( )
{
Timer scoped_timer ( __PRETTY_FUNCTION__ , __PRETTY_FUNCTION__ ) ;
2010-09-21 04:44:43 +08:00
lldb : : ScriptLanguage script_language = m_debugger . GetScriptLanguage ( ) ;
2010-09-04 08:03:46 +08:00
2010-09-18 09:14:36 +08:00
m_command_dict [ " apropos " ] = CommandObjectSP ( new CommandObjectApropos ( * this ) ) ;
2010-06-23 09:19:29 +08:00
m_command_dict [ " breakpoint " ] = CommandObjectSP ( new CommandObjectMultiwordBreakpoint ( * this ) ) ;
2015-07-02 18:03:37 +08:00
m_command_dict [ " bugreport " ] = CommandObjectSP ( new CommandObjectMultiwordBugreport ( * this ) ) ;
2011-04-21 08:39:18 +08:00
m_command_dict [ " command " ] = CommandObjectSP ( new CommandObjectMultiwordCommands ( * this ) ) ;
2010-09-18 09:14:36 +08:00
m_command_dict [ " disassemble " ] = CommandObjectSP ( new CommandObjectDisassemble ( * this ) ) ;
m_command_dict [ " expression " ] = CommandObjectSP ( new CommandObjectExpression ( * this ) ) ;
2010-06-23 09:19:29 +08:00
m_command_dict [ " frame " ] = CommandObjectSP ( new CommandObjectMultiwordFrame ( * this ) ) ;
2014-01-28 07:43:24 +08:00
m_command_dict [ " gui " ] = CommandObjectSP ( new CommandObjectGUI ( * this ) ) ;
2010-09-18 09:14:36 +08:00
m_command_dict [ " help " ] = CommandObjectSP ( new CommandObjectHelp ( * this ) ) ;
2010-06-23 09:19:29 +08:00
m_command_dict [ " log " ] = CommandObjectSP ( new CommandObjectLog ( * this ) ) ;
m_command_dict [ " memory " ] = CommandObjectSP ( new CommandObjectMemory ( * this ) ) ;
2011-03-19 09:12:21 +08:00
m_command_dict [ " platform " ] = CommandObjectSP ( new CommandObjectPlatform ( * this ) ) ;
2012-09-29 07:57:51 +08:00
m_command_dict [ " plugin " ] = CommandObjectSP ( new CommandObjectPlugin ( * this ) ) ;
2010-06-23 09:19:29 +08:00
m_command_dict [ " process " ] = CommandObjectSP ( new CommandObjectMultiwordProcess ( * this ) ) ;
2010-09-18 09:14:36 +08:00
m_command_dict [ " quit " ] = CommandObjectSP ( new CommandObjectQuit ( * this ) ) ;
2010-06-23 09:19:29 +08:00
m_command_dict [ " register " ] = CommandObjectSP ( new CommandObjectRegister ( * this ) ) ;
2010-09-18 09:14:36 +08:00
m_command_dict [ " script " ] = CommandObjectSP ( new CommandObjectScript ( * this , script_language ) ) ;
2010-09-04 08:03:46 +08:00
m_command_dict [ " settings " ] = CommandObjectSP ( new CommandObjectMultiwordSettings ( * this ) ) ;
2010-07-07 11:36:20 +08:00
m_command_dict [ " source " ] = CommandObjectSP ( new CommandObjectMultiwordSource ( * this ) ) ;
2010-06-23 09:19:29 +08:00
m_command_dict [ " target " ] = CommandObjectSP ( new CommandObjectMultiwordTarget ( * this ) ) ;
m_command_dict [ " thread " ] = CommandObjectSP ( new CommandObjectMultiwordThread ( * this ) ) ;
2011-08-17 07:24:13 +08:00
m_command_dict [ " type " ] = CommandObjectSP ( new CommandObjectType ( * this ) ) ;
2010-12-24 04:21:44 +08:00
m_command_dict [ " version " ] = CommandObjectSP ( new CommandObjectVersion ( * this ) ) ;
2011-09-23 02:04:58 +08:00
m_command_dict [ " watchpoint " ] = CommandObjectSP ( new CommandObjectMultiwordWatchpoint ( * this ) ) ;
2015-05-05 02:39:38 +08:00
m_command_dict [ " language " ] = CommandObjectSP ( new CommandObjectLanguage ( * this ) ) ;
2010-06-09 00:52:24 +08:00
2012-10-06 03:16:31 +08:00
const char * break_regexes [ ] [ 2 ] = { { " ^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$ " , " breakpoint set --file '%1' --line %2 " } ,
2014-12-02 06:34:03 +08:00
{ " ^/([^/]+)/$ " , " breakpoint set --source-pattern-regexp '%1' " } ,
2012-10-06 03:16:31 +08:00
{ " ^([[:digit:]]+)[[:space:]]*$ " , " breakpoint set --line %1 " } ,
2013-02-08 10:54:24 +08:00
{ " ^ \\ *?(0x[[:xdigit:]]+)[[:space:]]*$ " , " breakpoint set --address %1 " } ,
2013-01-30 08:18:29 +08:00
{ " ^[ \" ']?([-+]? \\ [.* \\ ])[ \" ']?[[:space:]]*$ " , " breakpoint set --name '%1' " } ,
2012-10-06 03:16:31 +08:00
{ " ^(-.*)$ " , " breakpoint set %1 " } ,
{ " ^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$ " , " breakpoint set --name '%2' --shlib '%1' " } ,
2013-02-08 10:54:24 +08:00
{ " ^ \\ &(.*[^[:space:]])[[:space:]]*$ " , " breakpoint set --name '%1' --skip-prologue=0 " } ,
2014-08-15 01:58:33 +08:00
{ " ^[ \" ']?(.*[^[:space:] \" '])[ \" ']?[[:space:]]*$ " , " breakpoint set --name '%1' " } } ;
2012-10-06 03:16:31 +08:00
2014-06-27 13:17:41 +08:00
size_t num_regexes = llvm : : array_lengthof ( break_regexes ) ;
2012-10-06 03:16:31 +08:00
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2010-09-18 09:14:36 +08:00
break_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2011-04-12 13:54:46 +08:00
" _regexp-break " ,
2015-03-07 08:01:46 +08:00
" Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex. \n " ,
" \n _regexp-break <filename>:<linenum> # _regexp-break main.c:12 // Break on line 12 of main.c \n "
" _regexp-break <linenum> # _regexp-break 12 // Break on line 12 of current file \n "
" _regexp-break <address> # _regexp-break 0x1234000 // Break on address 0x1234000 \n "
" _regexp-break <name> # _regexp-break main // Break in 'main' after the prologue \n "
" _regexp-break &<name> # _regexp-break &main // Break on the first instruction in 'main' \n "
" _regexp-break <module>`<name> # _regexp-break libc.so`malloc // Break in 'malloc' only in the 'libc.so' shared library \n "
" _regexp-break /<source-regex>/ # _regexp-break /break here/ // Break on all lines that match the regular expression 'break here' in the current file. \n " ,
2013-03-30 01:03:23 +08:00
2 ,
CommandCompletions : : eSymbolCompletion |
2015-01-10 03:08:20 +08:00
CommandCompletions : : eSourceFileCompletion ,
false ) ) ;
2012-10-06 03:16:31 +08:00
2010-06-09 00:52:24 +08:00
if ( break_regex_cmd_ap . get ( ) )
{
2012-10-06 03:16:31 +08:00
bool success = true ;
for ( size_t i = 0 ; i < num_regexes ; i + + )
{
success = break_regex_cmd_ap - > AddRegexCommand ( break_regexes [ i ] [ 0 ] , break_regexes [ i ] [ 1 ] ) ;
if ( ! success )
break ;
}
success = break_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " breakpoint list --full " ) ;
if ( success )
2010-06-09 00:52:24 +08:00
{
CommandObjectSP break_regex_cmd_sp ( break_regex_cmd_ap . release ( ) ) ;
m_command_dict [ break_regex_cmd_sp - > GetCommandName ( ) ] = break_regex_cmd_sp ;
}
}
2011-03-22 10:29:32 +08:00
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2012-10-06 03:16:31 +08:00
tbreak_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
" _regexp-tbreak " ,
" Set a one shot breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex. " ,
2013-03-30 01:03:23 +08:00
" _regexp-tbreak [<filename>:<linenum>] \n _regexp-break [<linenum>] \n _regexp-break [<address>] \n _regexp-break <...> " ,
2 ,
CommandCompletions : : eSymbolCompletion |
2015-01-10 03:08:20 +08:00
CommandCompletions : : eSourceFileCompletion ,
false ) ) ;
2012-10-06 03:16:31 +08:00
if ( tbreak_regex_cmd_ap . get ( ) )
{
bool success = true ;
for ( size_t i = 0 ; i < num_regexes ; i + + )
{
// If you add a resultant command string longer than 1024 characters be sure to increase the size of this buffer.
char buffer [ 1024 ] ;
int num_printed = snprintf ( buffer , 1024 , " %s %s " , break_regexes [ i ] [ 1 ] , " -o " ) ;
assert ( num_printed < 1024 ) ;
2015-07-24 08:23:29 +08:00
UNUSED_IF_ASSERT_DISABLED ( num_printed ) ;
2012-10-06 03:16:31 +08:00
success = tbreak_regex_cmd_ap - > AddRegexCommand ( break_regexes [ i ] [ 0 ] , buffer ) ;
if ( ! success )
break ;
}
success = tbreak_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " breakpoint list --full " ) ;
if ( success )
{
CommandObjectSP tbreak_regex_cmd_sp ( tbreak_regex_cmd_ap . release ( ) ) ;
m_command_dict [ tbreak_regex_cmd_sp - > GetCommandName ( ) ] = tbreak_regex_cmd_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2012-08-25 02:15:45 +08:00
attach_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
" _regexp-attach " ,
" Attach to a process id if in decimal, otherwise treat the argument as a process name to attach to. " ,
2013-03-30 01:03:23 +08:00
" _regexp-attach [<pid>] \n _regexp-attach [<process-name>] " ,
2015-01-10 03:08:20 +08:00
2 ,
0 ,
false ) ) ;
2012-08-25 02:15:45 +08:00
if ( attach_regex_cmd_ap . get ( ) )
{
2012-12-15 09:19:07 +08:00
if ( attach_regex_cmd_ap - > AddRegexCommand ( " ^([0-9]+)[[:space:]]*$ " , " process attach --pid %1 " ) & &
attach_regex_cmd_ap - > AddRegexCommand ( " ^(-.*|.* -.*)$ " , " process attach %1 " ) & & // Any options that are specified get passed to 'process attach'
attach_regex_cmd_ap - > AddRegexCommand ( " ^(.+)$ " , " process attach --name '%1' " ) & &
attach_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " process attach " ) )
2012-08-25 02:15:45 +08:00
{
CommandObjectSP attach_regex_cmd_sp ( attach_regex_cmd_ap . release ( ) ) ;
m_command_dict [ attach_regex_cmd_sp - > GetCommandName ( ) ] = attach_regex_cmd_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2011-03-22 10:29:32 +08:00
down_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2011-04-12 13:54:46 +08:00
" _regexp-down " ,
" Go down \" n \" frames in the stack (1 frame by default). " ,
2015-01-10 03:08:20 +08:00
" _regexp-down [n] " ,
2 ,
0 ,
false ) ) ;
2011-03-22 10:29:32 +08:00
if ( down_regex_cmd_ap . get ( ) )
{
if ( down_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " frame select -r -1 " ) & &
down_regex_cmd_ap - > AddRegexCommand ( " ^([0-9]+)$ " , " frame select -r -%1 " ) )
{
CommandObjectSP down_regex_cmd_sp ( down_regex_cmd_ap . release ( ) ) ;
m_command_dict [ down_regex_cmd_sp - > GetCommandName ( ) ] = down_regex_cmd_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2011-03-22 10:29:32 +08:00
up_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2011-04-12 13:54:46 +08:00
" _regexp-up " ,
" Go up \" n \" frames in the stack (1 frame by default). " ,
2015-01-10 03:08:20 +08:00
" _regexp-up [n] " ,
2 ,
0 ,
false ) ) ;
2011-03-22 10:29:32 +08:00
if ( up_regex_cmd_ap . get ( ) )
{
if ( up_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " frame select -r 1 " ) & &
up_regex_cmd_ap - > AddRegexCommand ( " ^([0-9]+)$ " , " frame select -r %1 " ) )
{
CommandObjectSP up_regex_cmd_sp ( up_regex_cmd_ap . release ( ) ) ;
m_command_dict [ up_regex_cmd_sp - > GetCommandName ( ) ] = up_regex_cmd_sp ;
}
}
2011-10-22 09:30:52 +08:00
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2011-10-22 09:30:52 +08:00
display_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2013-03-30 01:03:23 +08:00
" _regexp-display " ,
" Add an expression evaluation stop-hook. " ,
2015-01-10 03:08:20 +08:00
" _regexp-display expression " ,
2 ,
0 ,
false ) ) ;
2011-10-22 09:30:52 +08:00
if ( display_regex_cmd_ap . get ( ) )
{
if ( display_regex_cmd_ap - > AddRegexCommand ( " ^(.+)$ " , " target stop-hook add -o \" expr -- %1 \" " ) )
{
CommandObjectSP display_regex_cmd_sp ( display_regex_cmd_ap . release ( ) ) ;
m_command_dict [ display_regex_cmd_sp - > GetCommandName ( ) ] = display_regex_cmd_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2011-10-22 09:30:52 +08:00
undisplay_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2013-03-30 01:03:23 +08:00
" _regexp-undisplay " ,
" Remove an expression evaluation stop-hook. " ,
2015-01-10 03:08:20 +08:00
" _regexp-undisplay stop-hook-number " ,
2 ,
0 ,
false ) ) ;
2011-10-22 09:30:52 +08:00
if ( undisplay_regex_cmd_ap . get ( ) )
{
if ( undisplay_regex_cmd_ap - > AddRegexCommand ( " ^([0-9]+)$ " , " target stop-hook delete %1 " ) )
{
CommandObjectSP undisplay_regex_cmd_sp ( undisplay_regex_cmd_ap . release ( ) ) ;
m_command_dict [ undisplay_regex_cmd_sp - > GetCommandName ( ) ] = undisplay_regex_cmd_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2012-09-27 06:26:47 +08:00
connect_gdb_remote_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2013-03-30 01:03:23 +08:00
" gdb-remote " ,
" Connect to a remote GDB server. If no hostname is provided, localhost is assumed. " ,
2015-01-10 03:08:20 +08:00
" gdb-remote [<hostname>:]<portnum> " ,
2 ,
0 ,
false ) ) ;
2012-09-27 06:26:47 +08:00
if ( connect_gdb_remote_cmd_ap . get ( ) )
{
if ( connect_gdb_remote_cmd_ap - > AddRegexCommand ( " ^([^:]+:[[:digit:]]+)$ " , " process connect --plugin gdb-remote connect://%1 " ) & &
connect_gdb_remote_cmd_ap - > AddRegexCommand ( " ^([[:digit:]]+)$ " , " process connect --plugin gdb-remote connect://localhost:%1 " ) )
{
CommandObjectSP command_sp ( connect_gdb_remote_cmd_ap . release ( ) ) ;
m_command_dict [ command_sp - > GetCommandName ( ) ] = command_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2012-09-27 06:26:47 +08:00
connect_kdp_remote_cmd_ap ( new CommandObjectRegexCommand ( * this ,
" kdp-remote " ,
2012-10-23 11:05:16 +08:00
" Connect to a remote KDP server. udp port 41139 is the default port number. " ,
2015-01-10 03:08:20 +08:00
" kdp-remote <hostname>[:<portnum>] " ,
2 ,
0 ,
false ) ) ;
2012-09-27 06:26:47 +08:00
if ( connect_kdp_remote_cmd_ap . get ( ) )
{
if ( connect_kdp_remote_cmd_ap - > AddRegexCommand ( " ^([^:]+:[[:digit:]]+)$ " , " process connect --plugin kdp-remote udp://%1 " ) & &
2012-09-27 10:47:55 +08:00
connect_kdp_remote_cmd_ap - > AddRegexCommand ( " ^(.+)$ " , " process connect --plugin kdp-remote udp://%1:41139 " ) )
2012-09-27 06:26:47 +08:00
{
CommandObjectSP command_sp ( connect_kdp_remote_cmd_ap . release ( ) ) ;
m_command_dict [ command_sp - > GetCommandName ( ) ] = command_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2012-10-05 13:29:32 +08:00
bt_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2015-01-10 03:08:20 +08:00
" _regexp-bt " ,
" Show a backtrace. An optional argument is accepted; if that argument is a number, it specifies the number of frames to display. If that argument is 'all', full backtraces of all threads are displayed. " ,
" bt [<digit>|all] " ,
2 ,
0 ,
false ) ) ;
2012-10-05 13:29:32 +08:00
if ( bt_regex_cmd_ap . get ( ) )
{
// accept but don't document "bt -c <number>" -- before bt was a regex command if you wanted to backtrace
// three frames you would do "bt -c 3" but the intention is to have this emulate the gdb "bt" command and
// so now "bt 3" is the preferred form, in line with gdb.
if ( bt_regex_cmd_ap - > AddRegexCommand ( " ^([[:digit:]]+)$ " , " thread backtrace -c %1 " ) & &
bt_regex_cmd_ap - > AddRegexCommand ( " ^-c ([[:digit:]]+)$ " , " thread backtrace -c %1 " ) & &
bt_regex_cmd_ap - > AddRegexCommand ( " ^all$ " , " thread backtrace all " ) & &
bt_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " thread backtrace " ) )
{
CommandObjectSP command_sp ( bt_regex_cmd_ap . release ( ) ) ;
m_command_dict [ command_sp - > GetCommandName ( ) ] = command_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2013-02-02 07:33:03 +08:00
list_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
" _regexp-list " ,
" Implements the GDB 'list' command in all of its forms except FILE:FUNCTION and maps them to the appropriate 'source list' commands. " ,
2013-09-27 04:00:01 +08:00
" _regexp-list [<line>] \n _regexp-list [<file>:<line>] \n _regexp-list [<file>:<line>] " ,
2013-03-30 01:03:23 +08:00
2 ,
2015-01-10 03:08:20 +08:00
CommandCompletions : : eSourceFileCompletion ,
false ) ) ;
2013-02-02 07:33:03 +08:00
if ( list_regex_cmd_ap . get ( ) )
{
if ( list_regex_cmd_ap - > AddRegexCommand ( " ^([0-9]+)[[:space:]]*$ " , " source list --line %1 " ) & &
list_regex_cmd_ap - > AddRegexCommand ( " ^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$ " , " source list --file '%1' --line %2 " ) & &
list_regex_cmd_ap - > AddRegexCommand ( " ^ \\ *?(0x[[:xdigit:]]+)[[:space:]]*$ " , " source list --address %1 " ) & &
2013-02-13 02:42:05 +08:00
list_regex_cmd_ap - > AddRegexCommand ( " ^-[[:space:]]*$ " , " source list --reverse " ) & &
2013-03-14 02:25:49 +08:00
list_regex_cmd_ap - > AddRegexCommand ( " ^-([[:digit:]]+)[[:space:]]*$ " , " source list --reverse --count %1 " ) & &
2013-02-02 07:33:03 +08:00
list_regex_cmd_ap - > AddRegexCommand ( " ^(.+)$ " , " source list --name \" %1 \" " ) & &
list_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " source list " ) )
{
CommandObjectSP list_regex_cmd_sp ( list_regex_cmd_ap . release ( ) ) ;
m_command_dict [ list_regex_cmd_sp - > GetCommandName ( ) ] = list_regex_cmd_sp ;
}
}
2013-04-19 06:45:39 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
2013-02-13 02:52:24 +08:00
env_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
2013-03-30 01:03:23 +08:00
" _regexp-env " ,
" Implements a shortcut to viewing and setting environment variables. " ,
2015-01-10 03:08:20 +08:00
" _regexp-env \n _regexp-env FOO=BAR " ,
2 ,
0 ,
false ) ) ;
2013-02-13 02:52:24 +08:00
if ( env_regex_cmd_ap . get ( ) )
{
if ( env_regex_cmd_ap - > AddRegexCommand ( " ^$ " , " settings show target.env-vars " ) & &
env_regex_cmd_ap - > AddRegexCommand ( " ^([A-Za-z_][A-Za-z_0-9]*=.*)$ " , " settings set target.env-vars %1 " ) )
{
CommandObjectSP env_regex_cmd_sp ( env_regex_cmd_ap . release ( ) ) ;
m_command_dict [ env_regex_cmd_sp - > GetCommandName ( ) ] = env_regex_cmd_sp ;
}
}
2013-09-12 10:20:34 +08:00
std : : unique_ptr < CommandObjectRegexCommand >
jump_regex_cmd_ap ( new CommandObjectRegexCommand ( * this ,
" _regexp-jump " ,
" Sets the program counter to a new address. " ,
" _regexp-jump [<line>] \n "
" _regexp-jump [<+-lineoffset>] \n "
" _regexp-jump [<file>:<line>] \n "
2015-01-10 03:08:20 +08:00
" _regexp-jump [*<addr>] \n " ,
2 ,
0 ,
false ) ) ;
2013-09-12 10:20:34 +08:00
if ( jump_regex_cmd_ap . get ( ) )
{
if ( jump_regex_cmd_ap - > AddRegexCommand ( " ^ \\ *(.*)$ " , " thread jump --addr %1 " ) & &
jump_regex_cmd_ap - > AddRegexCommand ( " ^([0-9]+)$ " , " thread jump --line %1 " ) & &
jump_regex_cmd_ap - > AddRegexCommand ( " ^([^:]+):([0-9]+)$ " , " thread jump --file %1 --line %2 " ) & &
jump_regex_cmd_ap - > AddRegexCommand ( " ^([+ \\ -][0-9]+)$ " , " thread jump --by %1 " ) )
{
CommandObjectSP jump_regex_cmd_sp ( jump_regex_cmd_ap . release ( ) ) ;
m_command_dict [ jump_regex_cmd_sp - > GetCommandName ( ) ] = jump_regex_cmd_sp ;
}
}
2010-06-09 00:52:24 +08:00
}
int
CommandInterpreter : : GetCommandNamesMatchingPartialString ( const char * cmd_str , bool include_aliases ,
StringList & matches )
{
CommandObject : : AddNamesMatchingPartialString ( m_command_dict , cmd_str , matches ) ;
if ( include_aliases )
{
CommandObject : : AddNamesMatchingPartialString ( m_alias_dict , cmd_str , matches ) ;
}
return matches . GetSize ( ) ;
}
CommandObjectSP
CommandInterpreter : : GetCommandSP ( const char * cmd_cstr , bool include_aliases , bool exact , StringList * matches )
{
CommandObject : : CommandMap : : iterator pos ;
2013-01-26 02:06:21 +08:00
CommandObjectSP command_sp ;
2010-06-09 00:52:24 +08:00
std : : string cmd ( cmd_cstr ) ;
if ( HasCommands ( ) )
{
pos = m_command_dict . find ( cmd ) ;
if ( pos ! = m_command_dict . end ( ) )
2013-01-26 02:06:21 +08:00
command_sp = pos - > second ;
2010-06-09 00:52:24 +08:00
}
if ( include_aliases & & HasAliases ( ) )
{
pos = m_alias_dict . find ( cmd ) ;
if ( pos ! = m_alias_dict . end ( ) )
2013-01-26 02:06:21 +08:00
command_sp = pos - > second ;
2010-06-09 00:52:24 +08:00
}
if ( HasUserCommands ( ) )
{
pos = m_user_dict . find ( cmd ) ;
if ( pos ! = m_user_dict . end ( ) )
2013-01-26 02:06:21 +08:00
command_sp = pos - > second ;
2010-06-09 00:52:24 +08:00
}
2013-01-26 02:06:21 +08:00
if ( ! exact & & ! command_sp )
2010-06-09 00:52:24 +08:00
{
2010-07-07 06:46:59 +08:00
// We will only get into here if we didn't find any exact matches.
CommandObjectSP user_match_sp , alias_match_sp , real_match_sp ;
2010-06-09 00:52:24 +08:00
StringList local_matches ;
2014-04-20 08:31:37 +08:00
if ( matches = = nullptr )
2010-06-09 00:52:24 +08:00
matches = & local_matches ;
2010-07-07 06:46:59 +08:00
unsigned int num_cmd_matches = 0 ;
unsigned int num_alias_matches = 0 ;
unsigned int num_user_matches = 0 ;
// Look through the command dictionaries one by one, and if we get only one match from any of
// them in toto, then return that, otherwise return an empty CommandObjectSP and the list of matches.
2010-06-09 00:52:24 +08:00
if ( HasCommands ( ) )
{
num_cmd_matches = CommandObject : : AddNamesMatchingPartialString ( m_command_dict , cmd_cstr , * matches ) ;
}
if ( num_cmd_matches = = 1 )
{
cmd . assign ( matches - > GetStringAtIndex ( 0 ) ) ;
pos = m_command_dict . find ( cmd ) ;
if ( pos ! = m_command_dict . end ( ) )
2010-07-07 06:46:59 +08:00
real_match_sp = pos - > second ;
2010-06-09 00:52:24 +08:00
}
2010-06-25 04:28:42 +08:00
if ( include_aliases & & HasAliases ( ) )
2010-06-09 00:52:24 +08:00
{
num_alias_matches = CommandObject : : AddNamesMatchingPartialString ( m_alias_dict , cmd_cstr , * matches ) ;
}
2010-07-07 06:46:59 +08:00
if ( num_alias_matches = = 1 )
2010-06-09 00:52:24 +08:00
{
cmd . assign ( matches - > GetStringAtIndex ( num_cmd_matches ) ) ;
pos = m_alias_dict . find ( cmd ) ;
if ( pos ! = m_alias_dict . end ( ) )
2010-07-07 06:46:59 +08:00
alias_match_sp = pos - > second ;
2010-06-09 00:52:24 +08:00
}
2010-06-25 04:28:42 +08:00
if ( HasUserCommands ( ) )
2010-06-09 00:52:24 +08:00
{
num_user_matches = CommandObject : : AddNamesMatchingPartialString ( m_user_dict , cmd_cstr , * matches ) ;
}
2010-07-07 06:46:59 +08:00
if ( num_user_matches = = 1 )
2010-06-09 00:52:24 +08:00
{
cmd . assign ( matches - > GetStringAtIndex ( num_cmd_matches + num_alias_matches ) ) ;
pos = m_user_dict . find ( cmd ) ;
if ( pos ! = m_user_dict . end ( ) )
2010-07-07 06:46:59 +08:00
user_match_sp = pos - > second ;
}
// If we got exactly one match, return that, otherwise return the match list.
if ( num_user_matches + num_cmd_matches + num_alias_matches = = 1 )
{
if ( num_cmd_matches )
return real_match_sp ;
else if ( num_alias_matches )
return alias_match_sp ;
else
return user_match_sp ;
2010-06-09 00:52:24 +08:00
}
}
2013-01-26 02:06:21 +08:00
else if ( matches & & command_sp )
2010-07-07 06:46:59 +08:00
{
matches - > AppendString ( cmd_cstr ) ;
2010-06-09 00:52:24 +08:00
}
2013-01-26 02:06:21 +08:00
return command_sp ;
2010-06-09 00:52:24 +08:00
}
2011-04-21 00:37:46 +08:00
bool
CommandInterpreter : : AddCommand ( const char * name , const lldb : : CommandObjectSP & cmd_sp , bool can_replace )
{
2016-02-06 09:36:07 +08:00
if ( cmd_sp . get ( ) )
assert ( ( this = = & cmd_sp - > GetCommandInterpreter ( ) ) & & " tried to add a CommandObject from a different interpreter " ) ;
2011-04-21 00:37:46 +08:00
if ( name & & name [ 0 ] )
{
std : : string name_sstr ( name ) ;
2012-10-02 01:19:37 +08:00
bool found = ( m_command_dict . find ( name_sstr ) ! = m_command_dict . end ( ) ) ;
if ( found & & ! can_replace )
return false ;
if ( found & & m_command_dict [ name_sstr ] - > IsRemovable ( ) = = false )
2012-09-29 07:57:51 +08:00
return false ;
2011-04-21 00:37:46 +08:00
m_command_dict [ name_sstr ] = cmd_sp ;
return true ;
}
return false ;
}
2011-08-17 07:24:13 +08:00
bool
2011-11-08 06:57:04 +08:00
CommandInterpreter : : AddUserCommand ( std : : string name ,
2011-08-17 07:24:13 +08:00
const lldb : : CommandObjectSP & cmd_sp ,
bool can_replace )
{
2016-02-06 09:36:07 +08:00
if ( cmd_sp . get ( ) )
assert ( ( this = = & cmd_sp - > GetCommandInterpreter ( ) ) & & " tried to add a CommandObject from a different interpreter " ) ;
2011-11-08 06:57:04 +08:00
if ( ! name . empty ( ) )
2011-08-17 07:24:13 +08:00
{
2011-11-08 06:57:04 +08:00
const char * name_cstr = name . c_str ( ) ;
// do not allow replacement of internal commands
if ( CommandExists ( name_cstr ) )
2012-09-29 07:57:51 +08:00
{
if ( can_replace = = false )
return false ;
if ( m_command_dict [ name ] - > IsRemovable ( ) = = false )
return false ;
}
if ( UserCommandExists ( name_cstr ) )
{
if ( can_replace = = false )
return false ;
if ( m_user_dict [ name ] - > IsRemovable ( ) = = false )
return false ;
}
2011-11-08 06:57:04 +08:00
m_user_dict [ name ] = cmd_sp ;
2011-08-17 07:24:13 +08:00
return true ;
}
return false ;
}
2011-04-21 00:37:46 +08:00
2010-07-07 06:46:59 +08:00
CommandObjectSP
CommandInterpreter : : GetCommandSPExact ( const char * cmd_cstr , bool include_aliases )
{
2010-12-15 02:51:39 +08:00
Args cmd_words ( cmd_cstr ) ; // Break up the command string into words, in case it's a multi-word command.
CommandObjectSP ret_val ; // Possibly empty return value.
2014-04-20 08:31:37 +08:00
if ( cmd_cstr = = nullptr )
2010-12-15 02:51:39 +08:00
return ret_val ;
if ( cmd_words . GetArgumentCount ( ) = = 1 )
2014-04-20 08:31:37 +08:00
return GetCommandSP ( cmd_cstr , include_aliases , true , nullptr ) ;
2010-12-15 02:51:39 +08:00
else
{
// We have a multi-word command (seemingly), so we need to do more work.
// First, get the cmd_obj_sp for the first word in the command.
2014-04-20 08:31:37 +08:00
CommandObjectSP cmd_obj_sp = GetCommandSP ( cmd_words . GetArgumentAtIndex ( 0 ) , include_aliases , true , nullptr ) ;
if ( cmd_obj_sp . get ( ) ! = nullptr )
2010-12-15 02:51:39 +08:00
{
// Loop through the rest of the words in the command (everything passed in was supposed to be part of a
// command name), and find the appropriate sub-command SP for each command word....
size_t end = cmd_words . GetArgumentCount ( ) ;
for ( size_t j = 1 ; j < end ; + + j )
{
if ( cmd_obj_sp - > IsMultiwordObject ( ) )
{
2012-10-13 10:07:45 +08:00
cmd_obj_sp = cmd_obj_sp - > GetSubcommandSP ( cmd_words . GetArgumentAtIndex ( j ) ) ;
2014-04-20 08:31:37 +08:00
if ( cmd_obj_sp . get ( ) = = nullptr )
2010-12-15 02:51:39 +08:00
// The sub-command name was invalid. Fail and return the empty 'ret_val'.
return ret_val ;
}
else
// We have more words in the command name, but we don't have a multiword object. Fail and return
// empty 'ret_val'.
return ret_val ;
}
// We successfully looped through all the command words and got valid command objects for them. Assign the
// last object retrieved to 'ret_val'.
ret_val = cmd_obj_sp ;
}
}
return ret_val ;
2010-07-07 06:46:59 +08:00
}
2010-06-09 00:52:24 +08:00
CommandObject *
2010-07-07 06:46:59 +08:00
CommandInterpreter : : GetCommandObjectExact ( const char * cmd_cstr , bool include_aliases )
2010-06-09 00:52:24 +08:00
{
2010-07-07 06:46:59 +08:00
return GetCommandSPExact ( cmd_cstr , include_aliases ) . get ( ) ;
}
CommandObject *
CommandInterpreter : : GetCommandObject ( const char * cmd_cstr , StringList * matches )
{
CommandObject * command_obj = GetCommandSP ( cmd_cstr , false , true , matches ) . get ( ) ;
// If we didn't find an exact match to the command string in the commands, look in
// the aliases.
2013-06-19 02:01:08 +08:00
if ( command_obj )
return command_obj ;
2010-07-07 06:46:59 +08:00
2013-06-19 02:01:08 +08:00
command_obj = GetCommandSP ( cmd_cstr , true , true , matches ) . get ( ) ;
2010-07-07 06:46:59 +08:00
2013-06-19 02:01:08 +08:00
if ( command_obj )
return command_obj ;
// If there wasn't an exact match then look for an inexact one in just the commands
2014-04-20 08:31:37 +08:00
command_obj = GetCommandSP ( cmd_cstr , false , false , nullptr ) . get ( ) ;
2013-04-24 00:17:32 +08:00
// Finally, if there wasn't an inexact match among the commands, look for an inexact
// match in both the commands and aliases.
2013-06-19 02:01:08 +08:00
if ( command_obj )
{
if ( matches )
matches - > AppendString ( command_obj - > GetCommandName ( ) ) ;
return command_obj ;
}
return GetCommandSP ( cmd_cstr , true , false , matches ) . get ( ) ;
2010-06-09 00:52:24 +08:00
}
bool
CommandInterpreter : : CommandExists ( const char * cmd )
{
return m_command_dict . find ( cmd ) ! = m_command_dict . end ( ) ;
}
2011-05-07 05:37:15 +08:00
bool
CommandInterpreter : : ProcessAliasOptionsArgs ( lldb : : CommandObjectSP & cmd_obj_sp ,
const char * options_args ,
OptionArgVectorSP & option_arg_vector_sp )
{
bool success = true ;
OptionArgVector * option_arg_vector = option_arg_vector_sp . get ( ) ;
if ( ! options_args | | ( strlen ( options_args ) < 1 ) )
return true ;
std : : string options_string ( options_args ) ;
Args args ( options_args ) ;
CommandReturnObject result ;
// Check to see if the command being aliased can take any command options.
Options * options = cmd_obj_sp - > GetOptions ( ) ;
if ( options )
{
// See if any options were specified as part of the alias; if so, handle them appropriately.
options - > NotifyOptionParsingStarting ( ) ;
args . Unshift ( " dummy_arg " ) ;
args . ParseAliasOptions ( * options , result , option_arg_vector , options_string ) ;
args . Shift ( ) ;
if ( result . Succeeded ( ) )
options - > VerifyPartialOptions ( result ) ;
if ( ! result . Succeeded ( ) & & result . GetStatus ( ) ! = lldb : : eReturnStatusStarted )
{
result . AppendError ( " Unable to create requested alias. \n " ) ;
return false ;
}
}
2011-10-29 05:38:01 +08:00
if ( ! options_string . empty ( ) )
2011-05-07 05:37:15 +08:00
{
if ( cmd_obj_sp - > WantsRawCommandString ( ) )
option_arg_vector - > push_back ( OptionArgPair ( " <argument> " ,
OptionArgValue ( - 1 ,
options_string ) ) ) ;
else
{
2013-01-26 02:06:21 +08:00
const size_t argc = args . GetArgumentCount ( ) ;
2011-05-07 05:37:15 +08:00
for ( size_t i = 0 ; i < argc ; + + i )
if ( strcmp ( args . GetArgumentAtIndex ( i ) , " " ) ! = 0 )
option_arg_vector - > push_back
( OptionArgPair ( " <argument> " ,
OptionArgValue ( - 1 ,
std : : string ( args . GetArgumentAtIndex ( i ) ) ) ) ) ;
}
}
return success ;
}
2013-04-03 08:25:49 +08:00
bool
CommandInterpreter : : GetAliasFullName ( const char * cmd , std : : string & full_name )
{
bool exact_match = ( m_alias_dict . find ( cmd ) ! = m_alias_dict . end ( ) ) ;
if ( exact_match )
{
full_name . assign ( cmd ) ;
return exact_match ;
}
else
{
StringList matches ;
size_t num_alias_matches ;
num_alias_matches = CommandObject : : AddNamesMatchingPartialString ( m_alias_dict , cmd , matches ) ;
if ( num_alias_matches = = 1 )
{
// Make sure this isn't shadowing a command in the regular command space:
StringList regular_matches ;
const bool include_aliases = false ;
const bool exact = false ;
CommandObjectSP cmd_obj_sp ( GetCommandSP ( cmd , include_aliases , exact , & regular_matches ) ) ;
if ( cmd_obj_sp | | regular_matches . GetSize ( ) > 0 )
return false ;
else
{
full_name . assign ( matches . GetStringAtIndex ( 0 ) ) ;
return true ;
}
}
else
return false ;
}
}
2010-06-09 00:52:24 +08:00
bool
CommandInterpreter : : AliasExists ( const char * cmd )
{
return m_alias_dict . find ( cmd ) ! = m_alias_dict . end ( ) ;
}
bool
CommandInterpreter : : UserCommandExists ( const char * cmd )
{
return m_user_dict . find ( cmd ) ! = m_user_dict . end ( ) ;
}
void
CommandInterpreter : : AddAlias ( const char * alias_name , CommandObjectSP & command_obj_sp )
{
2016-02-06 09:36:07 +08:00
if ( command_obj_sp . get ( ) )
assert ( ( this = = & command_obj_sp - > GetCommandInterpreter ( ) ) & & " tried to add a CommandObject from a different interpreter " ) ;
2010-07-07 06:46:59 +08:00
command_obj_sp - > SetIsAlias ( true ) ;
2010-06-09 00:52:24 +08:00
m_alias_dict [ alias_name ] = command_obj_sp ;
}
bool
CommandInterpreter : : RemoveAlias ( const char * alias_name )
{
CommandObject : : CommandMap : : iterator pos = m_alias_dict . find ( alias_name ) ;
if ( pos ! = m_alias_dict . end ( ) )
{
m_alias_dict . erase ( pos ) ;
return true ;
}
return false ;
}
2015-01-10 03:08:20 +08:00
bool
CommandInterpreter : : RemoveCommand ( const char * cmd )
{
auto pos = m_command_dict . find ( cmd ) ;
if ( pos ! = m_command_dict . end ( ) )
{
if ( pos - > second - > IsRemovable ( ) )
{
// Only regular expression objects or python commands are removable
m_command_dict . erase ( pos ) ;
return true ;
}
}
return false ;
}
2010-06-09 00:52:24 +08:00
bool
CommandInterpreter : : RemoveUser ( const char * alias_name )
{
CommandObject : : CommandMap : : iterator pos = m_user_dict . find ( alias_name ) ;
if ( pos ! = m_user_dict . end ( ) )
{
m_user_dict . erase ( pos ) ;
return true ;
}
return false ;
}
void
CommandInterpreter : : GetAliasHelp ( const char * alias_name , const char * command_name , StreamString & help_string )
{
help_string . Printf ( " '%s " , command_name ) ;
OptionArgVectorSP option_arg_vector_sp = GetAliasOptions ( alias_name ) ;
2012-08-09 08:50:26 +08:00
if ( option_arg_vector_sp )
2010-06-09 00:52:24 +08:00
{
OptionArgVector * options = option_arg_vector_sp . get ( ) ;
2013-06-20 03:04:53 +08:00
for ( size_t i = 0 ; i < options - > size ( ) ; + + i )
2010-06-09 00:52:24 +08:00
{
OptionArgPair cur_option = ( * options ) [ i ] ;
std : : string opt = cur_option . first ;
2010-12-08 03:58:26 +08:00
OptionArgValue value_pair = cur_option . second ;
std : : string value = value_pair . second ;
2010-06-09 00:52:24 +08:00
if ( opt . compare ( " <argument> " ) = = 0 )
{
help_string . Printf ( " %s " , value . c_str ( ) ) ;
}
else
{
help_string . Printf ( " %s " , opt . c_str ( ) ) ;
if ( ( value . compare ( " <no-argument> " ) ! = 0 )
& & ( value . compare ( " <need-argument " ) ! = 0 ) )
{
help_string . Printf ( " %s " , value . c_str ( ) ) ;
}
}
}
}
help_string . Printf ( " ' " ) ;
}
2010-08-27 06:05:43 +08:00
size_t
2010-06-09 00:52:24 +08:00
CommandInterpreter : : FindLongestCommandWord ( CommandObject : : CommandMap & dict )
{
CommandObject : : CommandMap : : const_iterator pos ;
2010-08-27 06:05:43 +08:00
CommandObject : : CommandMap : : const_iterator end = dict . end ( ) ;
size_t max_len = 0 ;
2010-06-09 00:52:24 +08:00
2010-08-27 06:05:43 +08:00
for ( pos = dict . begin ( ) ; pos ! = end ; + + pos )
{
size_t len = pos - > first . size ( ) ;
if ( max_len < len )
max_len = len ;
}
return max_len ;
2010-06-09 00:52:24 +08:00
}
void
2011-08-17 07:24:13 +08:00
CommandInterpreter : : GetHelp ( CommandReturnObject & result ,
2011-09-10 01:49:36 +08:00
uint32_t cmd_types )
2010-06-09 00:52:24 +08:00
{
2015-01-15 08:52:41 +08:00
const char * help_prologue = GetDebugger ( ) . GetIOHandlerHelpPrologue ( ) ;
if ( help_prologue ! = NULL )
{
OutputFormattedHelpText ( result . GetOutputStream ( ) , NULL , help_prologue ) ;
}
2010-06-09 00:52:24 +08:00
CommandObject : : CommandMap : : const_iterator pos ;
2013-01-26 02:06:21 +08:00
size_t max_len = FindLongestCommandWord ( m_command_dict ) ;
2011-08-17 07:24:13 +08:00
if ( ( cmd_types & eCommandTypesBuiltin ) = = eCommandTypesBuiltin )
2010-06-09 00:52:24 +08:00
{
2015-01-15 08:52:41 +08:00
result . AppendMessage ( " Debugger commands: " ) ;
2011-08-17 07:24:13 +08:00
result . AppendMessage ( " " ) ;
for ( pos = m_command_dict . begin ( ) ; pos ! = m_command_dict . end ( ) ; + + pos )
{
2015-01-15 08:52:41 +08:00
if ( ! ( cmd_types & eCommandTypesHidden ) & & ( pos - > first . compare ( 0 , 1 , " _ " ) = = 0 ) )
continue ;
2011-08-17 07:24:13 +08:00
OutputFormattedHelpText ( result . GetOutputStream ( ) , pos - > first . c_str ( ) , " -- " , pos - > second - > GetHelp ( ) ,
max_len ) ;
}
result . AppendMessage ( " " ) ;
2010-06-09 00:52:24 +08:00
}
2011-10-29 05:38:01 +08:00
if ( ! m_alias_dict . empty ( ) & & ( ( cmd_types & eCommandTypesAliases ) = = eCommandTypesAliases ) )
2010-06-09 00:52:24 +08:00
{
2015-01-15 08:52:41 +08:00
result . AppendMessageWithFormat ( " Current command abbreviations "
" (type '%shelp command alias' for more info): \n " ,
GetCommandPrefix ( ) ) ;
2010-06-09 00:52:24 +08:00
result . AppendMessage ( " " ) ;
2010-08-27 06:05:43 +08:00
max_len = FindLongestCommandWord ( m_alias_dict ) ;
2010-06-09 00:52:24 +08:00
for ( pos = m_alias_dict . begin ( ) ; pos ! = m_alias_dict . end ( ) ; + + pos )
{
StreamString sstr ;
StreamString translation_and_help ;
std : : string entry_name = pos - > first ;
std : : string second_entry = pos - > second . get ( ) - > GetCommandName ( ) ;
GetAliasHelp ( pos - > first . c_str ( ) , pos - > second - > GetCommandName ( ) , sstr ) ;
translation_and_help . Printf ( " (%s) %s " , sstr . GetData ( ) , pos - > second - > GetHelp ( ) ) ;
OutputFormattedHelpText ( result . GetOutputStream ( ) , pos - > first . c_str ( ) , " -- " ,
translation_and_help . GetData ( ) , max_len ) ;
}
result . AppendMessage ( " " ) ;
}
2011-10-29 05:38:01 +08:00
if ( ! m_user_dict . empty ( ) & & ( ( cmd_types & eCommandTypesUserDef ) = = eCommandTypesUserDef ) )
2010-06-09 00:52:24 +08:00
{
2015-01-15 08:52:41 +08:00
result . AppendMessage ( " Current user-defined commands: " ) ;
2010-06-09 00:52:24 +08:00
result . AppendMessage ( " " ) ;
2011-08-17 07:24:13 +08:00
max_len = FindLongestCommandWord ( m_user_dict ) ;
2010-06-09 00:52:24 +08:00
for ( pos = m_user_dict . begin ( ) ; pos ! = m_user_dict . end ( ) ; + + pos )
{
2011-08-17 07:24:13 +08:00
OutputFormattedHelpText ( result . GetOutputStream ( ) , pos - > first . c_str ( ) , " -- " , pos - > second - > GetHelp ( ) ,
max_len ) ;
2010-06-09 00:52:24 +08:00
}
result . AppendMessage ( " " ) ;
}
2015-01-15 08:52:41 +08:00
result . AppendMessageWithFormat ( " For more information on any command, type '%shelp <command-name>'. \n " ,
GetCommandPrefix ( ) ) ;
2010-06-09 00:52:24 +08:00
}
2010-12-10 06:52:49 +08:00
CommandObject *
CommandInterpreter : : GetCommandObjectForCommand ( std : : string & command_string )
{
// This function finds the final, lowest-level, alias-resolved command object whose 'Execute' function will
// eventually be invoked by the given command line.
2014-04-20 08:31:37 +08:00
CommandObject * cmd_obj = nullptr ;
2015-04-24 04:00:25 +08:00
size_t start = command_string . find_first_not_of ( k_white_space ) ;
2010-12-10 06:52:49 +08:00
size_t end = 0 ;
bool done = false ;
while ( ! done )
{
if ( start ! = std : : string : : npos )
{
// Get the next word from command_string.
2015-04-24 04:00:25 +08:00
end = command_string . find_first_of ( k_white_space , start ) ;
2010-12-10 06:52:49 +08:00
if ( end = = std : : string : : npos )
end = command_string . size ( ) ;
std : : string cmd_word = command_string . substr ( start , end - start ) ;
2014-04-20 08:31:37 +08:00
if ( cmd_obj = = nullptr )
2010-12-10 06:52:49 +08:00
// Since cmd_obj is NULL we are on our first time through this loop. Check to see if cmd_word is a valid
// command or alias.
cmd_obj = GetCommandObject ( cmd_word . c_str ( ) ) ;
else if ( cmd_obj - > IsMultiwordObject ( ) )
{
// Our current object is a multi-word object; see if the cmd_word is a valid sub-command for our object.
2012-10-13 10:07:45 +08:00
CommandObject * sub_cmd_obj = cmd_obj - > GetSubcommandObject ( cmd_word . c_str ( ) ) ;
2010-12-10 06:52:49 +08:00
if ( sub_cmd_obj )
cmd_obj = sub_cmd_obj ;
2015-06-18 13:27:05 +08:00
else // cmd_word was not a valid sub-command word, so we are done
2010-12-10 06:52:49 +08:00
done = true ;
}
else
// We have a cmd_obj and it is not a multi-word object, so we are done.
done = true ;
// If we didn't find a valid command object, or our command object is not a multi-word object, or
// we are at the end of the command_string, then we are done. Otherwise, find the start of the
// next word.
if ( ! cmd_obj | | ! cmd_obj - > IsMultiwordObject ( ) | | end > = command_string . size ( ) )
done = true ;
else
2015-04-24 04:00:25 +08:00
start = command_string . find_first_not_of ( k_white_space , end ) ;
2010-12-10 06:52:49 +08:00
}
else
// Unable to find any more words.
done = true ;
}
if ( end = = command_string . size ( ) )
command_string . clear ( ) ;
else
command_string = command_string . substr ( end ) ;
return cmd_obj ;
}
2011-10-29 05:38:01 +08:00
static const char * k_valid_command_chars = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ " ;
2011-10-25 08:36:27 +08:00
static void
StripLeadingSpaces ( std : : string & s )
2010-06-09 00:52:24 +08:00
{
2011-10-25 08:36:27 +08:00
if ( ! s . empty ( ) )
{
size_t pos = s . find_first_not_of ( k_white_space ) ;
if ( pos = = std : : string : : npos )
s . clear ( ) ;
else if ( pos = = 0 )
return ;
s . erase ( 0 , pos ) ;
}
}
2011-11-10 07:25:03 +08:00
static size_t
FindArgumentTerminator ( const std : : string & s )
{
const size_t s_len = s . size ( ) ;
size_t offset = 0 ;
while ( offset < s_len )
{
size_t pos = s . find ( " -- " , offset ) ;
if ( pos = = std : : string : : npos )
break ;
if ( pos > 0 )
{
if ( isspace ( s [ pos - 1 ] ) )
{
// Check if the string ends "\s--" (where \s is a space character)
// or if we have "\s--\s".
if ( ( pos + 2 > = s_len ) | | isspace ( s [ pos + 2 ] ) )
{
return pos ;
}
}
}
offset = pos + 2 ;
}
return std : : string : : npos ;
}
2011-10-25 08:36:27 +08:00
static bool
2011-10-29 05:38:01 +08:00
ExtractCommand ( std : : string & command_string , std : : string & command , std : : string & suffix , char & quote_char )
2011-10-25 08:36:27 +08:00
{
2011-10-29 05:38:01 +08:00
command . clear ( ) ;
suffix . clear ( ) ;
2011-10-25 08:36:27 +08:00
StripLeadingSpaces ( command_string ) ;
bool result = false ;
quote_char = ' \0 ' ;
2010-12-10 06:52:49 +08:00
2011-10-25 08:36:27 +08:00
if ( ! command_string . empty ( ) )
2010-12-10 06:52:49 +08:00
{
2011-10-25 08:36:27 +08:00
const char first_char = command_string [ 0 ] ;
if ( first_char = = ' \' ' | | first_char = = ' " ' )
2010-12-10 06:52:49 +08:00
{
2011-10-25 08:36:27 +08:00
quote_char = first_char ;
const size_t end_quote_pos = command_string . find ( quote_char , 1 ) ;
if ( end_quote_pos = = std : : string : : npos )
2011-05-12 00:07:06 +08:00
{
2011-10-29 05:38:01 +08:00
command . swap ( command_string ) ;
2011-10-25 08:36:27 +08:00
command_string . erase ( ) ;
2011-05-12 00:07:06 +08:00
}
else
{
2011-10-29 05:38:01 +08:00
command . assign ( command_string , 1 , end_quote_pos - 1 ) ;
2011-10-25 08:36:27 +08:00
if ( end_quote_pos + 1 < command_string . size ( ) )
command_string . erase ( 0 , command_string . find_first_not_of ( k_white_space , end_quote_pos + 1 ) ) ;
else
command_string . erase ( ) ;
2011-05-12 00:07:06 +08:00
}
2010-12-10 06:52:49 +08:00
}
else
{
2011-10-25 08:36:27 +08:00
const size_t first_space_pos = command_string . find_first_of ( k_white_space ) ;
if ( first_space_pos = = std : : string : : npos )
2011-05-12 00:07:06 +08:00
{
2011-10-29 05:38:01 +08:00
command . swap ( command_string ) ;
2011-10-25 08:36:27 +08:00
command_string . erase ( ) ;
2011-05-12 00:07:06 +08:00
}
else
{
2011-10-29 05:38:01 +08:00
command . assign ( command_string , 0 , first_space_pos ) ;
command_string . erase ( 0 , command_string . find_first_not_of ( k_white_space , first_space_pos ) ) ;
2011-05-12 00:07:06 +08:00
}
2010-12-10 06:52:49 +08:00
}
2011-10-25 08:36:27 +08:00
result = true ;
2010-12-10 06:52:49 +08:00
}
2011-10-29 05:38:01 +08:00
if ( ! command . empty ( ) )
{
// actual commands can't start with '-' or '_'
if ( command [ 0 ] ! = ' - ' & & command [ 0 ] ! = ' _ ' )
{
size_t pos = command . find_first_not_of ( k_valid_command_chars ) ;
if ( pos > 0 & & pos ! = std : : string : : npos )
{
suffix . assign ( command . begin ( ) + pos , command . end ( ) ) ;
command . erase ( pos ) ;
}
}
}
2011-10-25 08:36:27 +08:00
return result ;
2010-12-10 06:52:49 +08:00
}
2011-10-29 05:38:01 +08:00
CommandObject *
CommandInterpreter : : BuildAliasResult ( const char * alias_name ,
std : : string & raw_input_string ,
std : : string & alias_result ,
CommandReturnObject & result )
2010-12-10 06:52:49 +08:00
{
2014-04-20 08:31:37 +08:00
CommandObject * alias_cmd_obj = nullptr ;
2015-03-02 20:46:22 +08:00
Args cmd_args ( raw_input_string ) ;
2010-12-10 06:52:49 +08:00
alias_cmd_obj = GetCommandObject ( alias_name ) ;
StreamString result_str ;
if ( alias_cmd_obj )
{
std : : string alias_name_str = alias_name ;
if ( ( cmd_args . GetArgumentCount ( ) = = 0 )
| | ( alias_name_str . compare ( cmd_args . GetArgumentAtIndex ( 0 ) ) ! = 0 ) )
cmd_args . Unshift ( alias_name ) ;
result_str . Printf ( " %s " , alias_cmd_obj - > GetCommandName ( ) ) ;
OptionArgVectorSP option_arg_vector_sp = GetAliasOptions ( alias_name ) ;
2010-06-09 00:52:24 +08:00
2010-12-10 06:52:49 +08:00
if ( option_arg_vector_sp . get ( ) )
{
OptionArgVector * option_arg_vector = option_arg_vector_sp . get ( ) ;
2013-06-20 03:04:53 +08:00
for ( size_t i = 0 ; i < option_arg_vector - > size ( ) ; + + i )
2010-12-10 06:52:49 +08:00
{
OptionArgPair option_pair = ( * option_arg_vector ) [ i ] ;
OptionArgValue value_pair = option_pair . second ;
int value_type = value_pair . first ;
std : : string option = option_pair . first ;
std : : string value = value_pair . second ;
if ( option . compare ( " <argument> " ) = = 0 )
result_str . Printf ( " %s " , value . c_str ( ) ) ;
else
{
result_str . Printf ( " %s " , option . c_str ( ) ) ;
2015-04-07 05:55:14 +08:00
if ( value_type ! = OptionParser : : eNoArgument )
2010-12-10 06:52:49 +08:00
{
2015-04-07 05:55:14 +08:00
if ( value_type ! = OptionParser : : eOptionalArgument )
result_str . Printf ( " " ) ;
2010-12-10 06:52:49 +08:00
int index = GetOptionArgumentPosition ( value . c_str ( ) ) ;
if ( index = = 0 )
result_str . Printf ( " %s " , value . c_str ( ) ) ;
2014-04-02 11:51:35 +08:00
else if ( static_cast < size_t > ( index ) > = cmd_args . GetArgumentCount ( ) )
2010-12-10 06:52:49 +08:00
{
result . AppendErrorWithFormat
( " Not enough arguments provided; you need at least %d arguments to use this alias. \n " ,
index ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2015-04-24 04:00:25 +08:00
return nullptr ;
2010-12-10 06:52:49 +08:00
}
else
{
size_t strpos = raw_input_string . find ( cmd_args . GetArgumentAtIndex ( index ) ) ;
if ( strpos ! = std : : string : : npos )
raw_input_string = raw_input_string . erase ( strpos ,
strlen ( cmd_args . GetArgumentAtIndex ( index ) ) ) ;
result_str . Printf ( " %s " , cmd_args . GetArgumentAtIndex ( index ) ) ;
}
}
}
}
}
alias_result = result_str . GetData ( ) ;
}
2011-10-29 05:38:01 +08:00
return alias_cmd_obj ;
2010-12-10 06:52:49 +08:00
}
2011-10-14 15:41:33 +08:00
Error
CommandInterpreter : : PreprocessCommand ( std : : string & command )
{
// The command preprocessor needs to do things to the command
// line before any parsing of arguments or anything else is done.
2015-04-24 04:00:25 +08:00
// The only current stuff that gets preprocessed is anything enclosed
2011-10-14 15:41:33 +08:00
// in backtick ('`') characters is evaluated as an expression and
// the result of the expression must be a scalar that can be substituted
// into the command. An example would be:
// (lldb) memory read `$rsp + 20`
Error error ; // Error for any expressions that might not evaluate
size_t start_backtick ;
size_t pos = 0 ;
while ( ( start_backtick = command . find ( ' ` ' , pos ) ) ! = std : : string : : npos )
{
if ( start_backtick > 0 & & command [ start_backtick - 1 ] = = ' \\ ' )
{
2015-06-18 13:27:05 +08:00
// The backtick was preceded by a '\' character, remove the slash
2011-10-14 15:41:33 +08:00
// and don't treat the backtick as the start of an expression
command . erase ( start_backtick - 1 , 1 ) ;
// No need to add one to start_backtick since we just deleted a char
pos = start_backtick ;
}
else
{
const size_t expr_content_start = start_backtick + 1 ;
const size_t end_backtick = command . find ( ' ` ' , expr_content_start ) ;
if ( end_backtick = = std : : string : : npos )
return error ;
else if ( end_backtick = = expr_content_start )
{
// Empty expression (two backticks in a row)
command . erase ( start_backtick , 2 ) ;
}
else
{
std : : string expr_str ( command , expr_content_start , end_backtick - expr_content_start ) ;
2012-07-13 04:32:19 +08:00
ExecutionContext exe_ctx ( GetExecutionContext ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
Get a dummy target to allow for calculator mode while processing backticks.
This also helps break the infinite loop caused when target is null.
So that we can have:
$ /Volumes/data/lldb/svn/trunk/build/Debug/lldb
(lldb) itob `0x123 - 0x321` 32 v
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]
(lldb)
llvm-svn: 143260
2011-10-29 08:21:50 +08:00
// Get a dummy target to allow for calculator mode while processing backticks.
// This also helps break the infinite loop caused when target is null.
if ( ! target )
2014-11-22 09:42:44 +08:00
target = m_debugger . GetDummyTarget ( ) ;
2011-10-14 15:41:33 +08:00
if ( target )
{
ValueObjectSP expr_result_valobj_sp ;
2012-09-06 04:41:26 +08:00
2012-10-17 05:41:58 +08:00
EvaluateExpressionOptions options ;
2013-11-07 08:11:47 +08:00
options . SetCoerceToId ( false ) ;
options . SetUnwindOnError ( true ) ;
options . SetIgnoreBreakpoints ( true ) ;
options . SetKeepInMemory ( false ) ;
options . SetTryAllThreads ( true ) ;
options . SetTimeoutUsec ( 0 ) ;
2012-09-06 04:41:26 +08:00
2014-05-05 10:26:40 +08:00
ExpressionResults expr_result = target - > EvaluateExpression ( expr_str . c_str ( ) ,
2014-10-10 07:09:40 +08:00
exe_ctx . GetFramePtr ( ) ,
expr_result_valobj_sp ,
options ) ;
2012-09-06 04:41:26 +08:00
2014-05-05 10:47:44 +08:00
if ( expr_result = = eExpressionCompleted )
2011-10-14 15:41:33 +08:00
{
Scalar scalar ;
2014-10-10 07:09:40 +08:00
if ( expr_result_valobj_sp )
expr_result_valobj_sp = expr_result_valobj_sp - > GetQualifiedRepresentationIfAvailable ( expr_result_valobj_sp - > GetDynamicValueType ( ) , true ) ;
2011-10-14 15:41:33 +08:00
if ( expr_result_valobj_sp - > ResolveValue ( scalar ) )
{
command . erase ( start_backtick , end_backtick - start_backtick + 1 ) ;
StreamString value_strm ;
const bool show_type = false ;
scalar . GetValue ( & value_strm , show_type ) ;
size_t value_string_size = value_strm . GetSize ( ) ;
if ( value_string_size )
{
command . insert ( start_backtick , value_strm . GetData ( ) , value_string_size ) ;
pos = start_backtick + value_string_size ;
continue ;
}
else
{
error . SetErrorStringWithFormat ( " expression value didn't result in a scalar value for the expression '%s' " , expr_str . c_str ( ) ) ;
}
}
else
{
error . SetErrorStringWithFormat ( " expression value didn't result in a scalar value for the expression '%s' " , expr_str . c_str ( ) ) ;
}
}
else
{
if ( expr_result_valobj_sp )
error = expr_result_valobj_sp - > GetError ( ) ;
if ( error . Success ( ) )
{
switch ( expr_result )
{
2014-05-05 10:47:44 +08:00
case eExpressionSetupError :
2011-10-14 15:41:33 +08:00
error . SetErrorStringWithFormat ( " expression setup error for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2014-05-05 10:47:44 +08:00
case eExpressionParseError :
2014-05-05 10:26:40 +08:00
error . SetErrorStringWithFormat ( " expression parse error for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2014-05-05 10:47:44 +08:00
case eExpressionResultUnavailable :
2014-05-05 10:26:40 +08:00
error . SetErrorStringWithFormat ( " expression error fetching result for the expression '%s' " , expr_str . c_str ( ) ) ;
2016-02-26 09:20:20 +08:00
break ;
2014-05-05 10:47:44 +08:00
case eExpressionCompleted :
2011-10-14 15:41:33 +08:00
break ;
2014-05-05 10:47:44 +08:00
case eExpressionDiscarded :
2011-10-14 15:41:33 +08:00
error . SetErrorStringWithFormat ( " expression discarded for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2014-05-05 10:47:44 +08:00
case eExpressionInterrupted :
2011-10-14 15:41:33 +08:00
error . SetErrorStringWithFormat ( " expression interrupted for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2014-05-05 10:47:44 +08:00
case eExpressionHitBreakpoint :
2013-01-15 10:47:48 +08:00
error . SetErrorStringWithFormat ( " expression hit breakpoint for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2014-05-05 10:47:44 +08:00
case eExpressionTimedOut :
2011-10-14 15:41:33 +08:00
error . SetErrorStringWithFormat ( " expression timed out for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2014-05-05 10:47:44 +08:00
case eExpressionStoppedForDebug :
2013-11-09 07:38:26 +08:00
error . SetErrorStringWithFormat ( " expression stop at entry point for debugging for the expression '%s' " , expr_str . c_str ( ) ) ;
break ;
2011-10-14 15:41:33 +08:00
}
}
}
}
}
if ( error . Fail ( ) )
break ;
}
}
return error ;
}
2010-12-10 06:52:49 +08:00
bool
CommandInterpreter : : HandleCommand ( const char * command_line ,
2012-05-31 09:09:06 +08:00
LazyBool lazy_add_to_history ,
2010-12-10 06:52:49 +08:00
CommandReturnObject & result ,
2011-02-18 08:54:25 +08:00
ExecutionContext * override_context ,
2011-10-05 08:42:59 +08:00
bool repeat_on_empty_command ,
bool no_context_switching )
2011-02-18 08:54:25 +08:00
2010-12-10 06:52:49 +08:00
{
2011-02-18 08:54:25 +08:00
2010-12-10 06:52:49 +08:00
std : : string command_string ( command_line ) ;
2011-07-12 11:12:18 +08:00
std : : string original_command_string ( command_line ) ;
2010-12-10 06:52:49 +08:00
2013-03-28 07:08:40 +08:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_COMMANDS ) ) ;
2010-11-10 12:57:04 +08:00
Host : : SetCrashDescriptionWithFormat ( " HandleCommand(command = \" %s \" ) " , command_line ) ;
// Make a scoped cleanup object that will clear the crash description string
// on exit of this function.
2014-04-20 08:31:37 +08:00
lldb_utility : : CleanUp < const char * > crash_description_cleanup ( nullptr , Host : : SetCrashDescription ) ;
2010-11-10 12:57:04 +08:00
2010-12-10 06:52:49 +08:00
if ( log )
log - > Printf ( " Processing command: %s " , command_line ) ;
2010-06-09 00:52:24 +08:00
2010-11-05 07:08:45 +08:00
Timer scoped_timer ( __PRETTY_FUNCTION__ , " Handling command: %s. " , command_line ) ;
2011-10-05 08:42:59 +08:00
if ( ! no_context_switching )
UpdateExecutionContext ( override_context ) ;
2012-05-31 09:09:06 +08:00
bool add_to_history ;
if ( lazy_add_to_history = = eLazyBoolCalculate )
add_to_history = ( m_command_source_depth = = 0 ) ;
else
add_to_history = ( lazy_add_to_history = = eLazyBoolYes ) ;
2011-02-18 08:54:25 +08:00
bool empty_command = false ;
bool comment_command = false ;
if ( command_string . empty ( ) )
empty_command = true ;
else
2010-06-09 00:52:24 +08:00
{
2011-02-18 08:54:25 +08:00
const char * k_space_characters = " \t \n \v \f \r " ;
size_t non_space = command_string . find_first_not_of ( k_space_characters ) ;
// Check for empty line or comment line (lines whose first
// non-space character is the comment character for this interpreter)
if ( non_space = = std : : string : : npos )
empty_command = true ;
else if ( command_string [ non_space ] = = m_comment_char )
comment_command = true ;
2013-06-18 06:51:50 +08:00
else if ( command_string [ non_space ] = = CommandHistory : : g_repeat_char )
2011-07-12 11:12:18 +08:00
{
2013-06-18 06:51:50 +08:00
const char * history_string = m_command_history . FindString ( command_string . c_str ( ) + non_space ) ;
2014-04-20 08:31:37 +08:00
if ( history_string = = nullptr )
2011-07-12 11:12:18 +08:00
{
result . AppendErrorWithFormat ( " Could not find entry: %s in history " , command_string . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
add_to_history = false ;
command_string = history_string ;
original_command_string = history_string ;
}
2011-02-18 08:54:25 +08:00
}
if ( empty_command )
{
if ( repeat_on_empty_command )
2010-06-09 00:52:24 +08:00
{
2013-06-18 06:51:50 +08:00
if ( m_command_history . IsEmpty ( ) )
2010-07-07 07:48:33 +08:00
{
2011-02-18 08:54:25 +08:00
result . AppendError ( " empty command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-07-07 07:48:33 +08:00
return false ;
}
2011-02-18 08:54:25 +08:00
else
{
command_line = m_repeat_command . c_str ( ) ;
command_string = command_line ;
2011-07-12 11:12:18 +08:00
original_command_string = command_line ;
2011-02-18 08:54:25 +08:00
if ( m_repeat_command . empty ( ) )
{
result . AppendErrorWithFormat ( " No auto repeat. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
add_to_history = false ;
}
else
{
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
return true ;
2010-06-09 00:52:24 +08:00
}
2011-02-18 08:54:25 +08:00
}
else if ( comment_command )
{
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
return true ;
2010-06-09 00:52:24 +08:00
}
2011-05-12 00:07:06 +08:00
2011-10-14 15:41:33 +08:00
Error error ( PreprocessCommand ( command_string ) ) ;
if ( error . Fail ( ) )
{
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-12-10 06:52:49 +08:00
2015-04-24 04:00:25 +08:00
// Phase 1.
2011-11-10 07:25:03 +08:00
2015-04-24 04:00:25 +08:00
// Before we do ANY kind of argument processing, we need to figure out what
// the real/final command object is for the specified command. This gets
// complicated by the fact that the user could have specified an alias, and,
// in translating the alias, there may also be command options and/or even
// data (including raw text strings) that need to be found and inserted into
// the command line as part of the translation. So this first step is plain
// look-up and replacement, resulting in:
// 1. the command object whose Execute method will actually be called
// 2. a revised command string, with all substitutions and replacements
// taken care of
// From 1 above, we can determine whether the Execute function wants raw
// input or not.
CommandObject * cmd_obj = ResolveCommandImpl ( command_string , result ) ;
// Although the user may have abbreviated the command, the command_string now
// has the command expanded to the full name. For example, if the input
// was "br s -n main", command_string is now "breakpoint set -n main".
2010-06-09 00:52:24 +08:00
2010-12-10 06:52:49 +08:00
if ( log )
{
2015-04-24 04:00:25 +08:00
log - > Printf ( " HandleCommand, cmd_obj : '%s' " , cmd_obj ? cmd_obj - > GetCommandName ( ) : " <not found> " ) ;
log - > Printf ( " HandleCommand, (revised) command_string: '%s' " , command_string . c_str ( ) ) ;
const bool wants_raw_input = ( cmd_obj ! = NULL ) ? cmd_obj - > WantsRawCommandString ( ) : false ;
log - > Printf ( " HandleCommand, wants_raw_input:'%s' " , wants_raw_input ? " True " : " False " ) ;
2010-12-10 06:52:49 +08:00
}
2010-06-09 00:52:24 +08:00
2010-12-10 06:52:49 +08:00
// Phase 2.
// Take care of things like setting up the history command & calling the appropriate Execute method on the
// CommandObject, with the appropriate arguments.
2014-04-20 08:31:37 +08:00
if ( cmd_obj ! = nullptr )
2010-12-10 06:52:49 +08:00
{
if ( add_to_history )
{
2015-04-24 04:00:25 +08:00
Args command_args ( command_string ) ;
2010-12-10 06:52:49 +08:00
const char * repeat_command = cmd_obj - > GetRepeatCommand ( command_args , 0 ) ;
2014-04-20 08:31:37 +08:00
if ( repeat_command ! = nullptr )
2010-12-10 06:52:49 +08:00
m_repeat_command . assign ( repeat_command ) ;
else
2011-07-12 11:12:18 +08:00
m_repeat_command . assign ( original_command_string . c_str ( ) ) ;
2010-12-10 06:52:49 +08:00
2013-06-18 06:51:50 +08:00
m_command_history . AppendString ( original_command_string ) ;
2010-12-10 06:52:49 +08:00
}
2010-12-11 16:16:56 +08:00
std : : string remainder ;
2015-04-24 04:00:25 +08:00
const std : : size_t actual_cmd_name_len = strlen ( cmd_obj - > GetCommandName ( ) ) ;
2010-12-11 16:16:56 +08:00
if ( actual_cmd_name_len < command_string . length ( ) )
2015-04-24 04:00:25 +08:00
remainder = command_string . substr ( actual_cmd_name_len ) ;
2010-12-10 06:52:49 +08:00
// Remove any initial spaces
2015-04-24 04:00:25 +08:00
size_t pos = remainder . find_first_not_of ( k_white_space ) ;
2010-12-10 06:52:49 +08:00
if ( pos ! = 0 & & pos ! = std : : string : : npos )
2011-04-23 04:58:45 +08:00
remainder . erase ( 0 , pos ) ;
2010-12-10 06:52:49 +08:00
if ( log )
2011-08-25 08:20:04 +08:00
log - > Printf ( " HandleCommand, command line after removing command name(s): '%s' " , remainder . c_str ( ) ) ;
2010-12-10 06:52:49 +08:00
2012-06-09 05:56:10 +08:00
cmd_obj - > Execute ( remainder . c_str ( ) , result ) ;
2010-12-10 06:52:49 +08:00
}
else
{
// We didn't find the first command object, so complete the first argument.
2015-04-24 04:00:25 +08:00
Args command_args ( command_string ) ;
2010-12-10 06:52:49 +08:00
StringList matches ;
int num_matches ;
int cursor_index = 0 ;
int cursor_char_position = strlen ( command_args . GetArgumentAtIndex ( 0 ) ) ;
bool word_complete ;
num_matches = HandleCompletionMatches ( command_args ,
cursor_index ,
cursor_char_position ,
0 ,
- 1 ,
word_complete ,
matches ) ;
if ( num_matches > 0 )
{
std : : string error_msg ;
error_msg . assign ( " ambiguous command ' " ) ;
error_msg . append ( command_args . GetArgumentAtIndex ( 0 ) ) ;
error_msg . append ( " '. " ) ;
error_msg . append ( " Possible completions: " ) ;
for ( int i = 0 ; i < num_matches ; i + + )
{
error_msg . append ( " \n \t " ) ;
error_msg . append ( matches . GetStringAtIndex ( i ) ) ;
2010-06-09 00:52:24 +08:00
}
2010-12-10 06:52:49 +08:00
error_msg . append ( " \n " ) ;
2013-01-26 02:06:21 +08:00
result . AppendRawError ( error_msg . c_str ( ) ) ;
2010-06-09 00:52:24 +08:00
}
2010-12-10 06:52:49 +08:00
else
result . AppendErrorWithFormat ( " Unrecognized command '%s'. \n " , command_args . GetArgumentAtIndex ( 0 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-06-09 00:52:24 +08:00
}
2010-12-10 06:52:49 +08:00
2011-08-25 08:20:04 +08:00
if ( log )
log - > Printf ( " HandleCommand, command %s " , ( result . Succeeded ( ) ? " succeeded " : " did not succeed " ) ) ;
2010-06-09 00:52:24 +08:00
return result . Succeeded ( ) ;
}
int
CommandInterpreter : : HandleCompletionMatches ( Args & parsed_line ,
int & cursor_index ,
int & cursor_char_position ,
int match_start_point ,
int max_return_elements ,
2010-06-30 13:02:46 +08:00
bool & word_complete ,
2010-06-09 00:52:24 +08:00
StringList & matches )
{
int num_command_matches = 0 ;
bool look_for_subcommand = false ;
2010-06-30 13:02:46 +08:00
// For any of the command completions a unique match will be a complete word.
word_complete = true ;
2010-06-09 00:52:24 +08:00
if ( cursor_index = = - 1 )
{
// We got nothing on the command line, so return the list of commands
2010-07-07 06:46:59 +08:00
bool include_aliases = true ;
2010-06-09 00:52:24 +08:00
num_command_matches = GetCommandNamesMatchingPartialString ( " " , include_aliases , matches ) ;
}
else if ( cursor_index = = 0 )
{
// The cursor is in the first argument, so just do a lookup in the dictionary.
2010-07-07 06:46:59 +08:00
CommandObject * cmd_obj = GetCommandObject ( parsed_line . GetArgumentAtIndex ( 0 ) , & matches ) ;
2010-06-09 00:52:24 +08:00
num_command_matches = matches . GetSize ( ) ;
if ( num_command_matches = = 1
& & cmd_obj & & cmd_obj - > IsMultiwordObject ( )
2014-04-20 08:31:37 +08:00
& & matches . GetStringAtIndex ( 0 ) ! = nullptr
2010-06-09 00:52:24 +08:00
& & strcmp ( parsed_line . GetArgumentAtIndex ( 0 ) , matches . GetStringAtIndex ( 0 ) ) = = 0 )
{
2013-12-11 03:14:04 +08:00
if ( parsed_line . GetArgumentCount ( ) = = 1 )
{
word_complete = true ;
}
else
{
look_for_subcommand = true ;
num_command_matches = 0 ;
matches . DeleteStringAtIndex ( 0 ) ;
parsed_line . AppendArgument ( " " ) ;
cursor_index + + ;
cursor_char_position = 0 ;
}
2010-06-09 00:52:24 +08:00
}
}
if ( cursor_index > 0 | | look_for_subcommand )
{
// We are completing further on into a commands arguments, so find the command and tell it
// to complete the command.
// First see if there is a matching initial command:
2010-07-07 06:46:59 +08:00
CommandObject * command_object = GetCommandObject ( parsed_line . GetArgumentAtIndex ( 0 ) ) ;
2014-04-20 08:31:37 +08:00
if ( command_object = = nullptr )
2010-06-09 00:52:24 +08:00
{
return 0 ;
}
else
{
parsed_line . Shift ( ) ;
cursor_index - - ;
2010-09-18 09:14:36 +08:00
num_command_matches = command_object - > HandleCompletion ( parsed_line ,
2010-06-23 09:19:29 +08:00
cursor_index ,
cursor_char_position ,
match_start_point ,
2010-06-30 13:02:46 +08:00
max_return_elements ,
word_complete ,
2010-06-09 00:52:24 +08:00
matches ) ;
}
}
return num_command_matches ;
}
int
CommandInterpreter : : HandleCompletion ( const char * current_line ,
const char * cursor ,
const char * last_char ,
int match_start_point ,
int max_return_elements ,
StringList & matches )
{
// We parse the argument up to the cursor, so the last argument in parsed_line is
// the one containing the cursor, and the cursor is after the last character.
2015-03-02 20:46:22 +08:00
Args parsed_line ( llvm : : StringRef ( current_line , last_char - current_line ) ) ;
Args partial_parsed_line ( llvm : : StringRef ( current_line , cursor - current_line ) ) ;
2010-06-09 00:52:24 +08:00
2011-07-12 11:12:18 +08:00
// Don't complete comments, and if the line we are completing is just the history repeat character,
// substitute the appropriate history line.
const char * first_arg = parsed_line . GetArgumentAtIndex ( 0 ) ;
if ( first_arg )
{
if ( first_arg [ 0 ] = = m_comment_char )
return 0 ;
2013-06-18 06:51:50 +08:00
else if ( first_arg [ 0 ] = = CommandHistory : : g_repeat_char )
2011-07-12 11:12:18 +08:00
{
2013-06-18 06:51:50 +08:00
const char * history_string = m_command_history . FindString ( first_arg ) ;
2014-04-20 08:31:37 +08:00
if ( history_string ! = nullptr )
2011-07-12 11:12:18 +08:00
{
matches . Clear ( ) ;
matches . InsertStringAtIndex ( 0 , history_string ) ;
return - 2 ;
}
else
return 0 ;
}
}
2010-06-09 00:52:24 +08:00
int num_args = partial_parsed_line . GetArgumentCount ( ) ;
int cursor_index = partial_parsed_line . GetArgumentCount ( ) - 1 ;
int cursor_char_position ;
if ( cursor_index = = - 1 )
cursor_char_position = 0 ;
else
cursor_char_position = strlen ( partial_parsed_line . GetArgumentAtIndex ( cursor_index ) ) ;
2010-12-15 03:56:01 +08:00
if ( cursor > current_line & & cursor [ - 1 ] = = ' ' )
{
// We are just after a space. If we are in an argument, then we will continue
// parsing, but if we are between arguments, then we have to complete whatever the next
// element would be.
// We can distinguish the two cases because if we are in an argument (e.g. because the space is
// protected by a quote) then the space will also be in the parsed argument...
const char * current_elem = partial_parsed_line . GetArgumentAtIndex ( cursor_index ) ;
if ( cursor_char_position = = 0 | | current_elem [ cursor_char_position - 1 ] ! = ' ' )
{
2013-12-11 03:14:04 +08:00
parsed_line . InsertArgumentAtIndex ( cursor_index + 1 , " " , ' \0 ' ) ;
2010-12-15 03:56:01 +08:00
cursor_index + + ;
cursor_char_position = 0 ;
}
}
2010-06-09 00:52:24 +08:00
int num_command_matches ;
matches . Clear ( ) ;
// Only max_return_elements == -1 is supported at present:
assert ( max_return_elements = = - 1 ) ;
2010-06-30 13:02:46 +08:00
bool word_complete ;
2010-06-23 09:19:29 +08:00
num_command_matches = HandleCompletionMatches ( parsed_line ,
cursor_index ,
cursor_char_position ,
match_start_point ,
2010-06-30 13:02:46 +08:00
max_return_elements ,
word_complete ,
2010-06-23 09:19:29 +08:00
matches ) ;
2010-06-09 00:52:24 +08:00
if ( num_command_matches < = 0 )
2015-09-02 18:35:27 +08:00
return num_command_matches ;
2010-06-09 00:52:24 +08:00
if ( num_args = = 0 )
{
// If we got an empty string, insert nothing.
matches . InsertStringAtIndex ( 0 , " " ) ;
}
else
{
// Now figure out if there is a common substring, and if so put that in element 0, otherwise
// put an empty string in element 0.
std : : string command_partial_str ;
if ( cursor_index > = 0 )
2010-10-23 02:47:16 +08:00
command_partial_str . assign ( parsed_line . GetArgumentAtIndex ( cursor_index ) ,
parsed_line . GetArgumentAtIndex ( cursor_index ) + cursor_char_position ) ;
2010-06-09 00:52:24 +08:00
std : : string common_prefix ;
matches . LongestCommonPrefix ( common_prefix ) ;
2013-01-26 02:06:21 +08:00
const size_t partial_name_len = command_partial_str . size ( ) ;
2015-09-02 18:35:27 +08:00
common_prefix . erase ( 0 , partial_name_len ) ;
2010-06-09 00:52:24 +08:00
// If we matched a unique single command, add a space...
2010-06-30 13:02:46 +08:00
// Only do this if the completer told us this was a complete word, however...
if ( num_command_matches = = 1 & & word_complete )
2010-06-09 00:52:24 +08:00
{
char quote_char = parsed_line . GetArgumentQuoteCharAtIndex ( cursor_index ) ;
2015-09-02 18:35:27 +08:00
common_prefix = Args : : EscapeLLDBCommandArgument ( common_prefix , quote_char ) ;
2010-06-09 00:52:24 +08:00
if ( quote_char ! = ' \0 ' )
common_prefix . push_back ( quote_char ) ;
common_prefix . push_back ( ' ' ) ;
}
matches . InsertStringAtIndex ( 0 , common_prefix . c_str ( ) ) ;
}
return num_command_matches ;
}
CommandInterpreter : : ~ CommandInterpreter ( )
{
}
void
2014-01-28 07:43:24 +08:00
CommandInterpreter : : UpdatePrompt ( const char * new_prompt )
2010-06-09 00:52:24 +08:00
{
2014-01-28 07:43:24 +08:00
EventSP prompt_change_event_sp ( new Event ( eBroadcastBitResetPrompt , new EventDataBytes ( new_prompt ) ) ) ; ;
BroadcastEvent ( prompt_change_event_sp ) ;
if ( m_command_io_handler_sp )
m_command_io_handler_sp - > SetPrompt ( new_prompt ) ;
2010-06-09 00:52:24 +08:00
}
2010-10-05 03:49:29 +08:00
bool
CommandInterpreter : : Confirm ( const char * message , bool default_answer )
{
2010-10-05 06:44:14 +08:00
// Check AutoConfirm first:
if ( m_debugger . GetAutoConfirm ( ) )
return default_answer ;
2014-01-28 07:43:24 +08:00
IOHandlerConfirm * confirm = new IOHandlerConfirm ( m_debugger ,
message ,
default_answer ) ;
IOHandlerSP io_handler_sp ( confirm ) ;
m_debugger . RunIOHandler ( io_handler_sp ) ;
return confirm - > GetResponse ( ) ;
2010-10-05 03:49:29 +08:00
}
2010-06-09 00:52:24 +08:00
OptionArgVectorSP
CommandInterpreter : : GetAliasOptions ( const char * alias_name )
{
OptionArgMap : : iterator pos ;
OptionArgVectorSP ret_val ;
std : : string alias ( alias_name ) ;
if ( HasAliasOptions ( ) )
{
pos = m_alias_options . find ( alias ) ;
if ( pos ! = m_alias_options . end ( ) )
ret_val = pos - > second ;
}
return ret_val ;
}
void
CommandInterpreter : : RemoveAliasOptions ( const char * alias_name )
{
OptionArgMap : : iterator pos = m_alias_options . find ( alias_name ) ;
if ( pos ! = m_alias_options . end ( ) )
{
m_alias_options . erase ( pos ) ;
}
}
void
CommandInterpreter : : AddOrReplaceAliasOptions ( const char * alias_name , OptionArgVectorSP & option_arg_vector_sp )
{
m_alias_options [ alias_name ] = option_arg_vector_sp ;
}
bool
CommandInterpreter : : HasCommands ( )
{
return ( ! m_command_dict . empty ( ) ) ;
}
bool
CommandInterpreter : : HasAliases ( )
{
return ( ! m_alias_dict . empty ( ) ) ;
}
bool
CommandInterpreter : : HasUserCommands ( )
{
return ( ! m_user_dict . empty ( ) ) ;
}
bool
CommandInterpreter : : HasAliasOptions ( )
{
return ( ! m_alias_options . empty ( ) ) ;
}
void
2010-10-13 05:57:09 +08:00
CommandInterpreter : : BuildAliasCommandArgs ( CommandObject * alias_cmd_obj ,
const char * alias_name ,
Args & cmd_args ,
2010-12-08 03:58:26 +08:00
std : : string & raw_input_string ,
2010-10-13 05:57:09 +08:00
CommandReturnObject & result )
2010-06-09 00:52:24 +08:00
{
OptionArgVectorSP option_arg_vector_sp = GetAliasOptions ( alias_name ) ;
2010-12-08 03:58:26 +08:00
bool wants_raw_input = alias_cmd_obj - > WantsRawCommandString ( ) ;
2010-06-09 00:52:24 +08:00
2010-12-08 03:58:26 +08:00
// Make sure that the alias name is the 0th element in cmd_args
std : : string alias_name_str = alias_name ;
if ( alias_name_str . compare ( cmd_args . GetArgumentAtIndex ( 0 ) ) ! = 0 )
cmd_args . Unshift ( alias_name ) ;
Args new_args ( alias_cmd_obj - > GetCommandName ( ) ) ;
if ( new_args . GetArgumentCount ( ) = = 2 )
new_args . Shift ( ) ;
2010-06-09 00:52:24 +08:00
if ( option_arg_vector_sp . get ( ) )
{
2010-12-08 03:58:26 +08:00
if ( wants_raw_input )
{
// We have a command that both has command options and takes raw input. Make *sure* it has a
// " -- " in the right place in the raw_input_string.
size_t pos = raw_input_string . find ( " -- " ) ;
if ( pos = = std : : string : : npos )
{
// None found; assume it goes at the beginning of the raw input string
raw_input_string . insert ( 0 , " -- " ) ;
}
}
2010-06-09 00:52:24 +08:00
OptionArgVector * option_arg_vector = option_arg_vector_sp . get ( ) ;
2013-01-26 02:06:21 +08:00
const size_t old_size = cmd_args . GetArgumentCount ( ) ;
2010-10-13 05:57:09 +08:00
std : : vector < bool > used ( old_size + 1 , false ) ;
used [ 0 ] = true ;
2010-06-09 00:52:24 +08:00
2013-06-20 03:04:53 +08:00
for ( size_t i = 0 ; i < option_arg_vector - > size ( ) ; + + i )
2010-06-09 00:52:24 +08:00
{
OptionArgPair option_pair = ( * option_arg_vector ) [ i ] ;
2010-12-08 03:58:26 +08:00
OptionArgValue value_pair = option_pair . second ;
int value_type = value_pair . first ;
2010-06-09 00:52:24 +08:00
std : : string option = option_pair . first ;
2010-12-08 03:58:26 +08:00
std : : string value = value_pair . second ;
2010-06-09 00:52:24 +08:00
if ( option . compare ( " <argument> " ) = = 0 )
2010-12-08 03:58:26 +08:00
{
if ( ! wants_raw_input
| | ( value . compare ( " -- " ) ! = 0 ) ) // Since we inserted this above, make sure we don't insert it twice
new_args . AppendArgument ( value . c_str ( ) ) ;
}
2010-06-09 00:52:24 +08:00
else
{
2013-09-06 00:42:23 +08:00
if ( value_type ! = OptionParser : : eOptionalArgument )
2010-12-08 03:58:26 +08:00
new_args . AppendArgument ( option . c_str ( ) ) ;
2010-06-09 00:52:24 +08:00
if ( value . compare ( " <no-argument> " ) ! = 0 )
{
int index = GetOptionArgumentPosition ( value . c_str ( ) ) ;
if ( index = = 0 )
2010-12-08 03:58:26 +08:00
{
2010-06-09 00:52:24 +08:00
// value was NOT a positional argument; must be a real value
2013-09-06 00:42:23 +08:00
if ( value_type ! = OptionParser : : eOptionalArgument )
2010-12-08 03:58:26 +08:00
new_args . AppendArgument ( value . c_str ( ) ) ;
else
{
char buffer [ 255 ] ;
: : snprintf ( buffer , sizeof ( buffer ) , " %s%s " , option . c_str ( ) , value . c_str ( ) ) ;
new_args . AppendArgument ( buffer ) ;
}
}
2014-04-02 11:51:35 +08:00
else if ( static_cast < size_t > ( index ) > = cmd_args . GetArgumentCount ( ) )
2010-06-09 00:52:24 +08:00
{
result . AppendErrorWithFormat
( " Not enough arguments provided; you need at least %d arguments to use this alias. \n " ,
index ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return ;
}
else
{
2010-12-08 03:58:26 +08:00
// Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
size_t strpos = raw_input_string . find ( cmd_args . GetArgumentAtIndex ( index ) ) ;
if ( strpos ! = std : : string : : npos )
{
raw_input_string = raw_input_string . erase ( strpos , strlen ( cmd_args . GetArgumentAtIndex ( index ) ) ) ;
}
2013-09-06 00:42:23 +08:00
if ( value_type ! = OptionParser : : eOptionalArgument )
2010-12-08 03:58:26 +08:00
new_args . AppendArgument ( cmd_args . GetArgumentAtIndex ( index ) ) ;
else
{
char buffer [ 255 ] ;
: : snprintf ( buffer , sizeof ( buffer ) , " %s%s " , option . c_str ( ) ,
cmd_args . GetArgumentAtIndex ( index ) ) ;
new_args . AppendArgument ( buffer ) ;
}
2010-10-13 05:57:09 +08:00
used [ index ] = true ;
2010-06-09 00:52:24 +08:00
}
}
}
}
2013-06-20 03:04:53 +08:00
for ( size_t j = 0 ; j < cmd_args . GetArgumentCount ( ) ; + + j )
2010-06-09 00:52:24 +08:00
{
2010-12-08 03:58:26 +08:00
if ( ! used [ j ] & & ! wants_raw_input )
2010-06-09 00:52:24 +08:00
new_args . AppendArgument ( cmd_args . GetArgumentAtIndex ( j ) ) ;
}
cmd_args . Clear ( ) ;
2015-05-13 08:25:54 +08:00
cmd_args . SetArguments ( new_args . GetArgumentCount ( ) , new_args . GetConstArgumentVector ( ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2010-12-08 03:58:26 +08:00
// This alias was not created with any options; nothing further needs to be done, unless it is a command that
// wants raw input, in which case we need to clear the rest of the data from cmd_args, since its in the raw
// input string.
if ( wants_raw_input )
{
cmd_args . Clear ( ) ;
2015-05-13 08:25:54 +08:00
cmd_args . SetArguments ( new_args . GetArgumentCount ( ) , new_args . GetConstArgumentVector ( ) ) ;
2010-12-08 03:58:26 +08:00
}
2010-06-09 00:52:24 +08:00
return ;
}
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
return ;
}
int
CommandInterpreter : : GetOptionArgumentPosition ( const char * in_string )
{
int position = 0 ; // Any string that isn't an argument position, i.e. '%' followed by an integer, gets a position
// of zero.
2015-05-13 08:25:54 +08:00
const char * cptr = in_string ;
2010-06-09 00:52:24 +08:00
// Does it start with '%'
if ( cptr [ 0 ] = = ' % ' )
{
+ + cptr ;
// Is the rest of it entirely digits?
if ( isdigit ( cptr [ 0 ] ) )
{
const char * start = cptr ;
while ( isdigit ( cptr [ 0 ] ) )
+ + cptr ;
// We've gotten to the end of the digits; are we at the end of the string?
if ( cptr [ 0 ] = = ' \0 ' )
position = atoi ( start ) ;
}
}
return position ;
}
void
CommandInterpreter : : SourceInitFile ( bool in_cwd , CommandReturnObject & result )
{
2011-08-13 07:34:31 +08:00
FileSpec init_file ;
2011-09-11 08:01:44 +08:00
if ( in_cwd )
2011-08-13 07:34:31 +08:00
{
2016-02-19 08:05:17 +08:00
ExecutionContext exe_ctx ( GetExecutionContext ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
if ( target )
{
// In the current working directory we don't load any program specific
// .lldbinit files, we only look for a ".lldbinit" file.
if ( m_skip_lldbinit_files )
return ;
2011-09-11 08:01:44 +08:00
2016-02-19 08:05:17 +08:00
LoadCWDlldbinitFile should_load = target - > TargetProperties : : GetLoadCWDlldbinitFile ( ) ;
if ( should_load = = eLoadCWDlldbinitWarn )
{
FileSpec dot_lldb ( " .lldbinit " , true ) ;
llvm : : SmallString < 64 > home_dir_path ;
llvm : : sys : : path : : home_directory ( home_dir_path ) ;
FileSpec homedir_dot_lldb ( home_dir_path . c_str ( ) , false ) ;
homedir_dot_lldb . AppendPathComponent ( " .lldbinit " ) ;
homedir_dot_lldb . ResolvePath ( ) ;
if ( dot_lldb . Exists ( )
& & dot_lldb . GetDirectory ( ) ! = homedir_dot_lldb . GetDirectory ( ) )
{
result . AppendErrorWithFormat (
" There is a .lldbinit file in the current directory which is not being read. \n "
" To silence this warning without sourcing in the local .lldbinit, \n "
" add the following to the lldbinit file in your home directory: \n "
" settings set target.load-cwd-lldbinit false \n "
" To allow lldb to source .lldbinit files in the current working directory, \n "
" set the value of this variable to true. Only do so if you understand and \n "
" accept the security risk. " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return ;
}
}
else if ( should_load = = eLoadCWDlldbinitTrue )
{
init_file . SetFile ( " ./.lldbinit " , true ) ;
}
}
2011-08-13 07:34:31 +08:00
}
2011-09-11 08:01:44 +08:00
else
2011-08-13 07:34:31 +08:00
{
2011-09-11 08:01:44 +08:00
// If we aren't looking in the current working directory we are looking
// in the home directory. We will first see if there is an application
// specific ".lldbinit" file whose name is "~/.lldbinit" followed by a
// "-" and the name of the program. If this file doesn't exist, we fall
// back to just the "~/.lldbinit" file. We also obey any requests to not
// load the init files.
2014-08-22 05:49:24 +08:00
llvm : : SmallString < 64 > home_dir_path ;
llvm : : sys : : path : : home_directory ( home_dir_path ) ;
FileSpec profilePath ( home_dir_path . c_str ( ) , false ) ;
2014-07-29 00:45:05 +08:00
profilePath . AppendPathComponent ( " .lldbinit " ) ;
std : : string init_file_path = profilePath . GetPath ( ) ;
2011-09-11 08:01:44 +08:00
if ( m_skip_app_init_files = = false )
{
2014-08-22 05:49:24 +08:00
FileSpec program_file_spec ( HostInfo : : GetProgramFileSpec ( ) ) ;
2011-09-11 08:01:44 +08:00
const char * program_name = program_file_spec . GetFilename ( ) . AsCString ( ) ;
2011-08-13 07:34:31 +08:00
2011-09-11 08:01:44 +08:00
if ( program_name )
{
char program_init_file_name [ PATH_MAX ] ;
2014-07-29 00:45:05 +08:00
: : snprintf ( program_init_file_name , sizeof ( program_init_file_name ) , " %s-%s " , init_file_path . c_str ( ) , program_name ) ;
2011-09-11 08:01:44 +08:00
init_file . SetFile ( program_init_file_name , true ) ;
if ( ! init_file . Exists ( ) )
init_file . Clear ( ) ;
}
}
if ( ! init_file & & ! m_skip_lldbinit_files )
2014-07-29 00:45:05 +08:00
init_file . SetFile ( init_file_path . c_str ( ) , false ) ;
2011-09-11 08:01:44 +08:00
}
2010-06-09 00:52:24 +08:00
// If the file exists, tell HandleCommand to 'source' it; this will do the actual broadcasting
// of the commands back to any appropriate listener (see CommandObjectSource::Execute for more details).
if ( init_file . Exists ( ) )
{
2014-01-28 07:43:24 +08:00
const bool saved_batch = SetBatchCommandMode ( true ) ;
2014-10-11 08:38:27 +08:00
CommandInterpreterRunOptions options ;
options . SetSilent ( true ) ;
options . SetStopOnError ( false ) ;
options . SetStopOnContinue ( true ) ;
2014-02-06 01:57:57 +08:00
HandleCommandsFromFile ( init_file ,
2014-04-20 08:31:37 +08:00
nullptr , // Execution context
2014-10-11 08:38:27 +08:00
options ,
2014-02-06 01:57:57 +08:00
result ) ;
2014-01-28 07:43:24 +08:00
SetBatchCommandMode ( saved_batch ) ;
2010-06-09 00:52:24 +08:00
}
else
{
// nothing to be done if the file doesn't exist
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
}
2015-01-15 08:52:41 +08:00
const char *
CommandInterpreter : : GetCommandPrefix ( )
{
const char * prefix = GetDebugger ( ) . GetIOHandlerCommandPrefix ( ) ;
return prefix = = NULL ? " " : prefix ;
}
2011-04-12 13:54:46 +08:00
PlatformSP
CommandInterpreter : : GetPlatform ( bool prefer_target_platform )
{
PlatformSP platform_sp ;
2011-09-22 12:58:26 +08:00
if ( prefer_target_platform )
{
2012-07-13 04:32:19 +08:00
ExecutionContext exe_ctx ( GetExecutionContext ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
2011-09-22 12:58:26 +08:00
if ( target )
platform_sp = target - > GetPlatform ( ) ;
}
2011-04-12 13:54:46 +08:00
if ( ! platform_sp )
platform_sp = m_debugger . GetPlatformList ( ) . GetSelectedPlatform ( ) ;
return platform_sp ;
}
2011-02-18 08:54:25 +08:00
void
2011-03-11 09:51:49 +08:00
CommandInterpreter : : HandleCommands ( const StringList & commands ,
2014-10-11 08:38:27 +08:00
ExecutionContext * override_context ,
CommandInterpreterRunOptions & options ,
2011-02-18 08:54:25 +08:00
CommandReturnObject & result )
{
size_t num_lines = commands . GetSize ( ) ;
// If we are going to continue past a "continue" then we need to run the commands synchronously.
// Make sure you reset this value anywhere you return from the function.
bool old_async_execution = m_debugger . GetAsyncExecution ( ) ;
// If we've been given an execution context, set it at the start, but don't keep resetting it or we will
// cause series of commands that change the context, then do an operation that relies on that context to fail.
2014-04-20 08:31:37 +08:00
if ( override_context ! = nullptr )
2011-04-12 13:54:46 +08:00
UpdateExecutionContext ( override_context ) ;
2011-02-18 08:54:25 +08:00
2014-10-11 08:38:27 +08:00
if ( ! options . GetStopOnContinue ( ) )
2011-02-18 08:54:25 +08:00
{
m_debugger . SetAsyncExecution ( false ) ;
}
2013-06-20 03:04:53 +08:00
for ( size_t idx = 0 ; idx < num_lines ; idx + + )
2011-02-18 08:54:25 +08:00
{
const char * cmd = commands . GetStringAtIndex ( idx ) ;
if ( cmd [ 0 ] = = ' \0 ' )
continue ;
2014-10-11 08:38:27 +08:00
if ( options . GetEchoCommands ( ) )
2011-02-18 08:54:25 +08:00
{
result . AppendMessageWithFormat ( " %s %s \n " ,
2014-01-28 07:43:24 +08:00
m_debugger . GetPrompt ( ) ,
cmd ) ;
2011-02-18 08:54:25 +08:00
}
2011-02-20 10:15:07 +08:00
CommandReturnObject tmp_result ;
2011-10-05 08:42:59 +08:00
// If override_context is not NULL, pass no_context_switching = true for
// HandleCommand() since we updated our context already.
2013-05-03 07:15:37 +08:00
// We might call into a regex or alias command, in which case the add_to_history will get lost. This
// m_command_source_depth dingus is the way we turn off adding to the history in that case, so set it up here.
2014-10-11 08:38:27 +08:00
if ( ! options . GetAddToHistory ( ) )
2013-05-03 07:15:37 +08:00
m_command_source_depth + + ;
2014-10-11 08:38:27 +08:00
bool success = HandleCommand ( cmd , options . m_add_to_history , tmp_result ,
2014-04-20 08:31:37 +08:00
nullptr , /* override_context */
2011-10-05 08:42:59 +08:00
true , /* repeat_on_empty_command */
2014-04-20 08:31:37 +08:00
override_context ! = nullptr /* no_context_switching */ ) ;
2014-10-11 08:38:27 +08:00
if ( ! options . GetAddToHistory ( ) )
2013-05-03 07:15:37 +08:00
m_command_source_depth - - ;
2011-02-18 08:54:25 +08:00
2014-10-11 08:38:27 +08:00
if ( options . GetPrintResults ( ) )
2011-02-18 08:54:25 +08:00
{
if ( tmp_result . Succeeded ( ) )
2011-02-19 10:53:09 +08:00
result . AppendMessageWithFormat ( " %s " , tmp_result . GetOutputData ( ) ) ;
2011-02-18 08:54:25 +08:00
}
if ( ! success | | ! tmp_result . Succeeded ( ) )
{
2012-04-24 10:25:07 +08:00
const char * error_msg = tmp_result . GetErrorData ( ) ;
2014-04-20 08:31:37 +08:00
if ( error_msg = = nullptr | | error_msg [ 0 ] = = ' \0 ' )
2012-04-24 10:25:07 +08:00
error_msg = " <unknown error>. \n " ;
2014-10-11 08:38:27 +08:00
if ( options . GetStopOnError ( ) )
2011-02-18 08:54:25 +08:00
{
2014-03-03 23:39:47 +08:00
result . AppendErrorWithFormat ( " Aborting reading of commands after command #% " PRIu64 " : '%s' failed with %s " ,
( uint64_t ) idx , cmd , error_msg ) ;
2011-02-18 08:54:25 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
m_debugger . SetAsyncExecution ( old_async_execution ) ;
return ;
}
2014-10-11 08:38:27 +08:00
else if ( options . GetPrintResults ( ) )
2011-02-18 08:54:25 +08:00
{
2014-03-03 23:39:47 +08:00
result . AppendMessageWithFormat ( " Command #% " PRIu64 " '%s' failed with %s " ,
( uint64_t ) idx + 1 ,
2011-02-18 08:54:25 +08:00
cmd ,
2012-04-24 10:25:07 +08:00
error_msg ) ;
2011-02-18 08:54:25 +08:00
}
}
This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.
As part of this it introduces a new Stream class,
StreamAsynchronousIO. A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast. When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string. When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.
Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.
I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired. I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).
llvm-svn: 130721
2011-05-03 04:41:46 +08:00
if ( result . GetImmediateOutputStream ( ) )
result . GetImmediateOutputStream ( ) - > Flush ( ) ;
if ( result . GetImmediateErrorStream ( ) )
result . GetImmediateErrorStream ( ) - > Flush ( ) ;
2011-02-18 08:54:25 +08:00
// N.B. Can't depend on DidChangeProcessState, because the state coming into the command execution
// could be running (for instance in Breakpoint Commands.
// So we check the return value to see if it is has running in it.
if ( ( tmp_result . GetStatus ( ) = = eReturnStatusSuccessContinuingNoResult )
| | ( tmp_result . GetStatus ( ) = = eReturnStatusSuccessContinuingResult ) )
{
2014-10-11 08:38:27 +08:00
if ( options . GetStopOnContinue ( ) )
2011-02-18 08:54:25 +08:00
{
// If we caused the target to proceed, and we're going to stop in that case, set the
// status in our real result before returning. This is an error if the continue was not the
// last command in the set of commands to be run.
if ( idx ! = num_lines - 1 )
2014-03-03 23:39:47 +08:00
result . AppendErrorWithFormat ( " Aborting reading of commands after command #% " PRIu64 " : '%s' continued the target. \n " ,
( uint64_t ) idx + 1 , cmd ) ;
2011-02-18 08:54:25 +08:00
else
2014-03-03 23:39:47 +08:00
result . AppendMessageWithFormat ( " Command #% " PRIu64 " '%s' continued the target. \n " , ( uint64_t ) idx + 1 , cmd ) ;
2011-02-18 08:54:25 +08:00
result . SetStatus ( tmp_result . GetStatus ( ) ) ;
m_debugger . SetAsyncExecution ( old_async_execution ) ;
return ;
}
}
2014-10-14 09:20:07 +08:00
// Also check for "stop on crash here:
bool should_stop = false ;
if ( tmp_result . GetDidChangeProcessState ( ) & & options . GetStopOnCrash ( ) )
{
TargetSP target_sp ( m_debugger . GetTargetList ( ) . GetSelectedTarget ( ) ) ;
if ( target_sp )
{
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
if ( process_sp )
{
for ( ThreadSP thread_sp : process_sp - > GetThreadList ( ) . Threads ( ) )
{
StopReason reason = thread_sp - > GetStopReason ( ) ;
if ( reason = = eStopReasonSignal | | reason = = eStopReasonException | | reason = = eStopReasonInstrumentation )
{
should_stop = true ;
break ;
}
}
}
}
if ( should_stop )
{
if ( idx ! = num_lines - 1 )
result . AppendErrorWithFormat ( " Aborting reading of commands after command #% " PRIu64 " : '%s' stopped with a signal or exception. \n " ,
( uint64_t ) idx + 1 , cmd ) ;
else
result . AppendMessageWithFormat ( " Command #% " PRIu64 " '%s' stopped with a signal or exception. \n " , ( uint64_t ) idx + 1 , cmd ) ;
result . SetStatus ( tmp_result . GetStatus ( ) ) ;
m_debugger . SetAsyncExecution ( old_async_execution ) ;
return ;
}
}
2011-02-18 08:54:25 +08:00
}
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
m_debugger . SetAsyncExecution ( old_async_execution ) ;
return ;
}
2014-02-06 01:57:57 +08:00
// Make flags that we can pass into the IOHandler so our delegates can do the right thing
enum {
eHandleCommandFlagStopOnContinue = ( 1u < < 0 ) ,
eHandleCommandFlagStopOnError = ( 1u < < 1 ) ,
eHandleCommandFlagEchoCommand = ( 1u < < 2 ) ,
2014-10-11 08:38:27 +08:00
eHandleCommandFlagPrintResult = ( 1u < < 3 ) ,
eHandleCommandFlagStopOnCrash = ( 1u < < 4 )
2014-02-06 01:57:57 +08:00
} ;
2011-02-18 08:54:25 +08:00
void
CommandInterpreter : : HandleCommandsFromFile ( FileSpec & cmd_file ,
ExecutionContext * context ,
2014-10-11 08:38:27 +08:00
CommandInterpreterRunOptions & options ,
2011-02-18 08:54:25 +08:00
CommandReturnObject & result )
{
if ( cmd_file . Exists ( ) )
{
2014-01-28 07:43:24 +08:00
StreamFileSP input_file_sp ( new StreamFile ( ) ) ;
std : : string cmd_file_path = cmd_file . GetPath ( ) ;
Error error = input_file_sp - > GetFile ( ) . Open ( cmd_file_path . c_str ( ) , File : : eOpenOptionRead ) ;
if ( error . Success ( ) )
{
Debugger & debugger = GetDebugger ( ) ;
2014-02-06 01:57:57 +08:00
uint32_t flags = 0 ;
2014-10-11 08:38:27 +08:00
if ( options . m_stop_on_continue = = eLazyBoolCalculate )
2014-02-06 01:57:57 +08:00
{
if ( m_command_source_flags . empty ( ) )
{
2014-02-06 05:03:22 +08:00
// Stop on continue by default
2014-02-06 01:57:57 +08:00
flags | = eHandleCommandFlagStopOnContinue ;
}
else if ( m_command_source_flags . back ( ) & eHandleCommandFlagStopOnContinue )
{
flags | = eHandleCommandFlagStopOnContinue ;
}
}
2014-10-11 08:38:27 +08:00
else if ( options . m_stop_on_continue = = eLazyBoolYes )
2014-02-06 01:57:57 +08:00
{
flags | = eHandleCommandFlagStopOnContinue ;
}
2014-10-11 08:38:27 +08:00
if ( options . m_stop_on_error = = eLazyBoolCalculate )
2014-02-06 01:57:57 +08:00
{
if ( m_command_source_flags . empty ( ) )
{
if ( GetStopCmdSourceOnError ( ) )
flags | = eHandleCommandFlagStopOnError ;
}
else if ( m_command_source_flags . back ( ) & eHandleCommandFlagStopOnError )
{
flags | = eHandleCommandFlagStopOnError ;
}
}
2014-10-11 08:38:27 +08:00
else if ( options . m_stop_on_error = = eLazyBoolYes )
2014-02-06 01:57:57 +08:00
{
flags | = eHandleCommandFlagStopOnError ;
}
2014-10-14 09:20:07 +08:00
if ( options . GetStopOnCrash ( ) )
{
if ( m_command_source_flags . empty ( ) )
{
// Echo command by default
flags | = eHandleCommandFlagStopOnCrash ;
}
else if ( m_command_source_flags . back ( ) & eHandleCommandFlagStopOnCrash )
{
flags | = eHandleCommandFlagStopOnCrash ;
}
}
2014-10-11 08:38:27 +08:00
if ( options . m_echo_commands = = eLazyBoolCalculate )
2014-02-06 01:57:57 +08:00
{
if ( m_command_source_flags . empty ( ) )
{
// Echo command by default
flags | = eHandleCommandFlagEchoCommand ;
}
else if ( m_command_source_flags . back ( ) & eHandleCommandFlagEchoCommand )
{
flags | = eHandleCommandFlagEchoCommand ;
}
}
2014-10-11 08:38:27 +08:00
else if ( options . m_echo_commands = = eLazyBoolYes )
2014-02-06 01:57:57 +08:00
{
flags | = eHandleCommandFlagEchoCommand ;
}
2014-10-11 08:38:27 +08:00
if ( options . m_print_results = = eLazyBoolCalculate )
2014-02-06 01:57:57 +08:00
{
if ( m_command_source_flags . empty ( ) )
{
2014-02-06 05:03:22 +08:00
// Print output by default
flags | = eHandleCommandFlagPrintResult ;
2014-02-06 01:57:57 +08:00
}
2014-02-06 05:03:22 +08:00
else if ( m_command_source_flags . back ( ) & eHandleCommandFlagPrintResult )
2014-02-06 01:57:57 +08:00
{
2014-02-06 05:03:22 +08:00
flags | = eHandleCommandFlagPrintResult ;
2014-02-06 01:57:57 +08:00
}
}
2014-10-11 08:38:27 +08:00
else if ( options . m_print_results = = eLazyBoolYes )
2014-02-06 01:57:57 +08:00
{
2014-02-06 05:03:22 +08:00
flags | = eHandleCommandFlagPrintResult ;
}
if ( flags & eHandleCommandFlagPrintResult )
{
2014-02-06 05:46:20 +08:00
debugger . GetOutputFile ( ) - > Printf ( " Executing commands in '%s'. \n " , cmd_file_path . c_str ( ) ) ;
2014-02-06 01:57:57 +08:00
}
// Used for inheriting the right settings when "command source" might have
// nested "command source" commands
2014-02-06 05:03:22 +08:00
lldb : : StreamFileSP empty_stream_sp ;
2014-02-06 01:57:57 +08:00
m_command_source_flags . push_back ( flags ) ;
2014-01-28 07:43:24 +08:00
IOHandlerSP io_handler_sp ( new IOHandlerEditline ( debugger ,
2014-11-18 03:06:59 +08:00
IOHandler : : Type : : CommandInterpreter ,
2014-01-28 07:43:24 +08:00
input_file_sp ,
2014-02-06 05:03:22 +08:00
empty_stream_sp , // Pass in an empty stream so we inherit the top input reader output stream
empty_stream_sp , // Pass in an empty stream so we inherit the top input reader error stream
2014-02-06 01:57:57 +08:00
flags ,
2014-04-20 08:31:37 +08:00
nullptr , // Pass in NULL for "editline_name" so no history is saved, or written
2014-02-06 05:46:20 +08:00
debugger . GetPrompt ( ) ,
2014-11-18 03:06:59 +08:00
NULL ,
2014-01-28 07:43:24 +08:00
false , // Not multi-line
2014-11-18 03:06:59 +08:00
debugger . GetUseColor ( ) ,
2014-03-07 08:53:24 +08:00
0 ,
2014-01-28 07:43:24 +08:00
* this ) ) ;
2014-02-06 05:46:20 +08:00
const bool old_async_execution = debugger . GetAsyncExecution ( ) ;
2014-10-14 09:20:07 +08:00
// Set synchronous execution if we are not stopping on continue
2014-02-06 05:46:20 +08:00
if ( ( flags & eHandleCommandFlagStopOnContinue ) = = 0 )
debugger . SetAsyncExecution ( false ) ;
2014-02-06 01:57:57 +08:00
m_command_source_depth + + ;
2014-02-06 05:46:20 +08:00
debugger . RunIOHandler ( io_handler_sp ) ;
2014-02-06 01:57:57 +08:00
if ( ! m_command_source_flags . empty ( ) )
m_command_source_flags . pop_back ( ) ;
m_command_source_depth - - ;
2014-01-28 07:43:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2014-02-06 05:46:20 +08:00
debugger . SetAsyncExecution ( old_async_execution ) ;
2014-01-28 07:43:24 +08:00
}
else
{
result . AppendErrorWithFormat ( " error: an error occurred read file '%s': %s \n " , cmd_file_path . c_str ( ) , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
2014-02-06 05:46:20 +08:00
2011-02-18 08:54:25 +08:00
}
else
{
result . AppendErrorWithFormat ( " Error reading commands from file %s - file not found. \n " ,
2014-12-20 03:20:44 +08:00
cmd_file . GetFilename ( ) . AsCString ( " <Unknown> " ) ) ;
2011-02-18 08:54:25 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return ;
}
}
2010-06-09 00:52:24 +08:00
ScriptInterpreter *
2015-07-31 04:28:07 +08:00
CommandInterpreter : : GetScriptInterpreter ( bool can_create )
2010-06-09 00:52:24 +08:00
{
2015-07-31 04:28:07 +08:00
if ( m_script_interpreter_sp )
return m_script_interpreter_sp . get ( ) ;
2012-10-30 05:18:03 +08:00
if ( ! can_create )
2014-04-20 08:31:37 +08:00
return nullptr ;
2015-07-31 04:28:07 +08:00
2011-01-14 08:29:16 +08:00
lldb : : ScriptLanguage script_lang = GetDebugger ( ) . GetScriptLanguage ( ) ;
2015-07-31 04:28:07 +08:00
m_script_interpreter_sp = PluginManager : : GetScriptInterpreterForLanguage ( script_lang , * this ) ;
return m_script_interpreter_sp . get ( ) ;
2010-06-09 00:52:24 +08:00
}
bool
CommandInterpreter : : GetSynchronous ( )
{
return m_synchronous_execution ;
}
void
CommandInterpreter : : SetSynchronous ( bool value )
{
2010-10-14 09:22:03 +08:00
m_synchronous_execution = value ;
2010-06-09 00:52:24 +08:00
}
void
CommandInterpreter : : OutputFormattedHelpText ( Stream & strm ,
2015-01-15 08:52:41 +08:00
const char * prefix ,
const char * help_text )
2010-06-09 00:52:24 +08:00
{
2010-09-18 09:14:36 +08:00
const uint32_t max_columns = m_debugger . GetTerminalWidth ( ) ;
2015-01-15 08:52:41 +08:00
if ( prefix = = NULL )
prefix = " " ;
size_t prefix_width = strlen ( prefix ) ;
size_t line_width_max = max_columns - prefix_width ;
const char * help_text_end = help_text + strlen ( help_text ) ;
const char * line_start = help_text ;
if ( line_width_max < 16 )
line_width_max = help_text_end - help_text + prefix_width ;
strm . IndentMore ( prefix_width ) ;
while ( line_start < help_text_end )
{
// Break each line at the first newline or last space/tab before
// the maximum number of characters that fit on a line. Lines with no
// natural break are left unbroken to wrap.
const char * line_end = help_text_end ;
const char * line_scan = line_start ;
const char * line_scan_end = help_text_end ;
while ( line_scan < line_scan_end )
{
char next = * line_scan ;
if ( next = = ' \t ' | | next = = ' ' )
2010-06-09 00:52:24 +08:00
{
2015-01-15 08:52:41 +08:00
line_end = line_scan ;
line_scan_end = line_start + line_width_max ;
2010-06-09 00:52:24 +08:00
}
2015-01-15 08:52:41 +08:00
else if ( next = = ' \n ' | | next = = ' \0 ' )
2010-06-09 00:52:24 +08:00
{
2015-01-15 08:52:41 +08:00
line_end = line_scan ;
break ;
2010-06-09 00:52:24 +08:00
}
2015-01-15 08:52:41 +08:00
+ + line_scan ;
2010-06-09 00:52:24 +08:00
}
2015-01-15 08:52:41 +08:00
// Prefix the first line, indent subsequent lines to line up
if ( line_start = = help_text )
strm . Write ( prefix , prefix_width ) ;
else
strm . Indent ( ) ;
strm . Write ( line_start , line_end - line_start ) ;
strm . EOL ( ) ;
// When a line breaks at whitespace consume it before continuing
line_start = line_end ;
char next = * line_start ;
if ( next = = ' \n ' )
+ + line_start ;
else while ( next = = ' ' | | next = = ' \t ' )
next = * ( + + line_start ) ;
}
strm . IndentLess ( prefix_width ) ;
}
void
CommandInterpreter : : OutputFormattedHelpText ( Stream & strm ,
const char * word_text ,
const char * separator ,
const char * help_text ,
size_t max_word_len )
{
StreamString prefix_stream ;
prefix_stream . Printf ( " %-*s %s " , ( int ) max_word_len , word_text , separator ) ;
OutputFormattedHelpText ( strm , prefix_stream . GetData ( ) , help_text ) ;
2010-06-09 00:52:24 +08:00
}
2011-07-07 08:38:40 +08:00
void
CommandInterpreter : : OutputHelpText ( Stream & strm ,
const char * word_text ,
const char * separator ,
const char * help_text ,
uint32_t max_word_len )
{
int indent_size = max_word_len + strlen ( separator ) + 2 ;
strm . IndentMore ( indent_size ) ;
StreamString text_strm ;
text_strm . Printf ( " %-*s %s %s " , max_word_len , word_text , separator , help_text ) ;
const uint32_t max_columns = m_debugger . GetTerminalWidth ( ) ;
size_t len = text_strm . GetSize ( ) ;
const char * text = text_strm . GetData ( ) ;
uint32_t chars_left = max_columns ;
for ( uint32_t i = 0 ; i < len ; i + + )
{
if ( ( text [ i ] = = ' ' & & : : strchr ( ( text + i + 1 ) , ' ' ) & & chars_left < : : strchr ( ( text + i + 1 ) , ' ' ) - ( text + i ) ) | | text [ i ] = = ' \n ' )
{
chars_left = max_columns - indent_size ;
strm . EOL ( ) ;
strm . Indent ( ) ;
}
else
{
strm . PutChar ( text [ i ] ) ;
chars_left - - ;
}
}
strm . EOL ( ) ;
strm . IndentLess ( indent_size ) ;
}
2010-06-09 00:52:24 +08:00
void
CommandInterpreter : : FindCommandsForApropos ( const char * search_word , StringList & commands_found ,
2013-05-17 09:30:37 +08:00
StringList & commands_help , bool search_builtin_commands , bool search_user_commands )
2010-06-09 00:52:24 +08:00
{
CommandObject : : CommandMap : : const_iterator pos ;
2013-05-17 09:30:37 +08:00
if ( search_builtin_commands )
2010-06-09 00:52:24 +08:00
{
2013-05-17 09:30:37 +08:00
for ( pos = m_command_dict . begin ( ) ; pos ! = m_command_dict . end ( ) ; + + pos )
2010-06-09 00:52:24 +08:00
{
2013-05-17 09:30:37 +08:00
const char * command_name = pos - > first . c_str ( ) ;
CommandObject * cmd_obj = pos - > second . get ( ) ;
if ( cmd_obj - > HelpTextContainsWord ( search_word ) )
{
commands_found . AppendString ( command_name ) ;
commands_help . AppendString ( cmd_obj - > GetHelp ( ) ) ;
}
if ( cmd_obj - > IsMultiwordObject ( ) )
cmd_obj - > AproposAllSubCommands ( command_name ,
search_word ,
commands_found ,
commands_help ) ;
2010-06-09 00:52:24 +08:00
}
2013-05-17 09:30:37 +08:00
}
if ( search_user_commands )
{
for ( pos = m_user_dict . begin ( ) ; pos ! = m_user_dict . end ( ) ; + + pos )
{
const char * command_name = pos - > first . c_str ( ) ;
CommandObject * cmd_obj = pos - > second . get ( ) ;
2010-06-09 00:52:24 +08:00
2013-05-17 09:30:37 +08:00
if ( cmd_obj - > HelpTextContainsWord ( search_word ) )
{
commands_found . AppendString ( command_name ) ;
commands_help . AppendString ( cmd_obj - > GetHelp ( ) ) ;
}
if ( cmd_obj - > IsMultiwordObject ( ) )
cmd_obj - > AproposAllSubCommands ( command_name ,
search_word ,
commands_found ,
commands_help ) ;
}
2010-06-09 00:52:24 +08:00
}
}
2011-04-12 13:54:46 +08:00
void
CommandInterpreter : : UpdateExecutionContext ( ExecutionContext * override_context )
{
2014-04-20 08:31:37 +08:00
if ( override_context ! = nullptr )
2011-04-12 13:54:46 +08:00
{
2012-07-13 04:32:19 +08:00
m_exe_ctx_ref = * override_context ;
2011-04-12 13:54:46 +08:00
}
else
{
2012-07-13 04:32:19 +08:00
const bool adopt_selected = true ;
m_exe_ctx_ref . SetTargetPtr ( m_debugger . GetSelectedTarget ( ) . get ( ) , adopt_selected ) ;
2011-04-12 13:54:46 +08:00
}
}
2014-01-28 07:43:24 +08:00
size_t
CommandInterpreter : : GetProcessOutput ( )
{
// The process has stuff waiting for stderr; get it and write it out to the appropriate place.
char stdio_buffer [ 1024 ] ;
size_t len ;
size_t total_bytes = 0 ;
Error error ;
TargetSP target_sp ( m_debugger . GetTargetList ( ) . GetSelectedTarget ( ) ) ;
if ( target_sp )
{
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
if ( process_sp )
{
while ( ( len = process_sp - > GetSTDOUT ( stdio_buffer , sizeof ( stdio_buffer ) , error ) ) > 0 )
{
size_t bytes_written = len ;
m_debugger . GetOutputFile ( ) - > Write ( stdio_buffer , bytes_written ) ;
total_bytes + = len ;
}
while ( ( len = process_sp - > GetSTDERR ( stdio_buffer , sizeof ( stdio_buffer ) , error ) ) > 0 )
{
size_t bytes_written = len ;
m_debugger . GetErrorFile ( ) - > Write ( stdio_buffer , bytes_written ) ;
total_bytes + = len ;
}
}
}
return total_bytes ;
}
void
CommandInterpreter : : IOHandlerInputComplete ( IOHandler & io_handler , std : : string & line )
{
2014-02-06 01:57:57 +08:00
const bool is_interactive = io_handler . GetIsInteractive ( ) ;
if ( is_interactive = = false )
{
// When we are not interactive, don't execute blank lines. This will happen
// sourcing a commands file. We don't want blank lines to repeat the previous
// command and cause any errors to occur (like redefining an alias, get an error
// and stop parsing the commands file).
if ( line . empty ( ) )
return ;
// When using a non-interactive file handle (like when sourcing commands from a file)
// we need to echo the command out so we don't just see the command output and no
// command...
if ( io_handler . GetFlags ( ) . Test ( eHandleCommandFlagEchoCommand ) )
io_handler . GetOutputStreamFile ( ) - > Printf ( " %s%s \n " , io_handler . GetPrompt ( ) , line . c_str ( ) ) ;
}
2014-01-28 07:43:24 +08:00
lldb_private : : CommandReturnObject result ;
HandleCommand ( line . c_str ( ) , eLazyBoolCalculate , result ) ;
// Now emit the command output text from the command we just executed
2014-02-06 01:57:57 +08:00
if ( io_handler . GetFlags ( ) . Test ( eHandleCommandFlagPrintResult ) )
{
// Display any STDOUT/STDERR _prior_ to emitting the command result text
GetProcessOutput ( ) ;
2014-02-06 05:46:20 +08:00
if ( ! result . GetImmediateOutputStream ( ) )
{
const char * output = result . GetOutputData ( ) ;
if ( output & & output [ 0 ] )
io_handler . GetOutputStreamFile ( ) - > PutCString ( output ) ;
}
2014-01-28 07:43:24 +08:00
2014-02-06 01:57:57 +08:00
// Now emit the command error text from the command we just executed
2014-02-06 05:46:20 +08:00
if ( ! result . GetImmediateErrorStream ( ) )
{
const char * error = result . GetErrorData ( ) ;
if ( error & & error [ 0 ] )
io_handler . GetErrorStreamFile ( ) - > PutCString ( error ) ;
}
2014-02-06 01:57:57 +08:00
}
2014-01-28 07:43:24 +08:00
switch ( result . GetStatus ( ) )
{
case eReturnStatusInvalid :
case eReturnStatusSuccessFinishNoResult :
case eReturnStatusSuccessFinishResult :
2014-02-06 01:57:57 +08:00
case eReturnStatusStarted :
break ;
2014-01-28 07:43:24 +08:00
case eReturnStatusSuccessContinuingNoResult :
case eReturnStatusSuccessContinuingResult :
2014-02-06 01:57:57 +08:00
if ( io_handler . GetFlags ( ) . Test ( eHandleCommandFlagStopOnContinue ) )
io_handler . SetIsDone ( true ) ;
break ;
2014-01-28 07:43:24 +08:00
case eReturnStatusFailed :
2014-10-11 08:38:27 +08:00
m_num_errors + + ;
2014-02-06 01:57:57 +08:00
if ( io_handler . GetFlags ( ) . Test ( eHandleCommandFlagStopOnError ) )
io_handler . SetIsDone ( true ) ;
2014-01-28 07:43:24 +08:00
break ;
case eReturnStatusQuit :
2014-10-11 08:38:27 +08:00
m_quit_requested = true ;
2014-01-28 07:43:24 +08:00
io_handler . SetIsDone ( true ) ;
break ;
}
2014-10-14 09:20:07 +08:00
// Finally, if we're going to stop on crash, check that here:
if ( ! m_quit_requested
& & result . GetDidChangeProcessState ( )
& & io_handler . GetFlags ( ) . Test ( eHandleCommandFlagStopOnCrash ) )
{
bool should_stop = false ;
TargetSP target_sp ( m_debugger . GetTargetList ( ) . GetSelectedTarget ( ) ) ;
if ( target_sp )
{
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
if ( process_sp )
{
for ( ThreadSP thread_sp : process_sp - > GetThreadList ( ) . Threads ( ) )
{
StopReason reason = thread_sp - > GetStopReason ( ) ;
2016-01-08 08:20:47 +08:00
if ( ( reason = = eStopReasonSignal
| | reason = = eStopReasonException
| | reason = = eStopReasonInstrumentation )
& & ! result . GetAbnormalStopWasExpected ( ) )
2014-10-14 09:20:07 +08:00
{
should_stop = true ;
break ;
}
}
}
}
if ( should_stop )
{
io_handler . SetIsDone ( true ) ;
m_stopped_for_crash = true ;
}
}
2014-01-28 07:43:24 +08:00
}
2014-05-02 08:45:31 +08:00
bool
CommandInterpreter : : IOHandlerInterrupt ( IOHandler & io_handler )
{
ExecutionContext exe_ctx ( GetExecutionContext ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
{
StateType state = process - > GetState ( ) ;
if ( StateIsRunningState ( state ) )
{
process - > Halt ( ) ;
return true ; // Don't do any updating when we are running
}
}
2015-01-27 09:58:22 +08:00
ScriptInterpreter * script_interpreter = GetScriptInterpreter ( false ) ;
if ( script_interpreter )
{
if ( script_interpreter - > Interrupt ( ) )
return true ;
}
2014-05-02 08:45:31 +08:00
return false ;
}
2014-01-28 07:43:24 +08:00
void
CommandInterpreter : : GetLLDBCommandsFromIOHandler ( const char * prompt ,
IOHandlerDelegate & delegate ,
bool asynchronously ,
void * baton )
{
Debugger & debugger = GetDebugger ( ) ;
IOHandlerSP io_handler_sp ( new IOHandlerEditline ( debugger ,
2014-11-18 03:06:59 +08:00
IOHandler : : Type : : CommandList ,
2014-01-28 07:43:24 +08:00
" lldb " , // Name of input reader for history
prompt , // Prompt
2014-11-18 03:06:59 +08:00
NULL , // Continuation prompt
2014-01-28 07:43:24 +08:00
true , // Get multiple lines
2014-11-18 03:06:59 +08:00
debugger . GetUseColor ( ) ,
2014-03-07 08:53:24 +08:00
0 , // Don't show line numbers
2014-01-28 07:43:24 +08:00
delegate ) ) ; // IOHandlerDelegate
if ( io_handler_sp )
{
io_handler_sp - > SetUserData ( baton ) ;
if ( asynchronously )
debugger . PushIOHandler ( io_handler_sp ) ;
else
debugger . RunIOHandler ( io_handler_sp ) ;
}
}
void
CommandInterpreter : : GetPythonCommandsFromIOHandler ( const char * prompt ,
IOHandlerDelegate & delegate ,
bool asynchronously ,
void * baton )
{
Debugger & debugger = GetDebugger ( ) ;
IOHandlerSP io_handler_sp ( new IOHandlerEditline ( debugger ,
2014-11-18 03:06:59 +08:00
IOHandler : : Type : : PythonCode ,
2014-01-28 07:43:24 +08:00
" lldb-python " , // Name of input reader for history
prompt , // Prompt
2014-11-18 03:06:59 +08:00
NULL , // Continuation prompt
2014-01-28 07:43:24 +08:00
true , // Get multiple lines
2014-11-18 03:06:59 +08:00
debugger . GetUseColor ( ) ,
2014-03-07 08:53:24 +08:00
0 , // Don't show line numbers
2014-01-28 07:43:24 +08:00
delegate ) ) ; // IOHandlerDelegate
if ( io_handler_sp )
{
io_handler_sp - > SetUserData ( baton ) ;
if ( asynchronously )
debugger . PushIOHandler ( io_handler_sp ) ;
else
debugger . RunIOHandler ( io_handler_sp ) ;
}
}
bool
CommandInterpreter : : IsActive ( )
{
return m_debugger . IsTopIOHandler ( m_command_io_handler_sp ) ;
}
2014-11-18 03:06:59 +08:00
lldb : : IOHandlerSP
CommandInterpreter : : GetIOHandler ( bool force_create , CommandInterpreterRunOptions * options )
{
// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
// input and now it does or vice versa.
if ( force_create | | ! m_command_io_handler_sp )
{
// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
// input and now it does or vice versa.
uint32_t flags = 0 ;
if ( options )
{
if ( options - > m_stop_on_continue = = eLazyBoolYes )
flags | = eHandleCommandFlagStopOnContinue ;
if ( options - > m_stop_on_error = = eLazyBoolYes )
flags | = eHandleCommandFlagStopOnError ;
if ( options - > m_stop_on_crash = = eLazyBoolYes )
flags | = eHandleCommandFlagStopOnCrash ;
if ( options - > m_echo_commands ! = eLazyBoolNo )
flags | = eHandleCommandFlagEchoCommand ;
if ( options - > m_print_results ! = eLazyBoolNo )
flags | = eHandleCommandFlagPrintResult ;
}
else
{
flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult ;
}
m_command_io_handler_sp . reset ( new IOHandlerEditline ( m_debugger ,
IOHandler : : Type : : CommandInterpreter ,
m_debugger . GetInputFile ( ) ,
m_debugger . GetOutputFile ( ) ,
m_debugger . GetErrorFile ( ) ,
flags ,
" lldb " ,
m_debugger . GetPrompt ( ) ,
NULL , // Continuation prompt
false , // Don't enable multiple line input, just single line commands
m_debugger . GetUseColor ( ) ,
0 , // Don't show line numbers
* this ) ) ;
}
return m_command_io_handler_sp ;
}
2014-01-28 07:43:24 +08:00
void
CommandInterpreter : : RunCommandInterpreter ( bool auto_handle_events ,
2014-10-11 08:38:27 +08:00
bool spawn_thread ,
CommandInterpreterRunOptions & options )
2014-01-28 07:43:24 +08:00
{
2015-06-18 13:27:05 +08:00
// Always re-create the command interpreter when we run it in case
2014-11-18 03:06:59 +08:00
// any file handles have changed.
bool force_create = true ;
m_debugger . PushIOHandler ( GetIOHandler ( force_create , & options ) ) ;
2014-10-14 09:20:07 +08:00
m_stopped_for_crash = false ;
2014-08-01 03:46:19 +08:00
2014-01-28 07:43:24 +08:00
if ( auto_handle_events )
m_debugger . StartEventHandlerThread ( ) ;
if ( spawn_thread )
{
m_debugger . StartIOHandlerThread ( ) ;
}
else
{
2015-02-27 03:26:36 +08:00
m_debugger . ExecuteIOHandlers ( ) ;
2014-11-18 03:06:59 +08:00
2014-01-28 07:43:24 +08:00
if ( auto_handle_events )
m_debugger . StopEventHandlerThread ( ) ;
}
2014-11-18 03:06:59 +08:00
2014-01-28 07:43:24 +08:00
}
2015-04-24 04:00:25 +08:00
CommandObject *
CommandInterpreter : : ResolveCommandImpl ( std : : string & command_line , CommandReturnObject & result )
{
std : : string scratch_command ( command_line ) ; // working copy so we don't modify command_line unless we succeed
CommandObject * cmd_obj = nullptr ;
StreamString revised_command_line ;
bool wants_raw_input = false ;
size_t actual_cmd_name_len = 0 ;
std : : string next_word ;
StringList matches ;
bool done = false ;
while ( ! done )
{
char quote_char = ' \0 ' ;
std : : string suffix ;
ExtractCommand ( scratch_command , next_word , suffix , quote_char ) ;
if ( cmd_obj = = nullptr )
{
std : : string full_name ;
if ( GetAliasFullName ( next_word . c_str ( ) , full_name ) )
{
std : : string alias_result ;
cmd_obj = BuildAliasResult ( full_name . c_str ( ) , scratch_command , alias_result , result ) ;
revised_command_line . Printf ( " %s " , alias_result . c_str ( ) ) ;
if ( cmd_obj )
{
wants_raw_input = cmd_obj - > WantsRawCommandString ( ) ;
actual_cmd_name_len = strlen ( cmd_obj - > GetCommandName ( ) ) ;
}
}
else
{
cmd_obj = GetCommandObject ( next_word . c_str ( ) , & matches ) ;
if ( cmd_obj )
{
actual_cmd_name_len + = strlen ( cmd_obj - > GetCommandName ( ) ) ;
revised_command_line . Printf ( " %s " , cmd_obj - > GetCommandName ( ) ) ;
wants_raw_input = cmd_obj - > WantsRawCommandString ( ) ;
}
else
{
revised_command_line . Printf ( " %s " , next_word . c_str ( ) ) ;
}
}
}
else
{
if ( cmd_obj - > IsMultiwordObject ( ) )
{
CommandObject * sub_cmd_obj = cmd_obj - > GetSubcommandObject ( next_word . c_str ( ) ) ;
if ( sub_cmd_obj )
{
// The subcommand's name includes the parent command's name,
// so restart rather than append to the revised_command_line.
actual_cmd_name_len = strlen ( sub_cmd_obj - > GetCommandName ( ) ) + 1 ;
revised_command_line . Clear ( ) ;
revised_command_line . Printf ( " %s " , sub_cmd_obj - > GetCommandName ( ) ) ;
cmd_obj = sub_cmd_obj ;
wants_raw_input = cmd_obj - > WantsRawCommandString ( ) ;
}
else
{
if ( quote_char )
revised_command_line . Printf ( " %c%s%s%c " , quote_char , next_word . c_str ( ) , suffix . c_str ( ) , quote_char ) ;
else
revised_command_line . Printf ( " %s%s " , next_word . c_str ( ) , suffix . c_str ( ) ) ;
done = true ;
}
}
else
{
if ( quote_char )
revised_command_line . Printf ( " %c%s%s%c " , quote_char , next_word . c_str ( ) , suffix . c_str ( ) , quote_char ) ;
else
revised_command_line . Printf ( " %s%s " , next_word . c_str ( ) , suffix . c_str ( ) ) ;
done = true ;
}
}
if ( cmd_obj = = nullptr )
{
const size_t num_matches = matches . GetSize ( ) ;
if ( matches . GetSize ( ) > 1 ) {
StreamString error_msg ;
error_msg . Printf ( " Ambiguous command '%s'. Possible matches: \n " , next_word . c_str ( ) ) ;
for ( uint32_t i = 0 ; i < num_matches ; + + i ) {
error_msg . Printf ( " \t %s \n " , matches . GetStringAtIndex ( i ) ) ;
}
result . AppendRawError ( error_msg . GetString ( ) . c_str ( ) ) ;
} else {
// We didn't have only one match, otherwise we wouldn't get here.
assert ( num_matches = = 0 ) ;
result . AppendErrorWithFormat ( " '%s' is not a valid command. \n " , next_word . c_str ( ) ) ;
}
result . SetStatus ( eReturnStatusFailed ) ;
return nullptr ;
}
if ( cmd_obj - > IsMultiwordObject ( ) )
{
if ( ! suffix . empty ( ) )
{
result . AppendErrorWithFormat ( " command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid). \n " ,
cmd_obj - > GetCommandName ( ) ,
next_word . empty ( ) ? " " : next_word . c_str ( ) ,
next_word . empty ( ) ? " -- " : " " ,
suffix . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return nullptr ;
}
}
else
{
// If we found a normal command, we are done
done = true ;
if ( ! suffix . empty ( ) )
{
switch ( suffix [ 0 ] )
{
case ' / ' :
// GDB format suffixes
{
Options * command_options = cmd_obj - > GetOptions ( ) ;
if ( command_options & & command_options - > SupportsLongOption ( " gdb-format " ) )
{
std : : string gdb_format_option ( " --gdb-format= " ) ;
gdb_format_option + = ( suffix . c_str ( ) + 1 ) ;
bool inserted = false ;
std : : string & cmd = revised_command_line . GetString ( ) ;
size_t arg_terminator_idx = FindArgumentTerminator ( cmd ) ;
if ( arg_terminator_idx ! = std : : string : : npos )
{
// Insert the gdb format option before the "--" that terminates options
gdb_format_option . append ( 1 , ' ' ) ;
cmd . insert ( arg_terminator_idx , gdb_format_option ) ;
inserted = true ;
}
if ( ! inserted )
revised_command_line . Printf ( " %s " , gdb_format_option . c_str ( ) ) ;
if ( wants_raw_input & & FindArgumentTerminator ( cmd ) = = std : : string : : npos )
revised_command_line . PutCString ( " -- " ) ;
}
else
{
result . AppendErrorWithFormat ( " the '%s' command doesn't support the --gdb-format option \n " ,
cmd_obj - > GetCommandName ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return nullptr ;
}
}
break ;
default :
result . AppendErrorWithFormat ( " unknown command shorthand suffix: '%s' \n " ,
suffix . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return nullptr ;
}
}
}
if ( scratch_command . empty ( ) )
done = true ;
}
if ( ! scratch_command . empty ( ) )
revised_command_line . Printf ( " %s " , scratch_command . c_str ( ) ) ;
if ( cmd_obj ! = NULL )
command_line = revised_command_line . GetData ( ) ;
return cmd_obj ;
}