1//===-- CommandCompletions.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 "llvm/ADT/SmallString.h"
10#include "llvm/ADT/StringSet.h"
11
12#include "lldb/Breakpoint/Watchpoint.h"
13#include "lldb/Core/FileSpecList.h"
14#include "lldb/Core/Module.h"
15#include "lldb/Core/PluginManager.h"
16#include "lldb/DataFormatters/DataVisualization.h"
17#include "lldb/Host/FileSystem.h"
18#include "lldb/Interpreter/CommandCompletions.h"
19#include "lldb/Interpreter/CommandInterpreter.h"
20#include "lldb/Interpreter/CommandObject.h"
21#include "lldb/Interpreter/CommandObjectMultiword.h"
22#include "lldb/Interpreter/OptionValueProperties.h"
23#include "lldb/Symbol/CompileUnit.h"
24#include "lldb/Symbol/Variable.h"
25#include "lldb/Target/Language.h"
26#include "lldb/Target/Process.h"
27#include "lldb/Target/RegisterContext.h"
28#include "lldb/Target/Thread.h"
29#include "lldb/Utility/FileSpec.h"
30#include "lldb/Utility/StreamString.h"
31#include "lldb/Utility/TildeExpressionResolver.h"
32
33#include "llvm/Support/FileSystem.h"
34#include "llvm/Support/Path.h"
35
36using namespace lldb_private;
37
38// This is the command completion callback that is used to complete the
39// argument of the option it is bound to (in the OptionDefinition table
40// below).
41typedef void (*CompletionCallback)(CommandInterpreter &interpreter,
42                                   CompletionRequest &request,
43                                   // A search filter to limit the search...
44                                   lldb_private::SearchFilter *searcher);
45
46struct CommonCompletionElement {
47  uint32_t type;
48  CompletionCallback callback;
49};
50
51bool CommandCompletions::InvokeCommonCompletionCallbacks(
52    CommandInterpreter &interpreter, uint32_t completion_mask,
53    CompletionRequest &request, SearchFilter *searcher) {
54  bool handled = false;
55
56  const CommonCompletionElement common_completions[] = {
57      {eSourceFileCompletion, CommandCompletions::SourceFiles},
58      {eDiskFileCompletion, CommandCompletions::DiskFiles},
59      {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
60      {eSymbolCompletion, CommandCompletions::Symbols},
61      {eModuleCompletion, CommandCompletions::Modules},
62      {eModuleUUIDCompletion, CommandCompletions::ModuleUUIDs},
63      {eSettingsNameCompletion, CommandCompletions::SettingsNames},
64      {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
65      {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
66      {eVariablePathCompletion, CommandCompletions::VariablePath},
67      {eRegisterCompletion, CommandCompletions::Registers},
68      {eBreakpointCompletion, CommandCompletions::Breakpoints},
69      {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames},
70      {eDisassemblyFlavorCompletion, CommandCompletions::DisassemblyFlavors},
71      {eTypeLanguageCompletion, CommandCompletions::TypeLanguages},
72      {eFrameIndexCompletion, CommandCompletions::FrameIndexes},
73      {eStopHookIDCompletion, CommandCompletions::StopHookIDs},
74      {eThreadIndexCompletion, CommandCompletions::ThreadIndexes},
75      {eWatchPointIDCompletion, CommandCompletions::WatchPointIDs},
76      {eBreakpointNameCompletion, CommandCompletions::BreakpointNames},
77      {eProcessIDCompletion, CommandCompletions::ProcessIDs},
78      {eProcessNameCompletion, CommandCompletions::ProcessNames},
79      {eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles},
80      {eRemoteDiskDirectoryCompletion,
81       CommandCompletions::RemoteDiskDirectories},
82      {eTypeCategoryNameCompletion, CommandCompletions::TypeCategoryNames},
83      {eNoCompletion, nullptr} // This one has to be last in the list.
84  };
85
86  for (int i = 0;; i++) {
87    if (common_completions[i].type == eNoCompletion)
88      break;
89    else if ((common_completions[i].type & completion_mask) ==
90                 common_completions[i].type &&
91             common_completions[i].callback != nullptr) {
92      handled = true;
93      common_completions[i].callback(interpreter, request, searcher);
94    }
95  }
96  return handled;
97}
98
99namespace {
100// The Completer class is a convenient base class for building searchers that
101// go along with the SearchFilter passed to the standard Completer functions.
102class Completer : public Searcher {
103public:
104  Completer(CommandInterpreter &interpreter, CompletionRequest &request)
105      : m_interpreter(interpreter), m_request(request) {}
106
107  ~Completer() override = default;
108
109  CallbackReturn SearchCallback(SearchFilter &filter, SymbolContext &context,
110                                Address *addr) override = 0;
111
112  lldb::SearchDepth GetDepth() override = 0;
113
114  virtual void DoCompletion(SearchFilter *filter) = 0;
115
116protected:
117  CommandInterpreter &m_interpreter;
118  CompletionRequest &m_request;
119
120private:
121  Completer(const Completer &) = delete;
122  const Completer &operator=(const Completer &) = delete;
123};
124} // namespace
125
126// SourceFileCompleter implements the source file completer
127namespace {
128class SourceFileCompleter : public Completer {
129public:
130  SourceFileCompleter(CommandInterpreter &interpreter,
131                      CompletionRequest &request)
132      : Completer(interpreter, request) {
133    FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
134    m_file_name = partial_spec.GetFilename().GetCString();
135    m_dir_name = partial_spec.GetDirectory().GetCString();
136  }
137
138  lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthCompUnit; }
139
140  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
141                                          SymbolContext &context,
142                                          Address *addr) override {
143    if (context.comp_unit != nullptr) {
144      const char *cur_file_name =
145          context.comp_unit->GetPrimaryFile().GetFilename().GetCString();
146      const char *cur_dir_name =
147          context.comp_unit->GetPrimaryFile().GetDirectory().GetCString();
148
149      bool match = false;
150      if (m_file_name && cur_file_name &&
151          strstr(cur_file_name, m_file_name) == cur_file_name)
152        match = true;
153
154      if (match && m_dir_name && cur_dir_name &&
155          strstr(cur_dir_name, m_dir_name) != cur_dir_name)
156        match = false;
157
158      if (match) {
159        m_matching_files.AppendIfUnique(context.comp_unit->GetPrimaryFile());
160      }
161    }
162    return Searcher::eCallbackReturnContinue;
163  }
164
165  void DoCompletion(SearchFilter *filter) override {
166    filter->Search(*this);
167    // Now convert the filelist to completions:
168    for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
169      m_request.AddCompletion(
170          m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
171    }
172  }
173
174private:
175  FileSpecList m_matching_files;
176  const char *m_file_name;
177  const char *m_dir_name;
178
179  SourceFileCompleter(const SourceFileCompleter &) = delete;
180  const SourceFileCompleter &operator=(const SourceFileCompleter &) = delete;
181};
182} // namespace
183
184static bool regex_chars(const char comp) {
185  return llvm::StringRef("[](){}+.*|^$\\?").contains(comp);
186}
187
188namespace {
189class SymbolCompleter : public Completer {
190
191public:
192  SymbolCompleter(CommandInterpreter &interpreter, CompletionRequest &request)
193      : Completer(interpreter, request) {
194    std::string regex_str;
195    if (!m_request.GetCursorArgumentPrefix().empty()) {
196      regex_str.append("^");
197      regex_str.append(std::string(m_request.GetCursorArgumentPrefix()));
198    } else {
199      // Match anything since the completion string is empty
200      regex_str.append(".");
201    }
202    std::string::iterator pos =
203        find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
204    while (pos < regex_str.end()) {
205      pos = regex_str.insert(pos, '\\');
206      pos = find_if(pos + 2, regex_str.end(), regex_chars);
207    }
208    m_regex = RegularExpression(regex_str);
209  }
210
211  lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; }
212
213  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
214                                          SymbolContext &context,
215                                          Address *addr) override {
216    if (context.module_sp) {
217      SymbolContextList sc_list;
218      ModuleFunctionSearchOptions function_options;
219      function_options.include_symbols = true;
220      function_options.include_inlines = true;
221      context.module_sp->FindFunctions(m_regex, function_options, sc_list);
222
223      SymbolContext sc;
224      // Now add the functions & symbols to the list - only add if unique:
225      for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
226        if (sc_list.GetContextAtIndex(i, sc)) {
227          ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
228          // Ensure that the function name matches the regex. This is more than
229          // a sanity check. It is possible that the demangled function name
230          // does not start with the prefix, for example when it's in an
231          // anonymous namespace.
232          if (!func_name.IsEmpty() && m_regex.Execute(func_name.GetStringRef()))
233            m_match_set.insert(func_name);
234        }
235      }
236    }
237    return Searcher::eCallbackReturnContinue;
238  }
239
240  void DoCompletion(SearchFilter *filter) override {
241    filter->Search(*this);
242    collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
243    for (pos = m_match_set.begin(); pos != end; pos++)
244      m_request.AddCompletion((*pos).GetCString());
245  }
246
247private:
248  RegularExpression m_regex;
249  typedef std::set<ConstString> collection;
250  collection m_match_set;
251
252  SymbolCompleter(const SymbolCompleter &) = delete;
253  const SymbolCompleter &operator=(const SymbolCompleter &) = delete;
254};
255} // namespace
256
257namespace {
258class ModuleCompleter : public Completer {
259public:
260  ModuleCompleter(CommandInterpreter &interpreter, CompletionRequest &request)
261      : Completer(interpreter, request) {
262    FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
263    m_file_name = partial_spec.GetFilename().GetCString();
264    m_dir_name = partial_spec.GetDirectory().GetCString();
265  }
266
267  lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; }
268
269  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
270                                          SymbolContext &context,
271                                          Address *addr) override {
272    if (context.module_sp) {
273      const char *cur_file_name =
274          context.module_sp->GetFileSpec().GetFilename().GetCString();
275      const char *cur_dir_name =
276          context.module_sp->GetFileSpec().GetDirectory().GetCString();
277
278      bool match = false;
279      if (m_file_name && cur_file_name &&
280          strstr(cur_file_name, m_file_name) == cur_file_name)
281        match = true;
282
283      if (match && m_dir_name && cur_dir_name &&
284          strstr(cur_dir_name, m_dir_name) != cur_dir_name)
285        match = false;
286
287      if (match) {
288        m_request.AddCompletion(cur_file_name);
289      }
290    }
291    return Searcher::eCallbackReturnContinue;
292  }
293
294  void DoCompletion(SearchFilter *filter) override { filter->Search(*this); }
295
296private:
297  const char *m_file_name;
298  const char *m_dir_name;
299
300  ModuleCompleter(const ModuleCompleter &) = delete;
301  const ModuleCompleter &operator=(const ModuleCompleter &) = delete;
302};
303} // namespace
304
305void CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
306                                     CompletionRequest &request,
307                                     SearchFilter *searcher) {
308  SourceFileCompleter completer(interpreter, request);
309
310  if (searcher == nullptr) {
311    lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
312    SearchFilterForUnconstrainedSearches null_searcher(target_sp);
313    completer.DoCompletion(&null_searcher);
314  } else {
315    completer.DoCompletion(searcher);
316  }
317}
318
319static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
320                                   bool only_directories,
321                                   CompletionRequest &request,
322                                   TildeExpressionResolver &Resolver) {
323  llvm::SmallString<256> CompletionBuffer;
324  llvm::SmallString<256> Storage;
325  partial_name.toVector(CompletionBuffer);
326
327  if (CompletionBuffer.size() >= PATH_MAX)
328    return;
329
330  namespace path = llvm::sys::path;
331
332  llvm::StringRef SearchDir;
333  llvm::StringRef PartialItem;
334
335  if (CompletionBuffer.startswith("~")) {
336    llvm::StringRef Buffer = CompletionBuffer;
337    size_t FirstSep =
338        Buffer.find_if([](char c) { return path::is_separator(c); });
339
340    llvm::StringRef Username = Buffer.take_front(FirstSep);
341    llvm::StringRef Remainder;
342    if (FirstSep != llvm::StringRef::npos)
343      Remainder = Buffer.drop_front(FirstSep + 1);
344
345    llvm::SmallString<256> Resolved;
346    if (!Resolver.ResolveExact(Username, Resolved)) {
347      // We couldn't resolve it as a full username.  If there were no slashes
348      // then this might be a partial username.   We try to resolve it as such
349      // but after that, we're done regardless of any matches.
350      if (FirstSep == llvm::StringRef::npos) {
351        llvm::StringSet<> MatchSet;
352        Resolver.ResolvePartial(Username, MatchSet);
353        for (const auto &S : MatchSet) {
354          Resolved = S.getKey();
355          path::append(Resolved, path::get_separator());
356          request.AddCompletion(Resolved, "", CompletionMode::Partial);
357        }
358      }
359      return;
360    }
361
362    // If there was no trailing slash, then we're done as soon as we resolve
363    // the expression to the correct directory.  Otherwise we need to continue
364    // looking for matches within that directory.
365    if (FirstSep == llvm::StringRef::npos) {
366      // Make sure it ends with a separator.
367      path::append(CompletionBuffer, path::get_separator());
368      request.AddCompletion(CompletionBuffer, "", CompletionMode::Partial);
369      return;
370    }
371
372    // We want to keep the form the user typed, so we special case this to
373    // search in the fully resolved directory, but CompletionBuffer keeps the
374    // unmodified form that the user typed.
375    Storage = Resolved;
376    llvm::StringRef RemainderDir = path::parent_path(Remainder);
377    if (!RemainderDir.empty()) {
378      // Append the remaining path to the resolved directory.
379      Storage.append(path::get_separator());
380      Storage.append(RemainderDir);
381    }
382    SearchDir = Storage;
383  } else {
384    SearchDir = path::parent_path(CompletionBuffer);
385  }
386
387  size_t FullPrefixLen = CompletionBuffer.size();
388
389  PartialItem = path::filename(CompletionBuffer);
390
391  // path::filename() will return "." when the passed path ends with a
392  // directory separator. We have to filter those out, but only when the
393  // "." doesn't come from the completion request itself.
394  if (PartialItem == "." && path::is_separator(CompletionBuffer.back()))
395    PartialItem = llvm::StringRef();
396
397  if (SearchDir.empty()) {
398    llvm::sys::fs::current_path(Storage);
399    SearchDir = Storage;
400  }
401  assert(!PartialItem.contains(path::get_separator()));
402
403  // SearchDir now contains the directory to search in, and Prefix contains the
404  // text we want to match against items in that directory.
405
406  FileSystem &fs = FileSystem::Instance();
407  std::error_code EC;
408  llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC);
409  llvm::vfs::directory_iterator End;
410  for (; Iter != End && !EC; Iter.increment(EC)) {
411    auto &Entry = *Iter;
412    llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path());
413
414    if (!Status)
415      continue;
416
417    auto Name = path::filename(Entry.path());
418
419    // Omit ".", ".."
420    if (Name == "." || Name == ".." || !Name.startswith(PartialItem))
421      continue;
422
423    bool is_dir = Status->isDirectory();
424
425    // If it's a symlink, then we treat it as a directory as long as the target
426    // is a directory.
427    if (Status->isSymlink()) {
428      FileSpec symlink_filespec(Entry.path());
429      FileSpec resolved_filespec;
430      auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec);
431      if (error.Success())
432        is_dir = fs.IsDirectory(symlink_filespec);
433    }
434
435    if (only_directories && !is_dir)
436      continue;
437
438    // Shrink it back down so that it just has the original prefix the user
439    // typed and remove the part of the name which is common to the located
440    // item and what the user typed.
441    CompletionBuffer.resize(FullPrefixLen);
442    Name = Name.drop_front(PartialItem.size());
443    CompletionBuffer.append(Name);
444
445    if (is_dir) {
446      path::append(CompletionBuffer, path::get_separator());
447    }
448
449    CompletionMode mode =
450        is_dir ? CompletionMode::Partial : CompletionMode::Normal;
451    request.AddCompletion(CompletionBuffer, "", mode);
452  }
453}
454
455static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
456                                   bool only_directories, StringList &matches,
457                                   TildeExpressionResolver &Resolver) {
458  CompletionResult result;
459  std::string partial_name_str = partial_name.str();
460  CompletionRequest request(partial_name_str, partial_name_str.size(), result);
461  DiskFilesOrDirectories(partial_name, only_directories, request, Resolver);
462  result.GetMatches(matches);
463}
464
465static void DiskFilesOrDirectories(CompletionRequest &request,
466                                   bool only_directories) {
467  StandardTildeExpressionResolver resolver;
468  DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories,
469                         request, resolver);
470}
471
472void CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
473                                   CompletionRequest &request,
474                                   SearchFilter *searcher) {
475  DiskFilesOrDirectories(request, /*only_dirs*/ false);
476}
477
478void CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name,
479                                   StringList &matches,
480                                   TildeExpressionResolver &Resolver) {
481  DiskFilesOrDirectories(partial_file_name, false, matches, Resolver);
482}
483
484void CommandCompletions::DiskDirectories(CommandInterpreter &interpreter,
485                                         CompletionRequest &request,
486                                         SearchFilter *searcher) {
487  DiskFilesOrDirectories(request, /*only_dirs*/ true);
488}
489
490void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
491                                         StringList &matches,
492                                         TildeExpressionResolver &Resolver) {
493  DiskFilesOrDirectories(partial_file_name, true, matches, Resolver);
494}
495
496void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter,
497                                         CompletionRequest &request,
498                                         SearchFilter *searcher) {
499  lldb::PlatformSP platform_sp =
500      interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
501  if (platform_sp)
502    platform_sp->AutoCompleteDiskFileOrDirectory(request, false);
503}
504
505void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter,
506                                               CompletionRequest &request,
507                                               SearchFilter *searcher) {
508  lldb::PlatformSP platform_sp =
509      interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
510  if (platform_sp)
511    platform_sp->AutoCompleteDiskFileOrDirectory(request, true);
512}
513
514void CommandCompletions::Modules(CommandInterpreter &interpreter,
515                                 CompletionRequest &request,
516                                 SearchFilter *searcher) {
517  ModuleCompleter completer(interpreter, request);
518
519  if (searcher == nullptr) {
520    lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
521    SearchFilterForUnconstrainedSearches null_searcher(target_sp);
522    completer.DoCompletion(&null_searcher);
523  } else {
524    completer.DoCompletion(searcher);
525  }
526}
527
528void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter,
529                                     CompletionRequest &request,
530                                     SearchFilter *searcher) {
531  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
532  if (!exe_ctx.HasTargetScope())
533    return;
534
535  exe_ctx.GetTargetPtr()->GetImages().ForEach(
536      [&request](const lldb::ModuleSP &module) {
537        StreamString strm;
538        module->GetDescription(strm.AsRawOstream(),
539                               lldb::eDescriptionLevelInitial);
540        request.TryCompleteCurrentArg(module->GetUUID().GetAsString(),
541                                      strm.GetString());
542        return true;
543      });
544}
545
546void CommandCompletions::Symbols(CommandInterpreter &interpreter,
547                                 CompletionRequest &request,
548                                 SearchFilter *searcher) {
549  SymbolCompleter completer(interpreter, request);
550
551  if (searcher == nullptr) {
552    lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
553    SearchFilterForUnconstrainedSearches null_searcher(target_sp);
554    completer.DoCompletion(&null_searcher);
555  } else {
556    completer.DoCompletion(searcher);
557  }
558}
559
560void CommandCompletions::SettingsNames(CommandInterpreter &interpreter,
561                                       CompletionRequest &request,
562                                       SearchFilter *searcher) {
563  // Cache the full setting name list
564  static StringList g_property_names;
565  if (g_property_names.GetSize() == 0) {
566    // Generate the full setting name list on demand
567    lldb::OptionValuePropertiesSP properties_sp(
568        interpreter.GetDebugger().GetValueProperties());
569    if (properties_sp) {
570      StreamString strm;
571      properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
572      const std::string &str = std::string(strm.GetString());
573      g_property_names.SplitIntoLines(str.c_str(), str.size());
574    }
575  }
576
577  for (const std::string &s : g_property_names)
578    request.TryCompleteCurrentArg(s);
579}
580
581void CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter,
582                                             CompletionRequest &request,
583                                             SearchFilter *searcher) {
584  PluginManager::AutoCompletePlatformName(request.GetCursorArgumentPrefix(),
585                                          request);
586}
587
588void CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter,
589                                           CompletionRequest &request,
590                                           SearchFilter *searcher) {
591  ArchSpec::AutoComplete(request);
592}
593
594void CommandCompletions::VariablePath(CommandInterpreter &interpreter,
595                                      CompletionRequest &request,
596                                      SearchFilter *searcher) {
597  Variable::AutoComplete(interpreter.GetExecutionContext(), request);
598}
599
600void CommandCompletions::Registers(CommandInterpreter &interpreter,
601                                   CompletionRequest &request,
602                                   SearchFilter *searcher) {
603  std::string reg_prefix;
604  if (request.GetCursorArgumentPrefix().startswith("$"))
605    reg_prefix = "$";
606
607  RegisterContext *reg_ctx =
608      interpreter.GetExecutionContext().GetRegisterContext();
609  const size_t reg_num = reg_ctx->GetRegisterCount();
610  for (size_t reg_idx = 0; reg_idx < reg_num; ++reg_idx) {
611    const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx);
612    request.TryCompleteCurrentArg(reg_prefix + reg_info->name,
613                                  reg_info->alt_name);
614  }
615}
616
617void CommandCompletions::Breakpoints(CommandInterpreter &interpreter,
618                                     CompletionRequest &request,
619                                     SearchFilter *searcher) {
620  lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget();
621  if (!target)
622    return;
623
624  const BreakpointList &breakpoints = target->GetBreakpointList();
625
626  std::unique_lock<std::recursive_mutex> lock;
627  target->GetBreakpointList().GetListMutex(lock);
628
629  size_t num_breakpoints = breakpoints.GetSize();
630  if (num_breakpoints == 0)
631    return;
632
633  for (size_t i = 0; i < num_breakpoints; ++i) {
634    lldb::BreakpointSP bp = breakpoints.GetBreakpointAtIndex(i);
635
636    StreamString s;
637    bp->GetDescription(&s, lldb::eDescriptionLevelBrief);
638    llvm::StringRef bp_info = s.GetString();
639
640    const size_t colon_pos = bp_info.find_first_of(':');
641    if (colon_pos != llvm::StringRef::npos)
642      bp_info = bp_info.drop_front(colon_pos + 2);
643
644    request.TryCompleteCurrentArg(std::to_string(bp->GetID()), bp_info);
645  }
646}
647
648void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter,
649                                         CompletionRequest &request,
650                                         SearchFilter *searcher) {
651  lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget();
652  if (!target)
653    return;
654
655  std::vector<std::string> name_list;
656  target->GetBreakpointNames(name_list);
657
658  for (const std::string &name : name_list)
659    request.TryCompleteCurrentArg(name);
660}
661
662void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter,
663                                            CompletionRequest &request,
664                                            SearchFilter *searcher) {
665  PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(),
666                                         request);
667}
668void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter,
669                                            CompletionRequest &request,
670                                            SearchFilter *searcher) {
671  // Currently the only valid options for disassemble -F are default, and for
672  // Intel architectures, att and intel.
673  static const char *flavors[] = {"default", "att", "intel"};
674  for (const char *flavor : flavors) {
675    request.TryCompleteCurrentArg(flavor);
676  }
677}
678
679void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter,
680                                    CompletionRequest &request,
681                                    SearchFilter *searcher) {
682  lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
683  if (!platform_sp)
684    return;
685  ProcessInstanceInfoList process_infos;
686  ProcessInstanceInfoMatch match_info;
687  platform_sp->FindProcesses(match_info, process_infos);
688  for (const ProcessInstanceInfo &info : process_infos)
689    request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()),
690                                  info.GetNameAsStringRef());
691}
692
693void CommandCompletions::ProcessNames(CommandInterpreter &interpreter,
694                                      CompletionRequest &request,
695                                      SearchFilter *searcher) {
696  lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
697  if (!platform_sp)
698    return;
699  ProcessInstanceInfoList process_infos;
700  ProcessInstanceInfoMatch match_info;
701  platform_sp->FindProcesses(match_info, process_infos);
702  for (const ProcessInstanceInfo &info : process_infos)
703    request.TryCompleteCurrentArg(info.GetNameAsStringRef());
704}
705
706void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter,
707                                       CompletionRequest &request,
708                                       SearchFilter *searcher) {
709  for (int bit :
710       Language::GetLanguagesSupportingTypeSystems().bitvector.set_bits()) {
711    request.TryCompleteCurrentArg(
712        Language::GetNameForLanguageType(static_cast<lldb::LanguageType>(bit)));
713  }
714}
715
716void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter,
717                                      CompletionRequest &request,
718                                      SearchFilter *searcher) {
719  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
720  if (!exe_ctx.HasProcessScope())
721    return;
722
723  lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP();
724  const uint32_t frame_num = thread_sp->GetStackFrameCount();
725  for (uint32_t i = 0; i < frame_num; ++i) {
726    lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
727    StreamString strm;
728    frame_sp->Dump(&strm, false, true);
729    request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
730  }
731}
732
733void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter,
734                                     CompletionRequest &request,
735                                     SearchFilter *searcher) {
736  const lldb::TargetSP target_sp =
737      interpreter.GetExecutionContext().GetTargetSP();
738  if (!target_sp)
739    return;
740
741  const size_t num = target_sp->GetNumStopHooks();
742  for (size_t idx = 0; idx < num; ++idx) {
743    StreamString strm;
744    // The value 11 is an offset to make the completion description looks
745    // neater.
746    strm.SetIndentLevel(11);
747    const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx);
748    stophook_sp->GetDescription(&strm, lldb::eDescriptionLevelInitial);
749    request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()),
750                                  strm.GetString());
751  }
752}
753
754void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter,
755                                       CompletionRequest &request,
756                                       SearchFilter *searcher) {
757  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
758  if (!exe_ctx.HasProcessScope())
759    return;
760
761  ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList();
762  lldb::ThreadSP thread_sp;
763  for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) {
764    StreamString strm;
765    thread_sp->GetStatus(strm, 0, 1, 1, true);
766    request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()),
767                                  strm.GetString());
768  }
769}
770
771void CommandCompletions::WatchPointIDs(CommandInterpreter &interpreter,
772                                       CompletionRequest &request,
773                                       SearchFilter *searcher) {
774  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
775  if (!exe_ctx.HasTargetScope())
776    return;
777
778  const WatchpointList &wp_list = exe_ctx.GetTargetPtr()->GetWatchpointList();
779  for (lldb::WatchpointSP wp_sp : wp_list.Watchpoints()) {
780    StreamString strm;
781    wp_sp->Dump(&strm);
782    request.TryCompleteCurrentArg(std::to_string(wp_sp->GetID()),
783                                  strm.GetString());
784  }
785}
786
787void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter,
788                                           CompletionRequest &request,
789                                           SearchFilter *searcher) {
790  DataVisualization::Categories::ForEach(
791      [&request](const lldb::TypeCategoryImplSP &category_sp) {
792        request.TryCompleteCurrentArg(category_sp->GetName(),
793                                      category_sp->GetDescription());
794        return true;
795      });
796}
797
798void CommandCompletions::CompleteModifiableCmdPathArgs(
799    CommandInterpreter &interpreter, CompletionRequest &request,
800    OptionElementVector &opt_element_vector) {
801  // The only arguments constitute a command path, however, there might be
802  // options interspersed among the arguments, and we need to skip those.  Do that
803  // by copying the args vector, and just dropping all the option bits:
804  Args args = request.GetParsedLine();
805  std::vector<size_t> to_delete;
806  for (auto &elem : opt_element_vector) {
807    to_delete.push_back(elem.opt_pos);
808    if (elem.opt_arg_pos != 0)
809      to_delete.push_back(elem.opt_arg_pos);
810  }
811  sort(to_delete.begin(), to_delete.end(), std::greater<size_t>());
812  for (size_t idx : to_delete)
813    args.DeleteArgumentAtIndex(idx);
814
815  // At this point, we should only have args, so now lookup the command up to
816  // the cursor element.
817
818  // There's nothing here but options.  It doesn't seem very useful here to
819  // dump all the commands, so just return.
820  size_t num_args = args.GetArgumentCount();
821  if (num_args == 0)
822    return;
823
824  // There's just one argument, so we should complete its name:
825  StringList matches;
826  if (num_args == 1) {
827    interpreter.GetUserCommandObject(args.GetArgumentAtIndex(0), &matches,
828                                     nullptr);
829    request.AddCompletions(matches);
830    return;
831  }
832
833  // There was more than one path element, lets find the containing command:
834  Status error;
835  CommandObjectMultiword *mwc =
836      interpreter.VerifyUserMultiwordCmdPath(args, true, error);
837
838  // Something was wrong somewhere along the path, but I don't think there's
839  // a good way to go back and fill in the missing elements:
840  if (error.Fail())
841    return;
842
843  // This should never happen.  We already handled the case of one argument
844  // above, and we can only get Success & nullptr back if there's a one-word
845  // leaf.
846  assert(mwc != nullptr);
847
848  mwc->GetSubcommandObject(args.GetArgumentAtIndex(num_args - 1), &matches);
849  if (matches.GetSize() == 0)
850    return;
851
852  request.AddCompletions(matches);
853}
854