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