//===-- 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 #include #include #include #include "../Commands/CommandObjectApropos.h" #include "../Commands/CommandObjectArgs.h" #include "../Commands/CommandObjectBreakpoint.h" //#include "../Commands/CommandObjectCall.h" #include "../Commands/CommandObjectDisassemble.h" #include "../Commands/CommandObjectExpression.h" #include "../Commands/CommandObjectFile.h" #include "../Commands/CommandObjectFrame.h" #include "../Commands/CommandObjectHelp.h" #include "../Commands/CommandObjectImage.h" #include "../Commands/CommandObjectLog.h" #include "../Commands/CommandObjectMemory.h" #include "../Commands/CommandObjectProcess.h" #include "../Commands/CommandObjectQuit.h" #include "lldb/Interpreter/CommandObjectRegexCommand.h" #include "../Commands/CommandObjectRegister.h" #include "CommandObjectScript.h" #include "../Commands/CommandObjectSettings.h" #include "../Commands/CommandObjectSource.h" #include "../Commands/CommandObjectCommands.h" #include "../Commands/CommandObjectSyntax.h" #include "../Commands/CommandObjectTarget.h" #include "../Commands/CommandObjectThread.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/InputReader.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 ( Debugger &debugger, ScriptLanguage script_language, bool synchronous_execution ) : Broadcaster ("CommandInterpreter"), m_debugger (debugger), m_synchronous_execution (synchronous_execution), m_skip_lldbinit_files (false) { const char *dbg_name = debugger.GetInstanceName().AsCString(); std::string lang_name = ScriptInterpreter::LanguageToString (script_language); StreamString var_name; var_name.Printf ("[%s].script-lang", dbg_name); debugger.GetSettingsController()->SetVariable (var_name.GetData(), lang_name.c_str(), lldb::eVarSetOperationAssign, false, m_debugger.GetInstanceName().AsCString()); } void CommandInterpreter::Initialize () { Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); CommandReturnObject result; LoadCommandDictionary (); // Set up some initial aliases. result.Clear(); HandleCommand ("command alias q quit", false, result); result.Clear(); HandleCommand ("command alias run process launch", false, result); result.Clear(); HandleCommand ("command alias r process launch", false, result); result.Clear(); HandleCommand ("command alias c process continue", false, result); result.Clear(); HandleCommand ("command alias continue process continue", false, result); result.Clear(); HandleCommand ("command alias expr expression", false, result); result.Clear(); HandleCommand ("command alias exit quit", false, result); result.Clear(); HandleCommand ("command alias b regexp-break", false, result); result.Clear(); HandleCommand ("command alias bt thread backtrace", false, result); result.Clear(); HandleCommand ("command alias si thread step-inst", false, result); result.Clear(); HandleCommand ("command alias step thread step-in", false, result); result.Clear(); HandleCommand ("command alias s thread step-in", false, result); result.Clear(); HandleCommand ("command alias next thread step-over", false, result); result.Clear(); HandleCommand ("command alias n thread step-over", false, result); result.Clear(); HandleCommand ("command alias finish thread step-out", false, result); result.Clear(); HandleCommand ("command alias x memory read", false, result); result.Clear(); HandleCommand ("command alias l source list", false, result); result.Clear(); HandleCommand ("command alias list source list", false, result); result.Clear(); HandleCommand ("command alias p frame variable", false, result); result.Clear(); HandleCommand ("command alias print frame variable", false, result); } 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. // Non-CommandObjectCrossref commands can now be created. lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage(); m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos (*this)); m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this)); //m_command_dict["call"] = CommandObjectSP (new CommandObjectCall (*this)); m_command_dict["commands"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this)); m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this)); m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this)); m_command_dict["file"] = CommandObjectSP (new CommandObjectFile (*this)); m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (*this)); m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp (*this)); 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 (*this)); m_command_dict["register"] = CommandObjectSP (new CommandObjectRegister (*this)); m_command_dict["script"] = CommandObjectSP (new CommandObjectScript (*this, script_language)); m_command_dict["settings"] = CommandObjectSP (new CommandObjectMultiwordSettings (*this)); m_command_dict["source"] = CommandObjectSP (new CommandObjectMultiwordSource (*this)); m_command_dict["target"] = CommandObjectSP (new CommandObjectMultiwordTarget (*this)); m_command_dict["thread"] = CommandObjectSP (new CommandObjectMultiwordThread (*this)); std::auto_ptr break_regex_cmd_ap(new CommandObjectRegexCommand (*this, "regexp-break", "Set a breakpoint using a regular expression to specify the location.", "regexp-break [:]\nregexp-break [
]\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) { // We will only get into here if we didn't find any exact matches. CommandObjectSP user_match_sp, alias_match_sp, real_match_sp; StringList local_matches; if (matches == NULL) matches = &local_matches; 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. 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()) real_match_sp = pos->second; } if (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()) alias_match_sp = pos->second; } if (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()) 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; } } else if (matches && ret_val != NULL) { matches->AppendString (cmd_cstr); } return ret_val; } CommandObjectSP CommandInterpreter::GetCommandSPExact (const char *cmd_cstr, bool include_aliases) { return GetCommandSP(cmd_cstr, include_aliases, true, NULL); } CommandObject * CommandInterpreter::GetCommandObjectExact (const char *cmd_cstr, bool include_aliases) { 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. if (command_obj == NULL) { command_obj = GetCommandSP (cmd_cstr, true, true, matches).get(); } // Finally, if there wasn't an exact match among the aliases, look for an inexact match // in both the commands and the aliases. if (command_obj == NULL) command_obj = GetCommandSP(cmd_cstr, true, false, matches).get(); return command_obj; } 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) { command_obj_sp->SetIsAlias (true); 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; } 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("") == 0) { help_string.Printf (" %s", value.c_str()); } else { help_string.Printf (" %s", opt.c_str()); if ((value.compare ("") != 0) && (value.compare ("first.size(); if (max_len < len) max_len = len; } return max_len; } 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(""); uint32_t max_len = FindLongestCommandWord (m_command_dict); 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 'help commands alias' for more info):"); result.AppendMessage(""); max_len = FindLongestCommandWord (m_alias_dict); 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 '."); } 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_debugger.UpdateExecutionContext (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_repeat_command.c_str(); if (m_repeat_command.empty()) { result.AppendErrorWithFormat("No auto repeat.\n"); result.SetStatus (eReturnStatusFailed); return false; } } 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); if (command_obj != NULL) { if (command_obj->IsAlias()) { BuildAliasCommandArgs (command_obj, command_cstr, command_args, result); if (!result.Succeeded()) return false; } if (add_to_history) { const char *repeat_command = command_obj->GetRepeatCommand(command_args, 0); if (repeat_command != NULL) m_repeat_command.assign(repeat_command); else m_repeat_command.assign(command_line); m_command_history.push_back (command_line); } 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, result); } } else { // Remove the command from the args. command_args.Shift(); command_obj->ExecuteWithOptions (command_args, result); } } else { // We didn't find the first command object, so complete the first argument. 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_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, bool &word_complete, StringList &matches) { int num_command_matches = 0; bool look_for_subcommand = false; // For any of the command completions a unique match will be a complete word. word_complete = true; if (cursor_index == -1) { // We got nothing on the command line, so return the list of commands bool include_aliases = true; 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), &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)); 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, word_complete, 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); bool word_complete; num_command_matches = HandleCompletionMatches (parsed_line, cursor_index, cursor_char_position, match_start_point, max_return_elements, word_complete, 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... // Only do this if the completer told us this was a complete word, however... if (num_command_matches == 1 && word_complete) { 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; } CommandInterpreter::~CommandInterpreter () { } const char * CommandInterpreter::GetPrompt () { return m_debugger.GetPrompt(); } void CommandInterpreter::SetPrompt (const char *new_prompt) { m_debugger.SetPrompt (new_prompt); } size_t CommandInterpreter::GetConfirmationInputReaderCallback (void *baton, InputReader &reader, lldb::InputReaderAction action, const char *bytes, size_t bytes_len) { FILE *out_fh = reader.GetDebugger().GetOutputFileHandle(); bool *response_ptr = (bool *) baton; switch (action) { case eInputReaderActivate: if (out_fh) { if (reader.GetPrompt()) ::fprintf (out_fh, "%s", reader.GetPrompt()); } break; case eInputReaderDeactivate: break; case eInputReaderReactivate: if (out_fh && reader.GetPrompt()) ::fprintf (out_fh, "%s", reader.GetPrompt()); break; case eInputReaderGotToken: if (bytes_len == 0) { reader.SetIsDone(true); } else if (bytes[0] == 'y') { *response_ptr = true; reader.SetIsDone(true); } else if (bytes[0] == 'n') { *response_ptr = false; reader.SetIsDone(true); } else { if (out_fh && !reader.IsDone() && reader.GetPrompt()) { ::fprintf (out_fh, "Please answer \"y\" or \"n\"\n"); ::fprintf (out_fh, "%s", reader.GetPrompt()); } } break; case eInputReaderDone: break; } return bytes_len; } bool CommandInterpreter::Confirm (const char *message, bool default_answer) { // Check AutoConfirm first: if (m_debugger.GetAutoConfirm()) return default_answer; InputReaderSP reader_sp (new InputReader(GetDebugger())); bool response = default_answer; if (reader_sp) { std::string prompt(message); prompt.append(": ["); if (default_answer) prompt.append ("Y/n] "); else prompt.append ("y/N] "); Error err (reader_sp->Initialize (CommandInterpreter::GetConfirmationInputReaderCallback, &response, // baton eInputReaderGranularityLine, // token size, to pass to callback function NULL, // end token prompt.c_str(), // prompt true)); // echo input if (err.Success()) { GetDebugger().PushInputReader (reader_sp); } reader_sp->WaitOnReaderIsDone(); } return response; } void CommandInterpreter::CrossRegisterCommand (const char * dest_cmd, const char * object_type) { CommandObjectSP cmd_obj_sp = GetCommandSPExact (dest_cmd, true); if (cmd_obj_sp != NULL) { CommandObject *cmd_obj = cmd_obj_sp.get(); if (cmd_obj->IsCrossRefObject ()) cmd_obj->AddObject (object_type); } } 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 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(); std::vector used (old_size + 1, false); used[0] = true; 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 ("") == 0) new_args.AppendArgument (value.c_str()); else { new_args.AppendArgument (option.c_str()); if (value.compare ("") != 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] = true; } } } } 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) { // Don't parse any .lldbinit files if we were asked not to if (m_skip_lldbinit_files) return; 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 ("command 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 (); } 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) { const uint32_t max_columns = m_debugger.GetTerminalWidth(); 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); } }