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