1 //===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 #include <sys/stat.h> 12 #if defined(__APPLE__) || defined(__linux__) 13 #include <pwd.h> 14 #endif 15 16 // C++ Includes 17 // Other libraries and framework includes 18 #include "llvm/ADT/SmallString.h" 19 20 // Project includes 21 #include "lldb/Core/FileSpecList.h" 22 #include "lldb/Core/Module.h" 23 #include "lldb/Core/PluginManager.h" 24 #include "lldb/Host/FileSpec.h" 25 #include "lldb/Host/FileSystem.h" 26 #include "lldb/Interpreter/Args.h" 27 #include "lldb/Interpreter/CommandCompletions.h" 28 #include "lldb/Interpreter/CommandInterpreter.h" 29 #include "lldb/Interpreter/OptionValueProperties.h" 30 #include "lldb/Symbol/CompileUnit.h" 31 #include "lldb/Symbol/Variable.h" 32 #include "lldb/Target/Target.h" 33 #include "lldb/Utility/CleanUp.h" 34 35 #include "llvm/ADT/SmallString.h" 36 37 using namespace lldb_private; 38 39 CommandCompletions::CommonCompletionElement 40 CommandCompletions::g_common_completions[] = 41 { 42 {eCustomCompletion, nullptr}, 43 {eSourceFileCompletion, CommandCompletions::SourceFiles}, 44 {eDiskFileCompletion, CommandCompletions::DiskFiles}, 45 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, 46 {eSymbolCompletion, CommandCompletions::Symbols}, 47 {eModuleCompletion, CommandCompletions::Modules}, 48 {eSettingsNameCompletion, CommandCompletions::SettingsNames}, 49 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, 50 {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, 51 {eVariablePathCompletion, CommandCompletions::VariablePath}, 52 {eNoCompletion, nullptr} // This one has to be last in the list. 53 }; 54 55 bool 56 CommandCompletions::InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, 57 uint32_t completion_mask, 58 const char *completion_str, 59 int match_start_point, 60 int max_return_elements, 61 SearchFilter *searcher, 62 bool &word_complete, 63 StringList &matches) 64 { 65 bool handled = false; 66 67 if (completion_mask & eCustomCompletion) 68 return false; 69 70 for (int i = 0; ; i++) 71 { 72 if (g_common_completions[i].type == eNoCompletion) 73 break; 74 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type 75 && g_common_completions[i].callback != nullptr) 76 { 77 handled = true; 78 g_common_completions[i].callback (interpreter, 79 completion_str, 80 match_start_point, 81 max_return_elements, 82 searcher, 83 word_complete, 84 matches); 85 } 86 } 87 return handled; 88 } 89 90 int 91 CommandCompletions::SourceFiles(CommandInterpreter &interpreter, 92 const char *partial_file_name, 93 int match_start_point, 94 int max_return_elements, 95 SearchFilter *searcher, 96 bool &word_complete, 97 StringList &matches) 98 { 99 word_complete = true; 100 // Find some way to switch "include support files..." 101 SourceFileCompleter completer (interpreter, 102 false, 103 partial_file_name, 104 match_start_point, 105 max_return_elements, 106 matches); 107 108 if (searcher == nullptr) 109 { 110 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 111 SearchFilterForUnconstrainedSearches null_searcher (target_sp); 112 completer.DoCompletion (&null_searcher); 113 } 114 else 115 { 116 completer.DoCompletion (searcher); 117 } 118 return matches.GetSize(); 119 } 120 121 typedef struct DiskFilesOrDirectoriesBaton 122 { 123 const char *remainder; 124 char *partial_name_copy; 125 bool only_directories; 126 bool *saw_directory; 127 StringList *matches; 128 char *end_ptr; 129 size_t baselen; 130 } DiskFilesOrDirectoriesBaton; 131 132 FileSpec::EnumerateDirectoryResult DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type, const FileSpec &spec) 133 { 134 const char *name = spec.GetFilename().AsCString(); 135 136 const DiskFilesOrDirectoriesBaton *parameters = (DiskFilesOrDirectoriesBaton*)baton; 137 char *end_ptr = parameters->end_ptr; 138 char *partial_name_copy = parameters->partial_name_copy; 139 const char *remainder = parameters->remainder; 140 141 // Omit ".", ".." and any . files if the match string doesn't start with . 142 if (name[0] == '.') 143 { 144 if (name[1] == '\0') 145 return FileSpec::eEnumerateDirectoryResultNext; 146 else if (name[1] == '.' && name[2] == '\0') 147 return FileSpec::eEnumerateDirectoryResultNext; 148 else if (remainder[0] != '.') 149 return FileSpec::eEnumerateDirectoryResultNext; 150 } 151 152 // If we found a directory, we put a "/" at the end of the name. 153 154 if (remainder[0] == '\0' || strstr(name, remainder) == name) 155 { 156 if (strlen(name) + parameters->baselen >= PATH_MAX) 157 return FileSpec::eEnumerateDirectoryResultNext; 158 159 strcpy(end_ptr, name); 160 161 bool isa_directory = false; 162 if (file_type == FileSpec::eFileTypeDirectory) 163 isa_directory = true; 164 else if (file_type == FileSpec::eFileTypeSymbolicLink) 165 { 166 if (FileSpec(partial_name_copy, false).IsDirectory()) 167 isa_directory = true; 168 } 169 170 if (isa_directory) 171 { 172 *parameters->saw_directory = true; 173 size_t len = strlen(parameters->partial_name_copy); 174 partial_name_copy[len] = '/'; 175 partial_name_copy[len + 1] = '\0'; 176 } 177 if (parameters->only_directories && !isa_directory) 178 return FileSpec::eEnumerateDirectoryResultNext; 179 parameters->matches->AppendString(partial_name_copy); 180 } 181 182 return FileSpec::eEnumerateDirectoryResultNext; 183 } 184 185 static int 186 DiskFilesOrDirectories(const char *partial_file_name, 187 bool only_directories, 188 bool &saw_directory, 189 StringList &matches) 190 { 191 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion. 192 // If it is not defined on your host system, you'll need to implement it yourself... 193 194 size_t partial_name_len = strlen(partial_file_name); 195 196 if (partial_name_len >= PATH_MAX) 197 return matches.GetSize(); 198 199 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr 200 // below will point to the place of the remainder in this string. Then when we've resolved the 201 // containing directory, and opened it, we'll read the directory contents and overwrite the 202 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve 203 // the form the user originally typed. 204 205 char partial_name_copy[PATH_MAX]; 206 memcpy(partial_name_copy, partial_file_name, partial_name_len); 207 partial_name_copy[partial_name_len] = '\0'; 208 209 // We'll need to save a copy of the remainder for comparison, which we do here. 210 char remainder[PATH_MAX]; 211 212 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string. 213 char *end_ptr; 214 215 end_ptr = strrchr(partial_name_copy, '/'); 216 217 // This will store the resolved form of the containing directory 218 llvm::SmallString<64> containing_part; 219 220 if (end_ptr == nullptr) 221 { 222 // There's no directory. If the thing begins with a "~" then this is a bare 223 // user name. 224 if (*partial_name_copy == '~') 225 { 226 // Nothing here but the user name. We could just put a slash on the end, 227 // but for completeness sake we'll resolve the user name and only put a slash 228 // on the end if it exists. 229 llvm::SmallString<64> resolved_username(partial_name_copy); 230 FileSpec::ResolveUsername (resolved_username); 231 232 // Not sure how this would happen, a username longer than PATH_MAX? Still... 233 if (resolved_username.size() == 0) 234 { 235 // The user name didn't resolve, let's look in the password database for matches. 236 // The user name database contains duplicates, and is not in alphabetical order, so 237 // we'll use a set to manage that for us. 238 FileSpec::ResolvePartialUsername (partial_name_copy, matches); 239 if (matches.GetSize() > 0) 240 saw_directory = true; 241 return matches.GetSize(); 242 } 243 else 244 { 245 //The thing exists, put a '/' on the end, and return it... 246 // FIXME: complete user names here: 247 partial_name_copy[partial_name_len] = '/'; 248 partial_name_copy[partial_name_len+1] = '\0'; 249 matches.AppendString(partial_name_copy); 250 saw_directory = true; 251 return matches.GetSize(); 252 } 253 } 254 else 255 { 256 // The containing part is the CWD, and the whole string is the remainder. 257 containing_part = "."; 258 strcpy(remainder, partial_name_copy); 259 end_ptr = partial_name_copy; 260 } 261 } 262 else 263 { 264 if (end_ptr == partial_name_copy) 265 { 266 // We're completing a file or directory in the root volume. 267 containing_part = "/"; 268 } 269 else 270 { 271 containing_part.append(partial_name_copy, end_ptr); 272 } 273 // Push end_ptr past the final "/" and set remainder. 274 end_ptr++; 275 strcpy(remainder, end_ptr); 276 } 277 278 // Look for a user name in the containing part, and if it's there, resolve it and stick the 279 // result back into the containing_part: 280 281 if (*partial_name_copy == '~') 282 { 283 FileSpec::ResolveUsername(containing_part); 284 // User name doesn't exist, we're not getting any further... 285 if (containing_part.empty()) 286 return matches.GetSize(); 287 } 288 289 // Okay, containing_part is now the directory we want to open and look for files: 290 291 size_t baselen = end_ptr - partial_name_copy; 292 293 DiskFilesOrDirectoriesBaton parameters; 294 parameters.remainder = remainder; 295 parameters.partial_name_copy = partial_name_copy; 296 parameters.only_directories = only_directories; 297 parameters.saw_directory = &saw_directory; 298 parameters.matches = &matches; 299 parameters.end_ptr = end_ptr; 300 parameters.baselen = baselen; 301 302 FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true, DiskFilesOrDirectoriesCallback, ¶meters); 303 304 return matches.GetSize(); 305 } 306 307 int 308 CommandCompletions::DiskFiles(CommandInterpreter &interpreter, 309 const char *partial_file_name, 310 int match_start_point, 311 int max_return_elements, 312 SearchFilter *searcher, 313 bool &word_complete, 314 StringList &matches) 315 { 316 int ret_val = DiskFilesOrDirectories (partial_file_name, 317 false, 318 word_complete, 319 matches); 320 word_complete = !word_complete; 321 return ret_val; 322 } 323 324 int 325 CommandCompletions::DiskDirectories(CommandInterpreter &interpreter, 326 const char *partial_file_name, 327 int match_start_point, 328 int max_return_elements, 329 SearchFilter *searcher, 330 bool &word_complete, 331 StringList &matches) 332 { 333 int ret_val = DiskFilesOrDirectories (partial_file_name, 334 true, 335 word_complete, 336 matches); 337 word_complete = false; 338 return ret_val; 339 } 340 341 int 342 CommandCompletions::Modules(CommandInterpreter &interpreter, 343 const char *partial_file_name, 344 int match_start_point, 345 int max_return_elements, 346 SearchFilter *searcher, 347 bool &word_complete, 348 StringList &matches) 349 { 350 word_complete = true; 351 ModuleCompleter completer (interpreter, 352 partial_file_name, 353 match_start_point, 354 max_return_elements, 355 matches); 356 357 if (searcher == nullptr) 358 { 359 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 360 SearchFilterForUnconstrainedSearches null_searcher (target_sp); 361 completer.DoCompletion (&null_searcher); 362 } 363 else 364 { 365 completer.DoCompletion (searcher); 366 } 367 return matches.GetSize(); 368 } 369 370 int 371 CommandCompletions::Symbols(CommandInterpreter &interpreter, 372 const char *partial_file_name, 373 int match_start_point, 374 int max_return_elements, 375 SearchFilter *searcher, 376 bool &word_complete, 377 StringList &matches) 378 { 379 word_complete = true; 380 SymbolCompleter completer (interpreter, 381 partial_file_name, 382 match_start_point, 383 max_return_elements, 384 matches); 385 386 if (searcher == nullptr) 387 { 388 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 389 SearchFilterForUnconstrainedSearches null_searcher (target_sp); 390 completer.DoCompletion (&null_searcher); 391 } 392 else 393 { 394 completer.DoCompletion (searcher); 395 } 396 return matches.GetSize(); 397 } 398 399 int 400 CommandCompletions::SettingsNames (CommandInterpreter &interpreter, 401 const char *partial_setting_name, 402 int match_start_point, 403 int max_return_elements, 404 SearchFilter *searcher, 405 bool &word_complete, 406 StringList &matches) 407 { 408 // Cache the full setting name list 409 static StringList g_property_names; 410 if (g_property_names.GetSize() == 0) 411 { 412 // Generate the full setting name list on demand 413 lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties()); 414 if (properties_sp) 415 { 416 StreamString strm; 417 properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName); 418 const std::string &str = strm.GetString(); 419 g_property_names.SplitIntoLines(str.c_str(), str.size()); 420 } 421 } 422 423 size_t exact_matches_idx = SIZE_MAX; 424 const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx); 425 word_complete = exact_matches_idx != SIZE_MAX; 426 return num_matches; 427 } 428 429 int 430 CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter, 431 const char *partial_name, 432 int match_start_point, 433 int max_return_elements, 434 SearchFilter *searcher, 435 bool &word_complete, 436 lldb_private::StringList &matches) 437 { 438 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches); 439 word_complete = num_matches == 1; 440 return num_matches; 441 } 442 443 int 444 CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter, 445 const char *partial_name, 446 int match_start_point, 447 int max_return_elements, 448 SearchFilter *searcher, 449 bool &word_complete, 450 lldb_private::StringList &matches) 451 { 452 const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches); 453 word_complete = num_matches == 1; 454 return num_matches; 455 } 456 457 int 458 CommandCompletions::VariablePath (CommandInterpreter &interpreter, 459 const char *partial_name, 460 int match_start_point, 461 int max_return_elements, 462 SearchFilter *searcher, 463 bool &word_complete, 464 lldb_private::StringList &matches) 465 { 466 return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete); 467 } 468 469 CommandCompletions::Completer::Completer(CommandInterpreter &interpreter, 470 const char *completion_str, 471 int match_start_point, 472 int max_return_elements, 473 StringList &matches) : 474 m_interpreter (interpreter), 475 m_completion_str (completion_str), 476 m_match_start_point (match_start_point), 477 m_max_return_elements (max_return_elements), 478 m_matches (matches) 479 { 480 } 481 482 CommandCompletions::Completer::~Completer() = default; 483 484 //---------------------------------------------------------------------- 485 // SourceFileCompleter 486 //---------------------------------------------------------------------- 487 488 CommandCompletions::SourceFileCompleter::SourceFileCompleter(CommandInterpreter &interpreter, 489 bool include_support_files, 490 const char *completion_str, 491 int match_start_point, 492 int max_return_elements, 493 StringList &matches) : 494 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches), 495 m_include_support_files (include_support_files), 496 m_matching_files() 497 { 498 FileSpec partial_spec (m_completion_str.c_str(), false); 499 m_file_name = partial_spec.GetFilename().GetCString(); 500 m_dir_name = partial_spec.GetDirectory().GetCString(); 501 } 502 503 Searcher::Depth 504 CommandCompletions::SourceFileCompleter::GetDepth() 505 { 506 return eDepthCompUnit; 507 } 508 509 Searcher::CallbackReturn 510 CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter, 511 SymbolContext &context, 512 Address *addr, 513 bool complete) 514 { 515 if (context.comp_unit != nullptr) 516 { 517 if (m_include_support_files) 518 { 519 FileSpecList supporting_files = context.comp_unit->GetSupportFiles(); 520 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) 521 { 522 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles); 523 const char *sfile_file_name = sfile_spec.GetFilename().GetCString(); 524 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString(); 525 bool match = false; 526 if (m_file_name && sfile_file_name 527 && strstr (sfile_file_name, m_file_name) == sfile_file_name) 528 match = true; 529 if (match && m_dir_name && sfile_dir_name 530 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name) 531 match = false; 532 533 if (match) 534 { 535 m_matching_files.AppendIfUnique(sfile_spec); 536 } 537 } 538 } 539 else 540 { 541 const char *cur_file_name = context.comp_unit->GetFilename().GetCString(); 542 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString(); 543 544 bool match = false; 545 if (m_file_name && cur_file_name 546 && strstr (cur_file_name, m_file_name) == cur_file_name) 547 match = true; 548 549 if (match && m_dir_name && cur_dir_name 550 && strstr (cur_dir_name, m_dir_name) != cur_dir_name) 551 match = false; 552 553 if (match) 554 { 555 m_matching_files.AppendIfUnique(context.comp_unit); 556 } 557 } 558 } 559 return Searcher::eCallbackReturnContinue; 560 } 561 562 size_t 563 CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter) 564 { 565 filter->Search (*this); 566 // Now convert the filelist to completions: 567 for (size_t i = 0; i < m_matching_files.GetSize(); i++) 568 { 569 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString()); 570 } 571 return m_matches.GetSize(); 572 } 573 574 //---------------------------------------------------------------------- 575 // SymbolCompleter 576 //---------------------------------------------------------------------- 577 578 static bool 579 regex_chars (const char comp) 580 { 581 return (comp == '[' || comp == ']' || 582 comp == '(' || comp == ')' || 583 comp == '{' || comp == '}' || 584 comp == '+' || 585 comp == '.' || 586 comp == '*' || 587 comp == '|' || 588 comp == '^' || 589 comp == '$' || 590 comp == '\\' || 591 comp == '?'); 592 } 593 594 CommandCompletions::SymbolCompleter::SymbolCompleter(CommandInterpreter &interpreter, 595 const char *completion_str, 596 int match_start_point, 597 int max_return_elements, 598 StringList &matches) : 599 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches) 600 { 601 std::string regex_str; 602 if (completion_str && completion_str[0]) 603 { 604 regex_str.append("^"); 605 regex_str.append(completion_str); 606 } 607 else 608 { 609 // Match anything since the completion string is empty 610 regex_str.append("."); 611 } 612 std::string::iterator pos = find_if(regex_str.begin() + 1, regex_str.end(), regex_chars); 613 while (pos < regex_str.end()) 614 { 615 pos = regex_str.insert(pos, '\\'); 616 pos = find_if(pos + 2, regex_str.end(), regex_chars); 617 } 618 m_regex.Compile(regex_str.c_str()); 619 } 620 621 Searcher::Depth 622 CommandCompletions::SymbolCompleter::GetDepth() 623 { 624 return eDepthModule; 625 } 626 627 Searcher::CallbackReturn 628 CommandCompletions::SymbolCompleter::SearchCallback(SearchFilter &filter, 629 SymbolContext &context, 630 Address *addr, 631 bool complete) 632 { 633 if (context.module_sp) 634 { 635 SymbolContextList sc_list; 636 const bool include_symbols = true; 637 const bool include_inlines = true; 638 const bool append = true; 639 context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list); 640 641 SymbolContext sc; 642 // Now add the functions & symbols to the list - only add if unique: 643 for (uint32_t i = 0; i < sc_list.GetSize(); i++) 644 { 645 if (sc_list.GetContextAtIndex(i, sc)) 646 { 647 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled); 648 if (!func_name.IsEmpty()) 649 m_match_set.insert (func_name); 650 } 651 } 652 } 653 return Searcher::eCallbackReturnContinue; 654 } 655 656 size_t 657 CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter) 658 { 659 filter->Search (*this); 660 collection::iterator pos = m_match_set.begin(), end = m_match_set.end(); 661 for (pos = m_match_set.begin(); pos != end; pos++) 662 m_matches.AppendString((*pos).GetCString()); 663 664 return m_matches.GetSize(); 665 } 666 667 //---------------------------------------------------------------------- 668 // ModuleCompleter 669 //---------------------------------------------------------------------- 670 CommandCompletions::ModuleCompleter::ModuleCompleter(CommandInterpreter &interpreter, 671 const char *completion_str, 672 int match_start_point, 673 int max_return_elements, 674 StringList &matches) : 675 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches) 676 { 677 FileSpec partial_spec (m_completion_str.c_str(), false); 678 m_file_name = partial_spec.GetFilename().GetCString(); 679 m_dir_name = partial_spec.GetDirectory().GetCString(); 680 } 681 682 Searcher::Depth 683 CommandCompletions::ModuleCompleter::GetDepth() 684 { 685 return eDepthModule; 686 } 687 688 Searcher::CallbackReturn 689 CommandCompletions::ModuleCompleter::SearchCallback(SearchFilter &filter, 690 SymbolContext &context, 691 Address *addr, 692 bool complete) 693 { 694 if (context.module_sp) 695 { 696 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString(); 697 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString(); 698 699 bool match = false; 700 if (m_file_name && cur_file_name 701 && strstr (cur_file_name, m_file_name) == cur_file_name) 702 match = true; 703 704 if (match && m_dir_name && cur_dir_name 705 && strstr (cur_dir_name, m_dir_name) != cur_dir_name) 706 match = false; 707 708 if (match) 709 { 710 m_matches.AppendString (cur_file_name); 711 } 712 } 713 return Searcher::eCallbackReturnContinue; 714 } 715 716 size_t 717 CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter) 718 { 719 filter->Search (*this); 720 return m_matches.GetSize(); 721 } 722