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