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