summaryrefslogtreecommitdiffstats
path: root/lldb/source/Interpreter/CommandInterpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Interpreter/CommandInterpreter.cpp')
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp1300
1 files changed, 1300 insertions, 0 deletions
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
new file mode 100644
index 00000000000..ed85b33bab3
--- /dev/null
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -0,0 +1,1300 @@
+//===-- 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>
+
+#include <getopt.h>
+#include <stdlib.h>
+
+#include "CommandObjectAdd.h"
+#include "CommandObjectAlias.h"
+#include "CommandObjectAppend.h"
+#include "CommandObjectApropos.h"
+#include "CommandObjectArgs.h"
+#include "CommandObjectBreakpoint.h"
+#include "CommandObjectCall.h"
+#include "CommandObjectDelete.h"
+#include "CommandObjectDisassemble.h"
+#include "CommandObjectExpression.h"
+#include "CommandObjectFile.h"
+#include "CommandObjectFrame.h"
+#include "CommandObjectHelp.h"
+#include "CommandObjectImage.h"
+#include "CommandObjectInfo.h"
+#include "CommandObjectLog.h"
+#include "CommandObjectMemory.h"
+#include "CommandObjectProcess.h"
+#include "CommandObjectQuit.h"
+#include "CommandObjectRegexCommand.h"
+#include "CommandObjectRegister.h"
+#include "CommandObjectRemove.h"
+#include "CommandObjectScript.h"
+#include "CommandObjectSelect.h"
+#include "CommandObjectSet.h"
+#include "CommandObjectSettings.h"
+#include "CommandObjectShow.h"
+#include "CommandObjectSource.h"
+#include "CommandObjectSourceFile.h"
+#include "CommandObjectStatus.h"
+#include "CommandObjectSyntax.h"
+#include "CommandObjectTarget.h"
+#include "CommandObjectThread.h"
+#include "CommandObjectTranslate.h"
+#include "CommandObjectUnalias.h"
+#include "CommandObjectVariable.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/TargetList.h"
+
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandInterpreter::CommandInterpreter
+(
+ ScriptLanguage script_language,
+ bool synchronous_execution,
+ Listener *listener,
+ SourceManager& source_manager
+) :
+ Broadcaster ("CommandInterpreter"),
+ m_script_language (script_language),
+ m_synchronous_execution (synchronous_execution),
+ m_listener (listener),
+ m_source_manager (source_manager)
+{
+}
+
+void
+CommandInterpreter::Initialize ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ CommandReturnObject result;
+
+ LoadCommandDictionary ();
+
+ InitializeVariables ();
+
+ // Set up some initial aliases.
+ result.Clear(); HandleCommand ("alias q quit", false, result);
+ result.Clear(); HandleCommand ("alias run process launch", false, result);
+ result.Clear(); HandleCommand ("alias r process launch", false, result);
+ result.Clear(); HandleCommand ("alias c process continue", false, result);
+ result.Clear(); HandleCommand ("alias continue process continue", false, result);
+ result.Clear(); HandleCommand ("alias expr expression", false, result);
+ result.Clear(); HandleCommand ("alias exit quit", false, result);
+ result.Clear(); HandleCommand ("alias bt thread backtrace", false, result);
+ result.Clear(); HandleCommand ("alias si thread step-inst", false, result);
+ result.Clear(); HandleCommand ("alias step thread step-in", false, result);
+ result.Clear(); HandleCommand ("alias s thread step-in", false, result);
+ result.Clear(); HandleCommand ("alias next thread step-over", false, result);
+ result.Clear(); HandleCommand ("alias n thread step-over", false, result);
+ result.Clear(); HandleCommand ("alias finish thread step-out", false, result);
+ result.Clear(); HandleCommand ("alias x memory read", false, result);
+ result.Clear(); HandleCommand ("alias l source-file", false, result);
+ result.Clear(); HandleCommand ("alias list source-file", false, result);
+}
+
+void
+CommandInterpreter::InitializeVariables ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ m_variables["prompt"] =
+ StateVariableSP (new StateVariable ("prompt",
+ "(lldb) ",
+ false,
+ "The debugger prompt displayed for the user.",
+ StateVariable::BroadcastPromptChange));
+
+ m_variables["run-args"] =
+ StateVariableSP (new StateVariable ("run-args",
+ (Args*)NULL,
+ "An argument list containing the arguments to be passed to the executable when it is launched."));
+
+
+ m_variables["env-vars"] =
+ StateVariableSP (new StateVariable ("env-vars",
+ (Args*)NULL,
+ "A list of strings containing the environment variables to be passed to the executable's environment."));
+
+ m_variables["input-path"] =
+ StateVariableSP (new StateVariable ("input-path",
+ "/dev/stdin",
+ false,
+ "The file/path to be used by the executable program for reading its input."));
+
+ m_variables["output-path"] =
+ StateVariableSP (new StateVariable ( "output-path",
+ "/dev/stdout",
+ false,
+ "The file/path to be used by the executable program for writing its output."));
+
+ m_variables["error-path"] =
+ StateVariableSP (new StateVariable ("error-path",
+ "/dev/stderr",
+ false,
+ "The file/path to be used by the executable program for writing its error messages."));
+
+ m_variables["arch"] =
+ StateVariableSP (new StateVariable ("arch",
+ "",
+ false,
+ "The architecture to be used for running the executable (e.g. i386, x86_64, etc)."));
+
+ m_variables["script-lang"] =
+ StateVariableSP (new StateVariable ("script-lang",
+ "Python",
+ false,
+ "The script language to be used for evaluating user-written scripts.",
+ StateVariable::VerifyScriptLanguage));
+
+ m_variables["term-width"] =
+ StateVariableSP (new StateVariable ("term-width",
+ 80,
+ "The maximum number of columns to use for displaying text."));
+
+}
+
+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__);
+
+ // **** IMPORTANT **** IMPORTANT *** IMPORTANT *** **** IMPORTANT **** IMPORTANT *** IMPORTANT ***
+ //
+ // Command objects that are used as cross reference objects (i.e. they inherit from CommandObjectCrossref)
+ // *MUST* be created and put into the command dictionary *BEFORE* any multi-word commands (which may use
+ // the cross-referencing stuff) are created!!!
+ //
+ // **** IMPORTANT **** IMPORTANT *** IMPORTANT *** **** IMPORTANT **** IMPORTANT *** IMPORTANT ***
+
+
+ // Command objects that inherit from CommandObjectCrossref must be created before other command objects
+ // are created. This is so that when another command is created that needs to go into a crossref object,
+ // the crossref object exists and is ready to take the cross reference. Put the cross referencing command
+ // objects into the CommandDictionary now, so they are ready for use when the other commands get created.
+
+ m_command_dict["select"] = CommandObjectSP (new CommandObjectSelect ());
+ m_command_dict["info"] = CommandObjectSP (new CommandObjectInfo ());
+ m_command_dict["delete"] = CommandObjectSP (new CommandObjectDelete ());
+
+ // Non-CommandObjectCrossref commands can now be created.
+
+ //m_command_dict["add"] = CommandObjectSP (new CommandObjectAdd ());
+ m_command_dict["alias"] = CommandObjectSP (new CommandObjectAlias ());
+ m_command_dict["append"] = CommandObjectSP (new CommandObjectAppend ());
+ m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos ());
+ //m_command_dict["args"] = CommandObjectSP (new CommandObjectArgs ());
+ m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (this));
+ m_command_dict["call"] = CommandObjectSP (new CommandObjectCall ());
+ m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble ());
+ m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression ());
+ m_command_dict["file"] = CommandObjectSP (new CommandObjectFile ());
+ m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (this));
+ m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp ());
+ m_command_dict["image"] = CommandObjectSP (new CommandObjectImage (this));
+ m_command_dict["log"] = CommandObjectSP (new CommandObjectLog (this));
+ m_command_dict["memory"] = CommandObjectSP (new CommandObjectMemory (this));
+ m_command_dict["process"] = CommandObjectSP (new CommandObjectMultiwordProcess (this));
+ m_command_dict["quit"] = CommandObjectSP (new CommandObjectQuit ());
+ m_command_dict["register"] = CommandObjectSP (new CommandObjectRegister (this));
+ //m_command_dict["remove"] = CommandObjectSP (new CommandObjectRemove ());
+ m_command_dict["script"] = CommandObjectSP (new CommandObjectScript (m_script_language));
+ m_command_dict["set"] = CommandObjectSP (new CommandObjectSet ());
+ m_command_dict["settings"] = CommandObjectSP (new CommandObjectSettings ());
+ m_command_dict["show"] = CommandObjectSP (new CommandObjectShow ());
+ m_command_dict["source"] = CommandObjectSP (new CommandObjectSource ());
+ m_command_dict["source-file"] = CommandObjectSP (new CommandObjectSourceFile ());
+ //m_command_dict["syntax"] = CommandObjectSP (new CommandObjectSyntax ());
+ m_command_dict["status"] = CommandObjectSP (new CommandObjectStatus ());
+ m_command_dict["target"] = CommandObjectSP (new CommandObjectMultiwordTarget (this));
+ m_command_dict["thread"] = CommandObjectSP (new CommandObjectMultiwordThread (this));
+ //m_command_dict["translate"] = CommandObjectSP (new CommandObjectTranslate ());
+ m_command_dict["unalias"] = CommandObjectSP (new CommandObjectUnalias ());
+ m_command_dict["variable"] = CommandObjectSP (new CommandObjectVariable (this));
+
+ std::auto_ptr<CommandObjectRegexCommand>
+ break_regex_cmd_ap(new CommandObjectRegexCommand ("regexp-break",
+ "Smart breakpoint command (using regular expressions).",
+ "regexp-break [<file>:<line>]\nregexp-break [<address>]\nregexp-break <...>", 2));
+ if (break_regex_cmd_ap.get())
+ {
+ if (break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2") &&
+ break_regex_cmd_ap->AddRegexCommand("^(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1") &&
+ break_regex_cmd_ap->AddRegexCommand("^[\"']?([-+]\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'") &&
+ break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list") &&
+ break_regex_cmd_ap->AddRegexCommand("^(-.*)$", "breakpoint set %1") &&
+ break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'"))
+ {
+ CommandObjectSP break_regex_cmd_sp(break_regex_cmd_ap.release());
+ m_command_dict[break_regex_cmd_sp->GetCommandName ()] = break_regex_cmd_sp;
+ }
+ }
+}
+
+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;
+ CommandObjectSP ret_val;
+
+ std::string cmd(cmd_cstr);
+
+ if (HasCommands())
+ {
+ pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ ret_val = pos->second;
+ }
+
+ if (include_aliases && HasAliases())
+ {
+ pos = m_alias_dict.find(cmd);
+ if (pos != m_alias_dict.end())
+ ret_val = pos->second;
+ }
+
+ if (HasUserCommands())
+ {
+ pos = m_user_dict.find(cmd);
+ if (pos != m_user_dict.end())
+ ret_val = pos->second;
+ }
+
+ if (!exact && ret_val == NULL)
+ {
+ StringList local_matches;
+ if (matches == NULL)
+ matches = &local_matches;
+
+ int num_cmd_matches = 0;
+ int num_alias_matches = 0;
+ int num_user_matches = 0;
+ 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())
+ ret_val = pos->second;
+ }
+
+ if (num_cmd_matches != 1 && include_aliases && HasAliases())
+ {
+ num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_cstr, *matches);
+
+ }
+
+ if (num_alias_matches == 1)
+ {
+ cmd.assign(matches->GetStringAtIndex (num_cmd_matches));
+ pos = m_alias_dict.find(cmd);
+ if (pos != m_alias_dict.end())
+ {
+ matches->Clear();
+ matches->AppendString (cmd.c_str());
+
+ ret_val = pos->second;
+ }
+ }
+
+ if (num_cmd_matches != 1 && num_alias_matches != 1 && HasUserCommands())
+ {
+ num_user_matches = CommandObject::AddNamesMatchingPartialString (m_user_dict, cmd_cstr, *matches);
+ }
+
+ if (num_user_matches == 1)
+ {
+ cmd.assign (matches->GetStringAtIndex (num_cmd_matches + num_alias_matches));
+
+ pos = m_user_dict.find (cmd);
+ if (pos != m_user_dict.end())
+ {
+ matches->Clear();
+ matches->AppendString (cmd.c_str());
+
+ ret_val = pos->second;
+ }
+ }
+ }
+ else {
+ if (matches)
+ matches->AppendString (cmd_cstr);
+ }
+
+
+ return ret_val;
+}
+
+CommandObject *
+CommandInterpreter::GetCommandObject (const char *cmd_cstr, bool include_aliases, bool exact, StringList *matches)
+{
+ return GetCommandSP (cmd_cstr, include_aliases, exact, matches).get();
+}
+
+bool
+CommandInterpreter::CommandExists (const char *cmd)
+{
+ return m_command_dict.find(cmd) != m_command_dict.end();
+}
+
+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)
+{
+ 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;
+}
+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;
+}
+
+StateVariable *
+CommandInterpreter::GetStateVariable(const char *name)
+{
+ VariableMap::const_iterator pos = m_variables.find(name);
+ if (pos != m_variables.end())
+ return pos->second.get();
+ return NULL;
+}
+
+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);
+
+ if (option_arg_vector_sp != NULL)
+ {
+ OptionArgVector *options = option_arg_vector_sp.get();
+ for (int i = 0; i < options->size(); ++i)
+ {
+ OptionArgPair cur_option = (*options)[i];
+ std::string opt = cur_option.first;
+ std::string value = cur_option.second;
+ 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 ("'");
+}
+
+std::string
+CommandInterpreter::FindLongestCommandWord (CommandObject::CommandMap &dict)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ int max_len = 0;
+ CommandObjectSP cmd_sp;
+ std::string longest_word;
+
+ for (pos = dict.begin(); pos != dict.end(); ++pos)
+ {
+ if ((max_len == 0)
+ || (strlen (pos->first.c_str()) > max_len))
+ {
+ longest_word = pos->first;
+ max_len = strlen (longest_word.c_str());
+ }
+ }
+
+ return longest_word;
+}
+
+void
+CommandInterpreter::GetHelp (CommandReturnObject &result)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ result.AppendMessage("The following is a list of built-in, permanent debugger commands:");
+ result.AppendMessage("");
+ std::string longest_word = FindLongestCommandWord (m_command_dict);
+ uint32_t max_len = strlen (longest_word.c_str());
+
+ for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos)
+ {
+ OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", pos->second->GetHelp(),
+ max_len);
+ }
+ result.AppendMessage("");
+
+ if (m_alias_dict.size() > 0)
+ {
+ result.AppendMessage("The following is a list of your current command abbreviations (see 'alias' for more info):");
+ result.AppendMessage("");
+ longest_word = FindLongestCommandWord (m_alias_dict);
+ max_len = strlen (longest_word.c_str());
+ 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("");
+ }
+
+ if (m_user_dict.size() > 0)
+ {
+ result.AppendMessage ("The following is a list of your current user-defined commands:");
+ result.AppendMessage("");
+ for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos)
+ {
+ result.AppendMessageWithFormat ("%s -- %s\n", pos->first.c_str(), pos->second->GetHelp());
+ }
+ result.AppendMessage("");
+ }
+
+ result.AppendMessage("For more information on any particular command, try 'help <command-name>'.");
+}
+
+void
+CommandInterpreter::ShowVariableValues (CommandReturnObject &result)
+{
+ result.AppendMessage ("Below is a list of all the debugger setting variables and their values:");
+
+ for (VariableMap::const_iterator pos = m_variables.begin(); pos != m_variables.end(); ++pos)
+ {
+ StateVariable *var = pos->second.get();
+ var->AppendVariableInformation (result);
+ }
+}
+
+void
+CommandInterpreter::ShowVariableHelp (CommandReturnObject &result)
+{
+ result.AppendMessage ("Below is a list of all the internal debugger variables that are settable:");
+ for (VariableMap::const_iterator pos = m_variables.begin(); pos != m_variables.end(); ++pos)
+ {
+ StateVariable *var = pos->second.get();
+ result.AppendMessageWithFormat (" %s -- %s \n", var->GetName(), var->GetHelp());
+ }
+}
+
+// Main entry point into the command_interpreter; this function takes a text
+// line containing a debugger command, with all its flags, options, etc,
+// parses the line and takes the appropriate actions.
+
+bool
+CommandInterpreter::HandleCommand (const char *command_line, bool add_to_history, CommandReturnObject &result,
+ ExecutionContext *override_context)
+{
+ // FIXME: there should probably be a mutex to make sure only one thread can
+ // run the interpreter at a time.
+
+ // TODO: this should be a logging channel in lldb.
+// if (DebugSelf())
+// {
+// result.AppendMessageWithFormat ("Processing command: %s\n", command_line);
+// }
+
+ m_current_context.Update (override_context);
+
+ if (command_line == NULL || command_line[0] == '\0')
+ {
+ if (m_command_history.empty())
+ {
+ result.AppendError ("empty command");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ command_line = m_command_history.back().c_str();
+ }
+ add_to_history = false;
+ }
+
+ Args command_args(command_line);
+
+ if (command_args.GetArgumentCount() > 0)
+ {
+ const char *command_cstr = command_args.GetArgumentAtIndex(0);
+ if (command_cstr)
+ {
+
+ // We're looking up the command object here. So first find an exact match to the
+ // command in the commands.
+
+ CommandObject *command_obj = GetCommandObject (command_cstr, false, true);
+
+ // If we didn't find an exact match to the command string in the commands, look in
+ // the aliases.
+
+ if (command_obj == NULL)
+ {
+ command_obj = GetCommandObject (command_cstr, true, true);
+ if (command_obj != NULL)
+ {
+ BuildAliasCommandArgs (command_obj, command_cstr, command_args, result);
+ if (!result.Succeeded())
+ return false;
+ }
+ }
+
+ // Finally, if there wasn't an exact match among the aliases, look for an inexact match.
+
+ if (command_obj == NULL)
+ command_obj = GetCommandObject(command_cstr, false, false);
+
+ if (command_obj)
+ {
+ if (command_obj->WantsRawCommandString())
+ {
+ const char *stripped_command = ::strstr (command_line, command_cstr);
+ if (stripped_command)
+ {
+ stripped_command += strlen(command_cstr);
+ while (isspace(*stripped_command))
+ ++stripped_command;
+ command_obj->ExecuteRawCommandString(stripped_command, Context(), this, result);
+ }
+ }
+ else
+ {
+ if (add_to_history)
+ m_command_history.push_back (command_line);
+
+ // Remove the command from the args.
+ command_args.Shift();
+ command_obj->ExecuteWithOptions (command_args, Context(), this, result);
+ }
+ }
+ else
+ {
+ StringList matches;
+ int num_matches;
+ int cursor_index = command_args.GetArgumentCount() - 1;
+ int cursor_char_position = strlen (command_args.GetArgumentAtIndex(command_args.GetArgumentCount() - 1));
+ num_matches = HandleCompletionMatches (command_args, cursor_index,
+ cursor_char_position,
+ 0, -1, matches);
+
+ if (num_matches > 0)
+ {
+ std::string error_msg;
+ error_msg.assign ("ambiguous command '");
+ error_msg.append(command_cstr);
+ 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));
+ }
+ error_msg.append ("\n");
+ result.AppendRawError (error_msg.c_str(), error_msg.size());
+ }
+ else
+ result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_cstr);
+
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ return result.Succeeded();
+}
+
+int
+CommandInterpreter::HandleCompletionMatches (Args &parsed_line,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches)
+{
+ int num_command_matches = 0;
+ bool include_aliases = true;
+ bool look_for_subcommand = false;
+
+ if (cursor_index == -1)
+ {
+ // We got nothing on the command line, so return the list of commands
+ 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.
+ CommandObject *cmd_obj = GetCommandObject (parsed_line.GetArgumentAtIndex(0), include_aliases, false,
+ &matches);
+ num_command_matches = matches.GetSize();
+
+ if (num_command_matches == 1
+ && cmd_obj && cmd_obj->IsMultiwordObject()
+ && matches.GetStringAtIndex(0) != NULL
+ && strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
+ {
+ look_for_subcommand = true;
+ num_command_matches = 0;
+ matches.DeleteStringAtIndex(0);
+ parsed_line.AppendArgument ("");
+ cursor_index++;
+ cursor_char_position = 0;
+ }
+ }
+
+ 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:
+ CommandObject *command_object = GetCommandObject (parsed_line.GetArgumentAtIndex(0), include_aliases, false);
+ if (command_object == NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ parsed_line.Shift();
+ cursor_index--;
+ num_command_matches = command_object->HandleCompletion (parsed_line, cursor_index, cursor_char_position,
+ match_start_point, max_return_elements, this,
+ 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.
+
+ Args parsed_line(current_line, last_char - current_line);
+ Args partial_parsed_line(current_line, cursor - current_line);
+
+ 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));
+
+ int num_command_matches;
+
+ matches.Clear();
+
+ // Only max_return_elements == -1 is supported at present:
+ assert (max_return_elements == -1);
+ num_command_matches = HandleCompletionMatches (parsed_line, cursor_index, cursor_char_position, match_start_point,
+ max_return_elements, matches);
+
+ if (num_command_matches <= 0)
+ return num_command_matches;
+
+ 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)
+ command_partial_str.assign(parsed_line.GetArgumentAtIndex(cursor_index), parsed_line.GetArgumentAtIndex(cursor_index) + cursor_char_position);
+
+ std::string common_prefix;
+ matches.LongestCommonPrefix (common_prefix);
+ int partial_name_len = command_partial_str.size();
+
+ // If we matched a unique single command, add a space...
+ if (num_command_matches == 1)
+ {
+ char quote_char = parsed_line.GetArgumentQuoteCharAtIndex(cursor_index);
+ if (quote_char != '\0')
+ common_prefix.push_back(quote_char);
+
+ common_prefix.push_back(' ');
+ }
+ common_prefix.erase (0, partial_name_len);
+ matches.InsertStringAtIndex(0, common_prefix.c_str());
+ }
+ return num_command_matches;
+}
+
+CommandContext *
+CommandInterpreter::Context ()
+{
+ return &m_current_context;
+}
+
+const Args *
+CommandInterpreter::GetProgramArguments ()
+{
+ if (! HasInterpreterVariables())
+ return NULL;
+
+ VariableMap::const_iterator pos = m_variables.find("run-args");
+ if (pos == m_variables.end())
+ return NULL;
+
+ StateVariable *var = pos->second.get();
+
+ if (var)
+ return &var->GetArgs();
+ return NULL;
+}
+
+const Args *
+CommandInterpreter::GetEnvironmentVariables ()
+{
+ if (! HasInterpreterVariables())
+ return NULL;
+
+ VariableMap::const_iterator pos = m_variables.find("env-vars");
+ if (pos == m_variables.end())
+ return NULL;
+
+ StateVariable *var = pos->second.get();
+ if (var)
+ return &var->GetArgs();
+ return NULL;
+}
+
+
+CommandInterpreter::~CommandInterpreter ()
+{
+}
+
+const char *
+CommandInterpreter::GetPrompt ()
+{
+ VariableMap::iterator pos;
+
+ if (! HasInterpreterVariables())
+ return NULL;
+
+ pos = m_variables.find("prompt");
+ if (pos == m_variables.end())
+ return NULL;
+
+ StateVariable *var = pos->second.get();
+
+ return ((char *) var->GetStringValue());
+}
+
+void
+CommandInterpreter::SetPrompt (const char *new_prompt)
+{
+ VariableMap::iterator pos;
+ CommandReturnObject result;
+
+ if (! HasInterpreterVariables())
+ return;
+
+ pos = m_variables.find ("prompt");
+ if (pos == m_variables.end())
+ return;
+
+ StateVariable *var = pos->second.get();
+
+ if (var->VerifyValue (this, (void *) new_prompt, result))
+ var->SetStringValue (new_prompt);
+}
+
+void
+CommandInterpreter::CrossRegisterCommand (const char * dest_cmd, const char * object_type)
+{
+ CommandObjectSP cmd_obj_sp = GetCommandSP (dest_cmd);
+
+ if (cmd_obj_sp != NULL)
+ {
+ CommandObject *cmd_obj = cmd_obj_sp.get();
+ if (cmd_obj->IsCrossRefObject ())
+ cmd_obj->AddObject (object_type);
+ }
+}
+
+void
+CommandInterpreter::SetScriptLanguage (ScriptLanguage lang)
+{
+ m_script_language = lang;
+}
+
+Listener *
+CommandInterpreter::GetListener ()
+{
+ return m_listener;
+}
+
+SourceManager &
+CommandInterpreter::GetSourceManager ()
+{
+ return m_source_manager;
+}
+
+
+
+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());
+}
+
+bool
+CommandInterpreter::HasInterpreterVariables ()
+{
+ return (!m_variables.empty());
+}
+
+void
+CommandInterpreter::BuildAliasCommandArgs
+(
+ CommandObject *alias_cmd_obj,
+ const char *alias_name,
+ Args &cmd_args,
+ CommandReturnObject &result
+)
+{
+ OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name);
+
+ if (option_arg_vector_sp.get())
+ {
+ // 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();
+
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+ int old_size = cmd_args.GetArgumentCount();
+ int *used = (int *) malloc ((old_size + 1) * sizeof (int));
+
+ memset (used, 0, (old_size + 1) * sizeof (int));
+ used[0] = 1;
+
+ for (int i = 0; i < option_arg_vector->size(); ++i)
+ {
+ OptionArgPair option_pair = (*option_arg_vector)[i];
+ std::string option = option_pair.first;
+ std::string value = option_pair.second;
+ if (option.compare ("<argument>") == 0)
+ new_args.AppendArgument (value.c_str());
+ else
+ {
+ new_args.AppendArgument (option.c_str());
+ if (value.compare ("<no-argument>") != 0)
+ {
+ int index = GetOptionArgumentPosition (value.c_str());
+ if (index == 0)
+ // value was NOT a positional argument; must be a real value
+ new_args.AppendArgument (value.c_str());
+ else if (index >= cmd_args.GetArgumentCount())
+ {
+ result.AppendErrorWithFormat
+ ("Not enough arguments provided; you need at least %d arguments to use this alias.\n",
+ index);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ else
+ {
+ new_args.AppendArgument (cmd_args.GetArgumentAtIndex (index));
+ used[index] = 1;
+ }
+ }
+ }
+ }
+
+ for (int j = 0; j < cmd_args.GetArgumentCount(); ++j)
+ {
+ if (!used[j])
+ new_args.AppendArgument (cmd_args.GetArgumentAtIndex (j));
+ }
+
+ cmd_args.Clear();
+ cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector());
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ // This alias was not created with any options; nothing further needs to be done.
+ 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.
+
+ char *cptr = (char *) in_string;
+
+ // 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)
+{
+ const char *init_file_path = in_cwd ? "./.lldbinit" : "~/.lldbinit";
+ FileSpec init_file (init_file_path);
+ // 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())
+ {
+ char path[PATH_MAX];
+ init_file.GetPath(path, sizeof(path));
+ StreamString source_command;
+ source_command.Printf ("source '%s'", path);
+ HandleCommand (source_command.GetData(), false, result);
+ }
+ else
+ {
+ // nothing to be done if the file doesn't exist
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+}
+
+ScriptInterpreter *
+CommandInterpreter::GetScriptInterpreter ()
+{
+ CommandObject::CommandMap::iterator pos;
+
+ pos = m_command_dict.find ("script");
+ if (pos != m_command_dict.end())
+ {
+ CommandObject *script_cmd_obj = pos->second.get();
+ return ((CommandObjectScript *) script_cmd_obj)->GetInterpreter ();
+ }
+ else
+ return NULL;
+}
+
+
+
+bool
+CommandInterpreter::GetSynchronous ()
+{
+ return m_synchronous_execution;
+}
+
+void
+CommandInterpreter::SetSynchronous (bool value)
+{
+ static bool value_set_once = false;
+ if (!value_set_once)
+ {
+ value_set_once = true;
+ m_synchronous_execution = value;
+ }
+}
+
+void
+CommandInterpreter::OutputFormattedHelpText (Stream &strm,
+ const char *word_text,
+ const char *separator,
+ const char *help_text,
+ uint32_t max_word_len)
+{
+ StateVariable *var = GetStateVariable ("term-width");
+ int max_columns = var->GetIntValue();
+ // Sanity check max_columns, to cope with emacs shell mode with TERM=dumb
+ // (0 rows; 0 columns;).
+ if (max_columns <= 0) max_columns = 80;
+
+ int indent_size = max_word_len + strlen (separator) + 2;
+
+ strm.IndentMore (indent_size);
+
+ int len = indent_size + strlen (help_text) + 1;
+ char *text = (char *) malloc (len);
+ sprintf (text, "%-*s %s %s", max_word_len, word_text, separator, help_text);
+ if (text[len - 1] == '\n')
+ text[--len] = '\0';
+
+ if (len < max_columns)
+ {
+ // Output it as a single line.
+ strm.Printf ("%s", text);
+ }
+ else
+ {
+ // We need to break it up into multiple lines.
+ bool first_line = true;
+ int text_width;
+ int start = 0;
+ int end = start;
+ int final_end = strlen (text);
+ int sub_len;
+
+ while (end < final_end)
+ {
+ if (first_line)
+ text_width = max_columns - 1;
+ else
+ text_width = max_columns - indent_size - 1;
+
+ // Don't start the 'text' on a space, since we're already outputting the indentation.
+ if (!first_line)
+ {
+ while ((start < final_end) && (text[start] == ' '))
+ start++;
+ }
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else
+ {
+ // If we're not at the end of the text, make sure we break the line on white space.
+ while (end > start
+ && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ end--;
+ }
+
+ sub_len = end - start;
+ if (start != 0)
+ strm.EOL();
+ if (!first_line)
+ strm.Indent();
+ else
+ first_line = false;
+ assert (start <= final_end);
+ assert (start + sub_len <= final_end);
+ if (sub_len > 0)
+ strm.Write (text + start, sub_len);
+ start = end + 1;
+ }
+ }
+ strm.EOL();
+ strm.IndentLess(indent_size);
+ free (text);
+}
+
+void
+CommandInterpreter::AproposAllSubCommands (CommandObject *cmd_obj, const char *prefix, const char *search_word,
+ StringList &commands_found, StringList &commands_help)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ CommandObject::CommandMap sub_cmd_dict = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict;
+ CommandObject *sub_cmd_obj;
+
+ for (pos = sub_cmd_dict.begin(); pos != sub_cmd_dict.end(); ++pos)
+ {
+ const char * command_name = pos->first.c_str();
+ sub_cmd_obj = pos->second.get();
+ StreamString complete_command_name;
+
+ complete_command_name.Printf ("%s %s", prefix, command_name);
+
+ if (sub_cmd_obj->HelpTextContainsWord (search_word))
+ {
+ commands_found.AppendString (complete_command_name.GetData());
+ commands_help.AppendString (sub_cmd_obj->GetHelp());
+ }
+
+ if (sub_cmd_obj->IsMultiwordObject())
+ AproposAllSubCommands (sub_cmd_obj, complete_command_name.GetData(), search_word, commands_found,
+ commands_help);
+ }
+
+}
+
+void
+CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList &commands_found,
+ StringList &commands_help)
+{
+ CommandObject::CommandMap::const_iterator pos;
+
+ for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos)
+ {
+ 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())
+ AproposAllSubCommands (cmd_obj, command_name, search_word, commands_found, commands_help);
+
+ }
+}
OpenPOWER on IntegriCloud