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