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