15ffd83dbSDimitry Andric //===-- CommandInterpreter.cpp --------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 9*0fca6ea1SDimitry Andric #include <chrono> 10fe6060f1SDimitry Andric #include <cstdlib> 11e8d8bef9SDimitry Andric #include <limits> 120b57cec5SDimitry Andric #include <memory> 13bdd1243dSDimitry Andric #include <optional> 140b57cec5SDimitry Andric #include <string> 150b57cec5SDimitry Andric #include <vector> 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "Commands/CommandObjectApropos.h" 180b57cec5SDimitry Andric #include "Commands/CommandObjectBreakpoint.h" 190b57cec5SDimitry Andric #include "Commands/CommandObjectCommands.h" 20bdd1243dSDimitry Andric #include "Commands/CommandObjectDWIMPrint.h" 21bdd1243dSDimitry Andric #include "Commands/CommandObjectDiagnostics.h" 220b57cec5SDimitry Andric #include "Commands/CommandObjectDisassemble.h" 230b57cec5SDimitry Andric #include "Commands/CommandObjectExpression.h" 240b57cec5SDimitry Andric #include "Commands/CommandObjectFrame.h" 250b57cec5SDimitry Andric #include "Commands/CommandObjectGUI.h" 260b57cec5SDimitry Andric #include "Commands/CommandObjectHelp.h" 270b57cec5SDimitry Andric #include "Commands/CommandObjectLanguage.h" 280b57cec5SDimitry Andric #include "Commands/CommandObjectLog.h" 290b57cec5SDimitry Andric #include "Commands/CommandObjectMemory.h" 300b57cec5SDimitry Andric #include "Commands/CommandObjectPlatform.h" 310b57cec5SDimitry Andric #include "Commands/CommandObjectPlugin.h" 320b57cec5SDimitry Andric #include "Commands/CommandObjectProcess.h" 330b57cec5SDimitry Andric #include "Commands/CommandObjectQuit.h" 34e8d8bef9SDimitry Andric #include "Commands/CommandObjectRegexCommand.h" 350b57cec5SDimitry Andric #include "Commands/CommandObjectRegister.h" 36*0fca6ea1SDimitry Andric #include "Commands/CommandObjectScripting.h" 37e8d8bef9SDimitry Andric #include "Commands/CommandObjectSession.h" 380b57cec5SDimitry Andric #include "Commands/CommandObjectSettings.h" 390b57cec5SDimitry Andric #include "Commands/CommandObjectSource.h" 400b57cec5SDimitry Andric #include "Commands/CommandObjectStats.h" 410b57cec5SDimitry Andric #include "Commands/CommandObjectTarget.h" 420b57cec5SDimitry Andric #include "Commands/CommandObjectThread.h" 43e8d8bef9SDimitry Andric #include "Commands/CommandObjectTrace.h" 440b57cec5SDimitry Andric #include "Commands/CommandObjectType.h" 450b57cec5SDimitry Andric #include "Commands/CommandObjectVersion.h" 460b57cec5SDimitry Andric #include "Commands/CommandObjectWatchpoint.h" 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric #include "lldb/Core/Debugger.h" 490b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 505f757f3fSDimitry Andric #include "lldb/Host/StreamFile.h" 51*0fca6ea1SDimitry Andric #include "lldb/Utility/ErrorMessages.h" 5281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 530b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 540b57cec5SDimitry Andric #include "lldb/Utility/State.h" 550b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 56*0fca6ea1SDimitry Andric #include "lldb/Utility/StructuredData.h" 570b57cec5SDimitry Andric #include "lldb/Utility/Timer.h" 580b57cec5SDimitry Andric 59480093f4SDimitry Andric #include "lldb/Host/Config.h" 60480093f4SDimitry Andric #if LLDB_ENABLE_LIBEDIT 610b57cec5SDimitry Andric #include "lldb/Host/Editline.h" 620b57cec5SDimitry Andric #endif 63e8d8bef9SDimitry Andric #include "lldb/Host/File.h" 64e8d8bef9SDimitry Andric #include "lldb/Host/FileCache.h" 650b57cec5SDimitry Andric #include "lldb/Host/Host.h" 660b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h" 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric #include "lldb/Interpreter/CommandCompletions.h" 690b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 700b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 710b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueProperties.h" 720b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 730b57cec5SDimitry Andric #include "lldb/Interpreter/Property.h" 740b57cec5SDimitry Andric #include "lldb/Utility/Args.h" 750b57cec5SDimitry Andric 76e8d8bef9SDimitry Andric #include "lldb/Target/Language.h" 770b57cec5SDimitry Andric #include "lldb/Target/Process.h" 789dba64beSDimitry Andric #include "lldb/Target/StopInfo.h" 790b57cec5SDimitry Andric #include "lldb/Target/TargetList.h" 800b57cec5SDimitry Andric #include "lldb/Target/Thread.h" 819dba64beSDimitry Andric #include "lldb/Target/UnixSignals.h" 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 84fe6060f1SDimitry Andric #include "llvm/ADT/ScopeExit.h" 850b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 869dba64beSDimitry Andric #include "llvm/Support/FormatAdapters.h" 870b57cec5SDimitry Andric #include "llvm/Support/Path.h" 880b57cec5SDimitry Andric #include "llvm/Support/PrettyStackTrace.h" 89e8d8bef9SDimitry Andric #include "llvm/Support/ScopedPrinter.h" 900b57cec5SDimitry Andric 9181ad6265SDimitry Andric #if defined(__APPLE__) 9281ad6265SDimitry Andric #include <TargetConditionals.h> 9381ad6265SDimitry Andric #endif 9481ad6265SDimitry Andric 950b57cec5SDimitry Andric using namespace lldb; 960b57cec5SDimitry Andric using namespace lldb_private; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric static const char *k_white_space = " \t\v"; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric static constexpr const char *InitFileWarning = 1010b57cec5SDimitry Andric "There is a .lldbinit file in the current directory which is not being " 1020b57cec5SDimitry Andric "read.\n" 1030b57cec5SDimitry Andric "To silence this warning without sourcing in the local .lldbinit,\n" 1040b57cec5SDimitry Andric "add the following to the lldbinit file in your home directory:\n" 1050b57cec5SDimitry Andric " settings set target.load-cwd-lldbinit false\n" 1060b57cec5SDimitry Andric "To allow lldb to source .lldbinit files in the current working " 1070b57cec5SDimitry Andric "directory,\n" 1080b57cec5SDimitry Andric "set the value of this variable to true. Only do so if you understand " 1090b57cec5SDimitry Andric "and\n" 1100b57cec5SDimitry Andric "accept the security risk."; 1110b57cec5SDimitry Andric 112bdd1243dSDimitry Andric const char *CommandInterpreter::g_no_argument = "<no-argument>"; 113bdd1243dSDimitry Andric const char *CommandInterpreter::g_need_argument = "<need-argument>"; 114bdd1243dSDimitry Andric const char *CommandInterpreter::g_argument = "<argument>"; 115bdd1243dSDimitry Andric 116bdd1243dSDimitry Andric 1179dba64beSDimitry Andric #define LLDB_PROPERTIES_interpreter 1189dba64beSDimitry Andric #include "InterpreterProperties.inc" 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric enum { 1219dba64beSDimitry Andric #define LLDB_PROPERTIES_interpreter 1229dba64beSDimitry Andric #include "InterpreterPropertiesEnum.inc" 1230b57cec5SDimitry Andric }; 1240b57cec5SDimitry Andric 125*0fca6ea1SDimitry Andric llvm::StringRef CommandInterpreter::GetStaticBroadcasterClass() { 126*0fca6ea1SDimitry Andric static constexpr llvm::StringLiteral class_name("lldb.commandInterpreter"); 1270b57cec5SDimitry Andric return class_name; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric CommandInterpreter::CommandInterpreter(Debugger &debugger, 1310b57cec5SDimitry Andric bool synchronous_execution) 1320b57cec5SDimitry Andric : Broadcaster(debugger.GetBroadcasterManager(), 133*0fca6ea1SDimitry Andric CommandInterpreter::GetStaticBroadcasterClass().str()), 1345f757f3fSDimitry Andric Properties( 1355f757f3fSDimitry Andric OptionValuePropertiesSP(new OptionValueProperties("interpreter"))), 1360b57cec5SDimitry Andric IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), 1379dba64beSDimitry Andric m_debugger(debugger), m_synchronous_execution(true), 1380b57cec5SDimitry Andric m_skip_lldbinit_files(false), m_skip_app_init_files(false), 139fe6060f1SDimitry Andric m_comment_char('#'), m_batch_command_mode(false), 14081ad6265SDimitry Andric m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission), 14181ad6265SDimitry Andric m_command_source_depth(0) { 1420b57cec5SDimitry Andric SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit"); 1430b57cec5SDimitry Andric SetEventName(eBroadcastBitResetPrompt, "reset-prompt"); 1440b57cec5SDimitry Andric SetEventName(eBroadcastBitQuitCommandReceived, "quit"); 1459dba64beSDimitry Andric SetSynchronous(synchronous_execution); 1460b57cec5SDimitry Andric CheckInWithManager(); 1479dba64beSDimitry Andric m_collection_sp->Initialize(g_interpreter_properties); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric bool CommandInterpreter::GetExpandRegexAliases() const { 1510b57cec5SDimitry Andric const uint32_t idx = ePropertyExpandRegexAliases; 15206c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 15306c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric bool CommandInterpreter::GetPromptOnQuit() const { 1570b57cec5SDimitry Andric const uint32_t idx = ePropertyPromptOnQuit; 15806c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 15906c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 162480093f4SDimitry Andric void CommandInterpreter::SetPromptOnQuit(bool enable) { 1630b57cec5SDimitry Andric const uint32_t idx = ePropertyPromptOnQuit; 16406c3fb27SDimitry Andric SetPropertyAtIndex(idx, enable); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 167*0fca6ea1SDimitry Andric bool CommandInterpreter::GetSaveTranscript() const { 168*0fca6ea1SDimitry Andric const uint32_t idx = ePropertySaveTranscript; 169*0fca6ea1SDimitry Andric return GetPropertyAtIndexAs<bool>( 170*0fca6ea1SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 171*0fca6ea1SDimitry Andric } 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric void CommandInterpreter::SetSaveTranscript(bool enable) { 174*0fca6ea1SDimitry Andric const uint32_t idx = ePropertySaveTranscript; 175*0fca6ea1SDimitry Andric SetPropertyAtIndex(idx, enable); 176*0fca6ea1SDimitry Andric } 177*0fca6ea1SDimitry Andric 178e8d8bef9SDimitry Andric bool CommandInterpreter::GetSaveSessionOnQuit() const { 179e8d8bef9SDimitry Andric const uint32_t idx = ePropertySaveSessionOnQuit; 18006c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 18106c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 182e8d8bef9SDimitry Andric } 183e8d8bef9SDimitry Andric 184e8d8bef9SDimitry Andric void CommandInterpreter::SetSaveSessionOnQuit(bool enable) { 185e8d8bef9SDimitry Andric const uint32_t idx = ePropertySaveSessionOnQuit; 18606c3fb27SDimitry Andric SetPropertyAtIndex(idx, enable); 187e8d8bef9SDimitry Andric } 188e8d8bef9SDimitry Andric 189bdd1243dSDimitry Andric bool CommandInterpreter::GetOpenTranscriptInEditor() const { 190bdd1243dSDimitry Andric const uint32_t idx = ePropertyOpenTranscriptInEditor; 19106c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 19206c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 193bdd1243dSDimitry Andric } 194bdd1243dSDimitry Andric 195bdd1243dSDimitry Andric void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) { 196bdd1243dSDimitry Andric const uint32_t idx = ePropertyOpenTranscriptInEditor; 19706c3fb27SDimitry Andric SetPropertyAtIndex(idx, enable); 198bdd1243dSDimitry Andric } 199bdd1243dSDimitry Andric 200fe6060f1SDimitry Andric FileSpec CommandInterpreter::GetSaveSessionDirectory() const { 201fe6060f1SDimitry Andric const uint32_t idx = ePropertySaveSessionDirectory; 20206c3fb27SDimitry Andric return GetPropertyAtIndexAs<FileSpec>(idx, {}); 203fe6060f1SDimitry Andric } 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) { 206fe6060f1SDimitry Andric const uint32_t idx = ePropertySaveSessionDirectory; 20706c3fb27SDimitry Andric SetPropertyAtIndex(idx, path); 208fe6060f1SDimitry Andric } 209fe6060f1SDimitry Andric 2100b57cec5SDimitry Andric bool CommandInterpreter::GetEchoCommands() const { 2119dba64beSDimitry Andric const uint32_t idx = ePropertyEchoCommands; 21206c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 21306c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 216480093f4SDimitry Andric void CommandInterpreter::SetEchoCommands(bool enable) { 2179dba64beSDimitry Andric const uint32_t idx = ePropertyEchoCommands; 21806c3fb27SDimitry Andric SetPropertyAtIndex(idx, enable); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric bool CommandInterpreter::GetEchoCommentCommands() const { 2229dba64beSDimitry Andric const uint32_t idx = ePropertyEchoCommentCommands; 22306c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 22406c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 227480093f4SDimitry Andric void CommandInterpreter::SetEchoCommentCommands(bool enable) { 2289dba64beSDimitry Andric const uint32_t idx = ePropertyEchoCommentCommands; 22906c3fb27SDimitry Andric SetPropertyAtIndex(idx, enable); 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric void CommandInterpreter::AllowExitCodeOnQuit(bool allow) { 2330b57cec5SDimitry Andric m_allow_exit_code = allow; 2340b57cec5SDimitry Andric if (!allow) 2350b57cec5SDimitry Andric m_quit_exit_code.reset(); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric bool CommandInterpreter::SetQuitExitCode(int exit_code) { 2390b57cec5SDimitry Andric if (!m_allow_exit_code) 2400b57cec5SDimitry Andric return false; 2410b57cec5SDimitry Andric m_quit_exit_code = exit_code; 2420b57cec5SDimitry Andric return true; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric int CommandInterpreter::GetQuitExitCode(bool &exited) const { 24681ad6265SDimitry Andric exited = m_quit_exit_code.has_value(); 2470b57cec5SDimitry Andric if (exited) 2480b57cec5SDimitry Andric return *m_quit_exit_code; 2490b57cec5SDimitry Andric return 0; 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric void CommandInterpreter::ResolveCommand(const char *command_line, 2530b57cec5SDimitry Andric CommandReturnObject &result) { 2540b57cec5SDimitry Andric std::string command = command_line; 2550b57cec5SDimitry Andric if (ResolveCommandImpl(command, result) != nullptr) { 2560b57cec5SDimitry Andric result.AppendMessageWithFormat("%s", command.c_str()); 2570b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric bool CommandInterpreter::GetStopCmdSourceOnError() const { 2620b57cec5SDimitry Andric const uint32_t idx = ePropertyStopCmdSourceOnError; 26306c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 26406c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric bool CommandInterpreter::GetSpaceReplPrompts() const { 2689dba64beSDimitry Andric const uint32_t idx = ePropertySpaceReplPrompts; 26906c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 27006c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 273fe6060f1SDimitry Andric bool CommandInterpreter::GetRepeatPreviousCommand() const { 274fe6060f1SDimitry Andric const uint32_t idx = ePropertyRepeatPreviousCommand; 27506c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 27606c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 277fe6060f1SDimitry Andric } 278fe6060f1SDimitry Andric 27981ad6265SDimitry Andric bool CommandInterpreter::GetRequireCommandOverwrite() const { 28081ad6265SDimitry Andric const uint32_t idx = ePropertyRequireCommandOverwrite; 28106c3fb27SDimitry Andric return GetPropertyAtIndexAs<bool>( 28206c3fb27SDimitry Andric idx, g_interpreter_properties[idx].default_uint_value != 0); 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric 2850b57cec5SDimitry Andric void CommandInterpreter::Initialize() { 286e8d8bef9SDimitry Andric LLDB_SCOPED_TIMER(); 2870b57cec5SDimitry Andric 2885ffd83dbSDimitry Andric CommandReturnObject result(m_debugger.GetUseColor()); 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric LoadCommandDictionary(); 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric // An alias arguments vector to reuse - reset it before use... 2930b57cec5SDimitry Andric OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector); 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric // Set up some initial aliases. 296e8d8bef9SDimitry Andric CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit"); 2970b57cec5SDimitry Andric if (cmd_obj_sp) { 2980b57cec5SDimitry Andric AddAlias("q", cmd_obj_sp); 2990b57cec5SDimitry Andric AddAlias("exit", cmd_obj_sp); 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric 302e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-attach"); 3030b57cec5SDimitry Andric if (cmd_obj_sp) 3040b57cec5SDimitry Andric AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3050b57cec5SDimitry Andric 306e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("process detach"); 3070b57cec5SDimitry Andric if (cmd_obj_sp) { 3080b57cec5SDimitry Andric AddAlias("detach", cmd_obj_sp); 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 311e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("process continue"); 3120b57cec5SDimitry Andric if (cmd_obj_sp) { 3130b57cec5SDimitry Andric AddAlias("c", cmd_obj_sp); 3140b57cec5SDimitry Andric AddAlias("continue", cmd_obj_sp); 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 317e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-break"); 3180b57cec5SDimitry Andric if (cmd_obj_sp) 3190b57cec5SDimitry Andric AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3200b57cec5SDimitry Andric 321e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-tbreak"); 3220b57cec5SDimitry Andric if (cmd_obj_sp) 3230b57cec5SDimitry Andric AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3240b57cec5SDimitry Andric 325e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("thread step-inst"); 3260b57cec5SDimitry Andric if (cmd_obj_sp) { 3270b57cec5SDimitry Andric AddAlias("stepi", cmd_obj_sp); 3280b57cec5SDimitry Andric AddAlias("si", cmd_obj_sp); 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 331e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("thread step-inst-over"); 3320b57cec5SDimitry Andric if (cmd_obj_sp) { 3330b57cec5SDimitry Andric AddAlias("nexti", cmd_obj_sp); 3340b57cec5SDimitry Andric AddAlias("ni", cmd_obj_sp); 3350b57cec5SDimitry Andric } 3360b57cec5SDimitry Andric 337e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("thread step-in"); 3380b57cec5SDimitry Andric if (cmd_obj_sp) { 3390b57cec5SDimitry Andric AddAlias("s", cmd_obj_sp); 3400b57cec5SDimitry Andric AddAlias("step", cmd_obj_sp); 3410b57cec5SDimitry Andric CommandAlias *sif_alias = AddAlias( 3420b57cec5SDimitry Andric "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1"); 3430b57cec5SDimitry Andric if (sif_alias) { 3440b57cec5SDimitry Andric sif_alias->SetHelp("Step through the current block, stopping if you step " 3450b57cec5SDimitry Andric "directly into a function whose name matches the " 3460b57cec5SDimitry Andric "TargetFunctionName."); 3470b57cec5SDimitry Andric sif_alias->SetSyntax("sif <TargetFunctionName>"); 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 351e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("thread step-over"); 3520b57cec5SDimitry Andric if (cmd_obj_sp) { 3530b57cec5SDimitry Andric AddAlias("n", cmd_obj_sp); 3540b57cec5SDimitry Andric AddAlias("next", cmd_obj_sp); 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 357e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("thread step-out"); 3580b57cec5SDimitry Andric if (cmd_obj_sp) { 3590b57cec5SDimitry Andric AddAlias("finish", cmd_obj_sp); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 362e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("frame select"); 3630b57cec5SDimitry Andric if (cmd_obj_sp) { 3640b57cec5SDimitry Andric AddAlias("f", cmd_obj_sp); 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 367e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("thread select"); 3680b57cec5SDimitry Andric if (cmd_obj_sp) { 3690b57cec5SDimitry Andric AddAlias("t", cmd_obj_sp); 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric 372e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-jump"); 3730b57cec5SDimitry Andric if (cmd_obj_sp) { 3740b57cec5SDimitry Andric AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3750b57cec5SDimitry Andric AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric 378e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-list"); 3790b57cec5SDimitry Andric if (cmd_obj_sp) { 3800b57cec5SDimitry Andric AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3810b57cec5SDimitry Andric AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric 384e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-env"); 3850b57cec5SDimitry Andric if (cmd_obj_sp) 3860b57cec5SDimitry Andric AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3870b57cec5SDimitry Andric 388e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("memory read"); 3890b57cec5SDimitry Andric if (cmd_obj_sp) 3900b57cec5SDimitry Andric AddAlias("x", cmd_obj_sp); 3910b57cec5SDimitry Andric 392e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-up"); 3930b57cec5SDimitry Andric if (cmd_obj_sp) 3940b57cec5SDimitry Andric AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3950b57cec5SDimitry Andric 396e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-down"); 3970b57cec5SDimitry Andric if (cmd_obj_sp) 3980b57cec5SDimitry Andric AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 3990b57cec5SDimitry Andric 400e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-display"); 4010b57cec5SDimitry Andric if (cmd_obj_sp) 4020b57cec5SDimitry Andric AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 4030b57cec5SDimitry Andric 404e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("disassemble"); 4050b57cec5SDimitry Andric if (cmd_obj_sp) 4060b57cec5SDimitry Andric AddAlias("dis", cmd_obj_sp); 4070b57cec5SDimitry Andric 408e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("disassemble"); 4090b57cec5SDimitry Andric if (cmd_obj_sp) 4100b57cec5SDimitry Andric AddAlias("di", cmd_obj_sp); 4110b57cec5SDimitry Andric 412e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-undisplay"); 4130b57cec5SDimitry Andric if (cmd_obj_sp) 4140b57cec5SDimitry Andric AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 4150b57cec5SDimitry Andric 416e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("_regexp-bt"); 4170b57cec5SDimitry Andric if (cmd_obj_sp) 4180b57cec5SDimitry Andric AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); 4190b57cec5SDimitry Andric 420e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("target create"); 4210b57cec5SDimitry Andric if (cmd_obj_sp) 4220b57cec5SDimitry Andric AddAlias("file", cmd_obj_sp); 4230b57cec5SDimitry Andric 424e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("target modules"); 4250b57cec5SDimitry Andric if (cmd_obj_sp) 4260b57cec5SDimitry Andric AddAlias("image", cmd_obj_sp); 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric alias_arguments_vector_sp = std::make_shared<OptionArgVector>(); 4290b57cec5SDimitry Andric 43006c3fb27SDimitry Andric cmd_obj_sp = GetCommandSPExact("dwim-print"); 4310b57cec5SDimitry Andric if (cmd_obj_sp) { 4320b57cec5SDimitry Andric AddAlias("p", cmd_obj_sp, "--")->SetHelpLong(""); 4330b57cec5SDimitry Andric AddAlias("print", cmd_obj_sp, "--")->SetHelpLong(""); 4345ffd83dbSDimitry Andric if (auto *po = AddAlias("po", cmd_obj_sp, "-O --")) { 4350b57cec5SDimitry Andric po->SetHelp("Evaluate an expression on the current thread. Displays any " 4360b57cec5SDimitry Andric "returned value with formatting " 4370b57cec5SDimitry Andric "controlled by the type's author."); 4380b57cec5SDimitry Andric po->SetHelpLong(""); 4390b57cec5SDimitry Andric } 44006c3fb27SDimitry Andric } 44106c3fb27SDimitry Andric 44206c3fb27SDimitry Andric cmd_obj_sp = GetCommandSPExact("expression"); 44306c3fb27SDimitry Andric if (cmd_obj_sp) { 44406c3fb27SDimitry Andric AddAlias("call", cmd_obj_sp, "--")->SetHelpLong(""); 445480093f4SDimitry Andric CommandAlias *parray_alias = 446480093f4SDimitry Andric AddAlias("parray", cmd_obj_sp, "--element-count %1 --"); 447480093f4SDimitry Andric if (parray_alias) { 448480093f4SDimitry Andric parray_alias->SetHelp 449480093f4SDimitry Andric ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION " 450480093f4SDimitry Andric "to get a typed-pointer-to-an-array in memory, and will display " 451480093f4SDimitry Andric "COUNT elements of that type from the array."); 452480093f4SDimitry Andric parray_alias->SetHelpLong(""); 453480093f4SDimitry Andric } 454480093f4SDimitry Andric CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp, 455480093f4SDimitry Andric "--object-description --element-count %1 --"); 456480093f4SDimitry Andric if (poarray_alias) { 457480093f4SDimitry Andric poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will " 458480093f4SDimitry Andric "evaluate EXPRESSION to get the address of an array of COUNT " 459480093f4SDimitry Andric "objects in memory, and will call po on them."); 460480093f4SDimitry Andric poarray_alias->SetHelpLong(""); 461480093f4SDimitry Andric } 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric 464e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("platform shell"); 4655ffd83dbSDimitry Andric if (cmd_obj_sp) { 4665ffd83dbSDimitry Andric CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --"); 4675ffd83dbSDimitry Andric if (shell_alias) { 4685ffd83dbSDimitry Andric shell_alias->SetHelp("Run a shell command on the host."); 4695ffd83dbSDimitry Andric shell_alias->SetHelpLong(""); 4705ffd83dbSDimitry Andric shell_alias->SetSyntax("shell <shell-command>"); 4715ffd83dbSDimitry Andric } 4725ffd83dbSDimitry Andric } 4735ffd83dbSDimitry Andric 474e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("process kill"); 4750b57cec5SDimitry Andric if (cmd_obj_sp) { 4760b57cec5SDimitry Andric AddAlias("kill", cmd_obj_sp); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 479e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("process launch"); 4800b57cec5SDimitry Andric if (cmd_obj_sp) { 4810b57cec5SDimitry Andric alias_arguments_vector_sp = std::make_shared<OptionArgVector>(); 482fe6060f1SDimitry Andric #if defined(__APPLE__) 48381ad6265SDimitry Andric #if TARGET_OS_IPHONE 4840b57cec5SDimitry Andric AddAlias("r", cmd_obj_sp, "--"); 4850b57cec5SDimitry Andric AddAlias("run", cmd_obj_sp, "--"); 4860b57cec5SDimitry Andric #else 4870b57cec5SDimitry Andric AddAlias("r", cmd_obj_sp, "--shell-expand-args true --"); 4880b57cec5SDimitry Andric AddAlias("run", cmd_obj_sp, "--shell-expand-args true --"); 489fe6060f1SDimitry Andric #endif 4900b57cec5SDimitry Andric #else 4910b57cec5SDimitry Andric StreamString defaultshell; 4920b57cec5SDimitry Andric defaultshell.Printf("--shell=%s --", 4930b57cec5SDimitry Andric HostInfo::GetDefaultShell().GetPath().c_str()); 4940b57cec5SDimitry Andric AddAlias("r", cmd_obj_sp, defaultshell.GetString()); 4950b57cec5SDimitry Andric AddAlias("run", cmd_obj_sp, defaultshell.GetString()); 4960b57cec5SDimitry Andric #endif 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 499e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("target symbols add"); 5000b57cec5SDimitry Andric if (cmd_obj_sp) { 5010b57cec5SDimitry Andric AddAlias("add-dsym", cmd_obj_sp); 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric 504e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("breakpoint set"); 5050b57cec5SDimitry Andric if (cmd_obj_sp) { 5060b57cec5SDimitry Andric AddAlias("rbreak", cmd_obj_sp, "--func-regex %1"); 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric 509e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("frame variable"); 5100b57cec5SDimitry Andric if (cmd_obj_sp) { 5110b57cec5SDimitry Andric AddAlias("v", cmd_obj_sp); 5120b57cec5SDimitry Andric AddAlias("var", cmd_obj_sp); 5130b57cec5SDimitry Andric AddAlias("vo", cmd_obj_sp, "--object-description"); 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 516e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("register"); 5170b57cec5SDimitry Andric if (cmd_obj_sp) { 5180b57cec5SDimitry Andric AddAlias("re", cmd_obj_sp); 5190b57cec5SDimitry Andric } 520e8d8bef9SDimitry Andric 521*0fca6ea1SDimitry Andric cmd_obj_sp = GetCommandSPExact("scripting run"); 522*0fca6ea1SDimitry Andric if (cmd_obj_sp) { 523*0fca6ea1SDimitry Andric AddAlias("sc", cmd_obj_sp); 524*0fca6ea1SDimitry Andric AddAlias("scr", cmd_obj_sp); 525*0fca6ea1SDimitry Andric AddAlias("scri", cmd_obj_sp); 526*0fca6ea1SDimitry Andric AddAlias("scrip", cmd_obj_sp); 527*0fca6ea1SDimitry Andric AddAlias("script", cmd_obj_sp); 528*0fca6ea1SDimitry Andric } 529*0fca6ea1SDimitry Andric 530e8d8bef9SDimitry Andric cmd_obj_sp = GetCommandSPExact("session history"); 531e8d8bef9SDimitry Andric if (cmd_obj_sp) { 532e8d8bef9SDimitry Andric AddAlias("history", cmd_obj_sp); 533e8d8bef9SDimitry Andric } 5345f757f3fSDimitry Andric 5355f757f3fSDimitry Andric cmd_obj_sp = GetCommandSPExact("help"); 5365f757f3fSDimitry Andric if (cmd_obj_sp) { 5375f757f3fSDimitry Andric AddAlias("h", cmd_obj_sp); 5385f757f3fSDimitry Andric } 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric void CommandInterpreter::Clear() { 5420b57cec5SDimitry Andric m_command_io_handler_sp.reset(); 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) { 5460b57cec5SDimitry Andric // This function has not yet been implemented. 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric // Look for any embedded script command 5490b57cec5SDimitry Andric // If found, 5500b57cec5SDimitry Andric // get interpreter object from the command dictionary, 5510b57cec5SDimitry Andric // call execute_one_command on it, 5520b57cec5SDimitry Andric // get the results as a string, 5530b57cec5SDimitry Andric // substitute that string for current stuff. 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric return arg; 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric 558e8d8bef9SDimitry Andric #define REGISTER_COMMAND_OBJECT(NAME, CLASS) \ 559e8d8bef9SDimitry Andric m_command_dict[NAME] = std::make_shared<CLASS>(*this); 560e8d8bef9SDimitry Andric 5610b57cec5SDimitry Andric void CommandInterpreter::LoadCommandDictionary() { 562e8d8bef9SDimitry Andric LLDB_SCOPED_TIMER(); 5630b57cec5SDimitry Andric 564e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos); 565e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint); 566e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands); 567bdd1243dSDimitry Andric REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics); 568e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble); 569bdd1243dSDimitry Andric REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint); 570e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression); 571e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame); 572e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI); 573e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("help", CommandObjectHelp); 574e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("log", CommandObjectLog); 575e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory); 576e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform); 577e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin); 578e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess); 579e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit); 580e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("register", CommandObjectRegister); 581*0fca6ea1SDimitry Andric REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting); 582e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings); 583e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("session", CommandObjectSession); 584e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource); 585e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats); 586e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget); 587e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread); 588e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace); 589e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("type", CommandObjectType); 590e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("version", CommandObjectVersion); 591e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint); 592e8d8bef9SDimitry Andric REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage); 5930b57cec5SDimitry Andric 5945ffd83dbSDimitry Andric // clang-format off 5950b57cec5SDimitry Andric const char *break_regexes[][2] = { 5965ffd83dbSDimitry Andric {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", 5975ffd83dbSDimitry Andric "breakpoint set --file '%1' --line %2 --column %3"}, 5980b57cec5SDimitry Andric {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", 5990b57cec5SDimitry Andric "breakpoint set --file '%1' --line %2"}, 6000b57cec5SDimitry Andric {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"}, 6010b57cec5SDimitry Andric {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"}, 6020b57cec5SDimitry Andric {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"}, 6030b57cec5SDimitry Andric {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$", 6040b57cec5SDimitry Andric "breakpoint set --name '%1'"}, 6050b57cec5SDimitry Andric {"^(-.*)$", "breakpoint set %1"}, 6060b57cec5SDimitry Andric {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", 6070b57cec5SDimitry Andric "breakpoint set --name '%2' --shlib '%1'"}, 6080b57cec5SDimitry Andric {"^\\&(.*[^[:space:]])[[:space:]]*$", 6090b57cec5SDimitry Andric "breakpoint set --name '%1' --skip-prologue=0"}, 6100b57cec5SDimitry Andric {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$", 6110b57cec5SDimitry Andric "breakpoint set --name '%1'"}}; 6125ffd83dbSDimitry Andric // clang-format on 6130b57cec5SDimitry Andric 614bdd1243dSDimitry Andric size_t num_regexes = std::size(break_regexes); 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up( 6170b57cec5SDimitry Andric new CommandObjectRegexCommand( 6180b57cec5SDimitry Andric *this, "_regexp-break", 6190b57cec5SDimitry Andric "Set a breakpoint using one of several shorthand formats.", 6200b57cec5SDimitry Andric "\n" 6215ffd83dbSDimitry Andric "_regexp-break <filename>:<linenum>:<colnum>\n" 6225ffd83dbSDimitry Andric " main.c:12:21 // Break at line 12 and column " 6235ffd83dbSDimitry Andric "21 of main.c\n\n" 6240b57cec5SDimitry Andric "_regexp-break <filename>:<linenum>\n" 6250b57cec5SDimitry Andric " main.c:12 // Break at line 12 of " 6260b57cec5SDimitry Andric "main.c\n\n" 6270b57cec5SDimitry Andric "_regexp-break <linenum>\n" 6280b57cec5SDimitry Andric " 12 // Break at line 12 of current " 6290b57cec5SDimitry Andric "file\n\n" 6300b57cec5SDimitry Andric "_regexp-break 0x<address>\n" 6310b57cec5SDimitry Andric " 0x1234000 // Break at address " 6320b57cec5SDimitry Andric "0x1234000\n\n" 6330b57cec5SDimitry Andric "_regexp-break <name>\n" 6340b57cec5SDimitry Andric " main // Break in 'main' after the " 6350b57cec5SDimitry Andric "prologue\n\n" 6360b57cec5SDimitry Andric "_regexp-break &<name>\n" 6370b57cec5SDimitry Andric " &main // Break at first instruction " 6380b57cec5SDimitry Andric "in 'main'\n\n" 6390b57cec5SDimitry Andric "_regexp-break <module>`<name>\n" 6400b57cec5SDimitry Andric " libc.so`malloc // Break in 'malloc' from " 6410b57cec5SDimitry Andric "'libc.so'\n\n" 6420b57cec5SDimitry Andric "_regexp-break /<source-regex>/\n" 6430b57cec5SDimitry Andric " /break here/ // Break on source lines in " 6440b57cec5SDimitry Andric "current file\n" 6450b57cec5SDimitry Andric " // containing text 'break " 6460b57cec5SDimitry Andric "here'.\n", 64706c3fb27SDimitry Andric lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false)); 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric if (break_regex_cmd_up) { 6500b57cec5SDimitry Andric bool success = true; 6510b57cec5SDimitry Andric for (size_t i = 0; i < num_regexes; i++) { 6520b57cec5SDimitry Andric success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0], 6530b57cec5SDimitry Andric break_regexes[i][1]); 6540b57cec5SDimitry Andric if (!success) 6550b57cec5SDimitry Andric break; 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric success = 6580b57cec5SDimitry Andric break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full"); 6590b57cec5SDimitry Andric 6600b57cec5SDimitry Andric if (success) { 6610b57cec5SDimitry Andric CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release()); 6625ffd83dbSDimitry Andric m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] = 6635ffd83dbSDimitry Andric break_regex_cmd_sp; 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric } 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up( 6680b57cec5SDimitry Andric new CommandObjectRegexCommand( 6690b57cec5SDimitry Andric *this, "_regexp-tbreak", 6700b57cec5SDimitry Andric "Set a one-shot breakpoint using one of several shorthand formats.", 6710b57cec5SDimitry Andric "\n" 6725ffd83dbSDimitry Andric "_regexp-break <filename>:<linenum>:<colnum>\n" 6735ffd83dbSDimitry Andric " main.c:12:21 // Break at line 12 and column " 6745ffd83dbSDimitry Andric "21 of main.c\n\n" 6750b57cec5SDimitry Andric "_regexp-break <filename>:<linenum>\n" 6760b57cec5SDimitry Andric " main.c:12 // Break at line 12 of " 6770b57cec5SDimitry Andric "main.c\n\n" 6780b57cec5SDimitry Andric "_regexp-break <linenum>\n" 6790b57cec5SDimitry Andric " 12 // Break at line 12 of current " 6800b57cec5SDimitry Andric "file\n\n" 6810b57cec5SDimitry Andric "_regexp-break 0x<address>\n" 6820b57cec5SDimitry Andric " 0x1234000 // Break at address " 6830b57cec5SDimitry Andric "0x1234000\n\n" 6840b57cec5SDimitry Andric "_regexp-break <name>\n" 6850b57cec5SDimitry Andric " main // Break in 'main' after the " 6860b57cec5SDimitry Andric "prologue\n\n" 6870b57cec5SDimitry Andric "_regexp-break &<name>\n" 6880b57cec5SDimitry Andric " &main // Break at first instruction " 6890b57cec5SDimitry Andric "in 'main'\n\n" 6900b57cec5SDimitry Andric "_regexp-break <module>`<name>\n" 6910b57cec5SDimitry Andric " libc.so`malloc // Break in 'malloc' from " 6920b57cec5SDimitry Andric "'libc.so'\n\n" 6930b57cec5SDimitry Andric "_regexp-break /<source-regex>/\n" 6940b57cec5SDimitry Andric " /break here/ // Break on source lines in " 6950b57cec5SDimitry Andric "current file\n" 6960b57cec5SDimitry Andric " // containing text 'break " 6970b57cec5SDimitry Andric "here'.\n", 69806c3fb27SDimitry Andric lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false)); 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric if (tbreak_regex_cmd_up) { 7010b57cec5SDimitry Andric bool success = true; 7020b57cec5SDimitry Andric for (size_t i = 0; i < num_regexes; i++) { 703e8d8bef9SDimitry Andric std::string command = break_regexes[i][1]; 704e8d8bef9SDimitry Andric command += " -o 1"; 7050b57cec5SDimitry Andric success = 706e8d8bef9SDimitry Andric tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command); 7070b57cec5SDimitry Andric if (!success) 7080b57cec5SDimitry Andric break; 7090b57cec5SDimitry Andric } 7100b57cec5SDimitry Andric success = 7110b57cec5SDimitry Andric tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full"); 7120b57cec5SDimitry Andric 7130b57cec5SDimitry Andric if (success) { 7140b57cec5SDimitry Andric CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release()); 7155ffd83dbSDimitry Andric m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] = 7160b57cec5SDimitry Andric tbreak_regex_cmd_sp; 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric 7200b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up( 7210b57cec5SDimitry Andric new CommandObjectRegexCommand( 7220b57cec5SDimitry Andric *this, "_regexp-attach", "Attach to process by ID or name.", 72306c3fb27SDimitry Andric "_regexp-attach <pid> | <process-name>", 0, false)); 7240b57cec5SDimitry Andric if (attach_regex_cmd_up) { 7250b57cec5SDimitry Andric if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$", 7260b57cec5SDimitry Andric "process attach --pid %1") && 7270b57cec5SDimitry Andric attach_regex_cmd_up->AddRegexCommand( 7280b57cec5SDimitry Andric "^(-.*|.* -.*)$", "process attach %1") && // Any options that are 7290b57cec5SDimitry Andric // specified get passed to 7300b57cec5SDimitry Andric // 'process attach' 7310b57cec5SDimitry Andric attach_regex_cmd_up->AddRegexCommand("^(.+)$", 7320b57cec5SDimitry Andric "process attach --name '%1'") && 7330b57cec5SDimitry Andric attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) { 7340b57cec5SDimitry Andric CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release()); 7355ffd83dbSDimitry Andric m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] = 7360b57cec5SDimitry Andric attach_regex_cmd_sp; 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric } 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up( 7410b57cec5SDimitry Andric new CommandObjectRegexCommand(*this, "_regexp-down", 7420b57cec5SDimitry Andric "Select a newer stack frame. Defaults to " 7430b57cec5SDimitry Andric "moving one frame, a numeric argument can " 7440b57cec5SDimitry Andric "specify an arbitrary number.", 74506c3fb27SDimitry Andric "_regexp-down [<count>]", 0, false)); 7460b57cec5SDimitry Andric if (down_regex_cmd_up) { 7470b57cec5SDimitry Andric if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") && 7480b57cec5SDimitry Andric down_regex_cmd_up->AddRegexCommand("^([0-9]+)$", 7490b57cec5SDimitry Andric "frame select -r -%1")) { 7500b57cec5SDimitry Andric CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release()); 7515ffd83dbSDimitry Andric m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] = 7525ffd83dbSDimitry Andric down_regex_cmd_sp; 7530b57cec5SDimitry Andric } 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up( 7570b57cec5SDimitry Andric new CommandObjectRegexCommand( 7580b57cec5SDimitry Andric *this, "_regexp-up", 7590b57cec5SDimitry Andric "Select an older stack frame. Defaults to moving one " 7600b57cec5SDimitry Andric "frame, a numeric argument can specify an arbitrary number.", 76106c3fb27SDimitry Andric "_regexp-up [<count>]", 0, false)); 7620b57cec5SDimitry Andric if (up_regex_cmd_up) { 7630b57cec5SDimitry Andric if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") && 7640b57cec5SDimitry Andric up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) { 7650b57cec5SDimitry Andric CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release()); 7665ffd83dbSDimitry Andric m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] = 7675ffd83dbSDimitry Andric up_regex_cmd_sp; 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric } 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up( 7720b57cec5SDimitry Andric new CommandObjectRegexCommand( 7730b57cec5SDimitry Andric *this, "_regexp-display", 7740b57cec5SDimitry Andric "Evaluate an expression at every stop (see 'help target stop-hook'.)", 77506c3fb27SDimitry Andric "_regexp-display expression", 0, false)); 7760b57cec5SDimitry Andric if (display_regex_cmd_up) { 7770b57cec5SDimitry Andric if (display_regex_cmd_up->AddRegexCommand( 7780b57cec5SDimitry Andric "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) { 7790b57cec5SDimitry Andric CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release()); 7805ffd83dbSDimitry Andric m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] = 7810b57cec5SDimitry Andric display_regex_cmd_sp; 7820b57cec5SDimitry Andric } 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up( 7860b57cec5SDimitry Andric new CommandObjectRegexCommand(*this, "_regexp-undisplay", 7870b57cec5SDimitry Andric "Stop displaying expression at every " 7880b57cec5SDimitry Andric "stop (specified by stop-hook index.)", 78906c3fb27SDimitry Andric "_regexp-undisplay stop-hook-number", 0, 7900b57cec5SDimitry Andric false)); 7910b57cec5SDimitry Andric if (undisplay_regex_cmd_up) { 7920b57cec5SDimitry Andric if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$", 7930b57cec5SDimitry Andric "target stop-hook delete %1")) { 7940b57cec5SDimitry Andric CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release()); 7955ffd83dbSDimitry Andric m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] = 7960b57cec5SDimitry Andric undisplay_regex_cmd_sp; 7970b57cec5SDimitry Andric } 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up( 8010b57cec5SDimitry Andric new CommandObjectRegexCommand( 8020b57cec5SDimitry Andric *this, "gdb-remote", 803349cc55cSDimitry Andric "Connect to a process via remote GDB server.\n" 804349cc55cSDimitry Andric "If no host is specifed, localhost is assumed.\n" 805349cc55cSDimitry Andric "gdb-remote is an abbreviation for 'process connect --plugin " 806349cc55cSDimitry Andric "gdb-remote connect://<hostname>:<port>'\n", 80706c3fb27SDimitry Andric "gdb-remote [<hostname>:]<portnum>", 0, false)); 8080b57cec5SDimitry Andric if (connect_gdb_remote_cmd_up) { 8090b57cec5SDimitry Andric if (connect_gdb_remote_cmd_up->AddRegexCommand( 8100b57cec5SDimitry Andric "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$", 8110b57cec5SDimitry Andric "process connect --plugin gdb-remote connect://%1:%2") && 8120b57cec5SDimitry Andric connect_gdb_remote_cmd_up->AddRegexCommand( 8130b57cec5SDimitry Andric "^([[:digit:]]+)$", 8140b57cec5SDimitry Andric "process connect --plugin gdb-remote connect://localhost:%1")) { 8150b57cec5SDimitry Andric CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release()); 8165ffd83dbSDimitry Andric m_command_dict[std::string(command_sp->GetCommandName())] = command_sp; 8170b57cec5SDimitry Andric } 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up( 8210b57cec5SDimitry Andric new CommandObjectRegexCommand( 8220b57cec5SDimitry Andric *this, "kdp-remote", 823349cc55cSDimitry Andric "Connect to a process via remote KDP server.\n" 824349cc55cSDimitry Andric "If no UDP port is specified, port 41139 is assumed.\n" 825349cc55cSDimitry Andric "kdp-remote is an abbreviation for 'process connect --plugin " 826349cc55cSDimitry Andric "kdp-remote udp://<hostname>:<port>'\n", 82706c3fb27SDimitry Andric "kdp-remote <hostname>[:<portnum>]", 0, false)); 8280b57cec5SDimitry Andric if (connect_kdp_remote_cmd_up) { 8290b57cec5SDimitry Andric if (connect_kdp_remote_cmd_up->AddRegexCommand( 8300b57cec5SDimitry Andric "^([^:]+:[[:digit:]]+)$", 8310b57cec5SDimitry Andric "process connect --plugin kdp-remote udp://%1") && 8320b57cec5SDimitry Andric connect_kdp_remote_cmd_up->AddRegexCommand( 8330b57cec5SDimitry Andric "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) { 8340b57cec5SDimitry Andric CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release()); 8355ffd83dbSDimitry Andric m_command_dict[std::string(command_sp->GetCommandName())] = command_sp; 8360b57cec5SDimitry Andric } 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up( 8400b57cec5SDimitry Andric new CommandObjectRegexCommand( 8410b57cec5SDimitry Andric *this, "_regexp-bt", 842*0fca6ea1SDimitry Andric "Show backtrace of the current thread's call stack. Any numeric " 843*0fca6ea1SDimitry Andric "argument displays at most that many frames. The argument 'all' " 844*0fca6ea1SDimitry Andric "displays all threads. Use 'settings set frame-format' to customize " 845*0fca6ea1SDimitry Andric "the printing of individual frames and 'settings set thread-format' " 846*0fca6ea1SDimitry Andric "to customize the thread header.", 84706c3fb27SDimitry Andric "bt [<digit> | all]", 0, false)); 8480b57cec5SDimitry Andric if (bt_regex_cmd_up) { 8490b57cec5SDimitry Andric // accept but don't document "bt -c <number>" -- before bt was a regex 8500b57cec5SDimitry Andric // command if you wanted to backtrace three frames you would do "bt -c 3" 8510b57cec5SDimitry Andric // but the intention is to have this emulate the gdb "bt" command and so 8520b57cec5SDimitry Andric // now "bt 3" is the preferred form, in line with gdb. 8530b57cec5SDimitry Andric if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$", 8540b57cec5SDimitry Andric "thread backtrace -c %1") && 8550b57cec5SDimitry Andric bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$", 8560b57cec5SDimitry Andric "thread backtrace -c %1") && 8570b57cec5SDimitry Andric bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") && 8580b57cec5SDimitry Andric bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) { 8590b57cec5SDimitry Andric CommandObjectSP command_sp(bt_regex_cmd_up.release()); 8605ffd83dbSDimitry Andric m_command_dict[std::string(command_sp->GetCommandName())] = command_sp; 8610b57cec5SDimitry Andric } 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up( 8650b57cec5SDimitry Andric new CommandObjectRegexCommand( 8660b57cec5SDimitry Andric *this, "_regexp-list", 8670b57cec5SDimitry Andric "List relevant source code using one of several shorthand formats.", 8680b57cec5SDimitry Andric "\n" 8690b57cec5SDimitry Andric "_regexp-list <file>:<line> // List around specific file/line\n" 8700b57cec5SDimitry Andric "_regexp-list <line> // List current file around specified " 8710b57cec5SDimitry Andric "line\n" 8720b57cec5SDimitry Andric "_regexp-list <function-name> // List specified function\n" 8730b57cec5SDimitry Andric "_regexp-list 0x<address> // List around specified address\n" 8740b57cec5SDimitry Andric "_regexp-list -[<count>] // List previous <count> lines\n" 8750b57cec5SDimitry Andric "_regexp-list // List subsequent lines", 87606c3fb27SDimitry Andric lldb::eSourceFileCompletion, false)); 8770b57cec5SDimitry Andric if (list_regex_cmd_up) { 8780b57cec5SDimitry Andric if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$", 8790b57cec5SDimitry Andric "source list --line %1") && 8800b57cec5SDimitry Andric list_regex_cmd_up->AddRegexCommand( 8810b57cec5SDimitry Andric "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]" 8820b57cec5SDimitry Andric "]*$", 8830b57cec5SDimitry Andric "source list --file '%1' --line %2") && 8840b57cec5SDimitry Andric list_regex_cmd_up->AddRegexCommand( 8850b57cec5SDimitry Andric "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", 8860b57cec5SDimitry Andric "source list --address %1") && 8870b57cec5SDimitry Andric list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$", 8880b57cec5SDimitry Andric "source list --reverse") && 8890b57cec5SDimitry Andric list_regex_cmd_up->AddRegexCommand( 8900b57cec5SDimitry Andric "^-([[:digit:]]+)[[:space:]]*$", 8910b57cec5SDimitry Andric "source list --reverse --count %1") && 8920b57cec5SDimitry Andric list_regex_cmd_up->AddRegexCommand("^(.+)$", 8930b57cec5SDimitry Andric "source list --name \"%1\"") && 8940b57cec5SDimitry Andric list_regex_cmd_up->AddRegexCommand("^$", "source list")) { 8950b57cec5SDimitry Andric CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release()); 8965ffd83dbSDimitry Andric m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] = 8975ffd83dbSDimitry Andric list_regex_cmd_sp; 8980b57cec5SDimitry Andric } 8990b57cec5SDimitry Andric } 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up( 9020b57cec5SDimitry Andric new CommandObjectRegexCommand( 9030b57cec5SDimitry Andric *this, "_regexp-env", 9040b57cec5SDimitry Andric "Shorthand for viewing and setting environment variables.", 9050b57cec5SDimitry Andric "\n" 9060b57cec5SDimitry Andric "_regexp-env // Show environment\n" 9070b57cec5SDimitry Andric "_regexp-env <name>=<value> // Set an environment variable", 90806c3fb27SDimitry Andric 0, false)); 9090b57cec5SDimitry Andric if (env_regex_cmd_up) { 9100b57cec5SDimitry Andric if (env_regex_cmd_up->AddRegexCommand("^$", 9110b57cec5SDimitry Andric "settings show target.env-vars") && 9120b57cec5SDimitry Andric env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$", 9130b57cec5SDimitry Andric "settings set target.env-vars %1")) { 9140b57cec5SDimitry Andric CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release()); 9155ffd83dbSDimitry Andric m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] = 9165ffd83dbSDimitry Andric env_regex_cmd_sp; 9170b57cec5SDimitry Andric } 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up( 9210b57cec5SDimitry Andric new CommandObjectRegexCommand( 9220b57cec5SDimitry Andric *this, "_regexp-jump", "Set the program counter to a new address.", 9230b57cec5SDimitry Andric "\n" 9240b57cec5SDimitry Andric "_regexp-jump <line>\n" 9250b57cec5SDimitry Andric "_regexp-jump +<line-offset> | -<line-offset>\n" 9260b57cec5SDimitry Andric "_regexp-jump <file>:<line>\n" 9270b57cec5SDimitry Andric "_regexp-jump *<addr>\n", 92806c3fb27SDimitry Andric 0, false)); 9290b57cec5SDimitry Andric if (jump_regex_cmd_up) { 9300b57cec5SDimitry Andric if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$", 9310b57cec5SDimitry Andric "thread jump --addr %1") && 9320b57cec5SDimitry Andric jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$", 9330b57cec5SDimitry Andric "thread jump --line %1") && 9340b57cec5SDimitry Andric jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$", 9350b57cec5SDimitry Andric "thread jump --file %1 --line %2") && 9360b57cec5SDimitry Andric jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$", 9370b57cec5SDimitry Andric "thread jump --by %1")) { 9380b57cec5SDimitry Andric CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release()); 9395ffd83dbSDimitry Andric m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] = 9405ffd83dbSDimitry Andric jump_regex_cmd_sp; 9410b57cec5SDimitry Andric } 9420b57cec5SDimitry Andric } 9430b57cec5SDimitry Andric } 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric int CommandInterpreter::GetCommandNamesMatchingPartialString( 9460b57cec5SDimitry Andric const char *cmd_str, bool include_aliases, StringList &matches, 9470b57cec5SDimitry Andric StringList &descriptions) { 9480b57cec5SDimitry Andric AddNamesMatchingPartialString(m_command_dict, cmd_str, matches, 9490b57cec5SDimitry Andric &descriptions); 9500b57cec5SDimitry Andric 9510b57cec5SDimitry Andric if (include_aliases) { 9520b57cec5SDimitry Andric AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches, 9530b57cec5SDimitry Andric &descriptions); 9540b57cec5SDimitry Andric } 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric return matches.GetSize(); 9570b57cec5SDimitry Andric } 9580b57cec5SDimitry Andric 959349cc55cSDimitry Andric CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath( 960349cc55cSDimitry Andric Args &path, bool leaf_is_command, Status &result) { 961349cc55cSDimitry Andric result.Clear(); 962349cc55cSDimitry Andric 963349cc55cSDimitry Andric auto get_multi_or_report_error = 964349cc55cSDimitry Andric [&result](CommandObjectSP cmd_sp, 965349cc55cSDimitry Andric const char *name) -> CommandObjectMultiword * { 966349cc55cSDimitry Andric if (!cmd_sp) { 967349cc55cSDimitry Andric result.SetErrorStringWithFormat("Path component: '%s' not found", name); 968349cc55cSDimitry Andric return nullptr; 969349cc55cSDimitry Andric } 970349cc55cSDimitry Andric if (!cmd_sp->IsUserCommand()) { 971349cc55cSDimitry Andric result.SetErrorStringWithFormat("Path component: '%s' is not a user " 972349cc55cSDimitry Andric "command", 973349cc55cSDimitry Andric name); 974349cc55cSDimitry Andric return nullptr; 975349cc55cSDimitry Andric } 976349cc55cSDimitry Andric CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand(); 977349cc55cSDimitry Andric if (!cmd_as_multi) { 978349cc55cSDimitry Andric result.SetErrorStringWithFormat("Path component: '%s' is not a container " 979349cc55cSDimitry Andric "command", 980349cc55cSDimitry Andric name); 981349cc55cSDimitry Andric return nullptr; 982349cc55cSDimitry Andric } 983349cc55cSDimitry Andric return cmd_as_multi; 984349cc55cSDimitry Andric }; 985349cc55cSDimitry Andric 986349cc55cSDimitry Andric size_t num_args = path.GetArgumentCount(); 987349cc55cSDimitry Andric if (num_args == 0) { 988349cc55cSDimitry Andric result.SetErrorString("empty command path"); 989349cc55cSDimitry Andric return nullptr; 990349cc55cSDimitry Andric } 991349cc55cSDimitry Andric 992349cc55cSDimitry Andric if (num_args == 1 && leaf_is_command) { 993349cc55cSDimitry Andric // We just got a leaf command to be added to the root. That's not an error, 994349cc55cSDimitry Andric // just return null for the container. 995349cc55cSDimitry Andric return nullptr; 996349cc55cSDimitry Andric } 997349cc55cSDimitry Andric 998349cc55cSDimitry Andric // Start by getting the root command from the interpreter. 999349cc55cSDimitry Andric const char *cur_name = path.GetArgumentAtIndex(0); 1000349cc55cSDimitry Andric CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name); 1001349cc55cSDimitry Andric CommandObjectMultiword *cur_as_multi = 1002349cc55cSDimitry Andric get_multi_or_report_error(cur_cmd_sp, cur_name); 1003349cc55cSDimitry Andric if (cur_as_multi == nullptr) 1004349cc55cSDimitry Andric return nullptr; 1005349cc55cSDimitry Andric 1006349cc55cSDimitry Andric size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0); 1007349cc55cSDimitry Andric for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr; 1008349cc55cSDimitry Andric cursor++) { 1009349cc55cSDimitry Andric cur_name = path.GetArgumentAtIndex(cursor); 1010349cc55cSDimitry Andric cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name); 1011349cc55cSDimitry Andric cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name); 1012349cc55cSDimitry Andric } 1013349cc55cSDimitry Andric return cur_as_multi; 1014349cc55cSDimitry Andric } 1015349cc55cSDimitry Andric 10160b57cec5SDimitry Andric CommandObjectSP 10170b57cec5SDimitry Andric CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases, 10180b57cec5SDimitry Andric bool exact, StringList *matches, 10190b57cec5SDimitry Andric StringList *descriptions) const { 10200b57cec5SDimitry Andric CommandObjectSP command_sp; 10210b57cec5SDimitry Andric 10225ffd83dbSDimitry Andric std::string cmd = std::string(cmd_str); 10230b57cec5SDimitry Andric 10240b57cec5SDimitry Andric if (HasCommands()) { 10250b57cec5SDimitry Andric auto pos = m_command_dict.find(cmd); 10260b57cec5SDimitry Andric if (pos != m_command_dict.end()) 10270b57cec5SDimitry Andric command_sp = pos->second; 10280b57cec5SDimitry Andric } 10290b57cec5SDimitry Andric 10300b57cec5SDimitry Andric if (include_aliases && HasAliases()) { 10310b57cec5SDimitry Andric auto alias_pos = m_alias_dict.find(cmd); 10320b57cec5SDimitry Andric if (alias_pos != m_alias_dict.end()) 10330b57cec5SDimitry Andric command_sp = alias_pos->second; 10340b57cec5SDimitry Andric } 10350b57cec5SDimitry Andric 10360b57cec5SDimitry Andric if (HasUserCommands()) { 10370b57cec5SDimitry Andric auto pos = m_user_dict.find(cmd); 10380b57cec5SDimitry Andric if (pos != m_user_dict.end()) 10390b57cec5SDimitry Andric command_sp = pos->second; 10400b57cec5SDimitry Andric } 10410b57cec5SDimitry Andric 1042349cc55cSDimitry Andric if (HasUserMultiwordCommands()) { 1043349cc55cSDimitry Andric auto pos = m_user_mw_dict.find(cmd); 1044349cc55cSDimitry Andric if (pos != m_user_mw_dict.end()) 1045349cc55cSDimitry Andric command_sp = pos->second; 1046349cc55cSDimitry Andric } 1047349cc55cSDimitry Andric 10480b57cec5SDimitry Andric if (!exact && !command_sp) { 10490b57cec5SDimitry Andric // We will only get into here if we didn't find any exact matches. 10500b57cec5SDimitry Andric 1051349cc55cSDimitry Andric CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp, 1052349cc55cSDimitry Andric real_match_sp; 10530b57cec5SDimitry Andric 10540b57cec5SDimitry Andric StringList local_matches; 10550b57cec5SDimitry Andric if (matches == nullptr) 10560b57cec5SDimitry Andric matches = &local_matches; 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric unsigned int num_cmd_matches = 0; 10590b57cec5SDimitry Andric unsigned int num_alias_matches = 0; 10600b57cec5SDimitry Andric unsigned int num_user_matches = 0; 1061349cc55cSDimitry Andric unsigned int num_user_mw_matches = 0; 10620b57cec5SDimitry Andric 10630b57cec5SDimitry Andric // Look through the command dictionaries one by one, and if we get only one 10640b57cec5SDimitry Andric // match from any of them in toto, then return that, otherwise return an 10650b57cec5SDimitry Andric // empty CommandObjectSP and the list of matches. 10660b57cec5SDimitry Andric 10670b57cec5SDimitry Andric if (HasCommands()) { 10680b57cec5SDimitry Andric num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str, 10690b57cec5SDimitry Andric *matches, descriptions); 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric 10720b57cec5SDimitry Andric if (num_cmd_matches == 1) { 10730b57cec5SDimitry Andric cmd.assign(matches->GetStringAtIndex(0)); 10740b57cec5SDimitry Andric auto pos = m_command_dict.find(cmd); 10750b57cec5SDimitry Andric if (pos != m_command_dict.end()) 10760b57cec5SDimitry Andric real_match_sp = pos->second; 10770b57cec5SDimitry Andric } 10780b57cec5SDimitry Andric 10790b57cec5SDimitry Andric if (include_aliases && HasAliases()) { 10800b57cec5SDimitry Andric num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str, 10810b57cec5SDimitry Andric *matches, descriptions); 10820b57cec5SDimitry Andric } 10830b57cec5SDimitry Andric 10840b57cec5SDimitry Andric if (num_alias_matches == 1) { 10850b57cec5SDimitry Andric cmd.assign(matches->GetStringAtIndex(num_cmd_matches)); 10860b57cec5SDimitry Andric auto alias_pos = m_alias_dict.find(cmd); 10870b57cec5SDimitry Andric if (alias_pos != m_alias_dict.end()) 10880b57cec5SDimitry Andric alias_match_sp = alias_pos->second; 10890b57cec5SDimitry Andric } 10900b57cec5SDimitry Andric 10910b57cec5SDimitry Andric if (HasUserCommands()) { 10920b57cec5SDimitry Andric num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str, 10930b57cec5SDimitry Andric *matches, descriptions); 10940b57cec5SDimitry Andric } 10950b57cec5SDimitry Andric 10960b57cec5SDimitry Andric if (num_user_matches == 1) { 10970b57cec5SDimitry Andric cmd.assign( 10980b57cec5SDimitry Andric matches->GetStringAtIndex(num_cmd_matches + num_alias_matches)); 10990b57cec5SDimitry Andric 11000b57cec5SDimitry Andric auto pos = m_user_dict.find(cmd); 11010b57cec5SDimitry Andric if (pos != m_user_dict.end()) 11020b57cec5SDimitry Andric user_match_sp = pos->second; 11030b57cec5SDimitry Andric } 11040b57cec5SDimitry Andric 1105349cc55cSDimitry Andric if (HasUserMultiwordCommands()) { 1106349cc55cSDimitry Andric num_user_mw_matches = AddNamesMatchingPartialString( 1107349cc55cSDimitry Andric m_user_mw_dict, cmd_str, *matches, descriptions); 1108349cc55cSDimitry Andric } 1109349cc55cSDimitry Andric 1110349cc55cSDimitry Andric if (num_user_mw_matches == 1) { 1111349cc55cSDimitry Andric cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches + 1112349cc55cSDimitry Andric num_user_matches)); 1113349cc55cSDimitry Andric 1114349cc55cSDimitry Andric auto pos = m_user_mw_dict.find(cmd); 1115349cc55cSDimitry Andric if (pos != m_user_mw_dict.end()) 1116349cc55cSDimitry Andric user_mw_match_sp = pos->second; 1117349cc55cSDimitry Andric } 1118349cc55cSDimitry Andric 11190b57cec5SDimitry Andric // If we got exactly one match, return that, otherwise return the match 11200b57cec5SDimitry Andric // list. 11210b57cec5SDimitry Andric 1122349cc55cSDimitry Andric if (num_user_matches + num_user_mw_matches + num_cmd_matches + 1123349cc55cSDimitry Andric num_alias_matches == 1124349cc55cSDimitry Andric 1) { 11250b57cec5SDimitry Andric if (num_cmd_matches) 11260b57cec5SDimitry Andric return real_match_sp; 11270b57cec5SDimitry Andric else if (num_alias_matches) 11280b57cec5SDimitry Andric return alias_match_sp; 1129349cc55cSDimitry Andric else if (num_user_mw_matches) 1130349cc55cSDimitry Andric return user_mw_match_sp; 11310b57cec5SDimitry Andric else 11320b57cec5SDimitry Andric return user_match_sp; 11330b57cec5SDimitry Andric } 11340b57cec5SDimitry Andric } else if (matches && command_sp) { 11350b57cec5SDimitry Andric matches->AppendString(cmd_str); 11360b57cec5SDimitry Andric if (descriptions) 11370b57cec5SDimitry Andric descriptions->AppendString(command_sp->GetHelp()); 11380b57cec5SDimitry Andric } 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric return command_sp; 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric bool CommandInterpreter::AddCommand(llvm::StringRef name, 11440b57cec5SDimitry Andric const lldb::CommandObjectSP &cmd_sp, 11450b57cec5SDimitry Andric bool can_replace) { 11460b57cec5SDimitry Andric if (cmd_sp.get()) 11470b57cec5SDimitry Andric lldbassert((this == &cmd_sp->GetCommandInterpreter()) && 11480b57cec5SDimitry Andric "tried to add a CommandObject from a different interpreter"); 11490b57cec5SDimitry Andric 11500b57cec5SDimitry Andric if (name.empty()) 11510b57cec5SDimitry Andric return false; 11520b57cec5SDimitry Andric 1153349cc55cSDimitry Andric cmd_sp->SetIsUserCommand(false); 1154349cc55cSDimitry Andric 11550b57cec5SDimitry Andric std::string name_sstr(name); 11560b57cec5SDimitry Andric auto name_iter = m_command_dict.find(name_sstr); 11570b57cec5SDimitry Andric if (name_iter != m_command_dict.end()) { 11580b57cec5SDimitry Andric if (!can_replace || !name_iter->second->IsRemovable()) 11590b57cec5SDimitry Andric return false; 11600b57cec5SDimitry Andric name_iter->second = cmd_sp; 11610b57cec5SDimitry Andric } else { 11620b57cec5SDimitry Andric m_command_dict[name_sstr] = cmd_sp; 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric return true; 11650b57cec5SDimitry Andric } 11660b57cec5SDimitry Andric 1167349cc55cSDimitry Andric Status CommandInterpreter::AddUserCommand(llvm::StringRef name, 11680b57cec5SDimitry Andric const lldb::CommandObjectSP &cmd_sp, 11690b57cec5SDimitry Andric bool can_replace) { 1170349cc55cSDimitry Andric Status result; 11710b57cec5SDimitry Andric if (cmd_sp.get()) 11720b57cec5SDimitry Andric lldbassert((this == &cmd_sp->GetCommandInterpreter()) && 11730b57cec5SDimitry Andric "tried to add a CommandObject from a different interpreter"); 1174349cc55cSDimitry Andric if (name.empty()) { 1175349cc55cSDimitry Andric result.SetErrorString("can't use the empty string for a command name"); 1176349cc55cSDimitry Andric return result; 1177349cc55cSDimitry Andric } 11780b57cec5SDimitry Andric // do not allow replacement of internal commands 11790b57cec5SDimitry Andric if (CommandExists(name)) { 1180349cc55cSDimitry Andric result.SetErrorString("can't replace builtin command"); 1181349cc55cSDimitry Andric return result; 11820b57cec5SDimitry Andric } 11830b57cec5SDimitry Andric 11840b57cec5SDimitry Andric if (UserCommandExists(name)) { 1185349cc55cSDimitry Andric if (!can_replace) { 1186cb14a3feSDimitry Andric result.SetErrorStringWithFormatv( 1187cb14a3feSDimitry Andric "user command \"{0}\" already exists and force replace was not set " 1188cb14a3feSDimitry Andric "by --overwrite or 'settings set interpreter.require-overwrite " 1189cb14a3feSDimitry Andric "false'", 1190cb14a3feSDimitry Andric name); 1191349cc55cSDimitry Andric return result; 1192349cc55cSDimitry Andric } 1193349cc55cSDimitry Andric if (cmd_sp->IsMultiwordObject()) { 1194349cc55cSDimitry Andric if (!m_user_mw_dict[std::string(name)]->IsRemovable()) { 1195349cc55cSDimitry Andric result.SetErrorString( 1196349cc55cSDimitry Andric "can't replace explicitly non-removable multi-word command"); 1197349cc55cSDimitry Andric return result; 1198349cc55cSDimitry Andric } 1199349cc55cSDimitry Andric } else { 1200349cc55cSDimitry Andric if (!m_user_dict[std::string(name)]->IsRemovable()) { 1201349cc55cSDimitry Andric result.SetErrorString("can't replace explicitly non-removable command"); 1202349cc55cSDimitry Andric return result; 1203349cc55cSDimitry Andric } 1204349cc55cSDimitry Andric } 12050b57cec5SDimitry Andric } 12060b57cec5SDimitry Andric 1207349cc55cSDimitry Andric cmd_sp->SetIsUserCommand(true); 1208349cc55cSDimitry Andric 1209349cc55cSDimitry Andric if (cmd_sp->IsMultiwordObject()) 1210349cc55cSDimitry Andric m_user_mw_dict[std::string(name)] = cmd_sp; 1211349cc55cSDimitry Andric else 12125ffd83dbSDimitry Andric m_user_dict[std::string(name)] = cmd_sp; 1213349cc55cSDimitry Andric return result; 12140b57cec5SDimitry Andric } 12150b57cec5SDimitry Andric 1216e8d8bef9SDimitry Andric CommandObjectSP 1217e8d8bef9SDimitry Andric CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str, 12180b57cec5SDimitry Andric bool include_aliases) const { 1219e8d8bef9SDimitry Andric // Break up the command string into words, in case it's a multi-word command. 1220e8d8bef9SDimitry Andric Args cmd_words(cmd_str); 12210b57cec5SDimitry Andric 12220b57cec5SDimitry Andric if (cmd_str.empty()) 1223e8d8bef9SDimitry Andric return {}; 12240b57cec5SDimitry Andric 12250b57cec5SDimitry Andric if (cmd_words.GetArgumentCount() == 1) 1226e8d8bef9SDimitry Andric return GetCommandSP(cmd_str, include_aliases, true); 1227e8d8bef9SDimitry Andric 12280b57cec5SDimitry Andric // We have a multi-word command (seemingly), so we need to do more work. 12290b57cec5SDimitry Andric // First, get the cmd_obj_sp for the first word in the command. 1230e8d8bef9SDimitry Andric CommandObjectSP cmd_obj_sp = 1231e8d8bef9SDimitry Andric GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true); 1232e8d8bef9SDimitry Andric if (!cmd_obj_sp) 1233e8d8bef9SDimitry Andric return {}; 1234e8d8bef9SDimitry Andric 1235e8d8bef9SDimitry Andric // Loop through the rest of the words in the command (everything passed in 1236e8d8bef9SDimitry Andric // was supposed to be part of a command name), and find the appropriate 1237e8d8bef9SDimitry Andric // sub-command SP for each command word.... 12380b57cec5SDimitry Andric size_t end = cmd_words.GetArgumentCount(); 1239e8d8bef9SDimitry Andric for (size_t i = 1; i < end; ++i) { 1240e8d8bef9SDimitry Andric if (!cmd_obj_sp->IsMultiwordObject()) { 12410b57cec5SDimitry Andric // We have more words in the command name, but we don't have a 1242e8d8bef9SDimitry Andric // multiword object. Fail and return. 1243e8d8bef9SDimitry Andric return {}; 12440b57cec5SDimitry Andric } 1245e8d8bef9SDimitry Andric 1246e8d8bef9SDimitry Andric cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i)); 1247e8d8bef9SDimitry Andric if (!cmd_obj_sp) { 1248e8d8bef9SDimitry Andric // The sub-command name was invalid. Fail and return. 1249e8d8bef9SDimitry Andric return {}; 1250e8d8bef9SDimitry Andric } 1251e8d8bef9SDimitry Andric } 1252e8d8bef9SDimitry Andric 12530b57cec5SDimitry Andric // We successfully looped through all the command words and got valid 1254e8d8bef9SDimitry Andric // command objects for them. 1255e8d8bef9SDimitry Andric return cmd_obj_sp; 12560b57cec5SDimitry Andric } 12570b57cec5SDimitry Andric 12580b57cec5SDimitry Andric CommandObject * 12590b57cec5SDimitry Andric CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str, 12600b57cec5SDimitry Andric StringList *matches, 12610b57cec5SDimitry Andric StringList *descriptions) const { 12625f757f3fSDimitry Andric // Try to find a match among commands and aliases. Allowing inexact matches, 12635f757f3fSDimitry Andric // but perferring exact matches. 12645f757f3fSDimitry Andric return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false, 12655f757f3fSDimitry Andric matches, descriptions) 12665f757f3fSDimitry Andric .get(); 12670b57cec5SDimitry Andric } 12680b57cec5SDimitry Andric 1269349cc55cSDimitry Andric CommandObject *CommandInterpreter::GetUserCommandObject( 1270349cc55cSDimitry Andric llvm::StringRef cmd, StringList *matches, StringList *descriptions) const { 1271349cc55cSDimitry Andric std::string cmd_str(cmd); 1272349cc55cSDimitry Andric auto find_exact = [&](const CommandObject::CommandMap &map) { 1273349cc55cSDimitry Andric auto found_elem = map.find(std::string(cmd)); 1274349cc55cSDimitry Andric if (found_elem == map.end()) 1275349cc55cSDimitry Andric return (CommandObject *)nullptr; 1276349cc55cSDimitry Andric CommandObject *exact_cmd = found_elem->second.get(); 1277349cc55cSDimitry Andric if (exact_cmd) { 1278349cc55cSDimitry Andric if (matches) 1279349cc55cSDimitry Andric matches->AppendString(exact_cmd->GetCommandName()); 1280349cc55cSDimitry Andric if (descriptions) 1281349cc55cSDimitry Andric descriptions->AppendString(exact_cmd->GetHelp()); 1282349cc55cSDimitry Andric return exact_cmd; 1283349cc55cSDimitry Andric } 1284349cc55cSDimitry Andric return (CommandObject *)nullptr; 1285349cc55cSDimitry Andric }; 1286349cc55cSDimitry Andric 1287349cc55cSDimitry Andric CommandObject *exact_cmd = find_exact(GetUserCommands()); 1288349cc55cSDimitry Andric if (exact_cmd) 1289349cc55cSDimitry Andric return exact_cmd; 1290349cc55cSDimitry Andric 1291349cc55cSDimitry Andric exact_cmd = find_exact(GetUserMultiwordCommands()); 1292349cc55cSDimitry Andric if (exact_cmd) 1293349cc55cSDimitry Andric return exact_cmd; 1294349cc55cSDimitry Andric 1295349cc55cSDimitry Andric // We didn't have an exact command, so now look for partial matches. 1296349cc55cSDimitry Andric StringList tmp_list; 1297349cc55cSDimitry Andric StringList *matches_ptr = matches ? matches : &tmp_list; 1298349cc55cSDimitry Andric AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr); 1299349cc55cSDimitry Andric AddNamesMatchingPartialString(GetUserMultiwordCommands(), 1300349cc55cSDimitry Andric cmd_str, *matches_ptr); 1301349cc55cSDimitry Andric 1302349cc55cSDimitry Andric return {}; 1303349cc55cSDimitry Andric } 1304349cc55cSDimitry Andric 13050b57cec5SDimitry Andric bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const { 13065ffd83dbSDimitry Andric return m_command_dict.find(std::string(cmd)) != m_command_dict.end(); 13070b57cec5SDimitry Andric } 13080b57cec5SDimitry Andric 13090b57cec5SDimitry Andric bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd, 13100b57cec5SDimitry Andric std::string &full_name) const { 13115ffd83dbSDimitry Andric bool exact_match = 13125ffd83dbSDimitry Andric (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end()); 13130b57cec5SDimitry Andric if (exact_match) { 13145ffd83dbSDimitry Andric full_name.assign(std::string(cmd)); 13150b57cec5SDimitry Andric return exact_match; 13160b57cec5SDimitry Andric } else { 13170b57cec5SDimitry Andric StringList matches; 13180b57cec5SDimitry Andric size_t num_alias_matches; 13190b57cec5SDimitry Andric num_alias_matches = 13200b57cec5SDimitry Andric AddNamesMatchingPartialString(m_alias_dict, cmd, matches); 13210b57cec5SDimitry Andric if (num_alias_matches == 1) { 13220b57cec5SDimitry Andric // Make sure this isn't shadowing a command in the regular command space: 13230b57cec5SDimitry Andric StringList regular_matches; 13240b57cec5SDimitry Andric const bool include_aliases = false; 13250b57cec5SDimitry Andric const bool exact = false; 13260b57cec5SDimitry Andric CommandObjectSP cmd_obj_sp( 13270b57cec5SDimitry Andric GetCommandSP(cmd, include_aliases, exact, ®ular_matches)); 13280b57cec5SDimitry Andric if (cmd_obj_sp || regular_matches.GetSize() > 0) 13290b57cec5SDimitry Andric return false; 13300b57cec5SDimitry Andric else { 13310b57cec5SDimitry Andric full_name.assign(matches.GetStringAtIndex(0)); 13320b57cec5SDimitry Andric return true; 13330b57cec5SDimitry Andric } 13340b57cec5SDimitry Andric } else 13350b57cec5SDimitry Andric return false; 13360b57cec5SDimitry Andric } 13370b57cec5SDimitry Andric } 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andric bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const { 13405ffd83dbSDimitry Andric return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end(); 13410b57cec5SDimitry Andric } 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const { 13445ffd83dbSDimitry Andric return m_user_dict.find(std::string(cmd)) != m_user_dict.end(); 13450b57cec5SDimitry Andric } 13460b57cec5SDimitry Andric 1347349cc55cSDimitry Andric bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const { 1348349cc55cSDimitry Andric return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end(); 1349349cc55cSDimitry Andric } 1350349cc55cSDimitry Andric 13510b57cec5SDimitry Andric CommandAlias * 13520b57cec5SDimitry Andric CommandInterpreter::AddAlias(llvm::StringRef alias_name, 13530b57cec5SDimitry Andric lldb::CommandObjectSP &command_obj_sp, 13540b57cec5SDimitry Andric llvm::StringRef args_string) { 13550b57cec5SDimitry Andric if (command_obj_sp.get()) 13560b57cec5SDimitry Andric lldbassert((this == &command_obj_sp->GetCommandInterpreter()) && 13570b57cec5SDimitry Andric "tried to add a CommandObject from a different interpreter"); 13580b57cec5SDimitry Andric 13590b57cec5SDimitry Andric std::unique_ptr<CommandAlias> command_alias_up( 13600b57cec5SDimitry Andric new CommandAlias(*this, command_obj_sp, args_string, alias_name)); 13610b57cec5SDimitry Andric 13620b57cec5SDimitry Andric if (command_alias_up && command_alias_up->IsValid()) { 13635ffd83dbSDimitry Andric m_alias_dict[std::string(alias_name)] = 13645ffd83dbSDimitry Andric CommandObjectSP(command_alias_up.get()); 13650b57cec5SDimitry Andric return command_alias_up.release(); 13660b57cec5SDimitry Andric } 13670b57cec5SDimitry Andric 13680b57cec5SDimitry Andric return nullptr; 13690b57cec5SDimitry Andric } 13700b57cec5SDimitry Andric 13710b57cec5SDimitry Andric bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) { 13725ffd83dbSDimitry Andric auto pos = m_alias_dict.find(std::string(alias_name)); 13730b57cec5SDimitry Andric if (pos != m_alias_dict.end()) { 13740b57cec5SDimitry Andric m_alias_dict.erase(pos); 13750b57cec5SDimitry Andric return true; 13760b57cec5SDimitry Andric } 13770b57cec5SDimitry Andric return false; 13780b57cec5SDimitry Andric } 13790b57cec5SDimitry Andric 138006c3fb27SDimitry Andric bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) { 13815ffd83dbSDimitry Andric auto pos = m_command_dict.find(std::string(cmd)); 13820b57cec5SDimitry Andric if (pos != m_command_dict.end()) { 138306c3fb27SDimitry Andric if (force || pos->second->IsRemovable()) { 138406c3fb27SDimitry Andric // Only regular expression objects or python commands are removable under 138506c3fb27SDimitry Andric // normal circumstances. 13860b57cec5SDimitry Andric m_command_dict.erase(pos); 13870b57cec5SDimitry Andric return true; 13880b57cec5SDimitry Andric } 13890b57cec5SDimitry Andric } 13900b57cec5SDimitry Andric return false; 13910b57cec5SDimitry Andric } 1392349cc55cSDimitry Andric 1393349cc55cSDimitry Andric bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) { 13945ffd83dbSDimitry Andric CommandObject::CommandMap::iterator pos = 1395349cc55cSDimitry Andric m_user_dict.find(std::string(user_name)); 13960b57cec5SDimitry Andric if (pos != m_user_dict.end()) { 13970b57cec5SDimitry Andric m_user_dict.erase(pos); 13980b57cec5SDimitry Andric return true; 13990b57cec5SDimitry Andric } 14000b57cec5SDimitry Andric return false; 14010b57cec5SDimitry Andric } 14020b57cec5SDimitry Andric 1403349cc55cSDimitry Andric bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) { 1404349cc55cSDimitry Andric CommandObject::CommandMap::iterator pos = 1405349cc55cSDimitry Andric m_user_mw_dict.find(std::string(multi_name)); 1406349cc55cSDimitry Andric if (pos != m_user_mw_dict.end()) { 1407349cc55cSDimitry Andric m_user_mw_dict.erase(pos); 1408349cc55cSDimitry Andric return true; 1409349cc55cSDimitry Andric } 1410349cc55cSDimitry Andric return false; 1411349cc55cSDimitry Andric } 1412349cc55cSDimitry Andric 14130b57cec5SDimitry Andric void CommandInterpreter::GetHelp(CommandReturnObject &result, 14140b57cec5SDimitry Andric uint32_t cmd_types) { 14150b57cec5SDimitry Andric llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue()); 14160b57cec5SDimitry Andric if (!help_prologue.empty()) { 14170b57cec5SDimitry Andric OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(), 14180b57cec5SDimitry Andric help_prologue); 14190b57cec5SDimitry Andric } 14200b57cec5SDimitry Andric 14210b57cec5SDimitry Andric CommandObject::CommandMap::const_iterator pos; 14220b57cec5SDimitry Andric size_t max_len = FindLongestCommandWord(m_command_dict); 14230b57cec5SDimitry Andric 14240b57cec5SDimitry Andric if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) { 14250b57cec5SDimitry Andric result.AppendMessage("Debugger commands:"); 14260b57cec5SDimitry Andric result.AppendMessage(""); 14270b57cec5SDimitry Andric 14280b57cec5SDimitry Andric for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) { 14290b57cec5SDimitry Andric if (!(cmd_types & eCommandTypesHidden) && 14300b57cec5SDimitry Andric (pos->first.compare(0, 1, "_") == 0)) 14310b57cec5SDimitry Andric continue; 14320b57cec5SDimitry Andric 14330b57cec5SDimitry Andric OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--", 14340b57cec5SDimitry Andric pos->second->GetHelp(), max_len); 14350b57cec5SDimitry Andric } 14360b57cec5SDimitry Andric result.AppendMessage(""); 14370b57cec5SDimitry Andric } 14380b57cec5SDimitry Andric 14390b57cec5SDimitry Andric if (!m_alias_dict.empty() && 14400b57cec5SDimitry Andric ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) { 14410b57cec5SDimitry Andric result.AppendMessageWithFormat( 14420b57cec5SDimitry Andric "Current command abbreviations " 14430b57cec5SDimitry Andric "(type '%shelp command alias' for more info):\n", 14440b57cec5SDimitry Andric GetCommandPrefix()); 14450b57cec5SDimitry Andric result.AppendMessage(""); 14460b57cec5SDimitry Andric max_len = FindLongestCommandWord(m_alias_dict); 14470b57cec5SDimitry Andric 14480b57cec5SDimitry Andric for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end(); 14490b57cec5SDimitry Andric ++alias_pos) { 14500b57cec5SDimitry Andric OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--", 14510b57cec5SDimitry Andric alias_pos->second->GetHelp(), max_len); 14520b57cec5SDimitry Andric } 14530b57cec5SDimitry Andric result.AppendMessage(""); 14540b57cec5SDimitry Andric } 14550b57cec5SDimitry Andric 14560b57cec5SDimitry Andric if (!m_user_dict.empty() && 14570b57cec5SDimitry Andric ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) { 14580b57cec5SDimitry Andric result.AppendMessage("Current user-defined commands:"); 14590b57cec5SDimitry Andric result.AppendMessage(""); 14600b57cec5SDimitry Andric max_len = FindLongestCommandWord(m_user_dict); 14610b57cec5SDimitry Andric for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) { 14620b57cec5SDimitry Andric OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--", 14630b57cec5SDimitry Andric pos->second->GetHelp(), max_len); 14640b57cec5SDimitry Andric } 14650b57cec5SDimitry Andric result.AppendMessage(""); 14660b57cec5SDimitry Andric } 14670b57cec5SDimitry Andric 1468349cc55cSDimitry Andric if (!m_user_mw_dict.empty() && 1469349cc55cSDimitry Andric ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) { 1470349cc55cSDimitry Andric result.AppendMessage("Current user-defined container commands:"); 1471349cc55cSDimitry Andric result.AppendMessage(""); 1472349cc55cSDimitry Andric max_len = FindLongestCommandWord(m_user_mw_dict); 147381ad6265SDimitry Andric for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) { 1474349cc55cSDimitry Andric OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--", 1475349cc55cSDimitry Andric pos->second->GetHelp(), max_len); 1476349cc55cSDimitry Andric } 1477349cc55cSDimitry Andric result.AppendMessage(""); 1478349cc55cSDimitry Andric } 1479349cc55cSDimitry Andric 14800b57cec5SDimitry Andric result.AppendMessageWithFormat( 14810b57cec5SDimitry Andric "For more information on any command, type '%shelp <command-name>'.\n", 14820b57cec5SDimitry Andric GetCommandPrefix()); 14830b57cec5SDimitry Andric } 14840b57cec5SDimitry Andric 14850b57cec5SDimitry Andric CommandObject *CommandInterpreter::GetCommandObjectForCommand( 14860b57cec5SDimitry Andric llvm::StringRef &command_string) { 14870b57cec5SDimitry Andric // This function finds the final, lowest-level, alias-resolved command object 14880b57cec5SDimitry Andric // whose 'Execute' function will eventually be invoked by the given command 14890b57cec5SDimitry Andric // line. 14900b57cec5SDimitry Andric 14910b57cec5SDimitry Andric CommandObject *cmd_obj = nullptr; 14920b57cec5SDimitry Andric size_t start = command_string.find_first_not_of(k_white_space); 14930b57cec5SDimitry Andric size_t end = 0; 14940b57cec5SDimitry Andric bool done = false; 14950b57cec5SDimitry Andric while (!done) { 14960b57cec5SDimitry Andric if (start != std::string::npos) { 14970b57cec5SDimitry Andric // Get the next word from command_string. 14980b57cec5SDimitry Andric end = command_string.find_first_of(k_white_space, start); 14990b57cec5SDimitry Andric if (end == std::string::npos) 15000b57cec5SDimitry Andric end = command_string.size(); 15015ffd83dbSDimitry Andric std::string cmd_word = 15025ffd83dbSDimitry Andric std::string(command_string.substr(start, end - start)); 15030b57cec5SDimitry Andric 15040b57cec5SDimitry Andric if (cmd_obj == nullptr) 15050b57cec5SDimitry Andric // Since cmd_obj is NULL we are on our first time through this loop. 15060b57cec5SDimitry Andric // Check to see if cmd_word is a valid command or alias. 15070b57cec5SDimitry Andric cmd_obj = GetCommandObject(cmd_word); 15080b57cec5SDimitry Andric else if (cmd_obj->IsMultiwordObject()) { 15090b57cec5SDimitry Andric // Our current object is a multi-word object; see if the cmd_word is a 15100b57cec5SDimitry Andric // valid sub-command for our object. 15110b57cec5SDimitry Andric CommandObject *sub_cmd_obj = 15120b57cec5SDimitry Andric cmd_obj->GetSubcommandObject(cmd_word.c_str()); 15130b57cec5SDimitry Andric if (sub_cmd_obj) 15140b57cec5SDimitry Andric cmd_obj = sub_cmd_obj; 15150b57cec5SDimitry Andric else // cmd_word was not a valid sub-command word, so we are done 15160b57cec5SDimitry Andric done = true; 15170b57cec5SDimitry Andric } else 15180b57cec5SDimitry Andric // We have a cmd_obj and it is not a multi-word object, so we are done. 15190b57cec5SDimitry Andric done = true; 15200b57cec5SDimitry Andric 15210b57cec5SDimitry Andric // If we didn't find a valid command object, or our command object is not 15220b57cec5SDimitry Andric // a multi-word object, or we are at the end of the command_string, then 15230b57cec5SDimitry Andric // we are done. Otherwise, find the start of the next word. 15240b57cec5SDimitry Andric 15250b57cec5SDimitry Andric if (!cmd_obj || !cmd_obj->IsMultiwordObject() || 15260b57cec5SDimitry Andric end >= command_string.size()) 15270b57cec5SDimitry Andric done = true; 15280b57cec5SDimitry Andric else 15290b57cec5SDimitry Andric start = command_string.find_first_not_of(k_white_space, end); 15300b57cec5SDimitry Andric } else 15310b57cec5SDimitry Andric // Unable to find any more words. 15320b57cec5SDimitry Andric done = true; 15330b57cec5SDimitry Andric } 15340b57cec5SDimitry Andric 15350b57cec5SDimitry Andric command_string = command_string.substr(end); 15360b57cec5SDimitry Andric return cmd_obj; 15370b57cec5SDimitry Andric } 15380b57cec5SDimitry Andric 15390b57cec5SDimitry Andric static const char *k_valid_command_chars = 15400b57cec5SDimitry Andric "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; 15410b57cec5SDimitry Andric static void StripLeadingSpaces(std::string &s) { 15420b57cec5SDimitry Andric if (!s.empty()) { 15430b57cec5SDimitry Andric size_t pos = s.find_first_not_of(k_white_space); 15440b57cec5SDimitry Andric if (pos == std::string::npos) 15450b57cec5SDimitry Andric s.clear(); 15460b57cec5SDimitry Andric else if (pos == 0) 15470b57cec5SDimitry Andric return; 15480b57cec5SDimitry Andric s.erase(0, pos); 15490b57cec5SDimitry Andric } 15500b57cec5SDimitry Andric } 15510b57cec5SDimitry Andric 15520b57cec5SDimitry Andric static size_t FindArgumentTerminator(const std::string &s) { 15530b57cec5SDimitry Andric const size_t s_len = s.size(); 15540b57cec5SDimitry Andric size_t offset = 0; 15550b57cec5SDimitry Andric while (offset < s_len) { 15560b57cec5SDimitry Andric size_t pos = s.find("--", offset); 15570b57cec5SDimitry Andric if (pos == std::string::npos) 15580b57cec5SDimitry Andric break; 15590b57cec5SDimitry Andric if (pos > 0) { 15605ffd83dbSDimitry Andric if (llvm::isSpace(s[pos - 1])) { 15610b57cec5SDimitry Andric // Check if the string ends "\s--" (where \s is a space character) or 15620b57cec5SDimitry Andric // if we have "\s--\s". 15635ffd83dbSDimitry Andric if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) { 15640b57cec5SDimitry Andric return pos; 15650b57cec5SDimitry Andric } 15660b57cec5SDimitry Andric } 15670b57cec5SDimitry Andric } 15680b57cec5SDimitry Andric offset = pos + 2; 15690b57cec5SDimitry Andric } 15700b57cec5SDimitry Andric return std::string::npos; 15710b57cec5SDimitry Andric } 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric static bool ExtractCommand(std::string &command_string, std::string &command, 15740b57cec5SDimitry Andric std::string &suffix, char "e_char) { 15750b57cec5SDimitry Andric command.clear(); 15760b57cec5SDimitry Andric suffix.clear(); 15770b57cec5SDimitry Andric StripLeadingSpaces(command_string); 15780b57cec5SDimitry Andric 15790b57cec5SDimitry Andric bool result = false; 15800b57cec5SDimitry Andric quote_char = '\0'; 15810b57cec5SDimitry Andric 15820b57cec5SDimitry Andric if (!command_string.empty()) { 15830b57cec5SDimitry Andric const char first_char = command_string[0]; 15840b57cec5SDimitry Andric if (first_char == '\'' || first_char == '"') { 15850b57cec5SDimitry Andric quote_char = first_char; 15860b57cec5SDimitry Andric const size_t end_quote_pos = command_string.find(quote_char, 1); 15870b57cec5SDimitry Andric if (end_quote_pos == std::string::npos) { 15880b57cec5SDimitry Andric command.swap(command_string); 15890b57cec5SDimitry Andric command_string.erase(); 15900b57cec5SDimitry Andric } else { 15910b57cec5SDimitry Andric command.assign(command_string, 1, end_quote_pos - 1); 15920b57cec5SDimitry Andric if (end_quote_pos + 1 < command_string.size()) 15930b57cec5SDimitry Andric command_string.erase(0, command_string.find_first_not_of( 15940b57cec5SDimitry Andric k_white_space, end_quote_pos + 1)); 15950b57cec5SDimitry Andric else 15960b57cec5SDimitry Andric command_string.erase(); 15970b57cec5SDimitry Andric } 15980b57cec5SDimitry Andric } else { 15990b57cec5SDimitry Andric const size_t first_space_pos = 16000b57cec5SDimitry Andric command_string.find_first_of(k_white_space); 16010b57cec5SDimitry Andric if (first_space_pos == std::string::npos) { 16020b57cec5SDimitry Andric command.swap(command_string); 16030b57cec5SDimitry Andric command_string.erase(); 16040b57cec5SDimitry Andric } else { 16050b57cec5SDimitry Andric command.assign(command_string, 0, first_space_pos); 16060b57cec5SDimitry Andric command_string.erase(0, command_string.find_first_not_of( 16070b57cec5SDimitry Andric k_white_space, first_space_pos)); 16080b57cec5SDimitry Andric } 16090b57cec5SDimitry Andric } 16100b57cec5SDimitry Andric result = true; 16110b57cec5SDimitry Andric } 16120b57cec5SDimitry Andric 16130b57cec5SDimitry Andric if (!command.empty()) { 16140b57cec5SDimitry Andric // actual commands can't start with '-' or '_' 16150b57cec5SDimitry Andric if (command[0] != '-' && command[0] != '_') { 16160b57cec5SDimitry Andric size_t pos = command.find_first_not_of(k_valid_command_chars); 16170b57cec5SDimitry Andric if (pos > 0 && pos != std::string::npos) { 16180b57cec5SDimitry Andric suffix.assign(command.begin() + pos, command.end()); 16190b57cec5SDimitry Andric command.erase(pos); 16200b57cec5SDimitry Andric } 16210b57cec5SDimitry Andric } 16220b57cec5SDimitry Andric } 16230b57cec5SDimitry Andric 16240b57cec5SDimitry Andric return result; 16250b57cec5SDimitry Andric } 16260b57cec5SDimitry Andric 16270b57cec5SDimitry Andric CommandObject *CommandInterpreter::BuildAliasResult( 16280b57cec5SDimitry Andric llvm::StringRef alias_name, std::string &raw_input_string, 16290b57cec5SDimitry Andric std::string &alias_result, CommandReturnObject &result) { 16300b57cec5SDimitry Andric CommandObject *alias_cmd_obj = nullptr; 16310b57cec5SDimitry Andric Args cmd_args(raw_input_string); 16320b57cec5SDimitry Andric alias_cmd_obj = GetCommandObject(alias_name); 16330b57cec5SDimitry Andric StreamString result_str; 16340b57cec5SDimitry Andric 16350b57cec5SDimitry Andric if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) { 16360b57cec5SDimitry Andric alias_result.clear(); 16370b57cec5SDimitry Andric return alias_cmd_obj; 16380b57cec5SDimitry Andric } 16390b57cec5SDimitry Andric std::pair<CommandObjectSP, OptionArgVectorSP> desugared = 16400b57cec5SDimitry Andric ((CommandAlias *)alias_cmd_obj)->Desugar(); 16410b57cec5SDimitry Andric OptionArgVectorSP option_arg_vector_sp = desugared.second; 16420b57cec5SDimitry Andric alias_cmd_obj = desugared.first.get(); 16435ffd83dbSDimitry Andric std::string alias_name_str = std::string(alias_name); 16440b57cec5SDimitry Andric if ((cmd_args.GetArgumentCount() == 0) || 16450b57cec5SDimitry Andric (alias_name_str != cmd_args.GetArgumentAtIndex(0))) 16460b57cec5SDimitry Andric cmd_args.Unshift(alias_name_str); 16470b57cec5SDimitry Andric 16480b57cec5SDimitry Andric result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str()); 16490b57cec5SDimitry Andric 16500b57cec5SDimitry Andric if (!option_arg_vector_sp.get()) { 16515ffd83dbSDimitry Andric alias_result = std::string(result_str.GetString()); 16520b57cec5SDimitry Andric return alias_cmd_obj; 16530b57cec5SDimitry Andric } 16540b57cec5SDimitry Andric OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 16550b57cec5SDimitry Andric 16560b57cec5SDimitry Andric int value_type; 16570b57cec5SDimitry Andric std::string option; 16580b57cec5SDimitry Andric std::string value; 16590b57cec5SDimitry Andric for (const auto &entry : *option_arg_vector) { 16600b57cec5SDimitry Andric std::tie(option, value_type, value) = entry; 1661bdd1243dSDimitry Andric if (option == g_argument) { 16620b57cec5SDimitry Andric result_str.Printf(" %s", value.c_str()); 16630b57cec5SDimitry Andric continue; 16640b57cec5SDimitry Andric } 16650b57cec5SDimitry Andric 16660b57cec5SDimitry Andric result_str.Printf(" %s", option.c_str()); 16670b57cec5SDimitry Andric if (value_type == OptionParser::eNoArgument) 16680b57cec5SDimitry Andric continue; 16690b57cec5SDimitry Andric 16700b57cec5SDimitry Andric if (value_type != OptionParser::eOptionalArgument) 16710b57cec5SDimitry Andric result_str.Printf(" "); 16720b57cec5SDimitry Andric int index = GetOptionArgumentPosition(value.c_str()); 16730b57cec5SDimitry Andric if (index == 0) 16740b57cec5SDimitry Andric result_str.Printf("%s", value.c_str()); 16750b57cec5SDimitry Andric else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) { 16760b57cec5SDimitry Andric 16770b57cec5SDimitry Andric result.AppendErrorWithFormat("Not enough arguments provided; you " 16780b57cec5SDimitry Andric "need at least %d arguments to use " 16790b57cec5SDimitry Andric "this alias.\n", 16800b57cec5SDimitry Andric index); 16810b57cec5SDimitry Andric return nullptr; 16820b57cec5SDimitry Andric } else { 1683bdd1243dSDimitry Andric const Args::ArgEntry &entry = cmd_args[index]; 1684bdd1243dSDimitry Andric size_t strpos = raw_input_string.find(entry.c_str()); 1685bdd1243dSDimitry Andric const char quote_char = entry.GetQuoteChar(); 1686bdd1243dSDimitry Andric if (strpos != std::string::npos) { 1687bdd1243dSDimitry Andric const size_t start_fudge = quote_char == '\0' ? 0 : 1; 1688bdd1243dSDimitry Andric const size_t len_fudge = quote_char == '\0' ? 0 : 2; 1689bdd1243dSDimitry Andric 1690bdd1243dSDimitry Andric // Make sure we aren't going outside the bounds of the cmd string: 1691bdd1243dSDimitry Andric if (strpos < start_fudge) { 1692bdd1243dSDimitry Andric result.AppendError("Unmatched quote at command beginning."); 1693bdd1243dSDimitry Andric return nullptr; 1694bdd1243dSDimitry Andric } 1695bdd1243dSDimitry Andric llvm::StringRef arg_text = entry.ref(); 169606c3fb27SDimitry Andric if (strpos - start_fudge + arg_text.size() + len_fudge > 169706c3fb27SDimitry Andric raw_input_string.size()) { 1698bdd1243dSDimitry Andric result.AppendError("Unmatched quote at command end."); 1699bdd1243dSDimitry Andric return nullptr; 1700bdd1243dSDimitry Andric } 17010b57cec5SDimitry Andric raw_input_string = raw_input_string.erase( 1702bdd1243dSDimitry Andric strpos - start_fudge, 1703bdd1243dSDimitry Andric strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge); 1704bdd1243dSDimitry Andric } 1705bdd1243dSDimitry Andric if (quote_char == '\0') 17060b57cec5SDimitry Andric result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index)); 1707bdd1243dSDimitry Andric else 170806c3fb27SDimitry Andric result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char); 17090b57cec5SDimitry Andric } 17100b57cec5SDimitry Andric } 17110b57cec5SDimitry Andric 17125ffd83dbSDimitry Andric alias_result = std::string(result_str.GetString()); 17130b57cec5SDimitry Andric return alias_cmd_obj; 17140b57cec5SDimitry Andric } 17150b57cec5SDimitry Andric 17160b57cec5SDimitry Andric Status CommandInterpreter::PreprocessCommand(std::string &command) { 17170b57cec5SDimitry Andric // The command preprocessor needs to do things to the command line before any 17180b57cec5SDimitry Andric // parsing of arguments or anything else is done. The only current stuff that 17190b57cec5SDimitry Andric // gets preprocessed is anything enclosed in backtick ('`') characters is 17200b57cec5SDimitry Andric // evaluated as an expression and the result of the expression must be a 17210b57cec5SDimitry Andric // scalar that can be substituted into the command. An example would be: 17220b57cec5SDimitry Andric // (lldb) memory read `$rsp + 20` 17230b57cec5SDimitry Andric Status error; // Status for any expressions that might not evaluate 17240b57cec5SDimitry Andric size_t start_backtick; 17250b57cec5SDimitry Andric size_t pos = 0; 17260b57cec5SDimitry Andric while ((start_backtick = command.find('`', pos)) != std::string::npos) { 17270b57cec5SDimitry Andric // Stop if an error was encountered during the previous iteration. 17280b57cec5SDimitry Andric if (error.Fail()) 17290b57cec5SDimitry Andric break; 17300b57cec5SDimitry Andric 17310b57cec5SDimitry Andric if (start_backtick > 0 && command[start_backtick - 1] == '\\') { 17320b57cec5SDimitry Andric // The backtick was preceded by a '\' character, remove the slash and 17330b57cec5SDimitry Andric // don't treat the backtick as the start of an expression. 17340b57cec5SDimitry Andric command.erase(start_backtick - 1, 1); 17350b57cec5SDimitry Andric // No need to add one to start_backtick since we just deleted a char. 17360b57cec5SDimitry Andric pos = start_backtick; 17370b57cec5SDimitry Andric continue; 17380b57cec5SDimitry Andric } 17390b57cec5SDimitry Andric 17400b57cec5SDimitry Andric const size_t expr_content_start = start_backtick + 1; 17410b57cec5SDimitry Andric const size_t end_backtick = command.find('`', expr_content_start); 17420b57cec5SDimitry Andric 17430b57cec5SDimitry Andric if (end_backtick == std::string::npos) { 17440b57cec5SDimitry Andric // Stop if there's no end backtick. 17450b57cec5SDimitry Andric break; 17460b57cec5SDimitry Andric } 17470b57cec5SDimitry Andric 17480b57cec5SDimitry Andric if (end_backtick == expr_content_start) { 17490b57cec5SDimitry Andric // Skip over empty expression. (two backticks in a row) 17500b57cec5SDimitry Andric command.erase(start_backtick, 2); 17510b57cec5SDimitry Andric continue; 17520b57cec5SDimitry Andric } 17530b57cec5SDimitry Andric 17540b57cec5SDimitry Andric std::string expr_str(command, expr_content_start, 17550b57cec5SDimitry Andric end_backtick - expr_content_start); 175606c3fb27SDimitry Andric error = PreprocessToken(expr_str); 175706c3fb27SDimitry Andric // We always stop at the first error: 175806c3fb27SDimitry Andric if (error.Fail()) 175906c3fb27SDimitry Andric break; 17600b57cec5SDimitry Andric 176106c3fb27SDimitry Andric command.erase(start_backtick, end_backtick - start_backtick + 1); 176206c3fb27SDimitry Andric command.insert(start_backtick, std::string(expr_str)); 176306c3fb27SDimitry Andric pos = start_backtick + expr_str.size(); 176406c3fb27SDimitry Andric } 176506c3fb27SDimitry Andric return error; 176606c3fb27SDimitry Andric } 176706c3fb27SDimitry Andric 176806c3fb27SDimitry Andric Status 176906c3fb27SDimitry Andric CommandInterpreter::PreprocessToken(std::string &expr_str) { 177006c3fb27SDimitry Andric Status error; 17710b57cec5SDimitry Andric ExecutionContext exe_ctx(GetExecutionContext()); 17720b57cec5SDimitry Andric 17730b57cec5SDimitry Andric // Get a dummy target to allow for calculator mode while processing 17740b57cec5SDimitry Andric // backticks. This also helps break the infinite loop caused when target is 17750b57cec5SDimitry Andric // null. 1776e8d8bef9SDimitry Andric Target *exe_target = exe_ctx.GetTargetPtr(); 1777e8d8bef9SDimitry Andric Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget(); 17780b57cec5SDimitry Andric 17790b57cec5SDimitry Andric ValueObjectSP expr_result_valobj_sp; 17800b57cec5SDimitry Andric 17810b57cec5SDimitry Andric EvaluateExpressionOptions options; 17820b57cec5SDimitry Andric options.SetCoerceToId(false); 17830b57cec5SDimitry Andric options.SetUnwindOnError(true); 17840b57cec5SDimitry Andric options.SetIgnoreBreakpoints(true); 17850b57cec5SDimitry Andric options.SetKeepInMemory(false); 17860b57cec5SDimitry Andric options.SetTryAllThreads(true); 1787bdd1243dSDimitry Andric options.SetTimeout(std::nullopt); 17880b57cec5SDimitry Andric 17890b57cec5SDimitry Andric ExpressionResults expr_result = 1790e8d8bef9SDimitry Andric target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), 17910b57cec5SDimitry Andric expr_result_valobj_sp, options); 17920b57cec5SDimitry Andric 17930b57cec5SDimitry Andric if (expr_result == eExpressionCompleted) { 17940b57cec5SDimitry Andric Scalar scalar; 17950b57cec5SDimitry Andric if (expr_result_valobj_sp) 17960b57cec5SDimitry Andric expr_result_valobj_sp = 17970b57cec5SDimitry Andric expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable( 17980b57cec5SDimitry Andric expr_result_valobj_sp->GetDynamicValueType(), true); 17990b57cec5SDimitry Andric if (expr_result_valobj_sp->ResolveValue(scalar)) { 180006c3fb27SDimitry Andric 18010b57cec5SDimitry Andric StreamString value_strm; 18020b57cec5SDimitry Andric const bool show_type = false; 18035f757f3fSDimitry Andric scalar.GetValue(value_strm, show_type); 18040b57cec5SDimitry Andric size_t value_string_size = value_strm.GetSize(); 18050b57cec5SDimitry Andric if (value_string_size) { 180606c3fb27SDimitry Andric expr_str = value_strm.GetData(); 18070b57cec5SDimitry Andric } else { 18080b57cec5SDimitry Andric error.SetErrorStringWithFormat("expression value didn't result " 18090b57cec5SDimitry Andric "in a scalar value for the " 18100b57cec5SDimitry Andric "expression '%s'", 18110b57cec5SDimitry Andric expr_str.c_str()); 18120b57cec5SDimitry Andric } 18130b57cec5SDimitry Andric } else { 18140b57cec5SDimitry Andric error.SetErrorStringWithFormat("expression value didn't result " 18150b57cec5SDimitry Andric "in a scalar value for the " 18160b57cec5SDimitry Andric "expression '%s'", 18170b57cec5SDimitry Andric expr_str.c_str()); 181806c3fb27SDimitry Andric } 181906c3fb27SDimitry Andric return error; 18200b57cec5SDimitry Andric } 18210b57cec5SDimitry Andric 182206c3fb27SDimitry Andric // If we have an error from the expression evaluation it will be in the 182306c3fb27SDimitry Andric // ValueObject error, which won't be success and we will just report it. 182406c3fb27SDimitry Andric // But if for some reason we didn't get a value object at all, then we will 182506c3fb27SDimitry Andric // make up some helpful errors from the expression result. 18260b57cec5SDimitry Andric if (expr_result_valobj_sp) 18270b57cec5SDimitry Andric error = expr_result_valobj_sp->GetError(); 18280b57cec5SDimitry Andric 18290b57cec5SDimitry Andric if (error.Success()) { 1830*0fca6ea1SDimitry Andric std::string result = lldb_private::toString(expr_result); 1831*0fca6ea1SDimitry Andric error.SetErrorString(result + "for the expression '" + expr_str + "'"); 18320b57cec5SDimitry Andric } 18330b57cec5SDimitry Andric return error; 18340b57cec5SDimitry Andric } 18350b57cec5SDimitry Andric 18360b57cec5SDimitry Andric bool CommandInterpreter::HandleCommand(const char *command_line, 18370b57cec5SDimitry Andric LazyBool lazy_add_to_history, 1838fe6060f1SDimitry Andric const ExecutionContext &override_context, 1839fe6060f1SDimitry Andric CommandReturnObject &result) { 18400b57cec5SDimitry Andric 1841fe6060f1SDimitry Andric OverrideExecutionContext(override_context); 1842fe6060f1SDimitry Andric bool status = HandleCommand(command_line, lazy_add_to_history, result); 1843fe6060f1SDimitry Andric RestoreExecutionContext(); 1844fe6060f1SDimitry Andric return status; 1845fe6060f1SDimitry Andric } 1846fe6060f1SDimitry Andric 1847fe6060f1SDimitry Andric bool CommandInterpreter::HandleCommand(const char *command_line, 1848fe6060f1SDimitry Andric LazyBool lazy_add_to_history, 184906c3fb27SDimitry Andric CommandReturnObject &result, 185006c3fb27SDimitry Andric bool force_repeat_command) { 18510b57cec5SDimitry Andric std::string command_string(command_line); 18520b57cec5SDimitry Andric std::string original_command_string(command_line); 18530b57cec5SDimitry Andric 185481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Commands); 18550b57cec5SDimitry Andric llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")", 18560b57cec5SDimitry Andric command_line); 18570b57cec5SDimitry Andric 18589dba64beSDimitry Andric LLDB_LOGF(log, "Processing command: %s", command_line); 1859e8d8bef9SDimitry Andric LLDB_SCOPED_TIMERF("Processing command: %s.", command_line); 18600b57cec5SDimitry Andric 186106c3fb27SDimitry Andric if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) { 186206c3fb27SDimitry Andric result.AppendError("... Interrupted"); 18630b57cec5SDimitry Andric return false; 18640b57cec5SDimitry Andric } 18650b57cec5SDimitry Andric 18660b57cec5SDimitry Andric bool add_to_history; 18670b57cec5SDimitry Andric if (lazy_add_to_history == eLazyBoolCalculate) 18680b57cec5SDimitry Andric add_to_history = (m_command_source_depth == 0); 18690b57cec5SDimitry Andric else 18700b57cec5SDimitry Andric add_to_history = (lazy_add_to_history == eLazyBoolYes); 18710b57cec5SDimitry Andric 1872*0fca6ea1SDimitry Andric // The same `transcript_item` will be used below to add output and error of 1873*0fca6ea1SDimitry Andric // the command. 1874*0fca6ea1SDimitry Andric StructuredData::DictionarySP transcript_item; 1875*0fca6ea1SDimitry Andric if (GetSaveTranscript()) { 1876e8d8bef9SDimitry Andric m_transcript_stream << "(lldb) " << command_line << '\n'; 1877e8d8bef9SDimitry Andric 1878*0fca6ea1SDimitry Andric transcript_item = std::make_shared<StructuredData::Dictionary>(); 1879*0fca6ea1SDimitry Andric transcript_item->AddStringItem("command", command_line); 1880*0fca6ea1SDimitry Andric transcript_item->AddIntegerItem( 1881*0fca6ea1SDimitry Andric "timestampInEpochSeconds", 1882*0fca6ea1SDimitry Andric std::chrono::duration_cast<std::chrono::seconds>( 1883*0fca6ea1SDimitry Andric std::chrono::system_clock::now().time_since_epoch()) 1884*0fca6ea1SDimitry Andric .count()); 1885*0fca6ea1SDimitry Andric m_transcript.AddItem(transcript_item); 1886*0fca6ea1SDimitry Andric } 1887*0fca6ea1SDimitry Andric 18880b57cec5SDimitry Andric bool empty_command = false; 18890b57cec5SDimitry Andric bool comment_command = false; 18900b57cec5SDimitry Andric if (command_string.empty()) 18910b57cec5SDimitry Andric empty_command = true; 18920b57cec5SDimitry Andric else { 18930b57cec5SDimitry Andric const char *k_space_characters = "\t\n\v\f\r "; 18940b57cec5SDimitry Andric 18950b57cec5SDimitry Andric size_t non_space = command_string.find_first_not_of(k_space_characters); 18960b57cec5SDimitry Andric // Check for empty line or comment line (lines whose first non-space 18970b57cec5SDimitry Andric // character is the comment character for this interpreter) 18980b57cec5SDimitry Andric if (non_space == std::string::npos) 18990b57cec5SDimitry Andric empty_command = true; 19000b57cec5SDimitry Andric else if (command_string[non_space] == m_comment_char) 19010b57cec5SDimitry Andric comment_command = true; 19020b57cec5SDimitry Andric else if (command_string[non_space] == CommandHistory::g_repeat_char) { 19030b57cec5SDimitry Andric llvm::StringRef search_str(command_string); 19040b57cec5SDimitry Andric search_str = search_str.drop_front(non_space); 19050b57cec5SDimitry Andric if (auto hist_str = m_command_history.FindString(search_str)) { 19060b57cec5SDimitry Andric add_to_history = false; 19075ffd83dbSDimitry Andric command_string = std::string(*hist_str); 19085ffd83dbSDimitry Andric original_command_string = std::string(*hist_str); 19090b57cec5SDimitry Andric } else { 19100b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find entry: %s in history", 19110b57cec5SDimitry Andric command_string.c_str()); 19120b57cec5SDimitry Andric return false; 19130b57cec5SDimitry Andric } 19140b57cec5SDimitry Andric } 19150b57cec5SDimitry Andric } 19160b57cec5SDimitry Andric 19170b57cec5SDimitry Andric if (empty_command) { 1918fe6060f1SDimitry Andric if (!GetRepeatPreviousCommand()) { 1919fe6060f1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 1920fe6060f1SDimitry Andric return true; 1921fe6060f1SDimitry Andric } 1922fe6060f1SDimitry Andric 19230b57cec5SDimitry Andric if (m_command_history.IsEmpty()) { 19240b57cec5SDimitry Andric result.AppendError("empty command"); 19250b57cec5SDimitry Andric return false; 1926fe6060f1SDimitry Andric } 1927fe6060f1SDimitry Andric 19280b57cec5SDimitry Andric command_line = m_repeat_command.c_str(); 19290b57cec5SDimitry Andric command_string = command_line; 19300b57cec5SDimitry Andric original_command_string = command_line; 19310b57cec5SDimitry Andric if (m_repeat_command.empty()) { 1932e8d8bef9SDimitry Andric result.AppendError("No auto repeat."); 19330b57cec5SDimitry Andric return false; 19340b57cec5SDimitry Andric } 1935fe6060f1SDimitry Andric 19360b57cec5SDimitry Andric add_to_history = false; 19370b57cec5SDimitry Andric } else if (comment_command) { 19380b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 19390b57cec5SDimitry Andric return true; 19400b57cec5SDimitry Andric } 19410b57cec5SDimitry Andric 19420b57cec5SDimitry Andric // Phase 1. 19430b57cec5SDimitry Andric 19440b57cec5SDimitry Andric // Before we do ANY kind of argument processing, we need to figure out what 19450b57cec5SDimitry Andric // the real/final command object is for the specified command. This gets 19460b57cec5SDimitry Andric // complicated by the fact that the user could have specified an alias, and, 19470b57cec5SDimitry Andric // in translating the alias, there may also be command options and/or even 19480b57cec5SDimitry Andric // data (including raw text strings) that need to be found and inserted into 19490b57cec5SDimitry Andric // the command line as part of the translation. So this first step is plain 19500b57cec5SDimitry Andric // look-up and replacement, resulting in: 19510b57cec5SDimitry Andric // 1. the command object whose Execute method will actually be called 19520b57cec5SDimitry Andric // 2. a revised command string, with all substitutions and replacements 19530b57cec5SDimitry Andric // taken care of 19540b57cec5SDimitry Andric // From 1 above, we can determine whether the Execute function wants raw 19550b57cec5SDimitry Andric // input or not. 19560b57cec5SDimitry Andric 19570b57cec5SDimitry Andric CommandObject *cmd_obj = ResolveCommandImpl(command_string, result); 19580b57cec5SDimitry Andric 1959bdd1243dSDimitry Andric // We have to preprocess the whole command string for Raw commands, since we 1960bdd1243dSDimitry Andric // don't know the structure of the command. For parsed commands, we only 1961bdd1243dSDimitry Andric // treat backticks as quote characters specially. 1962bdd1243dSDimitry Andric // FIXME: We probably want to have raw commands do their own preprocessing. 1963bdd1243dSDimitry Andric // For instance, I don't think people expect substitution in expr expressions. 1964bdd1243dSDimitry Andric if (cmd_obj && cmd_obj->WantsRawCommandString()) { 1965bdd1243dSDimitry Andric Status error(PreprocessCommand(command_string)); 1966bdd1243dSDimitry Andric 1967bdd1243dSDimitry Andric if (error.Fail()) { 1968bdd1243dSDimitry Andric result.AppendError(error.AsCString()); 1969bdd1243dSDimitry Andric return false; 1970bdd1243dSDimitry Andric } 1971bdd1243dSDimitry Andric } 1972bdd1243dSDimitry Andric 19730b57cec5SDimitry Andric // Although the user may have abbreviated the command, the command_string now 19740b57cec5SDimitry Andric // has the command expanded to the full name. For example, if the input was 19750b57cec5SDimitry Andric // "br s -n main", command_string is now "breakpoint set -n main". 19760b57cec5SDimitry Andric if (log) { 19770b57cec5SDimitry Andric llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>"; 19789dba64beSDimitry Andric LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str()); 19799dba64beSDimitry Andric LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'", 19800b57cec5SDimitry Andric command_string.c_str()); 19810b57cec5SDimitry Andric const bool wants_raw_input = 19820b57cec5SDimitry Andric (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false; 19839dba64beSDimitry Andric LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'", 19840b57cec5SDimitry Andric wants_raw_input ? "True" : "False"); 19850b57cec5SDimitry Andric } 19860b57cec5SDimitry Andric 19870b57cec5SDimitry Andric // Phase 2. 19880b57cec5SDimitry Andric // Take care of things like setting up the history command & calling the 19890b57cec5SDimitry Andric // appropriate Execute method on the CommandObject, with the appropriate 19900b57cec5SDimitry Andric // arguments. 1991*0fca6ea1SDimitry Andric StatsDuration execute_time; 19920b57cec5SDimitry Andric if (cmd_obj != nullptr) { 199306c3fb27SDimitry Andric bool generate_repeat_command = add_to_history; 199481ad6265SDimitry Andric // If we got here when empty_command was true, then this command is a 199581ad6265SDimitry Andric // stored "repeat command" which we should give a chance to produce it's 199681ad6265SDimitry Andric // repeat command, even though we don't add repeat commands to the history. 199706c3fb27SDimitry Andric generate_repeat_command |= empty_command; 199806c3fb27SDimitry Andric // For `command regex`, the regex command (ex `bt`) is added to history, but 199906c3fb27SDimitry Andric // the resolved command (ex `thread backtrace`) is _not_ added to history. 200006c3fb27SDimitry Andric // However, the resolved command must be given the opportunity to provide a 200106c3fb27SDimitry Andric // repeat command. `force_repeat_command` supports this case. 200206c3fb27SDimitry Andric generate_repeat_command |= force_repeat_command; 200306c3fb27SDimitry Andric if (generate_repeat_command) { 20040b57cec5SDimitry Andric Args command_args(command_string); 2005bdd1243dSDimitry Andric std::optional<std::string> repeat_command = 200681ad6265SDimitry Andric cmd_obj->GetRepeatCommand(command_args, 0); 200706c3fb27SDimitry Andric if (repeat_command) { 200806c3fb27SDimitry Andric LLDB_LOGF(log, "Repeat command: %s", repeat_command->data()); 200981ad6265SDimitry Andric m_repeat_command.assign(*repeat_command); 201006c3fb27SDimitry Andric } else { 20110b57cec5SDimitry Andric m_repeat_command.assign(original_command_string); 20120b57cec5SDimitry Andric } 201306c3fb27SDimitry Andric } 20140b57cec5SDimitry Andric 201581ad6265SDimitry Andric if (add_to_history) 201681ad6265SDimitry Andric m_command_history.AppendString(original_command_string); 201781ad6265SDimitry Andric 20180b57cec5SDimitry Andric std::string remainder; 20190b57cec5SDimitry Andric const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size(); 20200b57cec5SDimitry Andric if (actual_cmd_name_len < command_string.length()) 20210b57cec5SDimitry Andric remainder = command_string.substr(actual_cmd_name_len); 20220b57cec5SDimitry Andric 20230b57cec5SDimitry Andric // Remove any initial spaces 20240b57cec5SDimitry Andric size_t pos = remainder.find_first_not_of(k_white_space); 20250b57cec5SDimitry Andric if (pos != 0 && pos != std::string::npos) 20260b57cec5SDimitry Andric remainder.erase(0, pos); 20270b57cec5SDimitry Andric 20289dba64beSDimitry Andric LLDB_LOGF( 20299dba64beSDimitry Andric log, "HandleCommand, command line after removing command name(s): '%s'", 20300b57cec5SDimitry Andric remainder.c_str()); 20310b57cec5SDimitry Andric 2032*0fca6ea1SDimitry Andric // To test whether or not transcript should be saved, `transcript_item` is 2033*0fca6ea1SDimitry Andric // used instead of `GetSaveTrasncript()`. This is because the latter will 2034*0fca6ea1SDimitry Andric // fail when the command is "settings set interpreter.save-transcript true". 2035*0fca6ea1SDimitry Andric if (transcript_item) { 2036*0fca6ea1SDimitry Andric transcript_item->AddStringItem("commandName", cmd_obj->GetCommandName()); 2037*0fca6ea1SDimitry Andric transcript_item->AddStringItem("commandArguments", remainder); 2038*0fca6ea1SDimitry Andric } 2039*0fca6ea1SDimitry Andric 2040*0fca6ea1SDimitry Andric ElapsedTime elapsed(execute_time); 20410b57cec5SDimitry Andric cmd_obj->Execute(remainder.c_str(), result); 20420b57cec5SDimitry Andric } 20430b57cec5SDimitry Andric 20449dba64beSDimitry Andric LLDB_LOGF(log, "HandleCommand, command %s", 20450b57cec5SDimitry Andric (result.Succeeded() ? "succeeded" : "did not succeed")); 20460b57cec5SDimitry Andric 2047*0fca6ea1SDimitry Andric // To test whether or not transcript should be saved, `transcript_item` is 2048*0fca6ea1SDimitry Andric // used instead of `GetSaveTrasncript()`. This is because the latter will 2049*0fca6ea1SDimitry Andric // fail when the command is "settings set interpreter.save-transcript true". 2050*0fca6ea1SDimitry Andric if (transcript_item) { 2051e8d8bef9SDimitry Andric m_transcript_stream << result.GetOutputData(); 2052e8d8bef9SDimitry Andric m_transcript_stream << result.GetErrorData(); 2053e8d8bef9SDimitry Andric 2054*0fca6ea1SDimitry Andric transcript_item->AddStringItem("output", result.GetOutputData()); 2055*0fca6ea1SDimitry Andric transcript_item->AddStringItem("error", result.GetErrorData()); 2056*0fca6ea1SDimitry Andric transcript_item->AddFloatItem("durationInSeconds", 2057*0fca6ea1SDimitry Andric execute_time.get().count()); 2058*0fca6ea1SDimitry Andric } 2059*0fca6ea1SDimitry Andric 20600b57cec5SDimitry Andric return result.Succeeded(); 20610b57cec5SDimitry Andric } 20620b57cec5SDimitry Andric 20639dba64beSDimitry Andric void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) { 20640b57cec5SDimitry Andric bool look_for_subcommand = false; 20650b57cec5SDimitry Andric 20660b57cec5SDimitry Andric // For any of the command completions a unique match will be a complete word. 20670b57cec5SDimitry Andric 20689dba64beSDimitry Andric if (request.GetParsedLine().GetArgumentCount() == 0) { 20690b57cec5SDimitry Andric // We got nothing on the command line, so return the list of commands 20700b57cec5SDimitry Andric bool include_aliases = true; 20710b57cec5SDimitry Andric StringList new_matches, descriptions; 20729dba64beSDimitry Andric GetCommandNamesMatchingPartialString("", include_aliases, new_matches, 20739dba64beSDimitry Andric descriptions); 20740b57cec5SDimitry Andric request.AddCompletions(new_matches, descriptions); 20750b57cec5SDimitry Andric } else if (request.GetCursorIndex() == 0) { 20760b57cec5SDimitry Andric // The cursor is in the first argument, so just do a lookup in the 20770b57cec5SDimitry Andric // dictionary. 20780b57cec5SDimitry Andric StringList new_matches, new_descriptions; 20790b57cec5SDimitry Andric CommandObject *cmd_obj = 20800b57cec5SDimitry Andric GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0), 20810b57cec5SDimitry Andric &new_matches, &new_descriptions); 20820b57cec5SDimitry Andric 20839dba64beSDimitry Andric if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() && 20840b57cec5SDimitry Andric new_matches.GetStringAtIndex(0) != nullptr && 20850b57cec5SDimitry Andric strcmp(request.GetParsedLine().GetArgumentAtIndex(0), 20860b57cec5SDimitry Andric new_matches.GetStringAtIndex(0)) == 0) { 20879dba64beSDimitry Andric if (request.GetParsedLine().GetArgumentCount() != 1) { 20880b57cec5SDimitry Andric look_for_subcommand = true; 20890b57cec5SDimitry Andric new_matches.DeleteStringAtIndex(0); 20900b57cec5SDimitry Andric new_descriptions.DeleteStringAtIndex(0); 20919dba64beSDimitry Andric request.AppendEmptyArgument(); 20920b57cec5SDimitry Andric } 20930b57cec5SDimitry Andric } 20940b57cec5SDimitry Andric request.AddCompletions(new_matches, new_descriptions); 20950b57cec5SDimitry Andric } 20960b57cec5SDimitry Andric 20970b57cec5SDimitry Andric if (request.GetCursorIndex() > 0 || look_for_subcommand) { 20980b57cec5SDimitry Andric // We are completing further on into a commands arguments, so find the 20990b57cec5SDimitry Andric // command and tell it to complete the command. First see if there is a 21000b57cec5SDimitry Andric // matching initial command: 21010b57cec5SDimitry Andric CommandObject *command_object = 21020b57cec5SDimitry Andric GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0)); 21039dba64beSDimitry Andric if (command_object) { 21049dba64beSDimitry Andric request.ShiftArguments(); 21059dba64beSDimitry Andric command_object->HandleCompletion(request); 21069dba64beSDimitry Andric } 21070b57cec5SDimitry Andric } 21080b57cec5SDimitry Andric } 21090b57cec5SDimitry Andric 21109dba64beSDimitry Andric void CommandInterpreter::HandleCompletion(CompletionRequest &request) { 21110b57cec5SDimitry Andric 21120b57cec5SDimitry Andric // Don't complete comments, and if the line we are completing is just the 21130b57cec5SDimitry Andric // history repeat character, substitute the appropriate history line. 21149dba64beSDimitry Andric llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0); 21159dba64beSDimitry Andric 21169dba64beSDimitry Andric if (!first_arg.empty()) { 21179dba64beSDimitry Andric if (first_arg.front() == m_comment_char) 21189dba64beSDimitry Andric return; 21199dba64beSDimitry Andric if (first_arg.front() == CommandHistory::g_repeat_char) { 21209dba64beSDimitry Andric if (auto hist_str = m_command_history.FindString(first_arg)) 21219dba64beSDimitry Andric request.AddCompletion(*hist_str, "Previous command history event", 21229dba64beSDimitry Andric CompletionMode::RewriteLine); 21239dba64beSDimitry Andric return; 21240b57cec5SDimitry Andric } 21250b57cec5SDimitry Andric } 21260b57cec5SDimitry Andric 21279dba64beSDimitry Andric HandleCompletionMatches(request); 21280b57cec5SDimitry Andric } 21290b57cec5SDimitry Andric 2130bdd1243dSDimitry Andric std::optional<std::string> 2131e8d8bef9SDimitry Andric CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) { 2132e8d8bef9SDimitry Andric if (line.empty()) 2133bdd1243dSDimitry Andric return std::nullopt; 2134e8d8bef9SDimitry Andric const size_t s = m_command_history.GetSize(); 2135e8d8bef9SDimitry Andric for (int i = s - 1; i >= 0; --i) { 2136e8d8bef9SDimitry Andric llvm::StringRef entry = m_command_history.GetStringAtIndex(i); 2137e8d8bef9SDimitry Andric if (entry.consume_front(line)) 2138e8d8bef9SDimitry Andric return entry.str(); 2139e8d8bef9SDimitry Andric } 2140bdd1243dSDimitry Andric return std::nullopt; 2141e8d8bef9SDimitry Andric } 2142e8d8bef9SDimitry Andric 21430b57cec5SDimitry Andric void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) { 21440b57cec5SDimitry Andric EventSP prompt_change_event_sp( 21450b57cec5SDimitry Andric new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt))); 21460b57cec5SDimitry Andric ; 21470b57cec5SDimitry Andric BroadcastEvent(prompt_change_event_sp); 21480b57cec5SDimitry Andric if (m_command_io_handler_sp) 21490b57cec5SDimitry Andric m_command_io_handler_sp->SetPrompt(new_prompt); 21500b57cec5SDimitry Andric } 21510b57cec5SDimitry Andric 21520b57cec5SDimitry Andric bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) { 21530b57cec5SDimitry Andric // Check AutoConfirm first: 21540b57cec5SDimitry Andric if (m_debugger.GetAutoConfirm()) 21550b57cec5SDimitry Andric return default_answer; 21560b57cec5SDimitry Andric 21570b57cec5SDimitry Andric IOHandlerConfirm *confirm = 21580b57cec5SDimitry Andric new IOHandlerConfirm(m_debugger, message, default_answer); 21590b57cec5SDimitry Andric IOHandlerSP io_handler_sp(confirm); 21605ffd83dbSDimitry Andric m_debugger.RunIOHandlerSync(io_handler_sp); 21610b57cec5SDimitry Andric return confirm->GetResponse(); 21620b57cec5SDimitry Andric } 21630b57cec5SDimitry Andric 21640b57cec5SDimitry Andric const CommandAlias * 21650b57cec5SDimitry Andric CommandInterpreter::GetAlias(llvm::StringRef alias_name) const { 21660b57cec5SDimitry Andric OptionArgVectorSP ret_val; 21670b57cec5SDimitry Andric 21685ffd83dbSDimitry Andric auto pos = m_alias_dict.find(std::string(alias_name)); 21690b57cec5SDimitry Andric if (pos != m_alias_dict.end()) 21700b57cec5SDimitry Andric return (CommandAlias *)pos->second.get(); 21710b57cec5SDimitry Andric 21720b57cec5SDimitry Andric return nullptr; 21730b57cec5SDimitry Andric } 21740b57cec5SDimitry Andric 21750b57cec5SDimitry Andric bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); } 21760b57cec5SDimitry Andric 21770b57cec5SDimitry Andric bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); } 21780b57cec5SDimitry Andric 21790b57cec5SDimitry Andric bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); } 21800b57cec5SDimitry Andric 2181349cc55cSDimitry Andric bool CommandInterpreter::HasUserMultiwordCommands() const { 2182349cc55cSDimitry Andric return (!m_user_mw_dict.empty()); 2183349cc55cSDimitry Andric } 2184349cc55cSDimitry Andric 21850b57cec5SDimitry Andric bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); } 21860b57cec5SDimitry Andric 21870b57cec5SDimitry Andric void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj, 21880b57cec5SDimitry Andric const char *alias_name, 21890b57cec5SDimitry Andric Args &cmd_args, 21900b57cec5SDimitry Andric std::string &raw_input_string, 21910b57cec5SDimitry Andric CommandReturnObject &result) { 21920b57cec5SDimitry Andric OptionArgVectorSP option_arg_vector_sp = 21930b57cec5SDimitry Andric GetAlias(alias_name)->GetOptionArguments(); 21940b57cec5SDimitry Andric 21950b57cec5SDimitry Andric bool wants_raw_input = alias_cmd_obj->WantsRawCommandString(); 21960b57cec5SDimitry Andric 21970b57cec5SDimitry Andric // Make sure that the alias name is the 0th element in cmd_args 21980b57cec5SDimitry Andric std::string alias_name_str = alias_name; 21990b57cec5SDimitry Andric if (alias_name_str != cmd_args.GetArgumentAtIndex(0)) 22000b57cec5SDimitry Andric cmd_args.Unshift(alias_name_str); 22010b57cec5SDimitry Andric 22020b57cec5SDimitry Andric Args new_args(alias_cmd_obj->GetCommandName()); 22030b57cec5SDimitry Andric if (new_args.GetArgumentCount() == 2) 22040b57cec5SDimitry Andric new_args.Shift(); 22050b57cec5SDimitry Andric 22060b57cec5SDimitry Andric if (option_arg_vector_sp.get()) { 22070b57cec5SDimitry Andric if (wants_raw_input) { 22080b57cec5SDimitry Andric // We have a command that both has command options and takes raw input. 22090b57cec5SDimitry Andric // Make *sure* it has a " -- " in the right place in the 22100b57cec5SDimitry Andric // raw_input_string. 22110b57cec5SDimitry Andric size_t pos = raw_input_string.find(" -- "); 22120b57cec5SDimitry Andric if (pos == std::string::npos) { 22130b57cec5SDimitry Andric // None found; assume it goes at the beginning of the raw input string 22140b57cec5SDimitry Andric raw_input_string.insert(0, " -- "); 22150b57cec5SDimitry Andric } 22160b57cec5SDimitry Andric } 22170b57cec5SDimitry Andric 22180b57cec5SDimitry Andric OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 22190b57cec5SDimitry Andric const size_t old_size = cmd_args.GetArgumentCount(); 22200b57cec5SDimitry Andric std::vector<bool> used(old_size + 1, false); 22210b57cec5SDimitry Andric 22220b57cec5SDimitry Andric used[0] = true; 22230b57cec5SDimitry Andric 22240b57cec5SDimitry Andric int value_type; 22250b57cec5SDimitry Andric std::string option; 22260b57cec5SDimitry Andric std::string value; 22270b57cec5SDimitry Andric for (const auto &option_entry : *option_arg_vector) { 22280b57cec5SDimitry Andric std::tie(option, value_type, value) = option_entry; 2229bdd1243dSDimitry Andric if (option == g_argument) { 22300b57cec5SDimitry Andric if (!wants_raw_input || (value != "--")) { 22310b57cec5SDimitry Andric // Since we inserted this above, make sure we don't insert it twice 22320b57cec5SDimitry Andric new_args.AppendArgument(value); 22330b57cec5SDimitry Andric } 22340b57cec5SDimitry Andric continue; 22350b57cec5SDimitry Andric } 22360b57cec5SDimitry Andric 22370b57cec5SDimitry Andric if (value_type != OptionParser::eOptionalArgument) 22380b57cec5SDimitry Andric new_args.AppendArgument(option); 22390b57cec5SDimitry Andric 2240bdd1243dSDimitry Andric if (value == g_no_argument) 22410b57cec5SDimitry Andric continue; 22420b57cec5SDimitry Andric 22430b57cec5SDimitry Andric int index = GetOptionArgumentPosition(value.c_str()); 22440b57cec5SDimitry Andric if (index == 0) { 22450b57cec5SDimitry Andric // value was NOT a positional argument; must be a real value 22460b57cec5SDimitry Andric if (value_type != OptionParser::eOptionalArgument) 22470b57cec5SDimitry Andric new_args.AppendArgument(value); 22480b57cec5SDimitry Andric else { 2249e8d8bef9SDimitry Andric new_args.AppendArgument(option + value); 22500b57cec5SDimitry Andric } 22510b57cec5SDimitry Andric 22520b57cec5SDimitry Andric } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) { 22530b57cec5SDimitry Andric result.AppendErrorWithFormat("Not enough arguments provided; you " 22540b57cec5SDimitry Andric "need at least %d arguments to use " 22550b57cec5SDimitry Andric "this alias.\n", 22560b57cec5SDimitry Andric index); 22570b57cec5SDimitry Andric return; 22580b57cec5SDimitry Andric } else { 22590b57cec5SDimitry Andric // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string 22600b57cec5SDimitry Andric size_t strpos = 22610b57cec5SDimitry Andric raw_input_string.find(cmd_args.GetArgumentAtIndex(index)); 22620b57cec5SDimitry Andric if (strpos != std::string::npos) { 22630b57cec5SDimitry Andric raw_input_string = raw_input_string.erase( 22640b57cec5SDimitry Andric strpos, strlen(cmd_args.GetArgumentAtIndex(index))); 22650b57cec5SDimitry Andric } 22660b57cec5SDimitry Andric 22670b57cec5SDimitry Andric if (value_type != OptionParser::eOptionalArgument) 22680b57cec5SDimitry Andric new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index)); 22690b57cec5SDimitry Andric else { 2270e8d8bef9SDimitry Andric new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index)); 22710b57cec5SDimitry Andric } 22720b57cec5SDimitry Andric used[index] = true; 22730b57cec5SDimitry Andric } 22740b57cec5SDimitry Andric } 22750b57cec5SDimitry Andric 22760b57cec5SDimitry Andric for (auto entry : llvm::enumerate(cmd_args.entries())) { 22770b57cec5SDimitry Andric if (!used[entry.index()] && !wants_raw_input) 22789dba64beSDimitry Andric new_args.AppendArgument(entry.value().ref()); 22790b57cec5SDimitry Andric } 22800b57cec5SDimitry Andric 22810b57cec5SDimitry Andric cmd_args.Clear(); 22820b57cec5SDimitry Andric cmd_args.SetArguments(new_args.GetArgumentCount(), 22830b57cec5SDimitry Andric new_args.GetConstArgumentVector()); 22840b57cec5SDimitry Andric } else { 22850b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 22860b57cec5SDimitry Andric // This alias was not created with any options; nothing further needs to be 22870b57cec5SDimitry Andric // done, unless it is a command that wants raw input, in which case we need 22880b57cec5SDimitry Andric // to clear the rest of the data from cmd_args, since its in the raw input 22890b57cec5SDimitry Andric // string. 22900b57cec5SDimitry Andric if (wants_raw_input) { 22910b57cec5SDimitry Andric cmd_args.Clear(); 22920b57cec5SDimitry Andric cmd_args.SetArguments(new_args.GetArgumentCount(), 22930b57cec5SDimitry Andric new_args.GetConstArgumentVector()); 22940b57cec5SDimitry Andric } 22950b57cec5SDimitry Andric return; 22960b57cec5SDimitry Andric } 22970b57cec5SDimitry Andric 22980b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 22990b57cec5SDimitry Andric } 23000b57cec5SDimitry Andric 23010b57cec5SDimitry Andric int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) { 23020b57cec5SDimitry Andric int position = 0; // Any string that isn't an argument position, i.e. '%' 23030b57cec5SDimitry Andric // followed by an integer, gets a position 23040b57cec5SDimitry Andric // of zero. 23050b57cec5SDimitry Andric 23060b57cec5SDimitry Andric const char *cptr = in_string; 23070b57cec5SDimitry Andric 23080b57cec5SDimitry Andric // Does it start with '%' 23090b57cec5SDimitry Andric if (cptr[0] == '%') { 23100b57cec5SDimitry Andric ++cptr; 23110b57cec5SDimitry Andric 23120b57cec5SDimitry Andric // Is the rest of it entirely digits? 23130b57cec5SDimitry Andric if (isdigit(cptr[0])) { 23140b57cec5SDimitry Andric const char *start = cptr; 23150b57cec5SDimitry Andric while (isdigit(cptr[0])) 23160b57cec5SDimitry Andric ++cptr; 23170b57cec5SDimitry Andric 23180b57cec5SDimitry Andric // We've gotten to the end of the digits; are we at the end of the 23190b57cec5SDimitry Andric // string? 23200b57cec5SDimitry Andric if (cptr[0] == '\0') 23210b57cec5SDimitry Andric position = atoi(start); 23220b57cec5SDimitry Andric } 23230b57cec5SDimitry Andric } 23240b57cec5SDimitry Andric 23250b57cec5SDimitry Andric return position; 23260b57cec5SDimitry Andric } 23270b57cec5SDimitry Andric 23280b57cec5SDimitry Andric static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file, 23290b57cec5SDimitry Andric llvm::StringRef suffix = {}) { 23300b57cec5SDimitry Andric std::string init_file_name = ".lldbinit"; 23310b57cec5SDimitry Andric if (!suffix.empty()) { 23320b57cec5SDimitry Andric init_file_name.append("-"); 23330b57cec5SDimitry Andric init_file_name.append(suffix.str()); 23340b57cec5SDimitry Andric } 23350b57cec5SDimitry Andric 2336e8d8bef9SDimitry Andric FileSystem::Instance().GetHomeDirectory(init_file); 23370b57cec5SDimitry Andric llvm::sys::path::append(init_file, init_file_name); 23380b57cec5SDimitry Andric 23390b57cec5SDimitry Andric FileSystem::Instance().Resolve(init_file); 23400b57cec5SDimitry Andric } 23410b57cec5SDimitry Andric 234204eeddc0SDimitry Andric static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file, 234304eeddc0SDimitry Andric LanguageType language) { 234404eeddc0SDimitry Andric if (language == eLanguageTypeUnknown) { 2345e8d8bef9SDimitry Andric LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs(); 2346e8d8bef9SDimitry Andric if (auto main_repl_language = repl_languages.GetSingularLanguage()) 2347e8d8bef9SDimitry Andric language = *main_repl_language; 2348e8d8bef9SDimitry Andric else 2349e8d8bef9SDimitry Andric return; 235004eeddc0SDimitry Andric } 2351e8d8bef9SDimitry Andric 2352e8d8bef9SDimitry Andric std::string init_file_name = 2353e8d8bef9SDimitry Andric (llvm::Twine(".lldbinit-") + 2354e8d8bef9SDimitry Andric llvm::Twine(Language::GetNameForLanguageType(language)) + 2355e8d8bef9SDimitry Andric llvm::Twine("-repl")) 2356e8d8bef9SDimitry Andric .str(); 2357e8d8bef9SDimitry Andric FileSystem::Instance().GetHomeDirectory(init_file); 2358e8d8bef9SDimitry Andric llvm::sys::path::append(init_file, init_file_name); 2359e8d8bef9SDimitry Andric FileSystem::Instance().Resolve(init_file); 2360e8d8bef9SDimitry Andric } 2361e8d8bef9SDimitry Andric 23620b57cec5SDimitry Andric static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) { 23630b57cec5SDimitry Andric llvm::StringRef s = ".lldbinit"; 23640b57cec5SDimitry Andric init_file.assign(s.begin(), s.end()); 23650b57cec5SDimitry Andric FileSystem::Instance().Resolve(init_file); 23660b57cec5SDimitry Andric } 23670b57cec5SDimitry Andric 23680b57cec5SDimitry Andric void CommandInterpreter::SourceInitFile(FileSpec file, 23690b57cec5SDimitry Andric CommandReturnObject &result) { 23700b57cec5SDimitry Andric assert(!m_skip_lldbinit_files); 23710b57cec5SDimitry Andric 23720b57cec5SDimitry Andric if (!FileSystem::Instance().Exists(file)) { 23730b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 23740b57cec5SDimitry Andric return; 23750b57cec5SDimitry Andric } 23760b57cec5SDimitry Andric 23770b57cec5SDimitry Andric // Use HandleCommand to 'source' the given file; this will do the actual 23780b57cec5SDimitry Andric // broadcasting of the commands back to any appropriate listener (see 23790b57cec5SDimitry Andric // CommandObjectSource::Execute for more details). 23800b57cec5SDimitry Andric const bool saved_batch = SetBatchCommandMode(true); 23810b57cec5SDimitry Andric CommandInterpreterRunOptions options; 23820b57cec5SDimitry Andric options.SetSilent(true); 23830b57cec5SDimitry Andric options.SetPrintErrors(true); 23840b57cec5SDimitry Andric options.SetStopOnError(false); 23850b57cec5SDimitry Andric options.SetStopOnContinue(true); 2386fe6060f1SDimitry Andric HandleCommandsFromFile(file, options, result); 23870b57cec5SDimitry Andric SetBatchCommandMode(saved_batch); 23880b57cec5SDimitry Andric } 23890b57cec5SDimitry Andric 23900b57cec5SDimitry Andric void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) { 23910b57cec5SDimitry Andric if (m_skip_lldbinit_files) { 23920b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 23930b57cec5SDimitry Andric return; 23940b57cec5SDimitry Andric } 23950b57cec5SDimitry Andric 23960b57cec5SDimitry Andric llvm::SmallString<128> init_file; 23970b57cec5SDimitry Andric GetCwdInitFile(init_file); 23980b57cec5SDimitry Andric if (!FileSystem::Instance().Exists(init_file)) { 23990b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 24000b57cec5SDimitry Andric return; 24010b57cec5SDimitry Andric } 24020b57cec5SDimitry Andric 2403349cc55cSDimitry Andric LoadCWDlldbinitFile should_load = 2404349cc55cSDimitry Andric Target::GetGlobalProperties().GetLoadCWDlldbinitFile(); 24050b57cec5SDimitry Andric 24060b57cec5SDimitry Andric switch (should_load) { 24070b57cec5SDimitry Andric case eLoadCWDlldbinitFalse: 24080b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 24090b57cec5SDimitry Andric break; 24100b57cec5SDimitry Andric case eLoadCWDlldbinitTrue: 24110b57cec5SDimitry Andric SourceInitFile(FileSpec(init_file.str()), result); 24120b57cec5SDimitry Andric break; 24130b57cec5SDimitry Andric case eLoadCWDlldbinitWarn: { 24140b57cec5SDimitry Andric llvm::SmallString<128> home_init_file; 24150b57cec5SDimitry Andric GetHomeInitFile(home_init_file); 24160b57cec5SDimitry Andric if (llvm::sys::path::parent_path(init_file) == 24170b57cec5SDimitry Andric llvm::sys::path::parent_path(home_init_file)) { 24180b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 24190b57cec5SDimitry Andric } else { 2420e8d8bef9SDimitry Andric result.AppendError(InitFileWarning); 24210b57cec5SDimitry Andric } 24220b57cec5SDimitry Andric } 24230b57cec5SDimitry Andric } 24240b57cec5SDimitry Andric } 24250b57cec5SDimitry Andric 24260b57cec5SDimitry Andric /// We will first see if there is an application specific ".lldbinit" file 24270b57cec5SDimitry Andric /// whose name is "~/.lldbinit" followed by a "-" and the name of the program. 2428e8d8bef9SDimitry Andric /// If this file doesn't exist, we fall back to the REPL init file or the 2429e8d8bef9SDimitry Andric /// default home init file in "~/.lldbinit". 2430e8d8bef9SDimitry Andric void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result, 2431e8d8bef9SDimitry Andric bool is_repl) { 24320b57cec5SDimitry Andric if (m_skip_lldbinit_files) { 24330b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 24340b57cec5SDimitry Andric return; 24350b57cec5SDimitry Andric } 24360b57cec5SDimitry Andric 24370b57cec5SDimitry Andric llvm::SmallString<128> init_file; 2438e8d8bef9SDimitry Andric 2439e8d8bef9SDimitry Andric if (is_repl) 244004eeddc0SDimitry Andric GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage()); 2441e8d8bef9SDimitry Andric 2442e8d8bef9SDimitry Andric if (init_file.empty()) 24430b57cec5SDimitry Andric GetHomeInitFile(init_file); 24440b57cec5SDimitry Andric 24450b57cec5SDimitry Andric if (!m_skip_app_init_files) { 24460b57cec5SDimitry Andric llvm::StringRef program_name = 24470b57cec5SDimitry Andric HostInfo::GetProgramFileSpec().GetFilename().GetStringRef(); 24480b57cec5SDimitry Andric llvm::SmallString<128> program_init_file; 24490b57cec5SDimitry Andric GetHomeInitFile(program_init_file, program_name); 24500b57cec5SDimitry Andric if (FileSystem::Instance().Exists(program_init_file)) 24510b57cec5SDimitry Andric init_file = program_init_file; 24520b57cec5SDimitry Andric } 24530b57cec5SDimitry Andric 24540b57cec5SDimitry Andric SourceInitFile(FileSpec(init_file.str()), result); 24550b57cec5SDimitry Andric } 24560b57cec5SDimitry Andric 245781ad6265SDimitry Andric void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) { 245881ad6265SDimitry Andric #ifdef LLDB_GLOBAL_INIT_DIRECTORY 245981ad6265SDimitry Andric if (!m_skip_lldbinit_files) { 246081ad6265SDimitry Andric FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY); 246181ad6265SDimitry Andric if (init_file) 246281ad6265SDimitry Andric init_file.MakeAbsolute(HostInfo::GetShlibDir()); 246381ad6265SDimitry Andric 246481ad6265SDimitry Andric init_file.AppendPathComponent("lldbinit"); 246581ad6265SDimitry Andric SourceInitFile(init_file, result); 246681ad6265SDimitry Andric return; 246781ad6265SDimitry Andric } 246881ad6265SDimitry Andric #endif 246981ad6265SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 247081ad6265SDimitry Andric } 247181ad6265SDimitry Andric 24720b57cec5SDimitry Andric const char *CommandInterpreter::GetCommandPrefix() { 24730b57cec5SDimitry Andric const char *prefix = GetDebugger().GetIOHandlerCommandPrefix(); 24740b57cec5SDimitry Andric return prefix == nullptr ? "" : prefix; 24750b57cec5SDimitry Andric } 24760b57cec5SDimitry Andric 24770b57cec5SDimitry Andric PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) { 24780b57cec5SDimitry Andric PlatformSP platform_sp; 24790b57cec5SDimitry Andric if (prefer_target_platform) { 24800b57cec5SDimitry Andric ExecutionContext exe_ctx(GetExecutionContext()); 24810b57cec5SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 24820b57cec5SDimitry Andric if (target) 24830b57cec5SDimitry Andric platform_sp = target->GetPlatform(); 24840b57cec5SDimitry Andric } 24850b57cec5SDimitry Andric 24860b57cec5SDimitry Andric if (!platform_sp) 24870b57cec5SDimitry Andric platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform(); 24880b57cec5SDimitry Andric return platform_sp; 24890b57cec5SDimitry Andric } 24900b57cec5SDimitry Andric 24919dba64beSDimitry Andric bool CommandInterpreter::DidProcessStopAbnormally() const { 2492fe6060f1SDimitry Andric auto exe_ctx = GetExecutionContext(); 2493fe6060f1SDimitry Andric TargetSP target_sp = exe_ctx.GetTargetSP(); 24949dba64beSDimitry Andric if (!target_sp) 24959dba64beSDimitry Andric return false; 24969dba64beSDimitry Andric 24979dba64beSDimitry Andric ProcessSP process_sp(target_sp->GetProcessSP()); 24989dba64beSDimitry Andric if (!process_sp) 24999dba64beSDimitry Andric return false; 25009dba64beSDimitry Andric 25019dba64beSDimitry Andric if (eStateStopped != process_sp->GetState()) 25029dba64beSDimitry Andric return false; 25039dba64beSDimitry Andric 25049dba64beSDimitry Andric for (const auto &thread_sp : process_sp->GetThreadList().Threads()) { 25059dba64beSDimitry Andric StopInfoSP stop_info = thread_sp->GetStopInfo(); 2506bdd1243dSDimitry Andric if (!stop_info) { 2507bdd1243dSDimitry Andric // If there's no stop_info, keep iterating through the other threads; 2508bdd1243dSDimitry Andric // it's enough that any thread has got a stop_info that indicates 2509bdd1243dSDimitry Andric // an abnormal stop, to consider the process to be stopped abnormally. 2510bdd1243dSDimitry Andric continue; 2511bdd1243dSDimitry Andric } 25129dba64beSDimitry Andric 25139dba64beSDimitry Andric const StopReason reason = stop_info->GetStopReason(); 2514fe6060f1SDimitry Andric if (reason == eStopReasonException || 2515fe6060f1SDimitry Andric reason == eStopReasonInstrumentation || 2516fe6060f1SDimitry Andric reason == eStopReasonProcessorTrace) 25179dba64beSDimitry Andric return true; 25189dba64beSDimitry Andric 25199dba64beSDimitry Andric if (reason == eStopReasonSignal) { 25209dba64beSDimitry Andric const auto stop_signal = static_cast<int32_t>(stop_info->GetValue()); 25219dba64beSDimitry Andric UnixSignalsSP signals_sp = process_sp->GetUnixSignals(); 25229dba64beSDimitry Andric if (!signals_sp || !signals_sp->SignalIsValid(stop_signal)) 25239dba64beSDimitry Andric // The signal is unknown, treat it as abnormal. 25249dba64beSDimitry Andric return true; 25259dba64beSDimitry Andric 25269dba64beSDimitry Andric const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT"); 25279dba64beSDimitry Andric const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP"); 25289dba64beSDimitry Andric if ((stop_signal != sigint_num) && (stop_signal != sigstop_num)) 25299dba64beSDimitry Andric // The signal very likely implies a crash. 25309dba64beSDimitry Andric return true; 25319dba64beSDimitry Andric } 25329dba64beSDimitry Andric } 25339dba64beSDimitry Andric 25349dba64beSDimitry Andric return false; 25359dba64beSDimitry Andric } 25369dba64beSDimitry Andric 2537fe6060f1SDimitry Andric void 2538fe6060f1SDimitry Andric CommandInterpreter::HandleCommands(const StringList &commands, 2539fe6060f1SDimitry Andric const ExecutionContext &override_context, 2540fe6060f1SDimitry Andric const CommandInterpreterRunOptions &options, 2541fe6060f1SDimitry Andric CommandReturnObject &result) { 2542fe6060f1SDimitry Andric 2543fe6060f1SDimitry Andric OverrideExecutionContext(override_context); 2544fe6060f1SDimitry Andric HandleCommands(commands, options, result); 2545fe6060f1SDimitry Andric RestoreExecutionContext(); 2546fe6060f1SDimitry Andric } 2547fe6060f1SDimitry Andric 25480b57cec5SDimitry Andric void CommandInterpreter::HandleCommands(const StringList &commands, 2549fe6060f1SDimitry Andric const CommandInterpreterRunOptions &options, 25500b57cec5SDimitry Andric CommandReturnObject &result) { 25510b57cec5SDimitry Andric size_t num_lines = commands.GetSize(); 25520b57cec5SDimitry Andric 25530b57cec5SDimitry Andric // If we are going to continue past a "continue" then we need to run the 25540b57cec5SDimitry Andric // commands synchronously. Make sure you reset this value anywhere you return 25550b57cec5SDimitry Andric // from the function. 25560b57cec5SDimitry Andric 25570b57cec5SDimitry Andric bool old_async_execution = m_debugger.GetAsyncExecution(); 25580b57cec5SDimitry Andric 25590b57cec5SDimitry Andric if (!options.GetStopOnContinue()) { 25600b57cec5SDimitry Andric m_debugger.SetAsyncExecution(false); 25610b57cec5SDimitry Andric } 25620b57cec5SDimitry Andric 256306c3fb27SDimitry Andric for (size_t idx = 0; idx < num_lines; idx++) { 25640b57cec5SDimitry Andric const char *cmd = commands.GetStringAtIndex(idx); 25650b57cec5SDimitry Andric if (cmd[0] == '\0') 25660b57cec5SDimitry Andric continue; 25670b57cec5SDimitry Andric 25680b57cec5SDimitry Andric if (options.GetEchoCommands()) { 25690b57cec5SDimitry Andric // TODO: Add Stream support. 25700b57cec5SDimitry Andric result.AppendMessageWithFormat("%s %s\n", 25710b57cec5SDimitry Andric m_debugger.GetPrompt().str().c_str(), cmd); 25720b57cec5SDimitry Andric } 25730b57cec5SDimitry Andric 25745ffd83dbSDimitry Andric CommandReturnObject tmp_result(m_debugger.GetUseColor()); 2575e8d8bef9SDimitry Andric tmp_result.SetInteractive(result.GetInteractive()); 2576fe6060f1SDimitry Andric tmp_result.SetSuppressImmediateOutput(true); 25770b57cec5SDimitry Andric 25780b57cec5SDimitry Andric // We might call into a regex or alias command, in which case the 25790b57cec5SDimitry Andric // add_to_history will get lost. This m_command_source_depth dingus is the 25800b57cec5SDimitry Andric // way we turn off adding to the history in that case, so set it up here. 25810b57cec5SDimitry Andric if (!options.GetAddToHistory()) 25820b57cec5SDimitry Andric m_command_source_depth++; 2583fe6060f1SDimitry Andric bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result); 25840b57cec5SDimitry Andric if (!options.GetAddToHistory()) 25850b57cec5SDimitry Andric m_command_source_depth--; 25860b57cec5SDimitry Andric 25870b57cec5SDimitry Andric if (options.GetPrintResults()) { 25880b57cec5SDimitry Andric if (tmp_result.Succeeded()) 25890b57cec5SDimitry Andric result.AppendMessage(tmp_result.GetOutputData()); 25900b57cec5SDimitry Andric } 25910b57cec5SDimitry Andric 25920b57cec5SDimitry Andric if (!success || !tmp_result.Succeeded()) { 25930b57cec5SDimitry Andric llvm::StringRef error_msg = tmp_result.GetErrorData(); 25940b57cec5SDimitry Andric if (error_msg.empty()) 25950b57cec5SDimitry Andric error_msg = "<unknown error>.\n"; 25960b57cec5SDimitry Andric if (options.GetStopOnError()) { 25970b57cec5SDimitry Andric result.AppendErrorWithFormat( 25980b57cec5SDimitry Andric "Aborting reading of commands after command #%" PRIu64 25990b57cec5SDimitry Andric ": '%s' failed with %s", 26000b57cec5SDimitry Andric (uint64_t)idx, cmd, error_msg.str().c_str()); 26010b57cec5SDimitry Andric m_debugger.SetAsyncExecution(old_async_execution); 26020b57cec5SDimitry Andric return; 26030b57cec5SDimitry Andric } else if (options.GetPrintResults()) { 26040b57cec5SDimitry Andric result.AppendMessageWithFormat( 26050b57cec5SDimitry Andric "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd, 26060b57cec5SDimitry Andric error_msg.str().c_str()); 26070b57cec5SDimitry Andric } 26080b57cec5SDimitry Andric } 26090b57cec5SDimitry Andric 26100b57cec5SDimitry Andric if (result.GetImmediateOutputStream()) 26110b57cec5SDimitry Andric result.GetImmediateOutputStream()->Flush(); 26120b57cec5SDimitry Andric 26130b57cec5SDimitry Andric if (result.GetImmediateErrorStream()) 26140b57cec5SDimitry Andric result.GetImmediateErrorStream()->Flush(); 26150b57cec5SDimitry Andric 26160b57cec5SDimitry Andric // N.B. Can't depend on DidChangeProcessState, because the state coming 26170b57cec5SDimitry Andric // into the command execution could be running (for instance in Breakpoint 26180b57cec5SDimitry Andric // Commands. So we check the return value to see if it is has running in 26190b57cec5SDimitry Andric // it. 26200b57cec5SDimitry Andric if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) || 26210b57cec5SDimitry Andric (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) { 26220b57cec5SDimitry Andric if (options.GetStopOnContinue()) { 26230b57cec5SDimitry Andric // If we caused the target to proceed, and we're going to stop in that 26240b57cec5SDimitry Andric // case, set the status in our real result before returning. This is 26250b57cec5SDimitry Andric // an error if the continue was not the last command in the set of 26260b57cec5SDimitry Andric // commands to be run. 26270b57cec5SDimitry Andric if (idx != num_lines - 1) 26280b57cec5SDimitry Andric result.AppendErrorWithFormat( 26290b57cec5SDimitry Andric "Aborting reading of commands after command #%" PRIu64 26300b57cec5SDimitry Andric ": '%s' continued the target.\n", 26310b57cec5SDimitry Andric (uint64_t)idx + 1, cmd); 26320b57cec5SDimitry Andric else 26330b57cec5SDimitry Andric result.AppendMessageWithFormat("Command #%" PRIu64 26340b57cec5SDimitry Andric " '%s' continued the target.\n", 26350b57cec5SDimitry Andric (uint64_t)idx + 1, cmd); 26360b57cec5SDimitry Andric 26370b57cec5SDimitry Andric result.SetStatus(tmp_result.GetStatus()); 26380b57cec5SDimitry Andric m_debugger.SetAsyncExecution(old_async_execution); 26390b57cec5SDimitry Andric 26400b57cec5SDimitry Andric return; 26410b57cec5SDimitry Andric } 26420b57cec5SDimitry Andric } 26430b57cec5SDimitry Andric 26440b57cec5SDimitry Andric // Also check for "stop on crash here: 26459dba64beSDimitry Andric if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() && 26469dba64beSDimitry Andric DidProcessStopAbnormally()) { 26470b57cec5SDimitry Andric if (idx != num_lines - 1) 26480b57cec5SDimitry Andric result.AppendErrorWithFormat( 26490b57cec5SDimitry Andric "Aborting reading of commands after command #%" PRIu64 26500b57cec5SDimitry Andric ": '%s' stopped with a signal or exception.\n", 26510b57cec5SDimitry Andric (uint64_t)idx + 1, cmd); 26520b57cec5SDimitry Andric else 26530b57cec5SDimitry Andric result.AppendMessageWithFormat( 26540b57cec5SDimitry Andric "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n", 26550b57cec5SDimitry Andric (uint64_t)idx + 1, cmd); 26560b57cec5SDimitry Andric 26570b57cec5SDimitry Andric result.SetStatus(tmp_result.GetStatus()); 26580b57cec5SDimitry Andric m_debugger.SetAsyncExecution(old_async_execution); 26590b57cec5SDimitry Andric 26600b57cec5SDimitry Andric return; 26610b57cec5SDimitry Andric } 26620b57cec5SDimitry Andric } 26630b57cec5SDimitry Andric 26640b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 26650b57cec5SDimitry Andric m_debugger.SetAsyncExecution(old_async_execution); 26660b57cec5SDimitry Andric } 26670b57cec5SDimitry Andric 26680b57cec5SDimitry Andric // Make flags that we can pass into the IOHandler so our delegates can do the 26690b57cec5SDimitry Andric // right thing 26700b57cec5SDimitry Andric enum { 26710b57cec5SDimitry Andric eHandleCommandFlagStopOnContinue = (1u << 0), 26720b57cec5SDimitry Andric eHandleCommandFlagStopOnError = (1u << 1), 26730b57cec5SDimitry Andric eHandleCommandFlagEchoCommand = (1u << 2), 26740b57cec5SDimitry Andric eHandleCommandFlagEchoCommentCommand = (1u << 3), 26750b57cec5SDimitry Andric eHandleCommandFlagPrintResult = (1u << 4), 26760b57cec5SDimitry Andric eHandleCommandFlagPrintErrors = (1u << 5), 2677*0fca6ea1SDimitry Andric eHandleCommandFlagStopOnCrash = (1u << 6), 2678*0fca6ea1SDimitry Andric eHandleCommandFlagAllowRepeats = (1u << 7) 26790b57cec5SDimitry Andric }; 26800b57cec5SDimitry Andric 26810b57cec5SDimitry Andric void CommandInterpreter::HandleCommandsFromFile( 2682fe6060f1SDimitry Andric FileSpec &cmd_file, const ExecutionContext &context, 2683fe6060f1SDimitry Andric const CommandInterpreterRunOptions &options, CommandReturnObject &result) { 2684fe6060f1SDimitry Andric OverrideExecutionContext(context); 2685fe6060f1SDimitry Andric HandleCommandsFromFile(cmd_file, options, result); 2686fe6060f1SDimitry Andric RestoreExecutionContext(); 2687fe6060f1SDimitry Andric } 2688fe6060f1SDimitry Andric 2689fe6060f1SDimitry Andric void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file, 2690fe6060f1SDimitry Andric const CommandInterpreterRunOptions &options, CommandReturnObject &result) { 26910b57cec5SDimitry Andric if (!FileSystem::Instance().Exists(cmd_file)) { 26920b57cec5SDimitry Andric result.AppendErrorWithFormat( 26930b57cec5SDimitry Andric "Error reading commands from file %s - file not found.\n", 26940b57cec5SDimitry Andric cmd_file.GetFilename().AsCString("<Unknown>")); 26950b57cec5SDimitry Andric return; 26960b57cec5SDimitry Andric } 26970b57cec5SDimitry Andric 26980b57cec5SDimitry Andric std::string cmd_file_path = cmd_file.GetPath(); 26999dba64beSDimitry Andric auto input_file_up = 2700349cc55cSDimitry Andric FileSystem::Instance().Open(cmd_file, File::eOpenOptionReadOnly); 27019dba64beSDimitry Andric if (!input_file_up) { 27029dba64beSDimitry Andric std::string error = llvm::toString(input_file_up.takeError()); 27039dba64beSDimitry Andric result.AppendErrorWithFormatv( 27049dba64beSDimitry Andric "error: an error occurred read file '{0}': {1}\n", cmd_file_path, 27059dba64beSDimitry Andric llvm::fmt_consume(input_file_up.takeError())); 27060b57cec5SDimitry Andric return; 27070b57cec5SDimitry Andric } 27089dba64beSDimitry Andric FileSP input_file_sp = FileSP(std::move(input_file_up.get())); 27090b57cec5SDimitry Andric 27100b57cec5SDimitry Andric Debugger &debugger = GetDebugger(); 27110b57cec5SDimitry Andric 27120b57cec5SDimitry Andric uint32_t flags = 0; 27130b57cec5SDimitry Andric 27140b57cec5SDimitry Andric if (options.m_stop_on_continue == eLazyBoolCalculate) { 27150b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27160b57cec5SDimitry Andric // Stop on continue by default 27170b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnContinue; 27180b57cec5SDimitry Andric } else if (m_command_source_flags.back() & 27190b57cec5SDimitry Andric eHandleCommandFlagStopOnContinue) { 27200b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnContinue; 27210b57cec5SDimitry Andric } 27220b57cec5SDimitry Andric } else if (options.m_stop_on_continue == eLazyBoolYes) { 27230b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnContinue; 27240b57cec5SDimitry Andric } 27250b57cec5SDimitry Andric 27260b57cec5SDimitry Andric if (options.m_stop_on_error == eLazyBoolCalculate) { 27270b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27280b57cec5SDimitry Andric if (GetStopCmdSourceOnError()) 27290b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnError; 27300b57cec5SDimitry Andric } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) { 27310b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnError; 27320b57cec5SDimitry Andric } 27330b57cec5SDimitry Andric } else if (options.m_stop_on_error == eLazyBoolYes) { 27340b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnError; 27350b57cec5SDimitry Andric } 27360b57cec5SDimitry Andric 27370b57cec5SDimitry Andric // stop-on-crash can only be set, if it is present in all levels of 27380b57cec5SDimitry Andric // pushed flag sets. 27390b57cec5SDimitry Andric if (options.GetStopOnCrash()) { 27400b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27410b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnCrash; 27420b57cec5SDimitry Andric } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) { 27430b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnCrash; 27440b57cec5SDimitry Andric } 27450b57cec5SDimitry Andric } 27460b57cec5SDimitry Andric 27470b57cec5SDimitry Andric if (options.m_echo_commands == eLazyBoolCalculate) { 27480b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27490b57cec5SDimitry Andric // Echo command by default 27500b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommand; 27510b57cec5SDimitry Andric } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) { 27520b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommand; 27530b57cec5SDimitry Andric } 27540b57cec5SDimitry Andric } else if (options.m_echo_commands == eLazyBoolYes) { 27550b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommand; 27560b57cec5SDimitry Andric } 27570b57cec5SDimitry Andric 27580b57cec5SDimitry Andric // We will only ever ask for this flag, if we echo commands in general. 27590b57cec5SDimitry Andric if (options.m_echo_comment_commands == eLazyBoolCalculate) { 27600b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27610b57cec5SDimitry Andric // Echo comments by default 27620b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommentCommand; 27630b57cec5SDimitry Andric } else if (m_command_source_flags.back() & 27640b57cec5SDimitry Andric eHandleCommandFlagEchoCommentCommand) { 27650b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommentCommand; 27660b57cec5SDimitry Andric } 27670b57cec5SDimitry Andric } else if (options.m_echo_comment_commands == eLazyBoolYes) { 27680b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommentCommand; 27690b57cec5SDimitry Andric } 27700b57cec5SDimitry Andric 27710b57cec5SDimitry Andric if (options.m_print_results == eLazyBoolCalculate) { 27720b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27730b57cec5SDimitry Andric // Print output by default 27740b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintResult; 27750b57cec5SDimitry Andric } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) { 27760b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintResult; 27770b57cec5SDimitry Andric } 27780b57cec5SDimitry Andric } else if (options.m_print_results == eLazyBoolYes) { 27790b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintResult; 27800b57cec5SDimitry Andric } 27810b57cec5SDimitry Andric 27820b57cec5SDimitry Andric if (options.m_print_errors == eLazyBoolCalculate) { 27830b57cec5SDimitry Andric if (m_command_source_flags.empty()) { 27840b57cec5SDimitry Andric // Print output by default 27850b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintErrors; 27860b57cec5SDimitry Andric } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) { 27870b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintErrors; 27880b57cec5SDimitry Andric } 27890b57cec5SDimitry Andric } else if (options.m_print_errors == eLazyBoolYes) { 27900b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintErrors; 27910b57cec5SDimitry Andric } 27920b57cec5SDimitry Andric 27930b57cec5SDimitry Andric if (flags & eHandleCommandFlagPrintResult) { 27949dba64beSDimitry Andric debugger.GetOutputFile().Printf("Executing commands in '%s'.\n", 27950b57cec5SDimitry Andric cmd_file_path.c_str()); 27960b57cec5SDimitry Andric } 27970b57cec5SDimitry Andric 27980b57cec5SDimitry Andric // Used for inheriting the right settings when "command source" might 27990b57cec5SDimitry Andric // have nested "command source" commands 28000b57cec5SDimitry Andric lldb::StreamFileSP empty_stream_sp; 28010b57cec5SDimitry Andric m_command_source_flags.push_back(flags); 28020b57cec5SDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerEditline( 28030b57cec5SDimitry Andric debugger, IOHandler::Type::CommandInterpreter, input_file_sp, 28040b57cec5SDimitry Andric empty_stream_sp, // Pass in an empty stream so we inherit the top 28050b57cec5SDimitry Andric // input reader output stream 28060b57cec5SDimitry Andric empty_stream_sp, // Pass in an empty stream so we inherit the top 28070b57cec5SDimitry Andric // input reader error stream 28080b57cec5SDimitry Andric flags, 28090b57cec5SDimitry Andric nullptr, // Pass in NULL for "editline_name" so no history is saved, 28100b57cec5SDimitry Andric // or written 28110b57cec5SDimitry Andric debugger.GetPrompt(), llvm::StringRef(), 28120b57cec5SDimitry Andric false, // Not multi-line 2813bdd1243dSDimitry Andric debugger.GetUseColor(), 0, *this)); 28140b57cec5SDimitry Andric const bool old_async_execution = debugger.GetAsyncExecution(); 28150b57cec5SDimitry Andric 28160b57cec5SDimitry Andric // Set synchronous execution if we are not stopping on continue 28170b57cec5SDimitry Andric if ((flags & eHandleCommandFlagStopOnContinue) == 0) 28180b57cec5SDimitry Andric debugger.SetAsyncExecution(false); 28190b57cec5SDimitry Andric 28200b57cec5SDimitry Andric m_command_source_depth++; 2821e8d8bef9SDimitry Andric m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent()); 28220b57cec5SDimitry Andric 28235ffd83dbSDimitry Andric debugger.RunIOHandlerSync(io_handler_sp); 28240b57cec5SDimitry Andric if (!m_command_source_flags.empty()) 28250b57cec5SDimitry Andric m_command_source_flags.pop_back(); 2826e8d8bef9SDimitry Andric 2827e8d8bef9SDimitry Andric m_command_source_dirs.pop_back(); 28280b57cec5SDimitry Andric m_command_source_depth--; 2829e8d8bef9SDimitry Andric 28300b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 28310b57cec5SDimitry Andric debugger.SetAsyncExecution(old_async_execution); 28320b57cec5SDimitry Andric } 28330b57cec5SDimitry Andric 28340b57cec5SDimitry Andric bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; } 28350b57cec5SDimitry Andric 28360b57cec5SDimitry Andric void CommandInterpreter::SetSynchronous(bool value) { 28370b57cec5SDimitry Andric m_synchronous_execution = value; 28380b57cec5SDimitry Andric } 28390b57cec5SDimitry Andric 28400b57cec5SDimitry Andric void CommandInterpreter::OutputFormattedHelpText(Stream &strm, 28410b57cec5SDimitry Andric llvm::StringRef prefix, 28420b57cec5SDimitry Andric llvm::StringRef help_text) { 28430b57cec5SDimitry Andric const uint32_t max_columns = m_debugger.GetTerminalWidth(); 28440b57cec5SDimitry Andric 28450b57cec5SDimitry Andric size_t line_width_max = max_columns - prefix.size(); 28460b57cec5SDimitry Andric if (line_width_max < 16) 28470b57cec5SDimitry Andric line_width_max = help_text.size() + prefix.size(); 28480b57cec5SDimitry Andric 28490b57cec5SDimitry Andric strm.IndentMore(prefix.size()); 28500b57cec5SDimitry Andric bool prefixed_yet = false; 2851349cc55cSDimitry Andric // Even if we have no help text we still want to emit the command name. 2852349cc55cSDimitry Andric if (help_text.empty()) 2853349cc55cSDimitry Andric help_text = "No help text"; 28540b57cec5SDimitry Andric while (!help_text.empty()) { 28550b57cec5SDimitry Andric // Prefix the first line, indent subsequent lines to line up 28560b57cec5SDimitry Andric if (!prefixed_yet) { 28570b57cec5SDimitry Andric strm << prefix; 28580b57cec5SDimitry Andric prefixed_yet = true; 28590b57cec5SDimitry Andric } else 28600b57cec5SDimitry Andric strm.Indent(); 28610b57cec5SDimitry Andric 28620b57cec5SDimitry Andric // Never print more than the maximum on one line. 28630b57cec5SDimitry Andric llvm::StringRef this_line = help_text.substr(0, line_width_max); 28640b57cec5SDimitry Andric 28650b57cec5SDimitry Andric // Always break on an explicit newline. 28660b57cec5SDimitry Andric std::size_t first_newline = this_line.find_first_of("\n"); 28670b57cec5SDimitry Andric 28680b57cec5SDimitry Andric // Don't break on space/tab unless the text is too long to fit on one line. 28690b57cec5SDimitry Andric std::size_t last_space = llvm::StringRef::npos; 28700b57cec5SDimitry Andric if (this_line.size() != help_text.size()) 28710b57cec5SDimitry Andric last_space = this_line.find_last_of(" \t"); 28720b57cec5SDimitry Andric 28730b57cec5SDimitry Andric // Break at whichever condition triggered first. 28740b57cec5SDimitry Andric this_line = this_line.substr(0, std::min(first_newline, last_space)); 28750b57cec5SDimitry Andric strm.PutCString(this_line); 28760b57cec5SDimitry Andric strm.EOL(); 28770b57cec5SDimitry Andric 28780b57cec5SDimitry Andric // Remove whitespace / newlines after breaking. 28790b57cec5SDimitry Andric help_text = help_text.drop_front(this_line.size()).ltrim(); 28800b57cec5SDimitry Andric } 28810b57cec5SDimitry Andric strm.IndentLess(prefix.size()); 28820b57cec5SDimitry Andric } 28830b57cec5SDimitry Andric 28840b57cec5SDimitry Andric void CommandInterpreter::OutputFormattedHelpText(Stream &strm, 28850b57cec5SDimitry Andric llvm::StringRef word_text, 28860b57cec5SDimitry Andric llvm::StringRef separator, 28870b57cec5SDimitry Andric llvm::StringRef help_text, 28880b57cec5SDimitry Andric size_t max_word_len) { 28890b57cec5SDimitry Andric StreamString prefix_stream; 28900b57cec5SDimitry Andric prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(), 28910b57cec5SDimitry Andric (int)separator.size(), separator.data()); 28920b57cec5SDimitry Andric OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text); 28930b57cec5SDimitry Andric } 28940b57cec5SDimitry Andric 28950b57cec5SDimitry Andric void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text, 28960b57cec5SDimitry Andric llvm::StringRef separator, 28970b57cec5SDimitry Andric llvm::StringRef help_text, 28980b57cec5SDimitry Andric uint32_t max_word_len) { 28990b57cec5SDimitry Andric int indent_size = max_word_len + separator.size() + 2; 29000b57cec5SDimitry Andric 29010b57cec5SDimitry Andric strm.IndentMore(indent_size); 29020b57cec5SDimitry Andric 29030b57cec5SDimitry Andric StreamString text_strm; 29040b57cec5SDimitry Andric text_strm.Printf("%-*s ", (int)max_word_len, word_text.data()); 29050b57cec5SDimitry Andric text_strm << separator << " " << help_text; 29060b57cec5SDimitry Andric 29070b57cec5SDimitry Andric const uint32_t max_columns = m_debugger.GetTerminalWidth(); 29080b57cec5SDimitry Andric 29090b57cec5SDimitry Andric llvm::StringRef text = text_strm.GetString(); 29100b57cec5SDimitry Andric 29110b57cec5SDimitry Andric uint32_t chars_left = max_columns; 29120b57cec5SDimitry Andric 29130b57cec5SDimitry Andric auto nextWordLength = [](llvm::StringRef S) { 29140b57cec5SDimitry Andric size_t pos = S.find(' '); 29150b57cec5SDimitry Andric return pos == llvm::StringRef::npos ? S.size() : pos; 29160b57cec5SDimitry Andric }; 29170b57cec5SDimitry Andric 29180b57cec5SDimitry Andric while (!text.empty()) { 29190b57cec5SDimitry Andric if (text.front() == '\n' || 29200b57cec5SDimitry Andric (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) { 29210b57cec5SDimitry Andric strm.EOL(); 29220b57cec5SDimitry Andric strm.Indent(); 29230b57cec5SDimitry Andric chars_left = max_columns - indent_size; 29240b57cec5SDimitry Andric if (text.front() == '\n') 29250b57cec5SDimitry Andric text = text.drop_front(); 29260b57cec5SDimitry Andric else 29270b57cec5SDimitry Andric text = text.ltrim(' '); 29280b57cec5SDimitry Andric } else { 29290b57cec5SDimitry Andric strm.PutChar(text.front()); 29300b57cec5SDimitry Andric --chars_left; 29310b57cec5SDimitry Andric text = text.drop_front(); 29320b57cec5SDimitry Andric } 29330b57cec5SDimitry Andric } 29340b57cec5SDimitry Andric 29350b57cec5SDimitry Andric strm.EOL(); 29360b57cec5SDimitry Andric strm.IndentLess(indent_size); 29370b57cec5SDimitry Andric } 29380b57cec5SDimitry Andric 29390b57cec5SDimitry Andric void CommandInterpreter::FindCommandsForApropos( 29400b57cec5SDimitry Andric llvm::StringRef search_word, StringList &commands_found, 294104eeddc0SDimitry Andric StringList &commands_help, const CommandObject::CommandMap &command_map) { 294204eeddc0SDimitry Andric for (const auto &pair : command_map) { 294304eeddc0SDimitry Andric llvm::StringRef command_name = pair.first; 294404eeddc0SDimitry Andric CommandObject *cmd_obj = pair.second.get(); 29450b57cec5SDimitry Andric 29460b57cec5SDimitry Andric const bool search_short_help = true; 29470b57cec5SDimitry Andric const bool search_long_help = false; 29480b57cec5SDimitry Andric const bool search_syntax = false; 29490b57cec5SDimitry Andric const bool search_options = false; 2950fe6060f1SDimitry Andric if (command_name.contains_insensitive(search_word) || 29510b57cec5SDimitry Andric cmd_obj->HelpTextContainsWord(search_word, search_short_help, 29520b57cec5SDimitry Andric search_long_help, search_syntax, 29530b57cec5SDimitry Andric search_options)) { 295404eeddc0SDimitry Andric commands_found.AppendString(command_name); 29550b57cec5SDimitry Andric commands_help.AppendString(cmd_obj->GetHelp()); 29560b57cec5SDimitry Andric } 29570b57cec5SDimitry Andric 295804eeddc0SDimitry Andric if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) { 295904eeddc0SDimitry Andric StringList subcommands_found; 296004eeddc0SDimitry Andric FindCommandsForApropos(search_word, subcommands_found, commands_help, 296104eeddc0SDimitry Andric multiword_cmd->GetSubcommandDictionary()); 296204eeddc0SDimitry Andric for (const auto &subcommand_name : subcommands_found) { 296304eeddc0SDimitry Andric std::string qualified_name = 296404eeddc0SDimitry Andric (command_name + " " + subcommand_name).str(); 296504eeddc0SDimitry Andric commands_found.AppendString(qualified_name); 296604eeddc0SDimitry Andric } 29670b57cec5SDimitry Andric } 29680b57cec5SDimitry Andric } 29690b57cec5SDimitry Andric } 29700b57cec5SDimitry Andric 29710b57cec5SDimitry Andric void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word, 29720b57cec5SDimitry Andric StringList &commands_found, 29730b57cec5SDimitry Andric StringList &commands_help, 29740b57cec5SDimitry Andric bool search_builtin_commands, 29750b57cec5SDimitry Andric bool search_user_commands, 2976349cc55cSDimitry Andric bool search_alias_commands, 2977349cc55cSDimitry Andric bool search_user_mw_commands) { 29780b57cec5SDimitry Andric CommandObject::CommandMap::const_iterator pos; 29790b57cec5SDimitry Andric 29800b57cec5SDimitry Andric if (search_builtin_commands) 29810b57cec5SDimitry Andric FindCommandsForApropos(search_word, commands_found, commands_help, 29820b57cec5SDimitry Andric m_command_dict); 29830b57cec5SDimitry Andric 29840b57cec5SDimitry Andric if (search_user_commands) 29850b57cec5SDimitry Andric FindCommandsForApropos(search_word, commands_found, commands_help, 29860b57cec5SDimitry Andric m_user_dict); 29870b57cec5SDimitry Andric 2988349cc55cSDimitry Andric if (search_user_mw_commands) 2989349cc55cSDimitry Andric FindCommandsForApropos(search_word, commands_found, commands_help, 2990349cc55cSDimitry Andric m_user_mw_dict); 2991349cc55cSDimitry Andric 29920b57cec5SDimitry Andric if (search_alias_commands) 29930b57cec5SDimitry Andric FindCommandsForApropos(search_word, commands_found, commands_help, 29940b57cec5SDimitry Andric m_alias_dict); 29950b57cec5SDimitry Andric } 29960b57cec5SDimitry Andric 2997fe6060f1SDimitry Andric ExecutionContext CommandInterpreter::GetExecutionContext() const { 2998fe6060f1SDimitry Andric return !m_overriden_exe_contexts.empty() 2999fe6060f1SDimitry Andric ? m_overriden_exe_contexts.top() 3000fe6060f1SDimitry Andric : m_debugger.GetSelectedExecutionContext(); 30010b57cec5SDimitry Andric } 3002fe6060f1SDimitry Andric 3003fe6060f1SDimitry Andric void CommandInterpreter::OverrideExecutionContext( 3004fe6060f1SDimitry Andric const ExecutionContext &override_context) { 3005fe6060f1SDimitry Andric m_overriden_exe_contexts.push(override_context); 3006fe6060f1SDimitry Andric } 3007fe6060f1SDimitry Andric 3008fe6060f1SDimitry Andric void CommandInterpreter::RestoreExecutionContext() { 3009fe6060f1SDimitry Andric if (!m_overriden_exe_contexts.empty()) 3010fe6060f1SDimitry Andric m_overriden_exe_contexts.pop(); 30110b57cec5SDimitry Andric } 30120b57cec5SDimitry Andric 30139dba64beSDimitry Andric void CommandInterpreter::GetProcessOutput() { 3014fe6060f1SDimitry Andric if (ProcessSP process_sp = GetExecutionContext().GetProcessSP()) 30159dba64beSDimitry Andric m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true, 30169dba64beSDimitry Andric /*flush_stderr*/ true); 30170b57cec5SDimitry Andric } 30180b57cec5SDimitry Andric 30190b57cec5SDimitry Andric void CommandInterpreter::StartHandlingCommand() { 30200b57cec5SDimitry Andric auto idle_state = CommandHandlingState::eIdle; 30210b57cec5SDimitry Andric if (m_command_state.compare_exchange_strong( 30220b57cec5SDimitry Andric idle_state, CommandHandlingState::eInProgress)) 30230b57cec5SDimitry Andric lldbassert(m_iohandler_nesting_level == 0); 30240b57cec5SDimitry Andric else 30250b57cec5SDimitry Andric lldbassert(m_iohandler_nesting_level > 0); 30260b57cec5SDimitry Andric ++m_iohandler_nesting_level; 30270b57cec5SDimitry Andric } 30280b57cec5SDimitry Andric 30290b57cec5SDimitry Andric void CommandInterpreter::FinishHandlingCommand() { 30300b57cec5SDimitry Andric lldbassert(m_iohandler_nesting_level > 0); 30310b57cec5SDimitry Andric if (--m_iohandler_nesting_level == 0) { 30320b57cec5SDimitry Andric auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle); 30330b57cec5SDimitry Andric lldbassert(prev_state != CommandHandlingState::eIdle); 30340b57cec5SDimitry Andric } 30350b57cec5SDimitry Andric } 30360b57cec5SDimitry Andric 30370b57cec5SDimitry Andric bool CommandInterpreter::InterruptCommand() { 30380b57cec5SDimitry Andric auto in_progress = CommandHandlingState::eInProgress; 30390b57cec5SDimitry Andric return m_command_state.compare_exchange_strong( 30400b57cec5SDimitry Andric in_progress, CommandHandlingState::eInterrupted); 30410b57cec5SDimitry Andric } 30420b57cec5SDimitry Andric 30430b57cec5SDimitry Andric bool CommandInterpreter::WasInterrupted() const { 304406c3fb27SDimitry Andric if (!m_debugger.IsIOHandlerThreadCurrentThread()) 304506c3fb27SDimitry Andric return false; 304606c3fb27SDimitry Andric 30470b57cec5SDimitry Andric bool was_interrupted = 30480b57cec5SDimitry Andric (m_command_state == CommandHandlingState::eInterrupted); 30490b57cec5SDimitry Andric lldbassert(!was_interrupted || m_iohandler_nesting_level > 0); 30500b57cec5SDimitry Andric return was_interrupted; 30510b57cec5SDimitry Andric } 30520b57cec5SDimitry Andric 305381ad6265SDimitry Andric void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, 305481ad6265SDimitry Andric llvm::StringRef str, 305581ad6265SDimitry Andric bool is_stdout) { 305681ad6265SDimitry Andric 305781ad6265SDimitry Andric lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP() 305881ad6265SDimitry Andric : io_handler.GetErrorStreamFileSP(); 30590b57cec5SDimitry Andric // Split the output into lines and poll for interrupt requests 306006c3fb27SDimitry Andric bool had_output = !str.empty(); 306106c3fb27SDimitry Andric while (!str.empty()) { 306281ad6265SDimitry Andric llvm::StringRef line; 306381ad6265SDimitry Andric std::tie(line, str) = str.split('\n'); 306481ad6265SDimitry Andric { 306581ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); 306681ad6265SDimitry Andric stream->Write(line.data(), line.size()); 306781ad6265SDimitry Andric stream->Write("\n", 1); 30680b57cec5SDimitry Andric } 30690b57cec5SDimitry Andric } 307081ad6265SDimitry Andric 307181ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); 3072*0fca6ea1SDimitry Andric if (had_output && 3073*0fca6ea1SDimitry Andric INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output")) 307481ad6265SDimitry Andric stream->Printf("\n... Interrupted.\n"); 307581ad6265SDimitry Andric stream->Flush(); 30760b57cec5SDimitry Andric } 30770b57cec5SDimitry Andric 30780b57cec5SDimitry Andric bool CommandInterpreter::EchoCommandNonInteractive( 30790b57cec5SDimitry Andric llvm::StringRef line, const Flags &io_handler_flags) const { 30800b57cec5SDimitry Andric if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand)) 30810b57cec5SDimitry Andric return false; 30820b57cec5SDimitry Andric 30830b57cec5SDimitry Andric llvm::StringRef command = line.trim(); 30840b57cec5SDimitry Andric if (command.empty()) 30850b57cec5SDimitry Andric return true; 30860b57cec5SDimitry Andric 30870b57cec5SDimitry Andric if (command.front() == m_comment_char) 30880b57cec5SDimitry Andric return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand); 30890b57cec5SDimitry Andric 30900b57cec5SDimitry Andric return true; 30910b57cec5SDimitry Andric } 30920b57cec5SDimitry Andric 30930b57cec5SDimitry Andric void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, 30940b57cec5SDimitry Andric std::string &line) { 30950b57cec5SDimitry Andric // If we were interrupted, bail out... 30960b57cec5SDimitry Andric if (WasInterrupted()) 30970b57cec5SDimitry Andric return; 30980b57cec5SDimitry Andric 30990b57cec5SDimitry Andric const bool is_interactive = io_handler.GetIsInteractive(); 3100*0fca6ea1SDimitry Andric const bool allow_repeats = 3101*0fca6ea1SDimitry Andric io_handler.GetFlags().Test(eHandleCommandFlagAllowRepeats); 3102*0fca6ea1SDimitry Andric 3103*0fca6ea1SDimitry Andric if (!is_interactive && !allow_repeats) { 31040b57cec5SDimitry Andric // When we are not interactive, don't execute blank lines. This will happen 31050b57cec5SDimitry Andric // sourcing a commands file. We don't want blank lines to repeat the 31060b57cec5SDimitry Andric // previous command and cause any errors to occur (like redefining an 31070b57cec5SDimitry Andric // alias, get an error and stop parsing the commands file). 3108*0fca6ea1SDimitry Andric // But obey the AllowRepeats flag if the user has set it. 31090b57cec5SDimitry Andric if (line.empty()) 31100b57cec5SDimitry Andric return; 3111*0fca6ea1SDimitry Andric } 3112*0fca6ea1SDimitry Andric if (!is_interactive) { 31130b57cec5SDimitry Andric // When using a non-interactive file handle (like when sourcing commands 31140b57cec5SDimitry Andric // from a file) we need to echo the command out so we don't just see the 31150b57cec5SDimitry Andric // command output and no command... 311681ad6265SDimitry Andric if (EchoCommandNonInteractive(line, io_handler.GetFlags())) { 311781ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); 31189dba64beSDimitry Andric io_handler.GetOutputStreamFileSP()->Printf( 31199dba64beSDimitry Andric "%s%s\n", io_handler.GetPrompt(), line.c_str()); 31200b57cec5SDimitry Andric } 312181ad6265SDimitry Andric } 31220b57cec5SDimitry Andric 31230b57cec5SDimitry Andric StartHandlingCommand(); 31240b57cec5SDimitry Andric 312581ad6265SDimitry Andric ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext(); 312681ad6265SDimitry Andric bool pushed_exe_ctx = false; 312781ad6265SDimitry Andric if (exe_ctx.HasTargetScope()) { 312881ad6265SDimitry Andric OverrideExecutionContext(exe_ctx); 312981ad6265SDimitry Andric pushed_exe_ctx = true; 313081ad6265SDimitry Andric } 313181ad6265SDimitry Andric auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() { 313281ad6265SDimitry Andric if (pushed_exe_ctx) 3133fe6060f1SDimitry Andric RestoreExecutionContext(); 3134fe6060f1SDimitry Andric }); 3135fe6060f1SDimitry Andric 31365ffd83dbSDimitry Andric lldb_private::CommandReturnObject result(m_debugger.GetUseColor()); 31370b57cec5SDimitry Andric HandleCommand(line.c_str(), eLazyBoolCalculate, result); 31380b57cec5SDimitry Andric 31390b57cec5SDimitry Andric // Now emit the command output text from the command we just executed 31400b57cec5SDimitry Andric if ((result.Succeeded() && 31410b57cec5SDimitry Andric io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) || 31420b57cec5SDimitry Andric io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) { 31430b57cec5SDimitry Andric // Display any STDOUT/STDERR _prior_ to emitting the command result text 31440b57cec5SDimitry Andric GetProcessOutput(); 31450b57cec5SDimitry Andric 31460b57cec5SDimitry Andric if (!result.GetImmediateOutputStream()) { 31470b57cec5SDimitry Andric llvm::StringRef output = result.GetOutputData(); 314881ad6265SDimitry Andric PrintCommandOutput(io_handler, output, true); 31490b57cec5SDimitry Andric } 31500b57cec5SDimitry Andric 31510b57cec5SDimitry Andric // Now emit the command error text from the command we just executed 31520b57cec5SDimitry Andric if (!result.GetImmediateErrorStream()) { 31530b57cec5SDimitry Andric llvm::StringRef error = result.GetErrorData(); 315481ad6265SDimitry Andric PrintCommandOutput(io_handler, error, false); 31550b57cec5SDimitry Andric } 31560b57cec5SDimitry Andric } 31570b57cec5SDimitry Andric 31580b57cec5SDimitry Andric FinishHandlingCommand(); 31590b57cec5SDimitry Andric 31600b57cec5SDimitry Andric switch (result.GetStatus()) { 31610b57cec5SDimitry Andric case eReturnStatusInvalid: 31620b57cec5SDimitry Andric case eReturnStatusSuccessFinishNoResult: 31630b57cec5SDimitry Andric case eReturnStatusSuccessFinishResult: 31640b57cec5SDimitry Andric case eReturnStatusStarted: 31650b57cec5SDimitry Andric break; 31660b57cec5SDimitry Andric 31670b57cec5SDimitry Andric case eReturnStatusSuccessContinuingNoResult: 31680b57cec5SDimitry Andric case eReturnStatusSuccessContinuingResult: 31690b57cec5SDimitry Andric if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue)) 31700b57cec5SDimitry Andric io_handler.SetIsDone(true); 31710b57cec5SDimitry Andric break; 31720b57cec5SDimitry Andric 31730b57cec5SDimitry Andric case eReturnStatusFailed: 31745ffd83dbSDimitry Andric m_result.IncrementNumberOfErrors(); 31755ffd83dbSDimitry Andric if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) { 31765ffd83dbSDimitry Andric m_result.SetResult(lldb::eCommandInterpreterResultCommandError); 31770b57cec5SDimitry Andric io_handler.SetIsDone(true); 31785ffd83dbSDimitry Andric } 31790b57cec5SDimitry Andric break; 31800b57cec5SDimitry Andric 31810b57cec5SDimitry Andric case eReturnStatusQuit: 31825ffd83dbSDimitry Andric m_result.SetResult(lldb::eCommandInterpreterResultQuitRequested); 31830b57cec5SDimitry Andric io_handler.SetIsDone(true); 31840b57cec5SDimitry Andric break; 31850b57cec5SDimitry Andric } 31860b57cec5SDimitry Andric 31870b57cec5SDimitry Andric // Finally, if we're going to stop on crash, check that here: 31885ffd83dbSDimitry Andric if (m_result.IsResult(lldb::eCommandInterpreterResultSuccess) && 31895ffd83dbSDimitry Andric result.GetDidChangeProcessState() && 31909dba64beSDimitry Andric io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) && 31919dba64beSDimitry Andric DidProcessStopAbnormally()) { 31920b57cec5SDimitry Andric io_handler.SetIsDone(true); 31935ffd83dbSDimitry Andric m_result.SetResult(lldb::eCommandInterpreterResultInferiorCrash); 31940b57cec5SDimitry Andric } 31950b57cec5SDimitry Andric } 31960b57cec5SDimitry Andric 31970b57cec5SDimitry Andric bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) { 31980b57cec5SDimitry Andric ExecutionContext exe_ctx(GetExecutionContext()); 31990b57cec5SDimitry Andric Process *process = exe_ctx.GetProcessPtr(); 32000b57cec5SDimitry Andric 32010b57cec5SDimitry Andric if (InterruptCommand()) 32020b57cec5SDimitry Andric return true; 32030b57cec5SDimitry Andric 32040b57cec5SDimitry Andric if (process) { 32050b57cec5SDimitry Andric StateType state = process->GetState(); 32060b57cec5SDimitry Andric if (StateIsRunningState(state)) { 32070b57cec5SDimitry Andric process->Halt(); 32080b57cec5SDimitry Andric return true; // Don't do any updating when we are running 32090b57cec5SDimitry Andric } 32100b57cec5SDimitry Andric } 32110b57cec5SDimitry Andric 32120b57cec5SDimitry Andric ScriptInterpreter *script_interpreter = 32130b57cec5SDimitry Andric m_debugger.GetScriptInterpreter(false); 32140b57cec5SDimitry Andric if (script_interpreter) { 32150b57cec5SDimitry Andric if (script_interpreter->Interrupt()) 32160b57cec5SDimitry Andric return true; 32170b57cec5SDimitry Andric } 32180b57cec5SDimitry Andric return false; 32190b57cec5SDimitry Andric } 32200b57cec5SDimitry Andric 3221e8d8bef9SDimitry Andric bool CommandInterpreter::SaveTranscript( 3222bdd1243dSDimitry Andric CommandReturnObject &result, std::optional<std::string> output_file) { 3223bdd1243dSDimitry Andric if (output_file == std::nullopt || output_file->empty()) { 3224e8d8bef9SDimitry Andric std::string now = llvm::to_string(std::chrono::system_clock::now()); 3225e8d8bef9SDimitry Andric std::replace(now.begin(), now.end(), ' ', '_'); 3226*0fca6ea1SDimitry Andric // Can't have file name with colons on Windows 3227*0fca6ea1SDimitry Andric std::replace(now.begin(), now.end(), ':', '-'); 3228e8d8bef9SDimitry Andric const std::string file_name = "lldb_session_" + now + ".log"; 3229fe6060f1SDimitry Andric 3230fe6060f1SDimitry Andric FileSpec save_location = GetSaveSessionDirectory(); 3231fe6060f1SDimitry Andric 3232fe6060f1SDimitry Andric if (!save_location) 3233fe6060f1SDimitry Andric save_location = HostInfo::GetGlobalTempDir(); 3234fe6060f1SDimitry Andric 3235fe6060f1SDimitry Andric FileSystem::Instance().Resolve(save_location); 3236fe6060f1SDimitry Andric save_location.AppendPathComponent(file_name); 3237fe6060f1SDimitry Andric output_file = save_location.GetPath(); 3238e8d8bef9SDimitry Andric } 3239e8d8bef9SDimitry Andric 3240e8d8bef9SDimitry Andric auto error_out = [&](llvm::StringRef error_message, std::string description) { 324181ad6265SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message, 324281ad6265SDimitry Andric output_file, description); 3243e8d8bef9SDimitry Andric result.AppendErrorWithFormatv( 3244e8d8bef9SDimitry Andric "Failed to save session's transcripts to {0}!", *output_file); 3245e8d8bef9SDimitry Andric return false; 3246e8d8bef9SDimitry Andric }; 3247e8d8bef9SDimitry Andric 3248349cc55cSDimitry Andric File::OpenOptions flags = File::eOpenOptionWriteOnly | 3249e8d8bef9SDimitry Andric File::eOpenOptionCanCreate | 3250e8d8bef9SDimitry Andric File::eOpenOptionTruncate; 3251e8d8bef9SDimitry Andric 3252e8d8bef9SDimitry Andric auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags); 3253e8d8bef9SDimitry Andric 3254e8d8bef9SDimitry Andric if (!opened_file) 3255e8d8bef9SDimitry Andric return error_out("Unable to create file", 3256e8d8bef9SDimitry Andric llvm::toString(opened_file.takeError())); 3257e8d8bef9SDimitry Andric 3258e8d8bef9SDimitry Andric FileUP file = std::move(opened_file.get()); 3259e8d8bef9SDimitry Andric 3260e8d8bef9SDimitry Andric size_t byte_size = m_transcript_stream.GetSize(); 3261e8d8bef9SDimitry Andric 3262e8d8bef9SDimitry Andric Status error = file->Write(m_transcript_stream.GetData(), byte_size); 3263e8d8bef9SDimitry Andric 3264e8d8bef9SDimitry Andric if (error.Fail() || byte_size != m_transcript_stream.GetSize()) 3265e8d8bef9SDimitry Andric return error_out("Unable to write to destination file", 3266e8d8bef9SDimitry Andric "Bytes written do not match transcript size."); 3267e8d8bef9SDimitry Andric 3268fe6060f1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 3269e8d8bef9SDimitry Andric result.AppendMessageWithFormat("Session's transcripts saved to %s\n", 3270e8d8bef9SDimitry Andric output_file->c_str()); 3271e8d8bef9SDimitry Andric 3272bdd1243dSDimitry Andric if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) { 3273bdd1243dSDimitry Andric const FileSpec file_spec; 3274bdd1243dSDimitry Andric error = file->GetFileSpec(const_cast<FileSpec &>(file_spec)); 327506c3fb27SDimitry Andric if (error.Success()) { 327606c3fb27SDimitry Andric if (llvm::Error e = Host::OpenFileInExternalEditor( 327706c3fb27SDimitry Andric m_debugger.GetExternalEditor(), file_spec, 1)) 327806c3fb27SDimitry Andric result.AppendError(llvm::toString(std::move(e))); 327906c3fb27SDimitry Andric } 3280bdd1243dSDimitry Andric } 3281bdd1243dSDimitry Andric 3282e8d8bef9SDimitry Andric return true; 3283e8d8bef9SDimitry Andric } 3284e8d8bef9SDimitry Andric 328581ad6265SDimitry Andric bool CommandInterpreter::IsInteractive() { 328681ad6265SDimitry Andric return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false); 328781ad6265SDimitry Andric } 328881ad6265SDimitry Andric 3289e8d8bef9SDimitry Andric FileSpec CommandInterpreter::GetCurrentSourceDir() { 3290e8d8bef9SDimitry Andric if (m_command_source_dirs.empty()) 3291e8d8bef9SDimitry Andric return {}; 3292e8d8bef9SDimitry Andric return m_command_source_dirs.back(); 3293e8d8bef9SDimitry Andric } 3294e8d8bef9SDimitry Andric 32950b57cec5SDimitry Andric void CommandInterpreter::GetLLDBCommandsFromIOHandler( 3296480093f4SDimitry Andric const char *prompt, IOHandlerDelegate &delegate, void *baton) { 32970b57cec5SDimitry Andric Debugger &debugger = GetDebugger(); 32980b57cec5SDimitry Andric IOHandlerSP io_handler_sp( 32990b57cec5SDimitry Andric new IOHandlerEditline(debugger, IOHandler::Type::CommandList, 33000b57cec5SDimitry Andric "lldb", // Name of input reader for history 3301fe6060f1SDimitry Andric llvm::StringRef(prompt), // Prompt 33020b57cec5SDimitry Andric llvm::StringRef(), // Continuation prompt 33030b57cec5SDimitry Andric true, // Get multiple lines 33040b57cec5SDimitry Andric debugger.GetUseColor(), 33050b57cec5SDimitry Andric 0, // Don't show line numbers 3306bdd1243dSDimitry Andric delegate)); // IOHandlerDelegate 33070b57cec5SDimitry Andric 33080b57cec5SDimitry Andric if (io_handler_sp) { 33090b57cec5SDimitry Andric io_handler_sp->SetUserData(baton); 33105ffd83dbSDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp); 33110b57cec5SDimitry Andric } 33120b57cec5SDimitry Andric } 33130b57cec5SDimitry Andric 33140b57cec5SDimitry Andric void CommandInterpreter::GetPythonCommandsFromIOHandler( 3315480093f4SDimitry Andric const char *prompt, IOHandlerDelegate &delegate, void *baton) { 33160b57cec5SDimitry Andric Debugger &debugger = GetDebugger(); 33170b57cec5SDimitry Andric IOHandlerSP io_handler_sp( 33180b57cec5SDimitry Andric new IOHandlerEditline(debugger, IOHandler::Type::PythonCode, 33190b57cec5SDimitry Andric "lldb-python", // Name of input reader for history 3320fe6060f1SDimitry Andric llvm::StringRef(prompt), // Prompt 33210b57cec5SDimitry Andric llvm::StringRef(), // Continuation prompt 33220b57cec5SDimitry Andric true, // Get multiple lines 33230b57cec5SDimitry Andric debugger.GetUseColor(), 33240b57cec5SDimitry Andric 0, // Don't show line numbers 3325bdd1243dSDimitry Andric delegate)); // IOHandlerDelegate 33260b57cec5SDimitry Andric 33270b57cec5SDimitry Andric if (io_handler_sp) { 33280b57cec5SDimitry Andric io_handler_sp->SetUserData(baton); 33295ffd83dbSDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp); 33300b57cec5SDimitry Andric } 33310b57cec5SDimitry Andric } 33320b57cec5SDimitry Andric 33330b57cec5SDimitry Andric bool CommandInterpreter::IsActive() { 33340b57cec5SDimitry Andric return m_debugger.IsTopIOHandler(m_command_io_handler_sp); 33350b57cec5SDimitry Andric } 33360b57cec5SDimitry Andric 33370b57cec5SDimitry Andric lldb::IOHandlerSP 33380b57cec5SDimitry Andric CommandInterpreter::GetIOHandler(bool force_create, 33390b57cec5SDimitry Andric CommandInterpreterRunOptions *options) { 33400b57cec5SDimitry Andric // Always re-create the IOHandlerEditline in case the input changed. The old 33410b57cec5SDimitry Andric // instance might have had a non-interactive input and now it does or vice 33420b57cec5SDimitry Andric // versa. 33430b57cec5SDimitry Andric if (force_create || !m_command_io_handler_sp) { 33440b57cec5SDimitry Andric // Always re-create the IOHandlerEditline in case the input changed. The 33450b57cec5SDimitry Andric // old instance might have had a non-interactive input and now it does or 33460b57cec5SDimitry Andric // vice versa. 33470b57cec5SDimitry Andric uint32_t flags = 0; 33480b57cec5SDimitry Andric 33490b57cec5SDimitry Andric if (options) { 33500b57cec5SDimitry Andric if (options->m_stop_on_continue == eLazyBoolYes) 33510b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnContinue; 33520b57cec5SDimitry Andric if (options->m_stop_on_error == eLazyBoolYes) 33530b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnError; 33540b57cec5SDimitry Andric if (options->m_stop_on_crash == eLazyBoolYes) 33550b57cec5SDimitry Andric flags |= eHandleCommandFlagStopOnCrash; 33560b57cec5SDimitry Andric if (options->m_echo_commands != eLazyBoolNo) 33570b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommand; 33580b57cec5SDimitry Andric if (options->m_echo_comment_commands != eLazyBoolNo) 33590b57cec5SDimitry Andric flags |= eHandleCommandFlagEchoCommentCommand; 33600b57cec5SDimitry Andric if (options->m_print_results != eLazyBoolNo) 33610b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintResult; 33620b57cec5SDimitry Andric if (options->m_print_errors != eLazyBoolNo) 33630b57cec5SDimitry Andric flags |= eHandleCommandFlagPrintErrors; 3364*0fca6ea1SDimitry Andric if (options->m_allow_repeats == eLazyBoolYes) 3365*0fca6ea1SDimitry Andric flags |= eHandleCommandFlagAllowRepeats; 33660b57cec5SDimitry Andric } else { 33670b57cec5SDimitry Andric flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult | 33680b57cec5SDimitry Andric eHandleCommandFlagPrintErrors; 33690b57cec5SDimitry Andric } 33700b57cec5SDimitry Andric 33710b57cec5SDimitry Andric m_command_io_handler_sp = std::make_shared<IOHandlerEditline>( 33720b57cec5SDimitry Andric m_debugger, IOHandler::Type::CommandInterpreter, 33739dba64beSDimitry Andric m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(), 33749dba64beSDimitry Andric m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(), 33750b57cec5SDimitry Andric llvm::StringRef(), // Continuation prompt 33760b57cec5SDimitry Andric false, // Don't enable multiple line input, just single line commands 33770b57cec5SDimitry Andric m_debugger.GetUseColor(), 33780b57cec5SDimitry Andric 0, // Don't show line numbers 3379bdd1243dSDimitry Andric *this); // IOHandlerDelegate 33800b57cec5SDimitry Andric } 33810b57cec5SDimitry Andric return m_command_io_handler_sp; 33820b57cec5SDimitry Andric } 33830b57cec5SDimitry Andric 33845ffd83dbSDimitry Andric CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter( 33850b57cec5SDimitry Andric CommandInterpreterRunOptions &options) { 33860b57cec5SDimitry Andric // Always re-create the command interpreter when we run it in case any file 33870b57cec5SDimitry Andric // handles have changed. 33880b57cec5SDimitry Andric bool force_create = true; 33895ffd83dbSDimitry Andric m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options)); 33905ffd83dbSDimitry Andric m_result = CommandInterpreterRunResult(); 33910b57cec5SDimitry Andric 33925ffd83dbSDimitry Andric if (options.GetAutoHandleEvents()) 33930b57cec5SDimitry Andric m_debugger.StartEventHandlerThread(); 33940b57cec5SDimitry Andric 33955ffd83dbSDimitry Andric if (options.GetSpawnThread()) { 33960b57cec5SDimitry Andric m_debugger.StartIOHandlerThread(); 33970b57cec5SDimitry Andric } else { 339806c3fb27SDimitry Andric // If the current thread is not managed by a host thread, we won't detect 339906c3fb27SDimitry Andric // that this IS the CommandInterpreter IOHandler thread, so make it so: 340006c3fb27SDimitry Andric HostThread new_io_handler_thread(Host::GetCurrentThread()); 340106c3fb27SDimitry Andric HostThread old_io_handler_thread = 340206c3fb27SDimitry Andric m_debugger.SetIOHandlerThread(new_io_handler_thread); 34035ffd83dbSDimitry Andric m_debugger.RunIOHandlers(); 340406c3fb27SDimitry Andric m_debugger.SetIOHandlerThread(old_io_handler_thread); 34050b57cec5SDimitry Andric 34065ffd83dbSDimitry Andric if (options.GetAutoHandleEvents()) 34070b57cec5SDimitry Andric m_debugger.StopEventHandlerThread(); 34080b57cec5SDimitry Andric } 34095ffd83dbSDimitry Andric 34105ffd83dbSDimitry Andric return m_result; 34110b57cec5SDimitry Andric } 34120b57cec5SDimitry Andric 34130b57cec5SDimitry Andric CommandObject * 34140b57cec5SDimitry Andric CommandInterpreter::ResolveCommandImpl(std::string &command_line, 34150b57cec5SDimitry Andric CommandReturnObject &result) { 34160b57cec5SDimitry Andric std::string scratch_command(command_line); // working copy so we don't modify 34170b57cec5SDimitry Andric // command_line unless we succeed 34180b57cec5SDimitry Andric CommandObject *cmd_obj = nullptr; 34190b57cec5SDimitry Andric StreamString revised_command_line; 34200b57cec5SDimitry Andric bool wants_raw_input = false; 34210b57cec5SDimitry Andric std::string next_word; 34220b57cec5SDimitry Andric StringList matches; 34230b57cec5SDimitry Andric bool done = false; 34240b57cec5SDimitry Andric while (!done) { 34250b57cec5SDimitry Andric char quote_char = '\0'; 34260b57cec5SDimitry Andric std::string suffix; 34270b57cec5SDimitry Andric ExtractCommand(scratch_command, next_word, suffix, quote_char); 34280b57cec5SDimitry Andric if (cmd_obj == nullptr) { 34290b57cec5SDimitry Andric std::string full_name; 34300b57cec5SDimitry Andric bool is_alias = GetAliasFullName(next_word, full_name); 34310b57cec5SDimitry Andric cmd_obj = GetCommandObject(next_word, &matches); 34320b57cec5SDimitry Andric bool is_real_command = 34330b57cec5SDimitry Andric (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias()); 34340b57cec5SDimitry Andric if (!is_real_command) { 34350b57cec5SDimitry Andric matches.Clear(); 34360b57cec5SDimitry Andric std::string alias_result; 34370b57cec5SDimitry Andric cmd_obj = 34380b57cec5SDimitry Andric BuildAliasResult(full_name, scratch_command, alias_result, result); 34390b57cec5SDimitry Andric revised_command_line.Printf("%s", alias_result.c_str()); 34400b57cec5SDimitry Andric if (cmd_obj) { 34410b57cec5SDimitry Andric wants_raw_input = cmd_obj->WantsRawCommandString(); 34420b57cec5SDimitry Andric } 34430b57cec5SDimitry Andric } else { 34440b57cec5SDimitry Andric if (cmd_obj) { 34450b57cec5SDimitry Andric llvm::StringRef cmd_name = cmd_obj->GetCommandName(); 34460b57cec5SDimitry Andric revised_command_line.Printf("%s", cmd_name.str().c_str()); 34470b57cec5SDimitry Andric wants_raw_input = cmd_obj->WantsRawCommandString(); 34480b57cec5SDimitry Andric } else { 34490b57cec5SDimitry Andric revised_command_line.Printf("%s", next_word.c_str()); 34500b57cec5SDimitry Andric } 34510b57cec5SDimitry Andric } 34520b57cec5SDimitry Andric } else { 34530b57cec5SDimitry Andric if (cmd_obj->IsMultiwordObject()) { 34540b57cec5SDimitry Andric CommandObject *sub_cmd_obj = 34550b57cec5SDimitry Andric cmd_obj->GetSubcommandObject(next_word.c_str()); 34560b57cec5SDimitry Andric if (sub_cmd_obj) { 34570b57cec5SDimitry Andric // The subcommand's name includes the parent command's name, so 34580b57cec5SDimitry Andric // restart rather than append to the revised_command_line. 34590b57cec5SDimitry Andric llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName(); 34600b57cec5SDimitry Andric revised_command_line.Clear(); 34610b57cec5SDimitry Andric revised_command_line.Printf("%s", sub_cmd_name.str().c_str()); 34620b57cec5SDimitry Andric cmd_obj = sub_cmd_obj; 34630b57cec5SDimitry Andric wants_raw_input = cmd_obj->WantsRawCommandString(); 34640b57cec5SDimitry Andric } else { 34650b57cec5SDimitry Andric if (quote_char) 34660b57cec5SDimitry Andric revised_command_line.Printf(" %c%s%s%c", quote_char, 34670b57cec5SDimitry Andric next_word.c_str(), suffix.c_str(), 34680b57cec5SDimitry Andric quote_char); 34690b57cec5SDimitry Andric else 34700b57cec5SDimitry Andric revised_command_line.Printf(" %s%s", next_word.c_str(), 34710b57cec5SDimitry Andric suffix.c_str()); 34720b57cec5SDimitry Andric done = true; 34730b57cec5SDimitry Andric } 34740b57cec5SDimitry Andric } else { 34750b57cec5SDimitry Andric if (quote_char) 34760b57cec5SDimitry Andric revised_command_line.Printf(" %c%s%s%c", quote_char, 34770b57cec5SDimitry Andric next_word.c_str(), suffix.c_str(), 34780b57cec5SDimitry Andric quote_char); 34790b57cec5SDimitry Andric else 34800b57cec5SDimitry Andric revised_command_line.Printf(" %s%s", next_word.c_str(), 34810b57cec5SDimitry Andric suffix.c_str()); 34820b57cec5SDimitry Andric done = true; 34830b57cec5SDimitry Andric } 34840b57cec5SDimitry Andric } 34850b57cec5SDimitry Andric 34860b57cec5SDimitry Andric if (cmd_obj == nullptr) { 34870b57cec5SDimitry Andric const size_t num_matches = matches.GetSize(); 34880b57cec5SDimitry Andric if (matches.GetSize() > 1) { 34890b57cec5SDimitry Andric StreamString error_msg; 34900b57cec5SDimitry Andric error_msg.Printf("Ambiguous command '%s'. Possible matches:\n", 34910b57cec5SDimitry Andric next_word.c_str()); 34920b57cec5SDimitry Andric 34930b57cec5SDimitry Andric for (uint32_t i = 0; i < num_matches; ++i) { 34940b57cec5SDimitry Andric error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i)); 34950b57cec5SDimitry Andric } 34960b57cec5SDimitry Andric result.AppendRawError(error_msg.GetString()); 34970b57cec5SDimitry Andric } else { 34980b57cec5SDimitry Andric // We didn't have only one match, otherwise we wouldn't get here. 34990b57cec5SDimitry Andric lldbassert(num_matches == 0); 35000b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' is not a valid command.\n", 35010b57cec5SDimitry Andric next_word.c_str()); 35020b57cec5SDimitry Andric } 35030b57cec5SDimitry Andric return nullptr; 35040b57cec5SDimitry Andric } 35050b57cec5SDimitry Andric 35060b57cec5SDimitry Andric if (cmd_obj->IsMultiwordObject()) { 35070b57cec5SDimitry Andric if (!suffix.empty()) { 35080b57cec5SDimitry Andric result.AppendErrorWithFormat( 35090b57cec5SDimitry Andric "command '%s' did not recognize '%s%s%s' as valid (subcommand " 35100b57cec5SDimitry Andric "might be invalid).\n", 35110b57cec5SDimitry Andric cmd_obj->GetCommandName().str().c_str(), 35120b57cec5SDimitry Andric next_word.empty() ? "" : next_word.c_str(), 35130b57cec5SDimitry Andric next_word.empty() ? " -- " : " ", suffix.c_str()); 35140b57cec5SDimitry Andric return nullptr; 35150b57cec5SDimitry Andric } 35160b57cec5SDimitry Andric } else { 35170b57cec5SDimitry Andric // If we found a normal command, we are done 35180b57cec5SDimitry Andric done = true; 35190b57cec5SDimitry Andric if (!suffix.empty()) { 35200b57cec5SDimitry Andric switch (suffix[0]) { 35210b57cec5SDimitry Andric case '/': 35220b57cec5SDimitry Andric // GDB format suffixes 35230b57cec5SDimitry Andric { 35240b57cec5SDimitry Andric Options *command_options = cmd_obj->GetOptions(); 35250b57cec5SDimitry Andric if (command_options && 35260b57cec5SDimitry Andric command_options->SupportsLongOption("gdb-format")) { 35270b57cec5SDimitry Andric std::string gdb_format_option("--gdb-format="); 35280b57cec5SDimitry Andric gdb_format_option += (suffix.c_str() + 1); 35290b57cec5SDimitry Andric 35305ffd83dbSDimitry Andric std::string cmd = std::string(revised_command_line.GetString()); 35310b57cec5SDimitry Andric size_t arg_terminator_idx = FindArgumentTerminator(cmd); 35320b57cec5SDimitry Andric if (arg_terminator_idx != std::string::npos) { 35330b57cec5SDimitry Andric // Insert the gdb format option before the "--" that terminates 35340b57cec5SDimitry Andric // options 35350b57cec5SDimitry Andric gdb_format_option.append(1, ' '); 35360b57cec5SDimitry Andric cmd.insert(arg_terminator_idx, gdb_format_option); 35370b57cec5SDimitry Andric revised_command_line.Clear(); 35380b57cec5SDimitry Andric revised_command_line.PutCString(cmd); 35390b57cec5SDimitry Andric } else 35400b57cec5SDimitry Andric revised_command_line.Printf(" %s", gdb_format_option.c_str()); 35410b57cec5SDimitry Andric 35420b57cec5SDimitry Andric if (wants_raw_input && 35430b57cec5SDimitry Andric FindArgumentTerminator(cmd) == std::string::npos) 35440b57cec5SDimitry Andric revised_command_line.PutCString(" --"); 35450b57cec5SDimitry Andric } else { 35460b57cec5SDimitry Andric result.AppendErrorWithFormat( 35470b57cec5SDimitry Andric "the '%s' command doesn't support the --gdb-format option\n", 35480b57cec5SDimitry Andric cmd_obj->GetCommandName().str().c_str()); 35490b57cec5SDimitry Andric return nullptr; 35500b57cec5SDimitry Andric } 35510b57cec5SDimitry Andric } 35520b57cec5SDimitry Andric break; 35530b57cec5SDimitry Andric 35540b57cec5SDimitry Andric default: 35550b57cec5SDimitry Andric result.AppendErrorWithFormat( 35560b57cec5SDimitry Andric "unknown command shorthand suffix: '%s'\n", suffix.c_str()); 35570b57cec5SDimitry Andric return nullptr; 35580b57cec5SDimitry Andric } 35590b57cec5SDimitry Andric } 35600b57cec5SDimitry Andric } 35610b57cec5SDimitry Andric if (scratch_command.empty()) 35620b57cec5SDimitry Andric done = true; 35630b57cec5SDimitry Andric } 35640b57cec5SDimitry Andric 35650b57cec5SDimitry Andric if (!scratch_command.empty()) 35660b57cec5SDimitry Andric revised_command_line.Printf(" %s", scratch_command.c_str()); 35670b57cec5SDimitry Andric 35680b57cec5SDimitry Andric if (cmd_obj != nullptr) 35695ffd83dbSDimitry Andric command_line = std::string(revised_command_line.GetString()); 35700b57cec5SDimitry Andric 35710b57cec5SDimitry Andric return cmd_obj; 35720b57cec5SDimitry Andric } 3573*0fca6ea1SDimitry Andric 3574*0fca6ea1SDimitry Andric llvm::json::Value CommandInterpreter::GetStatistics() { 3575*0fca6ea1SDimitry Andric llvm::json::Object stats; 3576*0fca6ea1SDimitry Andric for (const auto &command_usage : m_command_usages) 3577*0fca6ea1SDimitry Andric stats.try_emplace(command_usage.getKey(), command_usage.getValue()); 3578*0fca6ea1SDimitry Andric return stats; 3579*0fca6ea1SDimitry Andric } 3580*0fca6ea1SDimitry Andric 3581*0fca6ea1SDimitry Andric const StructuredData::Array &CommandInterpreter::GetTranscript() const { 3582*0fca6ea1SDimitry Andric return m_transcript; 3583*0fca6ea1SDimitry Andric } 3584