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