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