1 //===-- SBCommandInterpreter.cpp --------------------------------*- C++ -*-===//
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/Listener.h"
16 
17 #include "lldb/API/SBBroadcaster.h"
18 #include "lldb/API/SBCommandInterpreter.h"
19 #include "lldb/API/SBCommandReturnObject.h"
20 #include "lldb/API/SBEvent.h"
21 #include "lldb/API/SBExecutionContext.h"
22 #include "lldb/API/SBListener.h"
23 #include "lldb/API/SBProcess.h"
24 #include "lldb/API/SBStream.h"
25 #include "lldb/API/SBStringList.h"
26 #include "lldb/API/SBTarget.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 SBCommandInterpreterRunOptions::SBCommandInterpreterRunOptions() {
32   m_opaque_up.reset(new CommandInterpreterRunOptions());
33 }
34 
35 SBCommandInterpreterRunOptions::~SBCommandInterpreterRunOptions() = default;
36 
37 bool SBCommandInterpreterRunOptions::GetStopOnContinue() const {
38   return m_opaque_up->GetStopOnContinue();
39 }
40 
41 void SBCommandInterpreterRunOptions::SetStopOnContinue(bool stop_on_continue) {
42   m_opaque_up->SetStopOnContinue(stop_on_continue);
43 }
44 
45 bool SBCommandInterpreterRunOptions::GetStopOnError() const {
46   return m_opaque_up->GetStopOnError();
47 }
48 
49 void SBCommandInterpreterRunOptions::SetStopOnError(bool stop_on_error) {
50   m_opaque_up->SetStopOnError(stop_on_error);
51 }
52 
53 bool SBCommandInterpreterRunOptions::GetStopOnCrash() const {
54   return m_opaque_up->GetStopOnCrash();
55 }
56 
57 void SBCommandInterpreterRunOptions::SetStopOnCrash(bool stop_on_crash) {
58   m_opaque_up->SetStopOnCrash(stop_on_crash);
59 }
60 
61 bool SBCommandInterpreterRunOptions::GetEchoCommands() const {
62   return m_opaque_up->GetEchoCommands();
63 }
64 
65 void SBCommandInterpreterRunOptions::SetEchoCommands(bool echo_commands) {
66   m_opaque_up->SetEchoCommands(echo_commands);
67 }
68 
69 bool SBCommandInterpreterRunOptions::GetEchoCommentCommands() const {
70   return m_opaque_up->GetEchoCommentCommands();
71 }
72 
73 void SBCommandInterpreterRunOptions::SetEchoCommentCommands(bool echo) {
74   m_opaque_up->SetEchoCommentCommands(echo);
75 }
76 
77 bool SBCommandInterpreterRunOptions::GetPrintResults() const {
78   return m_opaque_up->GetPrintResults();
79 }
80 
81 void SBCommandInterpreterRunOptions::SetPrintResults(bool print_results) {
82   m_opaque_up->SetPrintResults(print_results);
83 }
84 
85 bool SBCommandInterpreterRunOptions::GetAddToHistory() const {
86   return m_opaque_up->GetAddToHistory();
87 }
88 
89 void SBCommandInterpreterRunOptions::SetAddToHistory(bool add_to_history) {
90   m_opaque_up->SetAddToHistory(add_to_history);
91 }
92 
93 lldb_private::CommandInterpreterRunOptions *
94 SBCommandInterpreterRunOptions::get() const {
95   return m_opaque_up.get();
96 }
97 
98 lldb_private::CommandInterpreterRunOptions &
99 SBCommandInterpreterRunOptions::ref() const {
100   return *m_opaque_up;
101 }
102 
103 class CommandPluginInterfaceImplementation : public CommandObjectParsed {
104 public:
105   CommandPluginInterfaceImplementation(CommandInterpreter &interpreter,
106                                        const char *name,
107                                        lldb::SBCommandPluginInterface *backend,
108                                        const char *help = nullptr,
109                                        const char *syntax = nullptr,
110                                        uint32_t flags = 0)
111       : CommandObjectParsed(interpreter, name, help, syntax, flags),
112         m_backend(backend) {}
113 
114   bool IsRemovable() const override { return true; }
115 
116 protected:
117   bool DoExecute(Args &command, CommandReturnObject &result) override {
118     SBCommandReturnObject sb_return(&result);
119     SBCommandInterpreter sb_interpreter(&m_interpreter);
120     SBDebugger debugger_sb(m_interpreter.GetDebugger().shared_from_this());
121     bool ret = m_backend->DoExecute(
122         debugger_sb, (char **)command.GetArgumentVector(), sb_return);
123     sb_return.Release();
124     return ret;
125   }
126   std::shared_ptr<lldb::SBCommandPluginInterface> m_backend;
127 };
128 
129 SBCommandInterpreter::SBCommandInterpreter(CommandInterpreter *interpreter)
130     : m_opaque_ptr(interpreter) {
131   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
132 
133   if (log)
134     log->Printf("SBCommandInterpreter::SBCommandInterpreter (interpreter=%p)"
135                 " => SBCommandInterpreter(%p)",
136                 static_cast<void *>(interpreter),
137                 static_cast<void *>(m_opaque_ptr));
138 }
139 
140 SBCommandInterpreter::SBCommandInterpreter(const SBCommandInterpreter &rhs)
141     : m_opaque_ptr(rhs.m_opaque_ptr) {}
142 
143 SBCommandInterpreter::~SBCommandInterpreter() = default;
144 
145 const SBCommandInterpreter &SBCommandInterpreter::
146 operator=(const SBCommandInterpreter &rhs) {
147   m_opaque_ptr = rhs.m_opaque_ptr;
148   return *this;
149 }
150 
151 bool SBCommandInterpreter::IsValid() const { return m_opaque_ptr != nullptr; }
152 
153 bool SBCommandInterpreter::CommandExists(const char *cmd) {
154   return (((cmd != nullptr) && IsValid()) ? m_opaque_ptr->CommandExists(cmd)
155                                           : false);
156 }
157 
158 bool SBCommandInterpreter::AliasExists(const char *cmd) {
159   return (((cmd != nullptr) && IsValid()) ? m_opaque_ptr->AliasExists(cmd)
160                                           : false);
161 }
162 
163 bool SBCommandInterpreter::IsActive() {
164   return (IsValid() ? m_opaque_ptr->IsActive() : false);
165 }
166 
167 bool SBCommandInterpreter::WasInterrupted() const {
168   return (IsValid() ? m_opaque_ptr->WasInterrupted() : false);
169 }
170 
171 const char *SBCommandInterpreter::GetIOHandlerControlSequence(char ch) {
172   return (IsValid()
173               ? m_opaque_ptr->GetDebugger()
174                     .GetTopIOHandlerControlSequence(ch)
175                     .GetCString()
176               : nullptr);
177 }
178 
179 lldb::ReturnStatus
180 SBCommandInterpreter::HandleCommand(const char *command_line,
181                                     SBCommandReturnObject &result,
182                                     bool add_to_history) {
183   SBExecutionContext sb_exe_ctx;
184   return HandleCommand(command_line, sb_exe_ctx, result, add_to_history);
185 }
186 
187 lldb::ReturnStatus SBCommandInterpreter::HandleCommand(
188     const char *command_line, SBExecutionContext &override_context,
189     SBCommandReturnObject &result, bool add_to_history) {
190   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
191 
192   if (log)
193     log->Printf("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", "
194                 "SBCommandReturnObject(%p), add_to_history=%i)",
195                 static_cast<void *>(m_opaque_ptr), command_line,
196                 static_cast<void *>(result.get()), add_to_history);
197 
198   ExecutionContext ctx, *ctx_ptr;
199   if (override_context.get()) {
200     ctx = override_context.get()->Lock(true);
201     ctx_ptr = &ctx;
202   } else
203     ctx_ptr = nullptr;
204 
205   result.Clear();
206   if (command_line && IsValid()) {
207     result.ref().SetInteractive(false);
208     m_opaque_ptr->HandleCommand(command_line,
209                                 add_to_history ? eLazyBoolYes : eLazyBoolNo,
210                                 result.ref(), ctx_ptr);
211   } else {
212     result->AppendError(
213         "SBCommandInterpreter or the command line is not valid");
214     result->SetStatus(eReturnStatusFailed);
215   }
216 
217   // We need to get the value again, in case the command disabled the log!
218   log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API);
219   if (log) {
220     SBStream sstr;
221     result.GetDescription(sstr);
222     log->Printf("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", "
223                 "SBCommandReturnObject(%p): %s, add_to_history=%i) => %i",
224                 static_cast<void *>(m_opaque_ptr), command_line,
225                 static_cast<void *>(result.get()), sstr.GetData(),
226                 add_to_history, result.GetStatus());
227   }
228 
229   return result.GetStatus();
230 }
231 
232 void SBCommandInterpreter::HandleCommandsFromFile(
233     lldb::SBFileSpec &file, lldb::SBExecutionContext &override_context,
234     lldb::SBCommandInterpreterRunOptions &options,
235     lldb::SBCommandReturnObject result) {
236   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
237 
238   if (log) {
239     SBStream s;
240     file.GetDescription(s);
241     log->Printf("SBCommandInterpreter(%p)::HandleCommandsFromFile "
242                 "(file=\"%s\", SBCommandReturnObject(%p))",
243                 static_cast<void *>(m_opaque_ptr), s.GetData(),
244                 static_cast<void *>(result.get()));
245   }
246 
247   if (!IsValid()) {
248     result->AppendError("SBCommandInterpreter is not valid.");
249     result->SetStatus(eReturnStatusFailed);
250     return;
251   }
252 
253   if (!file.IsValid()) {
254     SBStream s;
255     file.GetDescription(s);
256     result->AppendErrorWithFormat("File is not valid: %s.", s.GetData());
257     result->SetStatus(eReturnStatusFailed);
258   }
259 
260   FileSpec tmp_spec = file.ref();
261   ExecutionContext ctx, *ctx_ptr;
262   if (override_context.get()) {
263     ctx = override_context.get()->Lock(true);
264     ctx_ptr = &ctx;
265   } else
266     ctx_ptr = nullptr;
267 
268   m_opaque_ptr->HandleCommandsFromFile(tmp_spec, ctx_ptr, options.ref(),
269                                        result.ref());
270 }
271 
272 int SBCommandInterpreter::HandleCompletion(
273     const char *current_line, const char *cursor, const char *last_char,
274     int match_start_point, int max_return_elements, SBStringList &matches) {
275   SBStringList dummy_descriptions;
276   return HandleCompletionWithDescriptions(
277       current_line, cursor, last_char, match_start_point, max_return_elements,
278       matches, dummy_descriptions);
279 }
280 
281 int SBCommandInterpreter::HandleCompletionWithDescriptions(
282     const char *current_line, const char *cursor, const char *last_char,
283     int match_start_point, int max_return_elements, SBStringList &matches,
284     SBStringList &descriptions) {
285   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
286   int num_completions = 0;
287 
288   // Sanity check the arguments that are passed in: cursor & last_char have to
289   // be within the current_line.
290   if (current_line == nullptr || cursor == nullptr || last_char == nullptr)
291     return 0;
292 
293   if (cursor < current_line || last_char < current_line)
294     return 0;
295 
296   size_t current_line_size = strlen(current_line);
297   if (cursor - current_line > static_cast<ptrdiff_t>(current_line_size) ||
298       last_char - current_line > static_cast<ptrdiff_t>(current_line_size))
299     return 0;
300 
301   if (log)
302     log->Printf("SBCommandInterpreter(%p)::HandleCompletion "
303                 "(current_line=\"%s\", cursor at: %" PRId64
304                 ", last char at: %" PRId64
305                 ", match_start_point: %d, max_return_elements: %d)",
306                 static_cast<void *>(m_opaque_ptr), current_line,
307                 static_cast<uint64_t>(cursor - current_line),
308                 static_cast<uint64_t>(last_char - current_line),
309                 match_start_point, max_return_elements);
310 
311   if (IsValid()) {
312     lldb_private::StringList lldb_matches, lldb_descriptions;
313     num_completions = m_opaque_ptr->HandleCompletion(
314         current_line, cursor, last_char, match_start_point, max_return_elements,
315         lldb_matches, lldb_descriptions);
316 
317     SBStringList temp_matches_list(&lldb_matches);
318     matches.AppendList(temp_matches_list);
319     SBStringList temp_descriptions_list(&lldb_descriptions);
320     descriptions.AppendList(temp_descriptions_list);
321   }
322   if (log)
323     log->Printf(
324         "SBCommandInterpreter(%p)::HandleCompletion - Found %d completions.",
325         static_cast<void *>(m_opaque_ptr), num_completions);
326 
327   return num_completions;
328 }
329 
330 int SBCommandInterpreter::HandleCompletionWithDescriptions(
331     const char *current_line, uint32_t cursor_pos, int match_start_point,
332     int max_return_elements, SBStringList &matches,
333     SBStringList &descriptions) {
334   const char *cursor = current_line + cursor_pos;
335   const char *last_char = current_line + strlen(current_line);
336   return HandleCompletionWithDescriptions(
337       current_line, cursor, last_char, match_start_point, max_return_elements,
338       matches, descriptions);
339 }
340 
341 int SBCommandInterpreter::HandleCompletion(const char *current_line,
342                                            uint32_t cursor_pos,
343                                            int match_start_point,
344                                            int max_return_elements,
345                                            lldb::SBStringList &matches) {
346   const char *cursor = current_line + cursor_pos;
347   const char *last_char = current_line + strlen(current_line);
348   return HandleCompletion(current_line, cursor, last_char, match_start_point,
349                           max_return_elements, matches);
350 }
351 
352 bool SBCommandInterpreter::HasCommands() {
353   return (IsValid() ? m_opaque_ptr->HasCommands() : false);
354 }
355 
356 bool SBCommandInterpreter::HasAliases() {
357   return (IsValid() ? m_opaque_ptr->HasAliases() : false);
358 }
359 
360 bool SBCommandInterpreter::HasAliasOptions() {
361   return (IsValid() ? m_opaque_ptr->HasAliasOptions() : false);
362 }
363 
364 SBProcess SBCommandInterpreter::GetProcess() {
365   SBProcess sb_process;
366   ProcessSP process_sp;
367   if (IsValid()) {
368     TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
369     if (target_sp) {
370       std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
371       process_sp = target_sp->GetProcessSP();
372       sb_process.SetSP(process_sp);
373     }
374   }
375   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
376 
377   if (log)
378     log->Printf("SBCommandInterpreter(%p)::GetProcess () => SBProcess(%p)",
379                 static_cast<void *>(m_opaque_ptr),
380                 static_cast<void *>(process_sp.get()));
381 
382   return sb_process;
383 }
384 
385 SBDebugger SBCommandInterpreter::GetDebugger() {
386   SBDebugger sb_debugger;
387   if (IsValid())
388     sb_debugger.reset(m_opaque_ptr->GetDebugger().shared_from_this());
389   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
390 
391   if (log)
392     log->Printf("SBCommandInterpreter(%p)::GetDebugger () => SBDebugger(%p)",
393                 static_cast<void *>(m_opaque_ptr),
394                 static_cast<void *>(sb_debugger.get()));
395 
396   return sb_debugger;
397 }
398 
399 bool SBCommandInterpreter::GetPromptOnQuit() {
400   return (IsValid() ? m_opaque_ptr->GetPromptOnQuit() : false);
401 }
402 
403 void SBCommandInterpreter::SetPromptOnQuit(bool b) {
404   if (IsValid())
405     m_opaque_ptr->SetPromptOnQuit(b);
406 }
407 
408 void SBCommandInterpreter::AllowExitCodeOnQuit(bool allow) {
409   if (m_opaque_ptr)
410     m_opaque_ptr->AllowExitCodeOnQuit(allow);
411 }
412 
413 bool SBCommandInterpreter::HasCustomQuitExitCode() {
414   bool exited = false;
415   if (m_opaque_ptr)
416     m_opaque_ptr->GetQuitExitCode(exited);
417   return exited;
418 }
419 
420 int SBCommandInterpreter::GetQuitStatus() {
421   bool exited = false;
422   return (m_opaque_ptr ? m_opaque_ptr->GetQuitExitCode(exited) : 0);
423 }
424 
425 void SBCommandInterpreter::ResolveCommand(const char *command_line,
426                                           SBCommandReturnObject &result) {
427   result.Clear();
428   if (command_line && IsValid()) {
429     m_opaque_ptr->ResolveCommand(command_line, result.ref());
430   } else {
431     result->AppendError(
432         "SBCommandInterpreter or the command line is not valid");
433     result->SetStatus(eReturnStatusFailed);
434   }
435 }
436 
437 CommandInterpreter *SBCommandInterpreter::get() { return m_opaque_ptr; }
438 
439 CommandInterpreter &SBCommandInterpreter::ref() {
440   assert(m_opaque_ptr);
441   return *m_opaque_ptr;
442 }
443 
444 void SBCommandInterpreter::reset(
445     lldb_private::CommandInterpreter *interpreter) {
446   m_opaque_ptr = interpreter;
447 }
448 
449 void SBCommandInterpreter::SourceInitFileInHomeDirectory(
450     SBCommandReturnObject &result) {
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->SourceInitFile(false, result.ref());
458   } else {
459     result->AppendError("SBCommandInterpreter is not valid");
460     result->SetStatus(eReturnStatusFailed);
461   }
462   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
463 
464   if (log)
465     log->Printf("SBCommandInterpreter(%p)::SourceInitFileInHomeDirectory "
466                 "(&SBCommandReturnObject(%p))",
467                 static_cast<void *>(m_opaque_ptr),
468                 static_cast<void *>(result.get()));
469 }
470 
471 void SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory(
472     SBCommandReturnObject &result) {
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->SourceInitFile(true, result.ref());
480   } else {
481     result->AppendError("SBCommandInterpreter is not valid");
482     result->SetStatus(eReturnStatusFailed);
483   }
484   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
485 
486   if (log)
487     log->Printf(
488         "SBCommandInterpreter(%p)::SourceInitFileInCurrentWorkingDirectory "
489         "(&SBCommandReturnObject(%p))",
490         static_cast<void *>(m_opaque_ptr), static_cast<void *>(result.get()));
491 }
492 
493 SBBroadcaster SBCommandInterpreter::GetBroadcaster() {
494   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
495 
496   SBBroadcaster broadcaster(m_opaque_ptr, false);
497 
498   if (log)
499     log->Printf(
500         "SBCommandInterpreter(%p)::GetBroadcaster() => SBBroadcaster(%p)",
501         static_cast<void *>(m_opaque_ptr),
502         static_cast<void *>(broadcaster.get()));
503 
504   return broadcaster;
505 }
506 
507 const char *SBCommandInterpreter::GetBroadcasterClass() {
508   return CommandInterpreter::GetStaticBroadcasterClass().AsCString();
509 }
510 
511 const char *SBCommandInterpreter::GetArgumentTypeAsCString(
512     const lldb::CommandArgumentType arg_type) {
513   return CommandObject::GetArgumentTypeAsCString(arg_type);
514 }
515 
516 const char *SBCommandInterpreter::GetArgumentDescriptionAsCString(
517     const lldb::CommandArgumentType arg_type) {
518   return CommandObject::GetArgumentDescriptionAsCString(arg_type);
519 }
520 
521 bool SBCommandInterpreter::EventIsCommandInterpreterEvent(
522     const lldb::SBEvent &event) {
523   return event.GetBroadcasterClass() ==
524          SBCommandInterpreter::GetBroadcasterClass();
525 }
526 
527 bool SBCommandInterpreter::SetCommandOverrideCallback(
528     const char *command_name, lldb::CommandOverrideCallback callback,
529     void *baton) {
530   if (command_name && command_name[0] && IsValid()) {
531     llvm::StringRef command_name_str = command_name;
532     CommandObject *cmd_obj =
533         m_opaque_ptr->GetCommandObjectForCommand(command_name_str);
534     if (cmd_obj) {
535       assert(command_name_str.empty());
536       cmd_obj->SetOverrideCallback(callback, baton);
537       return true;
538     }
539   }
540   return false;
541 }
542 
543 lldb::SBCommand SBCommandInterpreter::AddMultiwordCommand(const char *name,
544                                                           const char *help) {
545   CommandObjectMultiword *new_command =
546       new CommandObjectMultiword(*m_opaque_ptr, name, help);
547   new_command->SetRemovable(true);
548   lldb::CommandObjectSP new_command_sp(new_command);
549   if (new_command_sp &&
550       m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
551     return lldb::SBCommand(new_command_sp);
552   return lldb::SBCommand();
553 }
554 
555 lldb::SBCommand SBCommandInterpreter::AddCommand(
556     const char *name, lldb::SBCommandPluginInterface *impl, const char *help) {
557   lldb::CommandObjectSP new_command_sp;
558   new_command_sp.reset(new CommandPluginInterfaceImplementation(
559       *m_opaque_ptr, name, impl, help));
560 
561   if (new_command_sp &&
562       m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
563     return lldb::SBCommand(new_command_sp);
564   return lldb::SBCommand();
565 }
566 
567 lldb::SBCommand
568 SBCommandInterpreter::AddCommand(const char *name,
569                                  lldb::SBCommandPluginInterface *impl,
570                                  const char *help, const char *syntax) {
571   lldb::CommandObjectSP new_command_sp;
572   new_command_sp.reset(new CommandPluginInterfaceImplementation(
573       *m_opaque_ptr, name, impl, help, syntax));
574 
575   if (new_command_sp &&
576       m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
577     return lldb::SBCommand(new_command_sp);
578   return lldb::SBCommand();
579 }
580 
581 SBCommand::SBCommand() = default;
582 
583 SBCommand::SBCommand(lldb::CommandObjectSP cmd_sp) : m_opaque_sp(cmd_sp) {}
584 
585 bool SBCommand::IsValid() { return m_opaque_sp.get() != nullptr; }
586 
587 const char *SBCommand::GetName() {
588   return (IsValid() ? ConstString(m_opaque_sp->GetCommandName()).AsCString() : nullptr);
589 }
590 
591 const char *SBCommand::GetHelp() {
592   return (IsValid() ? ConstString(m_opaque_sp->GetHelp()).AsCString()
593                     : nullptr);
594 }
595 
596 const char *SBCommand::GetHelpLong() {
597   return (IsValid() ? ConstString(m_opaque_sp->GetHelpLong()).AsCString()
598                     : nullptr);
599 }
600 
601 void SBCommand::SetHelp(const char *help) {
602   if (IsValid())
603     m_opaque_sp->SetHelp(help);
604 }
605 
606 void SBCommand::SetHelpLong(const char *help) {
607   if (IsValid())
608     m_opaque_sp->SetHelpLong(help);
609 }
610 
611 lldb::SBCommand SBCommand::AddMultiwordCommand(const char *name,
612                                                const char *help) {
613   if (!IsValid())
614     return lldb::SBCommand();
615   if (!m_opaque_sp->IsMultiwordObject())
616     return lldb::SBCommand();
617   CommandObjectMultiword *new_command = new CommandObjectMultiword(
618       m_opaque_sp->GetCommandInterpreter(), name, help);
619   new_command->SetRemovable(true);
620   lldb::CommandObjectSP new_command_sp(new_command);
621   if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
622     return lldb::SBCommand(new_command_sp);
623   return lldb::SBCommand();
624 }
625 
626 lldb::SBCommand SBCommand::AddCommand(const char *name,
627                                       lldb::SBCommandPluginInterface *impl,
628                                       const char *help) {
629   if (!IsValid())
630     return lldb::SBCommand();
631   if (!m_opaque_sp->IsMultiwordObject())
632     return lldb::SBCommand();
633   lldb::CommandObjectSP new_command_sp;
634   new_command_sp.reset(new CommandPluginInterfaceImplementation(
635       m_opaque_sp->GetCommandInterpreter(), name, impl, help));
636   if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
637     return lldb::SBCommand(new_command_sp);
638   return lldb::SBCommand();
639 }
640 
641 lldb::SBCommand SBCommand::AddCommand(const char *name,
642                                       lldb::SBCommandPluginInterface *impl,
643                                       const char *help, const char *syntax) {
644   if (!IsValid())
645     return lldb::SBCommand();
646   if (!m_opaque_sp->IsMultiwordObject())
647     return lldb::SBCommand();
648   lldb::CommandObjectSP new_command_sp;
649   new_command_sp.reset(new CommandPluginInterfaceImplementation(
650       m_opaque_sp->GetCommandInterpreter(), name, impl, help, syntax));
651   if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
652     return lldb::SBCommand(new_command_sp);
653   return lldb::SBCommand();
654 }
655 
656 uint32_t SBCommand::GetFlags() {
657   return (IsValid() ? m_opaque_sp->GetFlags().Get() : 0);
658 }
659 
660 void SBCommand::SetFlags(uint32_t flags) {
661   if (IsValid())
662     m_opaque_sp->GetFlags().Set(flags);
663 }
664