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