1 //===-- SBCommandInterpreter.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/lldb-types.h"
10 
11 #include "lldb/Interpreter/CommandInterpreter.h"
12 #include "lldb/Interpreter/CommandObjectMultiword.h"
13 #include "lldb/Interpreter/CommandReturnObject.h"
14 #include "lldb/Target/Target.h"
15 #include "lldb/Utility/Instrumentation.h"
16 #include "lldb/Utility/Listener.h"
17 
18 #include "lldb/API/SBBroadcaster.h"
19 #include "lldb/API/SBCommandInterpreter.h"
20 #include "lldb/API/SBCommandInterpreterRunOptions.h"
21 #include "lldb/API/SBCommandReturnObject.h"
22 #include "lldb/API/SBEvent.h"
23 #include "lldb/API/SBExecutionContext.h"
24 #include "lldb/API/SBListener.h"
25 #include "lldb/API/SBProcess.h"
26 #include "lldb/API/SBStream.h"
27 #include "lldb/API/SBStringList.h"
28 #include "lldb/API/SBTarget.h"
29 
30 #include <memory>
31 #include <optional>
32 
33 using namespace lldb;
34 using namespace lldb_private;
35 
36 namespace lldb_private {
37 class CommandPluginInterfaceImplementation : public CommandObjectParsed {
38 public:
39   CommandPluginInterfaceImplementation(CommandInterpreter &interpreter,
40                                        const char *name,
41                                        lldb::SBCommandPluginInterface *backend,
42                                        const char *help = nullptr,
43                                        const char *syntax = nullptr,
44                                        uint32_t flags = 0,
45                                        const char *auto_repeat_command = "")
46       : CommandObjectParsed(interpreter, name, help, syntax, flags),
47         m_backend(backend) {
48     m_auto_repeat_command =
49         auto_repeat_command == nullptr
50             ? std::nullopt
51             : std::optional<std::string>(auto_repeat_command);
52     // We don't know whether any given command coming from this interface takes
53     // arguments or not so here we're just disabling the basic args check.
54     CommandArgumentData none_arg{eArgTypeNone, eArgRepeatStar};
55     m_arguments.push_back({none_arg});
56   }
57 
58   bool IsRemovable() const override { return true; }
59 
60   /// More documentation is available in lldb::CommandObject::GetRepeatCommand,
61   /// but in short, if std::nullopt is returned, the previous command will be
62   /// repeated, and if an empty string is returned, no commands will be
63   /// executed.
64   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
65                                               uint32_t index) override {
66     if (!m_auto_repeat_command)
67       return std::nullopt;
68     else
69       return m_auto_repeat_command;
70   }
71 
72 protected:
73   bool DoExecute(Args &command, CommandReturnObject &result) override {
74     SBCommandReturnObject sb_return(result);
75     SBCommandInterpreter sb_interpreter(&m_interpreter);
76     SBDebugger debugger_sb(m_interpreter.GetDebugger().shared_from_this());
77     bool ret = m_backend->DoExecute(debugger_sb, command.GetArgumentVector(),
78                                     sb_return);
79     return ret;
80   }
81   std::shared_ptr<lldb::SBCommandPluginInterface> m_backend;
82   std::optional<std::string> m_auto_repeat_command;
83 };
84 } // namespace lldb_private
85 
86 SBCommandInterpreter::SBCommandInterpreter(CommandInterpreter *interpreter)
87     : m_opaque_ptr(interpreter) {
88   LLDB_INSTRUMENT_VA(this, interpreter);
89 }
90 
91 SBCommandInterpreter::SBCommandInterpreter(const SBCommandInterpreter &rhs)
92     : m_opaque_ptr(rhs.m_opaque_ptr) {
93   LLDB_INSTRUMENT_VA(this, rhs);
94 }
95 
96 SBCommandInterpreter::~SBCommandInterpreter() = default;
97 
98 const SBCommandInterpreter &SBCommandInterpreter::
99 operator=(const SBCommandInterpreter &rhs) {
100   LLDB_INSTRUMENT_VA(this, rhs);
101 
102   m_opaque_ptr = rhs.m_opaque_ptr;
103   return *this;
104 }
105 
106 bool SBCommandInterpreter::IsValid() const {
107   LLDB_INSTRUMENT_VA(this);
108   return this->operator bool();
109 }
110 SBCommandInterpreter::operator bool() const {
111   LLDB_INSTRUMENT_VA(this);
112 
113   return m_opaque_ptr != nullptr;
114 }
115 
116 bool SBCommandInterpreter::CommandExists(const char *cmd) {
117   LLDB_INSTRUMENT_VA(this, cmd);
118 
119   return (((cmd != nullptr) && IsValid()) ? m_opaque_ptr->CommandExists(cmd)
120                                           : false);
121 }
122 
123 bool SBCommandInterpreter::UserCommandExists(const char *cmd) {
124   LLDB_INSTRUMENT_VA(this, cmd);
125 
126   return (((cmd != nullptr) && IsValid()) ? m_opaque_ptr->UserCommandExists(cmd)
127                                           : false);
128 }
129 
130 bool SBCommandInterpreter::AliasExists(const char *cmd) {
131   LLDB_INSTRUMENT_VA(this, cmd);
132 
133   return (((cmd != nullptr) && IsValid()) ? m_opaque_ptr->AliasExists(cmd)
134                                           : false);
135 }
136 
137 bool SBCommandInterpreter::IsActive() {
138   LLDB_INSTRUMENT_VA(this);
139 
140   return (IsValid() ? m_opaque_ptr->IsActive() : false);
141 }
142 
143 bool SBCommandInterpreter::WasInterrupted() const {
144   LLDB_INSTRUMENT_VA(this);
145 
146   return (IsValid() ? m_opaque_ptr->GetDebugger().InterruptRequested() : false);
147 }
148 
149 bool SBCommandInterpreter::InterruptCommand() {
150   LLDB_INSTRUMENT_VA(this);
151 
152   return (IsValid() ? m_opaque_ptr->InterruptCommand() : false);
153 }
154 
155 const char *SBCommandInterpreter::GetIOHandlerControlSequence(char ch) {
156   LLDB_INSTRUMENT_VA(this, ch);
157 
158   if (!IsValid())
159     return nullptr;
160 
161   return ConstString(
162              m_opaque_ptr->GetDebugger().GetTopIOHandlerControlSequence(ch))
163       .GetCString();
164 }
165 
166 lldb::ReturnStatus
167 SBCommandInterpreter::HandleCommand(const char *command_line,
168                                     SBCommandReturnObject &result,
169                                     bool add_to_history) {
170   LLDB_INSTRUMENT_VA(this, command_line, result, add_to_history);
171 
172   SBExecutionContext sb_exe_ctx;
173   return HandleCommand(command_line, sb_exe_ctx, result, add_to_history);
174 }
175 
176 lldb::ReturnStatus SBCommandInterpreter::HandleCommand(
177     const char *command_line, SBExecutionContext &override_context,
178     SBCommandReturnObject &result, bool add_to_history) {
179   LLDB_INSTRUMENT_VA(this, command_line, override_context, result,
180                      add_to_history);
181 
182   result.Clear();
183   if (command_line && IsValid()) {
184     result.ref().SetInteractive(false);
185     auto do_add_to_history = add_to_history ? eLazyBoolYes : eLazyBoolNo;
186     if (override_context.get())
187       m_opaque_ptr->HandleCommand(command_line, do_add_to_history,
188                                   override_context.get()->Lock(true),
189                                   result.ref());
190     else
191       m_opaque_ptr->HandleCommand(command_line, do_add_to_history,
192                                   result.ref());
193   } else {
194     result->AppendError(
195         "SBCommandInterpreter or the command line is not valid");
196   }
197 
198   return result.GetStatus();
199 }
200 
201 void SBCommandInterpreter::HandleCommandsFromFile(
202     lldb::SBFileSpec &file, lldb::SBExecutionContext &override_context,
203     lldb::SBCommandInterpreterRunOptions &options,
204     lldb::SBCommandReturnObject result) {
205   LLDB_INSTRUMENT_VA(this, file, override_context, options, result);
206 
207   if (!IsValid()) {
208     result->AppendError("SBCommandInterpreter is not valid.");
209     return;
210   }
211 
212   if (!file.IsValid()) {
213     SBStream s;
214     file.GetDescription(s);
215     result->AppendErrorWithFormat("File is not valid: %s.", s.GetData());
216   }
217 
218   FileSpec tmp_spec = file.ref();
219   if (override_context.get())
220     m_opaque_ptr->HandleCommandsFromFile(tmp_spec,
221                                          override_context.get()->Lock(true),
222                                          options.ref(),
223                                          result.ref());
224 
225   else
226     m_opaque_ptr->HandleCommandsFromFile(tmp_spec, options.ref(), result.ref());
227 }
228 
229 int SBCommandInterpreter::HandleCompletion(
230     const char *current_line, const char *cursor, const char *last_char,
231     int match_start_point, int max_return_elements, SBStringList &matches) {
232   LLDB_INSTRUMENT_VA(this, current_line, cursor, last_char, match_start_point,
233                      max_return_elements, matches);
234 
235   SBStringList dummy_descriptions;
236   return HandleCompletionWithDescriptions(
237       current_line, cursor, last_char, match_start_point, max_return_elements,
238       matches, dummy_descriptions);
239 }
240 
241 int SBCommandInterpreter::HandleCompletionWithDescriptions(
242     const char *current_line, const char *cursor, const char *last_char,
243     int match_start_point, int max_return_elements, SBStringList &matches,
244     SBStringList &descriptions) {
245   LLDB_INSTRUMENT_VA(this, current_line, cursor, last_char, match_start_point,
246                      max_return_elements, matches, descriptions);
247 
248   // Sanity check the arguments that are passed in: cursor & last_char have to
249   // be within the current_line.
250   if (current_line == nullptr || cursor == nullptr || last_char == nullptr)
251     return 0;
252 
253   if (cursor < current_line || last_char < current_line)
254     return 0;
255 
256   size_t current_line_size = strlen(current_line);
257   if (cursor - current_line > static_cast<ptrdiff_t>(current_line_size) ||
258       last_char - current_line > static_cast<ptrdiff_t>(current_line_size))
259     return 0;
260 
261   if (!IsValid())
262     return 0;
263 
264   lldb_private::StringList lldb_matches, lldb_descriptions;
265   CompletionResult result;
266   CompletionRequest request(current_line, cursor - current_line, result);
267   m_opaque_ptr->HandleCompletion(request);
268   result.GetMatches(lldb_matches);
269   result.GetDescriptions(lldb_descriptions);
270 
271   // Make the result array indexed from 1 again by adding the 'common prefix'
272   // of all completions as element 0. This is done to emulate the old API.
273   if (request.GetParsedLine().GetArgumentCount() == 0) {
274     // If we got an empty string, insert nothing.
275     lldb_matches.InsertStringAtIndex(0, "");
276     lldb_descriptions.InsertStringAtIndex(0, "");
277   } else {
278     // Now figure out if there is a common substring, and if so put that in
279     // element 0, otherwise put an empty string in element 0.
280     std::string command_partial_str = request.GetCursorArgumentPrefix().str();
281 
282     std::string common_prefix = lldb_matches.LongestCommonPrefix();
283     const size_t partial_name_len = command_partial_str.size();
284     common_prefix.erase(0, partial_name_len);
285 
286     // If we matched a unique single command, add a space... Only do this if
287     // the completer told us this was a complete word, however...
288     if (lldb_matches.GetSize() == 1) {
289       char quote_char = request.GetParsedArg().GetQuoteChar();
290       common_prefix =
291           Args::EscapeLLDBCommandArgument(common_prefix, quote_char);
292       if (request.GetParsedArg().IsQuoted())
293         common_prefix.push_back(quote_char);
294       common_prefix.push_back(' ');
295     }
296     lldb_matches.InsertStringAtIndex(0, common_prefix.c_str());
297     lldb_descriptions.InsertStringAtIndex(0, "");
298   }
299 
300   SBStringList temp_matches_list(&lldb_matches);
301   matches.AppendList(temp_matches_list);
302   SBStringList temp_descriptions_list(&lldb_descriptions);
303   descriptions.AppendList(temp_descriptions_list);
304   return result.GetNumberOfResults();
305 }
306 
307 int SBCommandInterpreter::HandleCompletionWithDescriptions(
308     const char *current_line, uint32_t cursor_pos, int match_start_point,
309     int max_return_elements, SBStringList &matches,
310     SBStringList &descriptions) {
311   LLDB_INSTRUMENT_VA(this, current_line, cursor_pos, match_start_point,
312                      max_return_elements, matches, descriptions);
313 
314   const char *cursor = current_line + cursor_pos;
315   const char *last_char = current_line + strlen(current_line);
316   return HandleCompletionWithDescriptions(
317       current_line, cursor, last_char, match_start_point, max_return_elements,
318       matches, descriptions);
319 }
320 
321 int SBCommandInterpreter::HandleCompletion(const char *current_line,
322                                            uint32_t cursor_pos,
323                                            int match_start_point,
324                                            int max_return_elements,
325                                            lldb::SBStringList &matches) {
326   LLDB_INSTRUMENT_VA(this, current_line, cursor_pos, match_start_point,
327                      max_return_elements, matches);
328 
329   const char *cursor = current_line + cursor_pos;
330   const char *last_char = current_line + strlen(current_line);
331   return HandleCompletion(current_line, cursor, last_char, match_start_point,
332                           max_return_elements, matches);
333 }
334 
335 bool SBCommandInterpreter::HasCommands() {
336   LLDB_INSTRUMENT_VA(this);
337 
338   return (IsValid() ? m_opaque_ptr->HasCommands() : false);
339 }
340 
341 bool SBCommandInterpreter::HasAliases() {
342   LLDB_INSTRUMENT_VA(this);
343 
344   return (IsValid() ? m_opaque_ptr->HasAliases() : false);
345 }
346 
347 bool SBCommandInterpreter::HasAliasOptions() {
348   LLDB_INSTRUMENT_VA(this);
349 
350   return (IsValid() ? m_opaque_ptr->HasAliasOptions() : false);
351 }
352 
353 bool SBCommandInterpreter::IsInteractive() {
354   LLDB_INSTRUMENT_VA(this);
355 
356   return (IsValid() ? m_opaque_ptr->IsInteractive() : false);
357 }
358 
359 SBProcess SBCommandInterpreter::GetProcess() {
360   LLDB_INSTRUMENT_VA(this);
361 
362   SBProcess sb_process;
363   ProcessSP process_sp;
364   if (IsValid()) {
365     TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
366     if (target_sp) {
367       std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
368       process_sp = target_sp->GetProcessSP();
369       sb_process.SetSP(process_sp);
370     }
371   }
372 
373   return sb_process;
374 }
375 
376 SBDebugger SBCommandInterpreter::GetDebugger() {
377   LLDB_INSTRUMENT_VA(this);
378 
379   SBDebugger sb_debugger;
380   if (IsValid())
381     sb_debugger.reset(m_opaque_ptr->GetDebugger().shared_from_this());
382 
383   return sb_debugger;
384 }
385 
386 bool SBCommandInterpreter::GetPromptOnQuit() {
387   LLDB_INSTRUMENT_VA(this);
388 
389   return (IsValid() ? m_opaque_ptr->GetPromptOnQuit() : false);
390 }
391 
392 void SBCommandInterpreter::SetPromptOnQuit(bool b) {
393   LLDB_INSTRUMENT_VA(this, b);
394 
395   if (IsValid())
396     m_opaque_ptr->SetPromptOnQuit(b);
397 }
398 
399 void SBCommandInterpreter::AllowExitCodeOnQuit(bool allow) {
400   LLDB_INSTRUMENT_VA(this, allow);
401 
402   if (m_opaque_ptr)
403     m_opaque_ptr->AllowExitCodeOnQuit(allow);
404 }
405 
406 bool SBCommandInterpreter::HasCustomQuitExitCode() {
407   LLDB_INSTRUMENT_VA(this);
408 
409   bool exited = false;
410   if (m_opaque_ptr)
411     m_opaque_ptr->GetQuitExitCode(exited);
412   return exited;
413 }
414 
415 int SBCommandInterpreter::GetQuitStatus() {
416   LLDB_INSTRUMENT_VA(this);
417 
418   bool exited = false;
419   return (m_opaque_ptr ? m_opaque_ptr->GetQuitExitCode(exited) : 0);
420 }
421 
422 void SBCommandInterpreter::ResolveCommand(const char *command_line,
423                                           SBCommandReturnObject &result) {
424   LLDB_INSTRUMENT_VA(this, command_line, result);
425 
426   result.Clear();
427   if (command_line && IsValid()) {
428     m_opaque_ptr->ResolveCommand(command_line, result.ref());
429   } else {
430     result->AppendError(
431         "SBCommandInterpreter or the command line is not valid");
432   }
433 }
434 
435 CommandInterpreter *SBCommandInterpreter::get() { return m_opaque_ptr; }
436 
437 CommandInterpreter &SBCommandInterpreter::ref() {
438   assert(m_opaque_ptr);
439   return *m_opaque_ptr;
440 }
441 
442 void SBCommandInterpreter::reset(
443     lldb_private::CommandInterpreter *interpreter) {
444   m_opaque_ptr = interpreter;
445 }
446 
447 void SBCommandInterpreter::SourceInitFileInGlobalDirectory(
448     SBCommandReturnObject &result) {
449   LLDB_INSTRUMENT_VA(this, result);
450 
451   result.Clear();
452   if (IsValid()) {
453     TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
454     std::unique_lock<std::recursive_mutex> lock;
455     if (target_sp)
456       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
457     m_opaque_ptr->SourceInitFileGlobal(result.ref());
458   } else {
459     result->AppendError("SBCommandInterpreter is not valid");
460   }
461 }
462 
463 void SBCommandInterpreter::SourceInitFileInHomeDirectory(
464     SBCommandReturnObject &result) {
465   LLDB_INSTRUMENT_VA(this, result);
466 
467   SourceInitFileInHomeDirectory(result, /*is_repl=*/false);
468 }
469 
470 void SBCommandInterpreter::SourceInitFileInHomeDirectory(
471     SBCommandReturnObject &result, bool is_repl) {
472   LLDB_INSTRUMENT_VA(this, result, is_repl);
473 
474   result.Clear();
475   if (IsValid()) {
476     TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
477     std::unique_lock<std::recursive_mutex> lock;
478     if (target_sp)
479       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
480     m_opaque_ptr->SourceInitFileHome(result.ref(), is_repl);
481   } else {
482     result->AppendError("SBCommandInterpreter is not valid");
483   }
484 }
485 
486 void SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory(
487     SBCommandReturnObject &result) {
488   LLDB_INSTRUMENT_VA(this, result);
489 
490   result.Clear();
491   if (IsValid()) {
492     TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
493     std::unique_lock<std::recursive_mutex> lock;
494     if (target_sp)
495       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
496     m_opaque_ptr->SourceInitFileCwd(result.ref());
497   } else {
498     result->AppendError("SBCommandInterpreter is not valid");
499   }
500 }
501 
502 SBBroadcaster SBCommandInterpreter::GetBroadcaster() {
503   LLDB_INSTRUMENT_VA(this);
504 
505   SBBroadcaster broadcaster(m_opaque_ptr, false);
506 
507   return broadcaster;
508 }
509 
510 const char *SBCommandInterpreter::GetBroadcasterClass() {
511   LLDB_INSTRUMENT();
512 
513   return CommandInterpreter::GetStaticBroadcasterClass().AsCString();
514 }
515 
516 const char *SBCommandInterpreter::GetArgumentTypeAsCString(
517     const lldb::CommandArgumentType arg_type) {
518   LLDB_INSTRUMENT_VA(arg_type);
519 
520   return ConstString(CommandObject::GetArgumentTypeAsCString(arg_type))
521       .GetCString();
522 }
523 
524 const char *SBCommandInterpreter::GetArgumentDescriptionAsCString(
525     const lldb::CommandArgumentType arg_type) {
526   LLDB_INSTRUMENT_VA(arg_type);
527 
528   return ConstString(CommandObject::GetArgumentDescriptionAsCString(arg_type))
529       .GetCString();
530 }
531 
532 bool SBCommandInterpreter::EventIsCommandInterpreterEvent(
533     const lldb::SBEvent &event) {
534   LLDB_INSTRUMENT_VA(event);
535 
536   return event.GetBroadcasterClass() ==
537          SBCommandInterpreter::GetBroadcasterClass();
538 }
539 
540 bool SBCommandInterpreter::SetCommandOverrideCallback(
541     const char *command_name, lldb::CommandOverrideCallback callback,
542     void *baton) {
543   LLDB_INSTRUMENT_VA(this, command_name, callback, baton);
544 
545   if (command_name && command_name[0] && IsValid()) {
546     llvm::StringRef command_name_str = command_name;
547     CommandObject *cmd_obj =
548         m_opaque_ptr->GetCommandObjectForCommand(command_name_str);
549     if (cmd_obj) {
550       assert(command_name_str.empty());
551       cmd_obj->SetOverrideCallback(callback, baton);
552       return true;
553     }
554   }
555   return false;
556 }
557 
558 lldb::SBCommand SBCommandInterpreter::AddMultiwordCommand(const char *name,
559                                                           const char *help) {
560   LLDB_INSTRUMENT_VA(this, name, help);
561 
562   lldb::CommandObjectSP new_command_sp(
563       new CommandObjectMultiword(*m_opaque_ptr, name, help));
564   new_command_sp->GetAsMultiwordCommand()->SetRemovable(true);
565   Status add_error = m_opaque_ptr->AddUserCommand(name, new_command_sp, true);
566   if (add_error.Success())
567     return lldb::SBCommand(new_command_sp);
568   return lldb::SBCommand();
569 }
570 
571 lldb::SBCommand SBCommandInterpreter::AddCommand(
572     const char *name, lldb::SBCommandPluginInterface *impl, const char *help) {
573   LLDB_INSTRUMENT_VA(this, name, impl, help);
574 
575   return AddCommand(name, impl, help, /*syntax=*/nullptr,
576                     /*auto_repeat_command=*/"");
577 }
578 
579 lldb::SBCommand
580 SBCommandInterpreter::AddCommand(const char *name,
581                                  lldb::SBCommandPluginInterface *impl,
582                                  const char *help, const char *syntax) {
583   LLDB_INSTRUMENT_VA(this, name, impl, help, syntax);
584   return AddCommand(name, impl, help, syntax, /*auto_repeat_command=*/"");
585 }
586 
587 lldb::SBCommand SBCommandInterpreter::AddCommand(
588     const char *name, lldb::SBCommandPluginInterface *impl, const char *help,
589     const char *syntax, const char *auto_repeat_command) {
590   LLDB_INSTRUMENT_VA(this, name, impl, help, syntax, auto_repeat_command);
591 
592   lldb::CommandObjectSP new_command_sp;
593   new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
594       *m_opaque_ptr, name, impl, help, syntax, /*flags=*/0,
595       auto_repeat_command);
596 
597   Status add_error = m_opaque_ptr->AddUserCommand(name, new_command_sp, true);
598   if (add_error.Success())
599     return lldb::SBCommand(new_command_sp);
600   return lldb::SBCommand();
601 }
602 
603 SBCommand::SBCommand() { LLDB_INSTRUMENT_VA(this); }
604 
605 SBCommand::SBCommand(lldb::CommandObjectSP cmd_sp) : m_opaque_sp(cmd_sp) {}
606 
607 bool SBCommand::IsValid() {
608   LLDB_INSTRUMENT_VA(this);
609   return this->operator bool();
610 }
611 SBCommand::operator bool() const {
612   LLDB_INSTRUMENT_VA(this);
613 
614   return m_opaque_sp.get() != nullptr;
615 }
616 
617 const char *SBCommand::GetName() {
618   LLDB_INSTRUMENT_VA(this);
619 
620   return (IsValid() ? ConstString(m_opaque_sp->GetCommandName()).AsCString() : nullptr);
621 }
622 
623 const char *SBCommand::GetHelp() {
624   LLDB_INSTRUMENT_VA(this);
625 
626   return (IsValid() ? ConstString(m_opaque_sp->GetHelp()).AsCString()
627                     : nullptr);
628 }
629 
630 const char *SBCommand::GetHelpLong() {
631   LLDB_INSTRUMENT_VA(this);
632 
633   return (IsValid() ? ConstString(m_opaque_sp->GetHelpLong()).AsCString()
634                     : nullptr);
635 }
636 
637 void SBCommand::SetHelp(const char *help) {
638   LLDB_INSTRUMENT_VA(this, help);
639 
640   if (IsValid())
641     m_opaque_sp->SetHelp(help);
642 }
643 
644 void SBCommand::SetHelpLong(const char *help) {
645   LLDB_INSTRUMENT_VA(this, help);
646 
647   if (IsValid())
648     m_opaque_sp->SetHelpLong(help);
649 }
650 
651 lldb::SBCommand SBCommand::AddMultiwordCommand(const char *name,
652                                                const char *help) {
653   LLDB_INSTRUMENT_VA(this, name, help);
654 
655   if (!IsValid())
656     return lldb::SBCommand();
657   if (!m_opaque_sp->IsMultiwordObject())
658     return lldb::SBCommand();
659   CommandObjectMultiword *new_command = new CommandObjectMultiword(
660       m_opaque_sp->GetCommandInterpreter(), name, help);
661   new_command->SetRemovable(true);
662   lldb::CommandObjectSP new_command_sp(new_command);
663   if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
664     return lldb::SBCommand(new_command_sp);
665   return lldb::SBCommand();
666 }
667 
668 lldb::SBCommand SBCommand::AddCommand(const char *name,
669                                       lldb::SBCommandPluginInterface *impl,
670                                       const char *help) {
671   LLDB_INSTRUMENT_VA(this, name, impl, help);
672   return AddCommand(name, impl, help, /*syntax=*/nullptr,
673                     /*auto_repeat_command=*/"");
674 }
675 
676 lldb::SBCommand SBCommand::AddCommand(const char *name,
677                                       lldb::SBCommandPluginInterface *impl,
678                                       const char *help, const char *syntax) {
679   LLDB_INSTRUMENT_VA(this, name, impl, help, syntax);
680   return AddCommand(name, impl, help, syntax, /*auto_repeat_command=*/"");
681 }
682 
683 lldb::SBCommand SBCommand::AddCommand(const char *name,
684                                       lldb::SBCommandPluginInterface *impl,
685                                       const char *help, const char *syntax,
686                                       const char *auto_repeat_command) {
687   LLDB_INSTRUMENT_VA(this, name, impl, help, syntax, auto_repeat_command);
688 
689   if (!IsValid())
690     return lldb::SBCommand();
691   if (!m_opaque_sp->IsMultiwordObject())
692     return lldb::SBCommand();
693   lldb::CommandObjectSP new_command_sp;
694   new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
695       m_opaque_sp->GetCommandInterpreter(), name, impl, help, syntax,
696       /*flags=*/0, auto_repeat_command);
697   if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
698     return lldb::SBCommand(new_command_sp);
699   return lldb::SBCommand();
700 }
701 
702 uint32_t SBCommand::GetFlags() {
703   LLDB_INSTRUMENT_VA(this);
704 
705   return (IsValid() ? m_opaque_sp->GetFlags().Get() : 0);
706 }
707 
708 void SBCommand::SetFlags(uint32_t flags) {
709   LLDB_INSTRUMENT_VA(this, flags);
710 
711   if (IsValid())
712     m_opaque_sp->GetFlags().Set(flags);
713 }
714