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