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