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 36 using 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). 41 typedef void (*CompletionCallback)(CommandInterpreter &interpreter, 42 CompletionRequest &request, 43 // A search filter to limit the search... 44 lldb_private::SearchFilter *searcher); 45 46 struct CommonCompletionElement { 47 uint32_t type; 48 CompletionCallback callback; 49 }; 50 51 bool 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 99 namespace { 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. 102 class Completer : public Searcher { 103 public: 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 116 protected: 117 CommandInterpreter &m_interpreter; 118 CompletionRequest &m_request; 119 120 private: 121 Completer(const Completer &) = delete; 122 const Completer &operator=(const Completer &) = delete; 123 }; 124 } // namespace 125 126 // SourceFileCompleter implements the source file completer 127 namespace { 128 class SourceFileCompleter : public Completer { 129 public: 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 174 private: 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 184 static bool regex_chars(const char comp) { 185 return llvm::StringRef("[](){}+.*|^$\\?").contains(comp); 186 } 187 188 namespace { 189 class SymbolCompleter : public Completer { 190 191 public: 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 247 private: 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 257 namespace { 258 class ModuleCompleter : public Completer { 259 public: 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 296 private: 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 305 void 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 319 static 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 455 static 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 465 static void DiskFilesOrDirectories(CompletionRequest &request, 466 bool only_directories) { 467 StandardTildeExpressionResolver resolver; 468 DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories, 469 request, resolver); 470 } 471 472 void CommandCompletions::DiskFiles(CommandInterpreter &interpreter, 473 CompletionRequest &request, 474 SearchFilter *searcher) { 475 DiskFilesOrDirectories(request, /*only_dirs*/ false); 476 } 477 478 void CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name, 479 StringList &matches, 480 TildeExpressionResolver &Resolver) { 481 DiskFilesOrDirectories(partial_file_name, false, matches, Resolver); 482 } 483 484 void CommandCompletions::DiskDirectories(CommandInterpreter &interpreter, 485 CompletionRequest &request, 486 SearchFilter *searcher) { 487 DiskFilesOrDirectories(request, /*only_dirs*/ true); 488 } 489 490 void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name, 491 StringList &matches, 492 TildeExpressionResolver &Resolver) { 493 DiskFilesOrDirectories(partial_file_name, true, matches, Resolver); 494 } 495 496 void 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 505 void 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 514 void 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 528 void 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 546 void 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 560 void 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 581 void CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter, 582 CompletionRequest &request, 583 SearchFilter *searcher) { 584 PluginManager::AutoCompletePlatformName(request.GetCursorArgumentPrefix(), 585 request); 586 } 587 588 void CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter, 589 CompletionRequest &request, 590 SearchFilter *searcher) { 591 ArchSpec::AutoComplete(request); 592 } 593 594 void CommandCompletions::VariablePath(CommandInterpreter &interpreter, 595 CompletionRequest &request, 596 SearchFilter *searcher) { 597 Variable::AutoComplete(interpreter.GetExecutionContext(), request); 598 } 599 600 void 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 617 void 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 648 void 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 662 void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter, 663 CompletionRequest &request, 664 SearchFilter *searcher) { 665 PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(), 666 request); 667 } 668 void 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 679 void 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 693 void 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 706 void 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 716 void 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 733 void 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 754 void 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 771 void 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 787 void 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 798 void 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