xref: /openbsd-src/gnu/llvm/lldb/source/Interpreter/CommandObject.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- CommandObject.cpp -------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Interpreter/CommandObject.h"
10061da546Spatrick 
11061da546Spatrick #include <map>
12061da546Spatrick #include <sstream>
13061da546Spatrick #include <string>
14061da546Spatrick 
15be691f3bSpatrick #include <cctype>
16be691f3bSpatrick #include <cstdlib>
17061da546Spatrick 
18061da546Spatrick #include "lldb/Core/Address.h"
19*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
20061da546Spatrick #include "lldb/Interpreter/Options.h"
21061da546Spatrick #include "lldb/Utility/ArchSpec.h"
22dda28197Spatrick #include "llvm/ADT/ScopeExit.h"
23061da546Spatrick 
24061da546Spatrick // These are for the Sourcename completers.
25061da546Spatrick // FIXME: Make a separate file for the completers.
26061da546Spatrick #include "lldb/Core/FileSpecList.h"
27061da546Spatrick #include "lldb/DataFormatters/FormatManager.h"
28061da546Spatrick #include "lldb/Target/Process.h"
29061da546Spatrick #include "lldb/Target/Target.h"
30061da546Spatrick #include "lldb/Utility/FileSpec.h"
31061da546Spatrick 
32061da546Spatrick #include "lldb/Target/Language.h"
33061da546Spatrick 
34061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
35*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
36061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
37061da546Spatrick 
38061da546Spatrick using namespace lldb;
39061da546Spatrick using namespace lldb_private;
40061da546Spatrick 
41061da546Spatrick // CommandObject
42061da546Spatrick 
CommandObject(CommandInterpreter & interpreter,llvm::StringRef name,llvm::StringRef help,llvm::StringRef syntax,uint32_t flags)43dda28197Spatrick CommandObject::CommandObject(CommandInterpreter &interpreter,
44dda28197Spatrick                              llvm::StringRef name, llvm::StringRef help,
45dda28197Spatrick                              llvm::StringRef syntax, uint32_t flags)
46dda28197Spatrick     : m_interpreter(interpreter), m_cmd_name(std::string(name)),
47be691f3bSpatrick       m_flags(flags), m_deprecated_command_override_callback(nullptr),
48061da546Spatrick       m_command_override_callback(nullptr), m_command_override_baton(nullptr) {
49dda28197Spatrick   m_cmd_help_short = std::string(help);
50dda28197Spatrick   m_cmd_syntax = std::string(syntax);
51061da546Spatrick }
52061da546Spatrick 
GetDebugger()53061da546Spatrick Debugger &CommandObject::GetDebugger() { return m_interpreter.GetDebugger(); }
54061da546Spatrick 
GetHelp()55061da546Spatrick llvm::StringRef CommandObject::GetHelp() { return m_cmd_help_short; }
56061da546Spatrick 
GetHelpLong()57061da546Spatrick llvm::StringRef CommandObject::GetHelpLong() { return m_cmd_help_long; }
58061da546Spatrick 
GetSyntax()59061da546Spatrick llvm::StringRef CommandObject::GetSyntax() {
60061da546Spatrick   if (!m_cmd_syntax.empty())
61061da546Spatrick     return m_cmd_syntax;
62061da546Spatrick 
63061da546Spatrick   StreamString syntax_str;
64061da546Spatrick   syntax_str.PutCString(GetCommandName());
65061da546Spatrick 
66061da546Spatrick   if (!IsDashDashCommand() && GetOptions() != nullptr)
67061da546Spatrick     syntax_str.PutCString(" <cmd-options>");
68061da546Spatrick 
69061da546Spatrick   if (!m_arguments.empty()) {
70061da546Spatrick     syntax_str.PutCString(" ");
71061da546Spatrick 
72061da546Spatrick     if (!IsDashDashCommand() && WantsRawCommandString() && GetOptions() &&
73061da546Spatrick         GetOptions()->NumCommandOptions())
74061da546Spatrick       syntax_str.PutCString("-- ");
75061da546Spatrick     GetFormattedCommandArguments(syntax_str);
76061da546Spatrick   }
77dda28197Spatrick   m_cmd_syntax = std::string(syntax_str.GetString());
78061da546Spatrick 
79061da546Spatrick   return m_cmd_syntax;
80061da546Spatrick }
81061da546Spatrick 
GetCommandName() const82061da546Spatrick llvm::StringRef CommandObject::GetCommandName() const { return m_cmd_name; }
83061da546Spatrick 
SetCommandName(llvm::StringRef name)84dda28197Spatrick void CommandObject::SetCommandName(llvm::StringRef name) {
85dda28197Spatrick   m_cmd_name = std::string(name);
86dda28197Spatrick }
87061da546Spatrick 
SetHelp(llvm::StringRef str)88dda28197Spatrick void CommandObject::SetHelp(llvm::StringRef str) {
89dda28197Spatrick   m_cmd_help_short = std::string(str);
90dda28197Spatrick }
91061da546Spatrick 
SetHelpLong(llvm::StringRef str)92dda28197Spatrick void CommandObject::SetHelpLong(llvm::StringRef str) {
93dda28197Spatrick   m_cmd_help_long = std::string(str);
94dda28197Spatrick }
95061da546Spatrick 
SetSyntax(llvm::StringRef str)96dda28197Spatrick void CommandObject::SetSyntax(llvm::StringRef str) {
97dda28197Spatrick   m_cmd_syntax = std::string(str);
98dda28197Spatrick }
99061da546Spatrick 
GetOptions()100061da546Spatrick Options *CommandObject::GetOptions() {
101061da546Spatrick   // By default commands don't have options unless this virtual function is
102061da546Spatrick   // overridden by base classes.
103061da546Spatrick   return nullptr;
104061da546Spatrick }
105061da546Spatrick 
ParseOptions(Args & args,CommandReturnObject & result)106061da546Spatrick bool CommandObject::ParseOptions(Args &args, CommandReturnObject &result) {
107061da546Spatrick   // See if the subclass has options?
108061da546Spatrick   Options *options = GetOptions();
109061da546Spatrick   if (options != nullptr) {
110061da546Spatrick     Status error;
111061da546Spatrick 
112061da546Spatrick     auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
113061da546Spatrick     options->NotifyOptionParsingStarting(&exe_ctx);
114061da546Spatrick 
115061da546Spatrick     const bool require_validation = true;
116061da546Spatrick     llvm::Expected<Args> args_or = options->Parse(
117061da546Spatrick         args, &exe_ctx, GetCommandInterpreter().GetPlatform(true),
118061da546Spatrick         require_validation);
119061da546Spatrick 
120061da546Spatrick     if (args_or) {
121061da546Spatrick       args = std::move(*args_or);
122061da546Spatrick       error = options->NotifyOptionParsingFinished(&exe_ctx);
123061da546Spatrick     } else
124061da546Spatrick       error = args_or.takeError();
125061da546Spatrick 
126061da546Spatrick     if (error.Success()) {
127061da546Spatrick       if (options->VerifyOptions(result))
128061da546Spatrick         return true;
129061da546Spatrick     } else {
130061da546Spatrick       const char *error_cstr = error.AsCString();
131061da546Spatrick       if (error_cstr) {
132061da546Spatrick         // We got an error string, lets use that
133061da546Spatrick         result.AppendError(error_cstr);
134061da546Spatrick       } else {
135061da546Spatrick         // No error string, output the usage information into result
136061da546Spatrick         options->GenerateOptionUsage(
137*f6aab3d8Srobert             result.GetErrorStream(), *this,
138061da546Spatrick             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
139061da546Spatrick       }
140061da546Spatrick     }
141061da546Spatrick     result.SetStatus(eReturnStatusFailed);
142061da546Spatrick     return false;
143061da546Spatrick   }
144061da546Spatrick   return true;
145061da546Spatrick }
146061da546Spatrick 
CheckRequirements(CommandReturnObject & result)147061da546Spatrick bool CommandObject::CheckRequirements(CommandReturnObject &result) {
148061da546Spatrick   // Nothing should be stored in m_exe_ctx between running commands as
149061da546Spatrick   // m_exe_ctx has shared pointers to the target, process, thread and frame and
150061da546Spatrick   // we don't want any CommandObject instances to keep any of these objects
151061da546Spatrick   // around longer than for a single command. Every command should call
152061da546Spatrick   // CommandObject::Cleanup() after it has completed.
153061da546Spatrick   assert(!m_exe_ctx.GetTargetPtr());
154061da546Spatrick   assert(!m_exe_ctx.GetProcessPtr());
155061da546Spatrick   assert(!m_exe_ctx.GetThreadPtr());
156061da546Spatrick   assert(!m_exe_ctx.GetFramePtr());
157061da546Spatrick 
158061da546Spatrick   // Lock down the interpreter's execution context prior to running the command
159061da546Spatrick   // so we guarantee the selected target, process, thread and frame can't go
160061da546Spatrick   // away during the execution
161061da546Spatrick   m_exe_ctx = m_interpreter.GetExecutionContext();
162061da546Spatrick 
163061da546Spatrick   const uint32_t flags = GetFlags().Get();
164061da546Spatrick   if (flags & (eCommandRequiresTarget | eCommandRequiresProcess |
165061da546Spatrick                eCommandRequiresThread | eCommandRequiresFrame |
166061da546Spatrick                eCommandTryTargetAPILock)) {
167061da546Spatrick 
168061da546Spatrick     if ((flags & eCommandRequiresTarget) && !m_exe_ctx.HasTargetScope()) {
169061da546Spatrick       result.AppendError(GetInvalidTargetDescription());
170061da546Spatrick       return false;
171061da546Spatrick     }
172061da546Spatrick 
173061da546Spatrick     if ((flags & eCommandRequiresProcess) && !m_exe_ctx.HasProcessScope()) {
174061da546Spatrick       if (!m_exe_ctx.HasTargetScope())
175061da546Spatrick         result.AppendError(GetInvalidTargetDescription());
176061da546Spatrick       else
177061da546Spatrick         result.AppendError(GetInvalidProcessDescription());
178061da546Spatrick       return false;
179061da546Spatrick     }
180061da546Spatrick 
181061da546Spatrick     if ((flags & eCommandRequiresThread) && !m_exe_ctx.HasThreadScope()) {
182061da546Spatrick       if (!m_exe_ctx.HasTargetScope())
183061da546Spatrick         result.AppendError(GetInvalidTargetDescription());
184061da546Spatrick       else if (!m_exe_ctx.HasProcessScope())
185061da546Spatrick         result.AppendError(GetInvalidProcessDescription());
186061da546Spatrick       else
187061da546Spatrick         result.AppendError(GetInvalidThreadDescription());
188061da546Spatrick       return false;
189061da546Spatrick     }
190061da546Spatrick 
191061da546Spatrick     if ((flags & eCommandRequiresFrame) && !m_exe_ctx.HasFrameScope()) {
192061da546Spatrick       if (!m_exe_ctx.HasTargetScope())
193061da546Spatrick         result.AppendError(GetInvalidTargetDescription());
194061da546Spatrick       else if (!m_exe_ctx.HasProcessScope())
195061da546Spatrick         result.AppendError(GetInvalidProcessDescription());
196061da546Spatrick       else if (!m_exe_ctx.HasThreadScope())
197061da546Spatrick         result.AppendError(GetInvalidThreadDescription());
198061da546Spatrick       else
199061da546Spatrick         result.AppendError(GetInvalidFrameDescription());
200061da546Spatrick       return false;
201061da546Spatrick     }
202061da546Spatrick 
203061da546Spatrick     if ((flags & eCommandRequiresRegContext) &&
204061da546Spatrick         (m_exe_ctx.GetRegisterContext() == nullptr)) {
205061da546Spatrick       result.AppendError(GetInvalidRegContextDescription());
206061da546Spatrick       return false;
207061da546Spatrick     }
208061da546Spatrick 
209061da546Spatrick     if (flags & eCommandTryTargetAPILock) {
210061da546Spatrick       Target *target = m_exe_ctx.GetTargetPtr();
211061da546Spatrick       if (target)
212061da546Spatrick         m_api_locker =
213061da546Spatrick             std::unique_lock<std::recursive_mutex>(target->GetAPIMutex());
214061da546Spatrick     }
215061da546Spatrick   }
216061da546Spatrick 
217061da546Spatrick   if (GetFlags().AnySet(eCommandProcessMustBeLaunched |
218061da546Spatrick                         eCommandProcessMustBePaused)) {
219061da546Spatrick     Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
220061da546Spatrick     if (process == nullptr) {
221061da546Spatrick       // A process that is not running is considered paused.
222061da546Spatrick       if (GetFlags().Test(eCommandProcessMustBeLaunched)) {
223061da546Spatrick         result.AppendError("Process must exist.");
224061da546Spatrick         return false;
225061da546Spatrick       }
226061da546Spatrick     } else {
227061da546Spatrick       StateType state = process->GetState();
228061da546Spatrick       switch (state) {
229061da546Spatrick       case eStateInvalid:
230061da546Spatrick       case eStateSuspended:
231061da546Spatrick       case eStateCrashed:
232061da546Spatrick       case eStateStopped:
233061da546Spatrick         break;
234061da546Spatrick 
235061da546Spatrick       case eStateConnected:
236061da546Spatrick       case eStateAttaching:
237061da546Spatrick       case eStateLaunching:
238061da546Spatrick       case eStateDetached:
239061da546Spatrick       case eStateExited:
240061da546Spatrick       case eStateUnloaded:
241061da546Spatrick         if (GetFlags().Test(eCommandProcessMustBeLaunched)) {
242061da546Spatrick           result.AppendError("Process must be launched.");
243061da546Spatrick           return false;
244061da546Spatrick         }
245061da546Spatrick         break;
246061da546Spatrick 
247061da546Spatrick       case eStateRunning:
248061da546Spatrick       case eStateStepping:
249061da546Spatrick         if (GetFlags().Test(eCommandProcessMustBePaused)) {
250061da546Spatrick           result.AppendError("Process is running.  Use 'process interrupt' to "
251061da546Spatrick                              "pause execution.");
252061da546Spatrick           return false;
253061da546Spatrick         }
254061da546Spatrick       }
255061da546Spatrick     }
256061da546Spatrick   }
257be691f3bSpatrick 
258be691f3bSpatrick   if (GetFlags().Test(eCommandProcessMustBeTraced)) {
259be691f3bSpatrick     Target *target = m_exe_ctx.GetTargetPtr();
260be691f3bSpatrick     if (target && !target->GetTrace()) {
261be691f3bSpatrick       result.AppendError("Process is not being traced.");
262be691f3bSpatrick       return false;
263be691f3bSpatrick     }
264be691f3bSpatrick   }
265be691f3bSpatrick 
266061da546Spatrick   return true;
267061da546Spatrick }
268061da546Spatrick 
Cleanup()269061da546Spatrick void CommandObject::Cleanup() {
270061da546Spatrick   m_exe_ctx.Clear();
271061da546Spatrick   if (m_api_locker.owns_lock())
272061da546Spatrick     m_api_locker.unlock();
273061da546Spatrick }
274061da546Spatrick 
HandleCompletion(CompletionRequest & request)275061da546Spatrick void CommandObject::HandleCompletion(CompletionRequest &request) {
276dda28197Spatrick 
277dda28197Spatrick   m_exe_ctx = m_interpreter.GetExecutionContext();
278dda28197Spatrick   auto reset_ctx = llvm::make_scope_exit([this]() { Cleanup(); });
279dda28197Spatrick 
280061da546Spatrick   // Default implementation of WantsCompletion() is !WantsRawCommandString().
281061da546Spatrick   // Subclasses who want raw command string but desire, for example, argument
282061da546Spatrick   // completion should override WantsCompletion() to return true, instead.
283061da546Spatrick   if (WantsRawCommandString() && !WantsCompletion()) {
284061da546Spatrick     // FIXME: Abstract telling the completion to insert the completion
285061da546Spatrick     // character.
286061da546Spatrick     return;
287061da546Spatrick   } else {
288061da546Spatrick     // Can we do anything generic with the options?
289061da546Spatrick     Options *cur_options = GetOptions();
290dda28197Spatrick     CommandReturnObject result(m_interpreter.GetDebugger().GetUseColor());
291061da546Spatrick     OptionElementVector opt_element_vector;
292061da546Spatrick 
293061da546Spatrick     if (cur_options != nullptr) {
294061da546Spatrick       opt_element_vector = cur_options->ParseForCompletion(
295061da546Spatrick           request.GetParsedLine(), request.GetCursorIndex());
296061da546Spatrick 
297061da546Spatrick       bool handled_by_options = cur_options->HandleOptionCompletion(
298061da546Spatrick           request, opt_element_vector, GetCommandInterpreter());
299061da546Spatrick       if (handled_by_options)
300061da546Spatrick         return;
301061da546Spatrick     }
302061da546Spatrick 
303061da546Spatrick     // If we got here, the last word is not an option or an option argument.
304061da546Spatrick     HandleArgumentCompletion(request, opt_element_vector);
305061da546Spatrick   }
306061da546Spatrick }
307061da546Spatrick 
HelpTextContainsWord(llvm::StringRef search_word,bool search_short_help,bool search_long_help,bool search_syntax,bool search_options)308061da546Spatrick bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word,
309061da546Spatrick                                          bool search_short_help,
310061da546Spatrick                                          bool search_long_help,
311061da546Spatrick                                          bool search_syntax,
312061da546Spatrick                                          bool search_options) {
313061da546Spatrick   std::string options_usage_help;
314061da546Spatrick 
315061da546Spatrick   bool found_word = false;
316061da546Spatrick 
317061da546Spatrick   llvm::StringRef short_help = GetHelp();
318061da546Spatrick   llvm::StringRef long_help = GetHelpLong();
319061da546Spatrick   llvm::StringRef syntax_help = GetSyntax();
320061da546Spatrick 
321be691f3bSpatrick   if (search_short_help && short_help.contains_insensitive(search_word))
322061da546Spatrick     found_word = true;
323be691f3bSpatrick   else if (search_long_help && long_help.contains_insensitive(search_word))
324061da546Spatrick     found_word = true;
325be691f3bSpatrick   else if (search_syntax && syntax_help.contains_insensitive(search_word))
326061da546Spatrick     found_word = true;
327061da546Spatrick 
328061da546Spatrick   if (!found_word && search_options && GetOptions() != nullptr) {
329061da546Spatrick     StreamString usage_help;
330061da546Spatrick     GetOptions()->GenerateOptionUsage(
331*f6aab3d8Srobert         usage_help, *this,
332061da546Spatrick         GetCommandInterpreter().GetDebugger().GetTerminalWidth());
333061da546Spatrick     if (!usage_help.Empty()) {
334061da546Spatrick       llvm::StringRef usage_text = usage_help.GetString();
335be691f3bSpatrick       if (usage_text.contains_insensitive(search_word))
336061da546Spatrick         found_word = true;
337061da546Spatrick     }
338061da546Spatrick   }
339061da546Spatrick 
340061da546Spatrick   return found_word;
341061da546Spatrick }
342061da546Spatrick 
ParseOptionsAndNotify(Args & args,CommandReturnObject & result,OptionGroupOptions & group_options,ExecutionContext & exe_ctx)343061da546Spatrick bool CommandObject::ParseOptionsAndNotify(Args &args,
344061da546Spatrick                                           CommandReturnObject &result,
345061da546Spatrick                                           OptionGroupOptions &group_options,
346061da546Spatrick                                           ExecutionContext &exe_ctx) {
347061da546Spatrick   if (!ParseOptions(args, result))
348061da546Spatrick     return false;
349061da546Spatrick 
350061da546Spatrick   Status error(group_options.NotifyOptionParsingFinished(&exe_ctx));
351061da546Spatrick   if (error.Fail()) {
352061da546Spatrick     result.AppendError(error.AsCString());
353061da546Spatrick     return false;
354061da546Spatrick   }
355061da546Spatrick   return true;
356061da546Spatrick }
357061da546Spatrick 
GetNumArgumentEntries()358061da546Spatrick int CommandObject::GetNumArgumentEntries() { return m_arguments.size(); }
359061da546Spatrick 
360061da546Spatrick CommandObject::CommandArgumentEntry *
GetArgumentEntryAtIndex(int idx)361061da546Spatrick CommandObject::GetArgumentEntryAtIndex(int idx) {
362061da546Spatrick   if (static_cast<size_t>(idx) < m_arguments.size())
363061da546Spatrick     return &(m_arguments[idx]);
364061da546Spatrick 
365061da546Spatrick   return nullptr;
366061da546Spatrick }
367061da546Spatrick 
368061da546Spatrick const CommandObject::ArgumentTableEntry *
FindArgumentDataByType(CommandArgumentType arg_type)369061da546Spatrick CommandObject::FindArgumentDataByType(CommandArgumentType arg_type) {
370061da546Spatrick   for (int i = 0; i < eArgTypeLastArg; ++i)
371*f6aab3d8Srobert     if (g_argument_table[i].arg_type == arg_type)
372*f6aab3d8Srobert       return &(g_argument_table[i]);
373061da546Spatrick 
374061da546Spatrick   return nullptr;
375061da546Spatrick }
376061da546Spatrick 
GetArgumentHelp(Stream & str,CommandArgumentType arg_type,CommandInterpreter & interpreter)377061da546Spatrick void CommandObject::GetArgumentHelp(Stream &str, CommandArgumentType arg_type,
378061da546Spatrick                                     CommandInterpreter &interpreter) {
379*f6aab3d8Srobert   const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);
380061da546Spatrick 
381061da546Spatrick   // The table is *supposed* to be kept in arg_type order, but someone *could*
382061da546Spatrick   // have messed it up...
383061da546Spatrick 
384061da546Spatrick   if (entry->arg_type != arg_type)
385061da546Spatrick     entry = CommandObject::FindArgumentDataByType(arg_type);
386061da546Spatrick 
387061da546Spatrick   if (!entry)
388061da546Spatrick     return;
389061da546Spatrick 
390061da546Spatrick   StreamString name_str;
391061da546Spatrick   name_str.Printf("<%s>", entry->arg_name);
392061da546Spatrick 
393061da546Spatrick   if (entry->help_function) {
394061da546Spatrick     llvm::StringRef help_text = entry->help_function();
395061da546Spatrick     if (!entry->help_function.self_formatting) {
396061da546Spatrick       interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",
397061da546Spatrick                                           help_text, name_str.GetSize());
398061da546Spatrick     } else {
399061da546Spatrick       interpreter.OutputHelpText(str, name_str.GetString(), "--", help_text,
400061da546Spatrick                                  name_str.GetSize());
401061da546Spatrick     }
402*f6aab3d8Srobert   } else {
403061da546Spatrick     interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",
404061da546Spatrick                                         entry->help_text, name_str.GetSize());
405*f6aab3d8Srobert 
406*f6aab3d8Srobert     // Print enum values and their description if any.
407*f6aab3d8Srobert     OptionEnumValues enum_values = g_argument_table[arg_type].enum_values;
408*f6aab3d8Srobert     if (!enum_values.empty()) {
409*f6aab3d8Srobert       str.EOL();
410*f6aab3d8Srobert       size_t longest = 0;
411*f6aab3d8Srobert       for (const OptionEnumValueElement &element : enum_values)
412*f6aab3d8Srobert         longest =
413*f6aab3d8Srobert             std::max(longest, llvm::StringRef(element.string_value).size());
414*f6aab3d8Srobert       str.IndentMore(5);
415*f6aab3d8Srobert       for (const OptionEnumValueElement &element : enum_values) {
416*f6aab3d8Srobert         str.Indent();
417*f6aab3d8Srobert         interpreter.OutputHelpText(str, element.string_value, ":",
418*f6aab3d8Srobert                                    element.usage, longest);
419*f6aab3d8Srobert       }
420*f6aab3d8Srobert       str.IndentLess(5);
421*f6aab3d8Srobert       str.EOL();
422*f6aab3d8Srobert     }
423*f6aab3d8Srobert   }
424061da546Spatrick }
425061da546Spatrick 
GetArgumentName(CommandArgumentType arg_type)426061da546Spatrick const char *CommandObject::GetArgumentName(CommandArgumentType arg_type) {
427*f6aab3d8Srobert   const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);
428061da546Spatrick 
429061da546Spatrick   // The table is *supposed* to be kept in arg_type order, but someone *could*
430061da546Spatrick   // have messed it up...
431061da546Spatrick 
432061da546Spatrick   if (entry->arg_type != arg_type)
433061da546Spatrick     entry = CommandObject::FindArgumentDataByType(arg_type);
434061da546Spatrick 
435061da546Spatrick   if (entry)
436061da546Spatrick     return entry->arg_name;
437061da546Spatrick 
438061da546Spatrick   return nullptr;
439061da546Spatrick }
440061da546Spatrick 
IsPairType(ArgumentRepetitionType arg_repeat_type)441061da546Spatrick bool CommandObject::IsPairType(ArgumentRepetitionType arg_repeat_type) {
442061da546Spatrick   return (arg_repeat_type == eArgRepeatPairPlain) ||
443061da546Spatrick          (arg_repeat_type == eArgRepeatPairOptional) ||
444061da546Spatrick          (arg_repeat_type == eArgRepeatPairPlus) ||
445061da546Spatrick          (arg_repeat_type == eArgRepeatPairStar) ||
446061da546Spatrick          (arg_repeat_type == eArgRepeatPairRange) ||
447061da546Spatrick          (arg_repeat_type == eArgRepeatPairRangeOptional);
448061da546Spatrick }
449061da546Spatrick 
450061da546Spatrick static CommandObject::CommandArgumentEntry
OptSetFiltered(uint32_t opt_set_mask,CommandObject::CommandArgumentEntry & cmd_arg_entry)451061da546Spatrick OptSetFiltered(uint32_t opt_set_mask,
452061da546Spatrick                CommandObject::CommandArgumentEntry &cmd_arg_entry) {
453061da546Spatrick   CommandObject::CommandArgumentEntry ret_val;
454061da546Spatrick   for (unsigned i = 0; i < cmd_arg_entry.size(); ++i)
455061da546Spatrick     if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association)
456061da546Spatrick       ret_val.push_back(cmd_arg_entry[i]);
457061da546Spatrick   return ret_val;
458061da546Spatrick }
459061da546Spatrick 
460061da546Spatrick // Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means
461061da546Spatrick // take all the argument data into account.  On rare cases where some argument
462061da546Spatrick // sticks with certain option sets, this function returns the option set
463061da546Spatrick // filtered args.
GetFormattedCommandArguments(Stream & str,uint32_t opt_set_mask)464061da546Spatrick void CommandObject::GetFormattedCommandArguments(Stream &str,
465061da546Spatrick                                                  uint32_t opt_set_mask) {
466061da546Spatrick   int num_args = m_arguments.size();
467061da546Spatrick   for (int i = 0; i < num_args; ++i) {
468061da546Spatrick     if (i > 0)
469061da546Spatrick       str.Printf(" ");
470061da546Spatrick     CommandArgumentEntry arg_entry =
471061da546Spatrick         opt_set_mask == LLDB_OPT_SET_ALL
472061da546Spatrick             ? m_arguments[i]
473061da546Spatrick             : OptSetFiltered(opt_set_mask, m_arguments[i]);
474*f6aab3d8Srobert     // This argument is not associated with the current option set, so skip it.
475*f6aab3d8Srobert     if (arg_entry.empty())
476*f6aab3d8Srobert       continue;
477061da546Spatrick     int num_alternatives = arg_entry.size();
478061da546Spatrick 
479061da546Spatrick     if ((num_alternatives == 2) && IsPairType(arg_entry[0].arg_repetition)) {
480061da546Spatrick       const char *first_name = GetArgumentName(arg_entry[0].arg_type);
481061da546Spatrick       const char *second_name = GetArgumentName(arg_entry[1].arg_type);
482061da546Spatrick       switch (arg_entry[0].arg_repetition) {
483061da546Spatrick       case eArgRepeatPairPlain:
484061da546Spatrick         str.Printf("<%s> <%s>", first_name, second_name);
485061da546Spatrick         break;
486061da546Spatrick       case eArgRepeatPairOptional:
487061da546Spatrick         str.Printf("[<%s> <%s>]", first_name, second_name);
488061da546Spatrick         break;
489061da546Spatrick       case eArgRepeatPairPlus:
490061da546Spatrick         str.Printf("<%s> <%s> [<%s> <%s> [...]]", first_name, second_name,
491061da546Spatrick                    first_name, second_name);
492061da546Spatrick         break;
493061da546Spatrick       case eArgRepeatPairStar:
494061da546Spatrick         str.Printf("[<%s> <%s> [<%s> <%s> [...]]]", first_name, second_name,
495061da546Spatrick                    first_name, second_name);
496061da546Spatrick         break;
497061da546Spatrick       case eArgRepeatPairRange:
498061da546Spatrick         str.Printf("<%s_1> <%s_1> ... <%s_n> <%s_n>", first_name, second_name,
499061da546Spatrick                    first_name, second_name);
500061da546Spatrick         break;
501061da546Spatrick       case eArgRepeatPairRangeOptional:
502061da546Spatrick         str.Printf("[<%s_1> <%s_1> ... <%s_n> <%s_n>]", first_name, second_name,
503061da546Spatrick                    first_name, second_name);
504061da546Spatrick         break;
505061da546Spatrick       // Explicitly test for all the rest of the cases, so if new types get
506061da546Spatrick       // added we will notice the missing case statement(s).
507061da546Spatrick       case eArgRepeatPlain:
508061da546Spatrick       case eArgRepeatOptional:
509061da546Spatrick       case eArgRepeatPlus:
510061da546Spatrick       case eArgRepeatStar:
511061da546Spatrick       case eArgRepeatRange:
512061da546Spatrick         // These should not be reached, as they should fail the IsPairType test
513061da546Spatrick         // above.
514061da546Spatrick         break;
515061da546Spatrick       }
516061da546Spatrick     } else {
517061da546Spatrick       StreamString names;
518061da546Spatrick       for (int j = 0; j < num_alternatives; ++j) {
519061da546Spatrick         if (j > 0)
520061da546Spatrick           names.Printf(" | ");
521061da546Spatrick         names.Printf("%s", GetArgumentName(arg_entry[j].arg_type));
522061da546Spatrick       }
523061da546Spatrick 
524dda28197Spatrick       std::string name_str = std::string(names.GetString());
525061da546Spatrick       switch (arg_entry[0].arg_repetition) {
526061da546Spatrick       case eArgRepeatPlain:
527061da546Spatrick         str.Printf("<%s>", name_str.c_str());
528061da546Spatrick         break;
529061da546Spatrick       case eArgRepeatPlus:
530061da546Spatrick         str.Printf("<%s> [<%s> [...]]", name_str.c_str(), name_str.c_str());
531061da546Spatrick         break;
532061da546Spatrick       case eArgRepeatStar:
533061da546Spatrick         str.Printf("[<%s> [<%s> [...]]]", name_str.c_str(), name_str.c_str());
534061da546Spatrick         break;
535061da546Spatrick       case eArgRepeatOptional:
536061da546Spatrick         str.Printf("[<%s>]", name_str.c_str());
537061da546Spatrick         break;
538061da546Spatrick       case eArgRepeatRange:
539061da546Spatrick         str.Printf("<%s_1> .. <%s_n>", name_str.c_str(), name_str.c_str());
540061da546Spatrick         break;
541061da546Spatrick       // Explicitly test for all the rest of the cases, so if new types get
542061da546Spatrick       // added we will notice the missing case statement(s).
543061da546Spatrick       case eArgRepeatPairPlain:
544061da546Spatrick       case eArgRepeatPairOptional:
545061da546Spatrick       case eArgRepeatPairPlus:
546061da546Spatrick       case eArgRepeatPairStar:
547061da546Spatrick       case eArgRepeatPairRange:
548061da546Spatrick       case eArgRepeatPairRangeOptional:
549061da546Spatrick         // These should not be hit, as they should pass the IsPairType test
550061da546Spatrick         // above, and control should have gone into the other branch of the if
551061da546Spatrick         // statement.
552061da546Spatrick         break;
553061da546Spatrick       }
554061da546Spatrick     }
555061da546Spatrick   }
556061da546Spatrick }
557061da546Spatrick 
558061da546Spatrick CommandArgumentType
LookupArgumentName(llvm::StringRef arg_name)559061da546Spatrick CommandObject::LookupArgumentName(llvm::StringRef arg_name) {
560061da546Spatrick   CommandArgumentType return_type = eArgTypeLastArg;
561061da546Spatrick 
562061da546Spatrick   arg_name = arg_name.ltrim('<').rtrim('>');
563061da546Spatrick 
564061da546Spatrick   for (int i = 0; i < eArgTypeLastArg; ++i)
565*f6aab3d8Srobert     if (arg_name == g_argument_table[i].arg_name)
566*f6aab3d8Srobert       return_type = g_argument_table[i].arg_type;
567061da546Spatrick 
568061da546Spatrick   return return_type;
569061da546Spatrick }
570061da546Spatrick 
FormatLongHelpText(Stream & output_strm,llvm::StringRef long_help)571061da546Spatrick void CommandObject::FormatLongHelpText(Stream &output_strm,
572061da546Spatrick                                        llvm::StringRef long_help) {
573061da546Spatrick   CommandInterpreter &interpreter = GetCommandInterpreter();
574dda28197Spatrick   std::stringstream lineStream{std::string(long_help)};
575061da546Spatrick   std::string line;
576061da546Spatrick   while (std::getline(lineStream, line)) {
577061da546Spatrick     if (line.empty()) {
578061da546Spatrick       output_strm << "\n";
579061da546Spatrick       continue;
580061da546Spatrick     }
581061da546Spatrick     size_t result = line.find_first_not_of(" \t");
582061da546Spatrick     if (result == std::string::npos) {
583061da546Spatrick       result = 0;
584061da546Spatrick     }
585061da546Spatrick     std::string whitespace_prefix = line.substr(0, result);
586061da546Spatrick     std::string remainder = line.substr(result);
587dda28197Spatrick     interpreter.OutputFormattedHelpText(output_strm, whitespace_prefix,
588dda28197Spatrick                                         remainder);
589061da546Spatrick   }
590061da546Spatrick }
591061da546Spatrick 
GenerateHelpText(CommandReturnObject & result)592061da546Spatrick void CommandObject::GenerateHelpText(CommandReturnObject &result) {
593061da546Spatrick   GenerateHelpText(result.GetOutputStream());
594061da546Spatrick 
595061da546Spatrick   result.SetStatus(eReturnStatusSuccessFinishNoResult);
596061da546Spatrick }
597061da546Spatrick 
GenerateHelpText(Stream & output_strm)598061da546Spatrick void CommandObject::GenerateHelpText(Stream &output_strm) {
599061da546Spatrick   CommandInterpreter &interpreter = GetCommandInterpreter();
600061da546Spatrick   std::string help_text(GetHelp());
601dda28197Spatrick   if (WantsRawCommandString()) {
602061da546Spatrick     help_text.append("  Expects 'raw' input (see 'help raw-input'.)");
603dda28197Spatrick   }
604dda28197Spatrick   interpreter.OutputFormattedHelpText(output_strm, "", help_text);
605061da546Spatrick   output_strm << "\nSyntax: " << GetSyntax() << "\n";
606061da546Spatrick   Options *options = GetOptions();
607061da546Spatrick   if (options != nullptr) {
608061da546Spatrick     options->GenerateOptionUsage(
609*f6aab3d8Srobert         output_strm, *this,
610061da546Spatrick         GetCommandInterpreter().GetDebugger().GetTerminalWidth());
611061da546Spatrick   }
612061da546Spatrick   llvm::StringRef long_help = GetHelpLong();
613061da546Spatrick   if (!long_help.empty()) {
614061da546Spatrick     FormatLongHelpText(output_strm, long_help);
615061da546Spatrick   }
616061da546Spatrick   if (!IsDashDashCommand() && options && options->NumCommandOptions() > 0) {
617061da546Spatrick     if (WantsRawCommandString() && !WantsCompletion()) {
618061da546Spatrick       // Emit the message about using ' -- ' between the end of the command
619061da546Spatrick       // options and the raw input conditionally, i.e., only if the command
620061da546Spatrick       // object does not want completion.
621061da546Spatrick       interpreter.OutputFormattedHelpText(
622061da546Spatrick           output_strm, "", "",
623061da546Spatrick           "\nImportant Note: Because this command takes 'raw' input, if you "
624061da546Spatrick           "use any command options"
625061da546Spatrick           " you must use ' -- ' between the end of the command options and the "
626061da546Spatrick           "beginning of the raw input.",
627061da546Spatrick           1);
628061da546Spatrick     } else if (GetNumArgumentEntries() > 0) {
629061da546Spatrick       // Also emit a warning about using "--" in case you are using a command
630061da546Spatrick       // that takes options and arguments.
631061da546Spatrick       interpreter.OutputFormattedHelpText(
632061da546Spatrick           output_strm, "", "",
633061da546Spatrick           "\nThis command takes options and free-form arguments.  If your "
634061da546Spatrick           "arguments resemble"
635061da546Spatrick           " option specifiers (i.e., they start with a - or --), you must use "
636061da546Spatrick           "' -- ' between"
637061da546Spatrick           " the end of the command options and the beginning of the arguments.",
638061da546Spatrick           1);
639061da546Spatrick     }
640061da546Spatrick   }
641061da546Spatrick }
642061da546Spatrick 
AddIDsArgumentData(CommandArgumentEntry & arg,CommandArgumentType ID,CommandArgumentType IDRange)643061da546Spatrick void CommandObject::AddIDsArgumentData(CommandArgumentEntry &arg,
644061da546Spatrick                                        CommandArgumentType ID,
645061da546Spatrick                                        CommandArgumentType IDRange) {
646061da546Spatrick   CommandArgumentData id_arg;
647061da546Spatrick   CommandArgumentData id_range_arg;
648061da546Spatrick 
649061da546Spatrick   // Create the first variant for the first (and only) argument for this
650061da546Spatrick   // command.
651061da546Spatrick   id_arg.arg_type = ID;
652061da546Spatrick   id_arg.arg_repetition = eArgRepeatOptional;
653061da546Spatrick 
654061da546Spatrick   // Create the second variant for the first (and only) argument for this
655061da546Spatrick   // command.
656061da546Spatrick   id_range_arg.arg_type = IDRange;
657061da546Spatrick   id_range_arg.arg_repetition = eArgRepeatOptional;
658061da546Spatrick 
659061da546Spatrick   // The first (and only) argument for this command could be either an id or an
660061da546Spatrick   // id_range. Push both variants into the entry for the first argument for
661061da546Spatrick   // this command.
662061da546Spatrick   arg.push_back(id_arg);
663061da546Spatrick   arg.push_back(id_range_arg);
664061da546Spatrick }
665061da546Spatrick 
GetArgumentTypeAsCString(const lldb::CommandArgumentType arg_type)666061da546Spatrick const char *CommandObject::GetArgumentTypeAsCString(
667061da546Spatrick     const lldb::CommandArgumentType arg_type) {
668061da546Spatrick   assert(arg_type < eArgTypeLastArg &&
669061da546Spatrick          "Invalid argument type passed to GetArgumentTypeAsCString");
670*f6aab3d8Srobert   return g_argument_table[arg_type].arg_name;
671061da546Spatrick }
672061da546Spatrick 
GetArgumentDescriptionAsCString(const lldb::CommandArgumentType arg_type)673061da546Spatrick const char *CommandObject::GetArgumentDescriptionAsCString(
674061da546Spatrick     const lldb::CommandArgumentType arg_type) {
675061da546Spatrick   assert(arg_type < eArgTypeLastArg &&
676061da546Spatrick          "Invalid argument type passed to GetArgumentDescriptionAsCString");
677*f6aab3d8Srobert   return g_argument_table[arg_type].help_text;
678061da546Spatrick }
679061da546Spatrick 
GetDummyTarget()680061da546Spatrick Target &CommandObject::GetDummyTarget() {
681be691f3bSpatrick   return m_interpreter.GetDebugger().GetDummyTarget();
682061da546Spatrick }
683061da546Spatrick 
GetSelectedOrDummyTarget(bool prefer_dummy)684061da546Spatrick Target &CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy) {
685be691f3bSpatrick   return m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy);
686061da546Spatrick }
687061da546Spatrick 
GetSelectedTarget()688061da546Spatrick Target &CommandObject::GetSelectedTarget() {
689061da546Spatrick   assert(m_flags.AnySet(eCommandRequiresTarget | eCommandProcessMustBePaused |
690061da546Spatrick                         eCommandProcessMustBeLaunched | eCommandRequiresFrame |
691061da546Spatrick                         eCommandRequiresThread | eCommandRequiresProcess |
692061da546Spatrick                         eCommandRequiresRegContext) &&
693061da546Spatrick          "GetSelectedTarget called from object that may have no target");
694061da546Spatrick   return *m_interpreter.GetDebugger().GetSelectedTarget();
695061da546Spatrick }
696061da546Spatrick 
GetDefaultThread()697061da546Spatrick Thread *CommandObject::GetDefaultThread() {
698061da546Spatrick   Thread *thread_to_use = m_exe_ctx.GetThreadPtr();
699061da546Spatrick   if (thread_to_use)
700061da546Spatrick     return thread_to_use;
701061da546Spatrick 
702061da546Spatrick   Process *process = m_exe_ctx.GetProcessPtr();
703061da546Spatrick   if (!process) {
704061da546Spatrick     Target *target = m_exe_ctx.GetTargetPtr();
705061da546Spatrick     if (!target) {
706061da546Spatrick       target = m_interpreter.GetDebugger().GetSelectedTarget().get();
707061da546Spatrick     }
708061da546Spatrick     if (target)
709061da546Spatrick       process = target->GetProcessSP().get();
710061da546Spatrick   }
711061da546Spatrick 
712061da546Spatrick   if (process)
713061da546Spatrick     return process->GetThreadList().GetSelectedThread().get();
714061da546Spatrick   else
715061da546Spatrick     return nullptr;
716061da546Spatrick }
717061da546Spatrick 
Execute(const char * args_string,CommandReturnObject & result)718061da546Spatrick bool CommandObjectParsed::Execute(const char *args_string,
719061da546Spatrick                                   CommandReturnObject &result) {
720061da546Spatrick   bool handled = false;
721061da546Spatrick   Args cmd_args(args_string);
722061da546Spatrick   if (HasOverrideCallback()) {
723061da546Spatrick     Args full_args(GetCommandName());
724061da546Spatrick     full_args.AppendArguments(cmd_args);
725061da546Spatrick     handled =
726061da546Spatrick         InvokeOverrideCallback(full_args.GetConstArgumentVector(), result);
727061da546Spatrick   }
728061da546Spatrick   if (!handled) {
729061da546Spatrick     for (auto entry : llvm::enumerate(cmd_args.entries())) {
730*f6aab3d8Srobert       if (!entry.value().ref().empty() && entry.value().GetQuoteChar() == '`') {
731061da546Spatrick         cmd_args.ReplaceArgumentAtIndex(
732061da546Spatrick             entry.index(),
733061da546Spatrick             m_interpreter.ProcessEmbeddedScriptCommands(entry.value().c_str()));
734061da546Spatrick       }
735061da546Spatrick     }
736061da546Spatrick 
737061da546Spatrick     if (CheckRequirements(result)) {
738061da546Spatrick       if (ParseOptions(cmd_args, result)) {
739061da546Spatrick         // Call the command-specific version of 'Execute', passing it the
740061da546Spatrick         // already processed arguments.
741*f6aab3d8Srobert         if (cmd_args.GetArgumentCount() != 0 && m_arguments.empty()) {
742*f6aab3d8Srobert           result.AppendErrorWithFormatv("'{0}' doesn't take any arguments.",
743*f6aab3d8Srobert                                         GetCommandName());
744*f6aab3d8Srobert           Cleanup();
745*f6aab3d8Srobert           return false;
746*f6aab3d8Srobert         }
747061da546Spatrick         handled = DoExecute(cmd_args, result);
748061da546Spatrick       }
749061da546Spatrick     }
750061da546Spatrick 
751061da546Spatrick     Cleanup();
752061da546Spatrick   }
753061da546Spatrick   return handled;
754061da546Spatrick }
755061da546Spatrick 
Execute(const char * args_string,CommandReturnObject & result)756061da546Spatrick bool CommandObjectRaw::Execute(const char *args_string,
757061da546Spatrick                                CommandReturnObject &result) {
758061da546Spatrick   bool handled = false;
759061da546Spatrick   if (HasOverrideCallback()) {
760061da546Spatrick     std::string full_command(GetCommandName());
761061da546Spatrick     full_command += ' ';
762061da546Spatrick     full_command += args_string;
763061da546Spatrick     const char *argv[2] = {nullptr, nullptr};
764061da546Spatrick     argv[0] = full_command.c_str();
765061da546Spatrick     handled = InvokeOverrideCallback(argv, result);
766061da546Spatrick   }
767061da546Spatrick   if (!handled) {
768061da546Spatrick     if (CheckRequirements(result))
769061da546Spatrick       handled = DoExecute(args_string, result);
770061da546Spatrick 
771061da546Spatrick     Cleanup();
772061da546Spatrick   }
773061da546Spatrick   return handled;
774061da546Spatrick }
775