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