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