1 //===-- Platform.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/Target/Platform.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Breakpoint/BreakpointIDList.h" 17 #include "lldb/Core/Error.h" 18 #include "lldb/Core/Log.h" 19 #include "lldb/Core/ModuleSpec.h" 20 #include "lldb/Core/PluginManager.h" 21 #include "lldb/Host/FileSpec.h" 22 #include "lldb/Host/FileSystem.h" 23 #include "lldb/Host/Host.h" 24 #include "lldb/Host/HostInfo.h" 25 #include "lldb/Target/Process.h" 26 #include "lldb/Target/Target.h" 27 #include "lldb/Utility/Utils.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 // Use a singleton function for g_local_platform_sp to avoid init 33 // constructors since LLDB is often part of a shared library 34 static PlatformSP& 35 GetHostPlatformSP () 36 { 37 static PlatformSP g_platform_sp; 38 return g_platform_sp; 39 } 40 41 const char * 42 Platform::GetHostPlatformName () 43 { 44 return "host"; 45 } 46 47 //------------------------------------------------------------------ 48 /// Get the native host platform plug-in. 49 /// 50 /// There should only be one of these for each host that LLDB runs 51 /// upon that should be statically compiled in and registered using 52 /// preprocessor macros or other similar build mechanisms. 53 /// 54 /// This platform will be used as the default platform when launching 55 /// or attaching to processes unless another platform is specified. 56 //------------------------------------------------------------------ 57 PlatformSP 58 Platform::GetHostPlatform () 59 { 60 return GetHostPlatformSP (); 61 } 62 63 static std::vector<PlatformSP> & 64 GetPlatformList() 65 { 66 static std::vector<PlatformSP> g_platform_list; 67 return g_platform_list; 68 } 69 70 static Mutex & 71 GetPlatformListMutex () 72 { 73 static Mutex g_mutex(Mutex::eMutexTypeRecursive); 74 return g_mutex; 75 } 76 77 void 78 Platform::SetHostPlatform (const lldb::PlatformSP &platform_sp) 79 { 80 // The native platform should use its static void Platform::Initialize() 81 // function to register itself as the native platform. 82 GetHostPlatformSP () = platform_sp; 83 84 if (platform_sp) 85 { 86 Mutex::Locker locker(GetPlatformListMutex ()); 87 GetPlatformList().push_back(platform_sp); 88 } 89 } 90 91 Error 92 Platform::GetFileWithUUID (const FileSpec &platform_file, 93 const UUID *uuid_ptr, 94 FileSpec &local_file) 95 { 96 // Default to the local case 97 local_file = platform_file; 98 return Error(); 99 } 100 101 FileSpecList 102 Platform::LocateExecutableScriptingResources (Target *target, Module &module, Stream* feedback_stream) 103 { 104 return FileSpecList(); 105 } 106 107 //PlatformSP 108 //Platform::FindPlugin (Process *process, const ConstString &plugin_name) 109 //{ 110 // PlatformCreateInstance create_callback = NULL; 111 // if (plugin_name) 112 // { 113 // create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); 114 // if (create_callback) 115 // { 116 // ArchSpec arch; 117 // if (process) 118 // { 119 // arch = process->GetTarget().GetArchitecture(); 120 // } 121 // PlatformSP platform_sp(create_callback(process, &arch)); 122 // if (platform_sp) 123 // return platform_sp; 124 // } 125 // } 126 // else 127 // { 128 // for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx) 129 // { 130 // PlatformSP platform_sp(create_callback(process, nullptr)); 131 // if (platform_sp) 132 // return platform_sp; 133 // } 134 // } 135 // return PlatformSP(); 136 //} 137 138 Error 139 Platform::GetSharedModule (const ModuleSpec &module_spec, 140 ModuleSP &module_sp, 141 const FileSpecList *module_search_paths_ptr, 142 ModuleSP *old_module_sp_ptr, 143 bool *did_create_ptr) 144 { 145 // Don't do any path remapping for the default implementation 146 // of the platform GetSharedModule function, just call through 147 // to our static ModuleList function. Platform subclasses that 148 // implement remote debugging, might have a developer kits 149 // installed that have cached versions of the files for the 150 // remote target, or might implement a download and cache 151 // locally implementation. 152 const bool always_create = false; 153 return ModuleList::GetSharedModule (module_spec, 154 module_sp, 155 module_search_paths_ptr, 156 old_module_sp_ptr, 157 did_create_ptr, 158 always_create); 159 } 160 161 PlatformSP 162 Platform::Find (const ConstString &name) 163 { 164 if (name) 165 { 166 static ConstString g_host_platform_name ("host"); 167 if (name == g_host_platform_name) 168 return GetHostPlatform(); 169 170 Mutex::Locker locker(GetPlatformListMutex ()); 171 for (const auto &platform_sp : GetPlatformList()) 172 { 173 if (platform_sp->GetName() == name) 174 return platform_sp; 175 } 176 } 177 return PlatformSP(); 178 } 179 180 PlatformSP 181 Platform::Create (const ConstString &name, Error &error) 182 { 183 PlatformCreateInstance create_callback = NULL; 184 lldb::PlatformSP platform_sp; 185 if (name) 186 { 187 static ConstString g_host_platform_name ("host"); 188 if (name == g_host_platform_name) 189 return GetHostPlatform(); 190 191 create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (name); 192 if (create_callback) 193 platform_sp = create_callback(true, NULL); 194 else 195 error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", name.GetCString()); 196 } 197 else 198 error.SetErrorString ("invalid platform name"); 199 200 if (platform_sp) 201 { 202 Mutex::Locker locker(GetPlatformListMutex ()); 203 GetPlatformList().push_back(platform_sp); 204 } 205 206 return platform_sp; 207 } 208 209 210 PlatformSP 211 Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error) 212 { 213 lldb::PlatformSP platform_sp; 214 if (arch.IsValid()) 215 { 216 // Scope for locker 217 { 218 // First try exact arch matches across all platforms already created 219 Mutex::Locker locker(GetPlatformListMutex ()); 220 for (const auto &platform_sp : GetPlatformList()) 221 { 222 if (platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr)) 223 return platform_sp; 224 } 225 226 // Next try compatible arch matches across all platforms already created 227 for (const auto &platform_sp : GetPlatformList()) 228 { 229 if (platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr)) 230 return platform_sp; 231 } 232 } 233 234 PlatformCreateInstance create_callback; 235 // First try exact arch matches across all platform plug-ins 236 uint32_t idx; 237 for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx) 238 { 239 if (create_callback) 240 { 241 platform_sp = create_callback(false, &arch); 242 if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr)) 243 { 244 Mutex::Locker locker(GetPlatformListMutex ()); 245 GetPlatformList().push_back(platform_sp); 246 return platform_sp; 247 } 248 } 249 } 250 // Next try compatible arch matches across all platform plug-ins 251 for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx) 252 { 253 if (create_callback) 254 { 255 platform_sp = create_callback(false, &arch); 256 if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr)) 257 { 258 Mutex::Locker locker(GetPlatformListMutex ()); 259 GetPlatformList().push_back(platform_sp); 260 return platform_sp; 261 } 262 } 263 } 264 } 265 else 266 error.SetErrorString ("invalid platform name"); 267 if (platform_arch_ptr) 268 platform_arch_ptr->Clear(); 269 platform_sp.reset(); 270 return platform_sp; 271 } 272 273 //------------------------------------------------------------------ 274 /// Default Constructor 275 //------------------------------------------------------------------ 276 Platform::Platform (bool is_host) : 277 m_is_host (is_host), 278 m_os_version_set_while_connected (false), 279 m_system_arch_set_while_connected (false), 280 m_sdk_sysroot (), 281 m_sdk_build (), 282 m_working_dir (), 283 m_remote_url (), 284 m_name (), 285 m_major_os_version (UINT32_MAX), 286 m_minor_os_version (UINT32_MAX), 287 m_update_os_version (UINT32_MAX), 288 m_system_arch(), 289 m_uid_map_mutex (Mutex::eMutexTypeNormal), 290 m_gid_map_mutex (Mutex::eMutexTypeNormal), 291 m_uid_map(), 292 m_gid_map(), 293 m_max_uid_name_len (0), 294 m_max_gid_name_len (0), 295 m_supports_rsync (false), 296 m_rsync_opts (), 297 m_rsync_prefix (), 298 m_supports_ssh (false), 299 m_ssh_opts (), 300 m_ignores_remote_hostname (false), 301 m_trap_handlers(), 302 m_calculated_trap_handlers (false), 303 m_trap_handler_mutex() 304 { 305 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); 306 if (log) 307 log->Printf ("%p Platform::Platform()", static_cast<void*>(this)); 308 } 309 310 //------------------------------------------------------------------ 311 /// Destructor. 312 /// 313 /// The destructor is virtual since this class is designed to be 314 /// inherited from by the plug-in instance. 315 //------------------------------------------------------------------ 316 Platform::~Platform() 317 { 318 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); 319 if (log) 320 log->Printf ("%p Platform::~Platform()", static_cast<void*>(this)); 321 } 322 323 void 324 Platform::GetStatus (Stream &strm) 325 { 326 uint32_t major = UINT32_MAX; 327 uint32_t minor = UINT32_MAX; 328 uint32_t update = UINT32_MAX; 329 std::string s; 330 strm.Printf (" Platform: %s\n", GetPluginName().GetCString()); 331 332 ArchSpec arch (GetSystemArchitecture()); 333 if (arch.IsValid()) 334 { 335 if (!arch.GetTriple().str().empty()) 336 strm.Printf(" Triple: %s\n", arch.GetTriple().str().c_str()); 337 } 338 339 if (GetOSVersion(major, minor, update)) 340 { 341 strm.Printf("OS Version: %u", major); 342 if (minor != UINT32_MAX) 343 strm.Printf(".%u", minor); 344 if (update != UINT32_MAX) 345 strm.Printf(".%u", update); 346 347 if (GetOSBuildString (s)) 348 strm.Printf(" (%s)", s.c_str()); 349 350 strm.EOL(); 351 } 352 353 if (GetOSKernelDescription (s)) 354 strm.Printf(" Kernel: %s\n", s.c_str()); 355 356 if (IsHost()) 357 { 358 strm.Printf(" Hostname: %s\n", GetHostname()); 359 } 360 else 361 { 362 const bool is_connected = IsConnected(); 363 if (is_connected) 364 strm.Printf(" Hostname: %s\n", GetHostname()); 365 strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); 366 } 367 368 if (GetWorkingDirectory()) 369 { 370 strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); 371 } 372 if (!IsConnected()) 373 return; 374 375 std::string specific_info(GetPlatformSpecificConnectionInformation()); 376 377 if (specific_info.empty() == false) 378 strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); 379 } 380 381 382 bool 383 Platform::GetOSVersion (uint32_t &major, 384 uint32_t &minor, 385 uint32_t &update) 386 { 387 bool success = m_major_os_version != UINT32_MAX; 388 if (IsHost()) 389 { 390 if (!success) 391 { 392 // We have a local host platform 393 success = HostInfo::GetOSVersion(m_major_os_version, m_minor_os_version, m_update_os_version); 394 m_os_version_set_while_connected = success; 395 } 396 } 397 else 398 { 399 // We have a remote platform. We can only fetch the remote 400 // OS version if we are connected, and we don't want to do it 401 // more than once. 402 403 const bool is_connected = IsConnected(); 404 405 bool fetch = false; 406 if (success) 407 { 408 // We have valid OS version info, check to make sure it wasn't 409 // manually set prior to connecting. If it was manually set prior 410 // to connecting, then lets fetch the actual OS version info 411 // if we are now connected. 412 if (is_connected && !m_os_version_set_while_connected) 413 fetch = true; 414 } 415 else 416 { 417 // We don't have valid OS version info, fetch it if we are connected 418 fetch = is_connected; 419 } 420 421 if (fetch) 422 { 423 success = GetRemoteOSVersion (); 424 m_os_version_set_while_connected = success; 425 } 426 } 427 428 if (success) 429 { 430 major = m_major_os_version; 431 minor = m_minor_os_version; 432 update = m_update_os_version; 433 } 434 return success; 435 } 436 437 bool 438 Platform::GetOSBuildString (std::string &s) 439 { 440 s.clear(); 441 442 if (IsHost()) 443 #if !defined(__linux__) 444 return HostInfo::GetOSBuildString(s); 445 #else 446 return false; 447 #endif 448 else 449 return GetRemoteOSBuildString (s); 450 } 451 452 bool 453 Platform::GetOSKernelDescription (std::string &s) 454 { 455 if (IsHost()) 456 #if !defined(__linux__) 457 return HostInfo::GetOSKernelDescription(s); 458 #else 459 return false; 460 #endif 461 else 462 return GetRemoteOSKernelDescription (s); 463 } 464 465 ConstString 466 Platform::GetWorkingDirectory () 467 { 468 if (IsHost()) 469 { 470 char cwd[PATH_MAX]; 471 if (getcwd(cwd, sizeof(cwd))) 472 return ConstString(cwd); 473 else 474 return ConstString(); 475 } 476 else 477 { 478 if (!m_working_dir) 479 m_working_dir = GetRemoteWorkingDirectory(); 480 return m_working_dir; 481 } 482 } 483 484 485 struct RecurseCopyBaton 486 { 487 const FileSpec& dst; 488 Platform *platform_ptr; 489 Error error; 490 }; 491 492 493 static FileSpec::EnumerateDirectoryResult 494 RecurseCopy_Callback (void *baton, 495 FileSpec::FileType file_type, 496 const FileSpec &src) 497 { 498 RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton; 499 switch (file_type) 500 { 501 case FileSpec::eFileTypePipe: 502 case FileSpec::eFileTypeSocket: 503 // we have no way to copy pipes and sockets - ignore them and continue 504 return FileSpec::eEnumerateDirectoryResultNext; 505 break; 506 507 case FileSpec::eFileTypeDirectory: 508 { 509 // make the new directory and get in there 510 FileSpec dst_dir = rc_baton->dst; 511 if (!dst_dir.GetFilename()) 512 dst_dir.GetFilename() = src.GetLastPathComponent(); 513 std::string dst_dir_path (dst_dir.GetPath()); 514 Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault); 515 if (error.Fail()) 516 { 517 rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str()); 518 return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out 519 } 520 521 // now recurse 522 std::string src_dir_path (src.GetPath()); 523 524 // Make a filespec that only fills in the directory of a FileSpec so 525 // when we enumerate we can quickly fill in the filename for dst copies 526 FileSpec recurse_dst; 527 recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); 528 RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() }; 529 FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2); 530 if (rc_baton2.error.Fail()) 531 { 532 rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); 533 return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out 534 } 535 return FileSpec::eEnumerateDirectoryResultNext; 536 } 537 break; 538 539 case FileSpec::eFileTypeSymbolicLink: 540 { 541 // copy the file and keep going 542 FileSpec dst_file = rc_baton->dst; 543 if (!dst_file.GetFilename()) 544 dst_file.GetFilename() = src.GetFilename(); 545 546 char buf[PATH_MAX]; 547 548 rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); 549 550 if (rc_baton->error.Fail()) 551 return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out 552 553 rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf); 554 555 if (rc_baton->error.Fail()) 556 return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out 557 558 return FileSpec::eEnumerateDirectoryResultNext; 559 } 560 break; 561 case FileSpec::eFileTypeRegular: 562 { 563 // copy the file and keep going 564 FileSpec dst_file = rc_baton->dst; 565 if (!dst_file.GetFilename()) 566 dst_file.GetFilename() = src.GetFilename(); 567 Error err = rc_baton->platform_ptr->PutFile(src, dst_file); 568 if (err.Fail()) 569 { 570 rc_baton->error.SetErrorString(err.AsCString()); 571 return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out 572 } 573 return FileSpec::eEnumerateDirectoryResultNext; 574 } 575 break; 576 577 case FileSpec::eFileTypeInvalid: 578 case FileSpec::eFileTypeOther: 579 case FileSpec::eFileTypeUnknown: 580 rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str()); 581 return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out 582 break; 583 } 584 llvm_unreachable("Unhandled FileSpec::FileType!"); 585 } 586 587 Error 588 Platform::Install (const FileSpec& src, const FileSpec& dst) 589 { 590 Error error; 591 592 Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); 593 if (log) 594 log->Printf ("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str()); 595 FileSpec fixed_dst(dst); 596 597 if (!fixed_dst.GetFilename()) 598 fixed_dst.GetFilename() = src.GetFilename(); 599 600 ConstString working_dir = GetWorkingDirectory(); 601 602 if (dst) 603 { 604 if (dst.GetDirectory()) 605 { 606 const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; 607 if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') 608 { 609 fixed_dst.GetDirectory() = dst.GetDirectory(); 610 } 611 // If the fixed destination file doesn't have a directory yet, 612 // then we must have a relative path. We will resolve this relative 613 // path against the platform's working directory 614 if (!fixed_dst.GetDirectory()) 615 { 616 FileSpec relative_spec; 617 std::string path; 618 if (working_dir) 619 { 620 relative_spec.SetFile(working_dir.GetCString(), false); 621 relative_spec.AppendPathComponent(dst.GetPath().c_str()); 622 fixed_dst.GetDirectory() = relative_spec.GetDirectory(); 623 } 624 else 625 { 626 error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); 627 return error; 628 } 629 } 630 } 631 else 632 { 633 if (working_dir) 634 { 635 fixed_dst.GetDirectory() = working_dir; 636 } 637 else 638 { 639 error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); 640 return error; 641 } 642 } 643 } 644 else 645 { 646 if (working_dir) 647 { 648 fixed_dst.GetDirectory() = working_dir; 649 } 650 else 651 { 652 error.SetErrorStringWithFormat("platform working directory must be valid when destination directory is empty"); 653 return error; 654 } 655 } 656 657 if (log) 658 log->Printf ("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", src.GetPath().c_str(), dst.GetPath().c_str(), fixed_dst.GetPath().c_str()); 659 660 if (GetSupportsRSync()) 661 { 662 error = PutFile(src, dst); 663 } 664 else 665 { 666 switch (src.GetFileType()) 667 { 668 case FileSpec::eFileTypeDirectory: 669 { 670 if (GetFileExists (fixed_dst)) 671 Unlink (fixed_dst.GetPath().c_str()); 672 uint32_t permissions = src.GetPermissions(); 673 if (permissions == 0) 674 permissions = eFilePermissionsDirectoryDefault; 675 std::string dst_dir_path(fixed_dst.GetPath()); 676 error = MakeDirectory(dst_dir_path.c_str(), permissions); 677 if (error.Success()) 678 { 679 // Make a filespec that only fills in the directory of a FileSpec so 680 // when we enumerate we can quickly fill in the filename for dst copies 681 FileSpec recurse_dst; 682 recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str()); 683 std::string src_dir_path (src.GetPath()); 684 RecurseCopyBaton baton = { recurse_dst, this, Error() }; 685 FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton); 686 return baton.error; 687 } 688 } 689 break; 690 691 case FileSpec::eFileTypeRegular: 692 if (GetFileExists (fixed_dst)) 693 Unlink (fixed_dst.GetPath().c_str()); 694 error = PutFile(src, fixed_dst); 695 break; 696 697 case FileSpec::eFileTypeSymbolicLink: 698 { 699 if (GetFileExists (fixed_dst)) 700 Unlink (fixed_dst.GetPath().c_str()); 701 char buf[PATH_MAX]; 702 error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); 703 if (error.Success()) 704 error = CreateSymlink(dst.GetPath().c_str(), buf); 705 } 706 break; 707 case FileSpec::eFileTypePipe: 708 error.SetErrorString("platform install doesn't handle pipes"); 709 break; 710 case FileSpec::eFileTypeSocket: 711 error.SetErrorString("platform install doesn't handle sockets"); 712 break; 713 case FileSpec::eFileTypeInvalid: 714 case FileSpec::eFileTypeUnknown: 715 case FileSpec::eFileTypeOther: 716 error.SetErrorString("platform install doesn't handle non file or directory items"); 717 break; 718 } 719 } 720 return error; 721 } 722 723 bool 724 Platform::SetWorkingDirectory (const ConstString &path) 725 { 726 if (IsHost()) 727 { 728 Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); 729 if (log) 730 log->Printf("Platform::SetWorkingDirectory('%s')", path.GetCString()); 731 #ifdef _WIN32 732 // Not implemented on Windows 733 return false; 734 #else 735 if (path) 736 { 737 if (chdir(path.GetCString()) == 0) 738 return true; 739 } 740 return false; 741 #endif 742 } 743 else 744 { 745 m_working_dir.Clear(); 746 return SetRemoteWorkingDirectory(path); 747 } 748 } 749 750 Error 751 Platform::MakeDirectory (const char *path, uint32_t permissions) 752 { 753 if (IsHost()) 754 return FileSystem::MakeDirectory(path, permissions); 755 else 756 { 757 Error error; 758 error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); 759 return error; 760 } 761 } 762 763 Error 764 Platform::GetFilePermissions (const char *path, uint32_t &file_permissions) 765 { 766 if (IsHost()) 767 return FileSystem::GetFilePermissions(path, file_permissions); 768 else 769 { 770 Error error; 771 error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); 772 return error; 773 } 774 } 775 776 Error 777 Platform::SetFilePermissions (const char *path, uint32_t file_permissions) 778 { 779 if (IsHost()) 780 return FileSystem::SetFilePermissions(path, file_permissions); 781 else 782 { 783 Error error; 784 error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); 785 return error; 786 } 787 } 788 789 ConstString 790 Platform::GetName () 791 { 792 return GetPluginName(); 793 } 794 795 const char * 796 Platform::GetHostname () 797 { 798 if (IsHost()) 799 return "127.0.0.1"; 800 801 if (m_name.empty()) 802 return NULL; 803 return m_name.c_str(); 804 } 805 806 bool 807 Platform::SetRemoteWorkingDirectory(const ConstString &path) 808 { 809 Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); 810 if (log) 811 log->Printf("Platform::SetRemoteWorkingDirectory('%s')", path.GetCString()); 812 m_working_dir = path; 813 return true; 814 } 815 816 const char * 817 Platform::GetUserName (uint32_t uid) 818 { 819 #if !defined(LLDB_DISABLE_POSIX) 820 const char *user_name = GetCachedUserName(uid); 821 if (user_name) 822 return user_name; 823 if (IsHost()) 824 { 825 std::string name; 826 if (HostInfo::LookupUserName(uid, name)) 827 return SetCachedUserName (uid, name.c_str(), name.size()); 828 } 829 #endif 830 return NULL; 831 } 832 833 const char * 834 Platform::GetGroupName (uint32_t gid) 835 { 836 #if !defined(LLDB_DISABLE_POSIX) 837 const char *group_name = GetCachedGroupName(gid); 838 if (group_name) 839 return group_name; 840 if (IsHost()) 841 { 842 std::string name; 843 if (HostInfo::LookupGroupName(gid, name)) 844 return SetCachedGroupName (gid, name.c_str(), name.size()); 845 } 846 #endif 847 return NULL; 848 } 849 850 bool 851 Platform::SetOSVersion (uint32_t major, 852 uint32_t minor, 853 uint32_t update) 854 { 855 if (IsHost()) 856 { 857 // We don't need anyone setting the OS version for the host platform, 858 // we should be able to figure it out by calling HostInfo::GetOSVersion(...). 859 return false; 860 } 861 else 862 { 863 // We have a remote platform, allow setting the target OS version if 864 // we aren't connected, since if we are connected, we should be able to 865 // request the remote OS version from the connected platform. 866 if (IsConnected()) 867 return false; 868 else 869 { 870 // We aren't connected and we might want to set the OS version 871 // ahead of time before we connect so we can peruse files and 872 // use a local SDK or PDK cache of support files to disassemble 873 // or do other things. 874 m_major_os_version = major; 875 m_minor_os_version = minor; 876 m_update_os_version = update; 877 return true; 878 } 879 } 880 return false; 881 } 882 883 884 Error 885 Platform::ResolveExecutable (const FileSpec &exe_file, 886 const ArchSpec &exe_arch, 887 lldb::ModuleSP &exe_module_sp, 888 const FileSpecList *module_search_paths_ptr) 889 { 890 Error error; 891 if (exe_file.Exists()) 892 { 893 ModuleSpec module_spec (exe_file, exe_arch); 894 if (module_spec.GetArchitecture().IsValid()) 895 { 896 error = ModuleList::GetSharedModule (module_spec, 897 exe_module_sp, 898 module_search_paths_ptr, 899 NULL, 900 NULL); 901 } 902 else 903 { 904 // No valid architecture was specified, ask the platform for 905 // the architectures that we should be using (in the correct order) 906 // and see if we can find a match that way 907 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx) 908 { 909 error = ModuleList::GetSharedModule (module_spec, 910 exe_module_sp, 911 module_search_paths_ptr, 912 NULL, 913 NULL); 914 // Did we find an executable using one of the 915 if (error.Success() && exe_module_sp) 916 break; 917 } 918 } 919 } 920 else 921 { 922 error.SetErrorStringWithFormat ("'%s' does not exist", 923 exe_file.GetPath().c_str()); 924 } 925 return error; 926 } 927 928 Error 929 Platform::ResolveSymbolFile (Target &target, 930 const ModuleSpec &sym_spec, 931 FileSpec &sym_file) 932 { 933 Error error; 934 if (sym_spec.GetSymbolFileSpec().Exists()) 935 sym_file = sym_spec.GetSymbolFileSpec(); 936 else 937 error.SetErrorString("unable to resolve symbol file"); 938 return error; 939 940 } 941 942 943 944 bool 945 Platform::ResolveRemotePath (const FileSpec &platform_path, 946 FileSpec &resolved_platform_path) 947 { 948 resolved_platform_path = platform_path; 949 return resolved_platform_path.ResolvePath(); 950 } 951 952 953 const ArchSpec & 954 Platform::GetSystemArchitecture() 955 { 956 if (IsHost()) 957 { 958 if (!m_system_arch.IsValid()) 959 { 960 // We have a local host platform 961 m_system_arch = HostInfo::GetArchitecture(); 962 m_system_arch_set_while_connected = m_system_arch.IsValid(); 963 } 964 } 965 else 966 { 967 // We have a remote platform. We can only fetch the remote 968 // system architecture if we are connected, and we don't want to do it 969 // more than once. 970 971 const bool is_connected = IsConnected(); 972 973 bool fetch = false; 974 if (m_system_arch.IsValid()) 975 { 976 // We have valid OS version info, check to make sure it wasn't 977 // manually set prior to connecting. If it was manually set prior 978 // to connecting, then lets fetch the actual OS version info 979 // if we are now connected. 980 if (is_connected && !m_system_arch_set_while_connected) 981 fetch = true; 982 } 983 else 984 { 985 // We don't have valid OS version info, fetch it if we are connected 986 fetch = is_connected; 987 } 988 989 if (fetch) 990 { 991 m_system_arch = GetRemoteSystemArchitecture (); 992 m_system_arch_set_while_connected = m_system_arch.IsValid(); 993 } 994 } 995 return m_system_arch; 996 } 997 998 999 Error 1000 Platform::ConnectRemote (Args& args) 1001 { 1002 Error error; 1003 if (IsHost()) 1004 error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString()); 1005 else 1006 error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetPluginName().GetCString()); 1007 return error; 1008 } 1009 1010 Error 1011 Platform::DisconnectRemote () 1012 { 1013 Error error; 1014 if (IsHost()) 1015 error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString()); 1016 else 1017 error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetPluginName().GetCString()); 1018 return error; 1019 } 1020 1021 bool 1022 Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 1023 { 1024 // Take care of the host case so that each subclass can just 1025 // call this function to get the host functionality. 1026 if (IsHost()) 1027 return Host::GetProcessInfo (pid, process_info); 1028 return false; 1029 } 1030 1031 uint32_t 1032 Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info, 1033 ProcessInstanceInfoList &process_infos) 1034 { 1035 // Take care of the host case so that each subclass can just 1036 // call this function to get the host functionality. 1037 uint32_t match_count = 0; 1038 if (IsHost()) 1039 match_count = Host::FindProcesses (match_info, process_infos); 1040 return match_count; 1041 } 1042 1043 1044 Error 1045 Platform::LaunchProcess (ProcessLaunchInfo &launch_info) 1046 { 1047 Error error; 1048 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 1049 if (log) 1050 log->Printf ("Platform::%s()", __FUNCTION__); 1051 1052 // Take care of the host case so that each subclass can just 1053 // call this function to get the host functionality. 1054 if (IsHost()) 1055 { 1056 if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY")) 1057 launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY); 1058 1059 if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell)) 1060 { 1061 const bool is_localhost = true; 1062 const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); 1063 const bool first_arg_is_full_shell_command = false; 1064 uint32_t num_resumes = GetResumeCountForLaunchInfo (launch_info); 1065 if (log) 1066 log->Printf ("Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 ", shell is '%s'", 1067 __FUNCTION__, 1068 num_resumes, 1069 launch_info.GetShell () ? launch_info.GetShell () : "<null>"); 1070 1071 if (!launch_info.ConvertArgumentsForLaunchingInShell (error, 1072 is_localhost, 1073 will_debug, 1074 first_arg_is_full_shell_command, 1075 num_resumes)) 1076 return error; 1077 } 1078 1079 if (log) 1080 log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ()); 1081 1082 error = Host::LaunchProcess (launch_info); 1083 } 1084 else 1085 error.SetErrorString ("base lldb_private::Platform class can't launch remote processes"); 1086 return error; 1087 } 1088 1089 lldb::ProcessSP 1090 Platform::DebugProcess (ProcessLaunchInfo &launch_info, 1091 Debugger &debugger, 1092 Target *target, // Can be NULL, if NULL create a new target, else use existing one 1093 Listener &listener, 1094 Error &error) 1095 { 1096 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 1097 if (log) 1098 log->Printf ("Platform::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target)); 1099 1100 ProcessSP process_sp; 1101 // Make sure we stop at the entry point 1102 launch_info.GetFlags ().Set (eLaunchFlagDebug); 1103 // We always launch the process we are going to debug in a separate process 1104 // group, since then we can handle ^C interrupts ourselves w/o having to worry 1105 // about the target getting them as well. 1106 launch_info.SetLaunchInSeparateProcessGroup(true); 1107 1108 error = LaunchProcess (launch_info); 1109 if (error.Success()) 1110 { 1111 if (log) 1112 log->Printf ("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")", __FUNCTION__, launch_info.GetProcessID ()); 1113 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) 1114 { 1115 ProcessAttachInfo attach_info (launch_info); 1116 process_sp = Attach (attach_info, debugger, target, listener, error); 1117 if (process_sp) 1118 { 1119 if (log) 1120 log->Printf ("Platform::%s Attach() succeeded, Process plugin: %s", __FUNCTION__, process_sp->GetPluginName ().AsCString ()); 1121 launch_info.SetHijackListener(attach_info.GetHijackListener()); 1122 1123 // Since we attached to the process, it will think it needs to detach 1124 // if the process object just goes away without an explicit call to 1125 // Process::Kill() or Process::Detach(), so let it know to kill the 1126 // process if this happens. 1127 process_sp->SetShouldDetach (false); 1128 1129 // If we didn't have any file actions, the pseudo terminal might 1130 // have been used where the slave side was given as the file to 1131 // open for stdin/out/err after we have already opened the master 1132 // so we can read/write stdin/out/err. 1133 int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); 1134 if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) 1135 { 1136 process_sp->SetSTDIOFileDescriptor(pty_fd); 1137 } 1138 } 1139 else 1140 { 1141 if (log) 1142 log->Printf ("Platform::%s Attach() failed: %s", __FUNCTION__, error.AsCString ()); 1143 } 1144 } 1145 else 1146 { 1147 if (log) 1148 log->Printf ("Platform::%s LaunchProcess() returned launch_info with invalid process id", __FUNCTION__); 1149 } 1150 } 1151 else 1152 { 1153 if (log) 1154 log->Printf ("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, error.AsCString ()); 1155 } 1156 1157 return process_sp; 1158 } 1159 1160 1161 lldb::PlatformSP 1162 Platform::GetPlatformForArchitecture (const ArchSpec &arch, ArchSpec *platform_arch_ptr) 1163 { 1164 lldb::PlatformSP platform_sp; 1165 Error error; 1166 if (arch.IsValid()) 1167 platform_sp = Platform::Create (arch, platform_arch_ptr, error); 1168 return platform_sp; 1169 } 1170 1171 1172 //------------------------------------------------------------------ 1173 /// Lets a platform answer if it is compatible with a given 1174 /// architecture and the target triple contained within. 1175 //------------------------------------------------------------------ 1176 bool 1177 Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, ArchSpec *compatible_arch_ptr) 1178 { 1179 // If the architecture is invalid, we must answer true... 1180 if (arch.IsValid()) 1181 { 1182 ArchSpec platform_arch; 1183 // Try for an exact architecture match first. 1184 if (exact_arch_match) 1185 { 1186 for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx) 1187 { 1188 if (arch.IsExactMatch(platform_arch)) 1189 { 1190 if (compatible_arch_ptr) 1191 *compatible_arch_ptr = platform_arch; 1192 return true; 1193 } 1194 } 1195 } 1196 else 1197 { 1198 for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx) 1199 { 1200 if (arch.IsCompatibleMatch(platform_arch)) 1201 { 1202 if (compatible_arch_ptr) 1203 *compatible_arch_ptr = platform_arch; 1204 return true; 1205 } 1206 } 1207 } 1208 } 1209 if (compatible_arch_ptr) 1210 compatible_arch_ptr->Clear(); 1211 return false; 1212 } 1213 1214 Error 1215 Platform::PutFile (const FileSpec& source, 1216 const FileSpec& destination, 1217 uint32_t uid, 1218 uint32_t gid) 1219 { 1220 Error error("unimplemented"); 1221 return error; 1222 } 1223 1224 Error 1225 Platform::GetFile (const FileSpec& source, 1226 const FileSpec& destination) 1227 { 1228 Error error("unimplemented"); 1229 return error; 1230 } 1231 1232 Error 1233 Platform::CreateSymlink (const char *src, // The name of the link is in src 1234 const char *dst)// The symlink points to dst 1235 { 1236 Error error("unimplemented"); 1237 return error; 1238 } 1239 1240 bool 1241 Platform::GetFileExists (const lldb_private::FileSpec& file_spec) 1242 { 1243 return false; 1244 } 1245 1246 Error 1247 Platform::Unlink (const char *path) 1248 { 1249 Error error("unimplemented"); 1250 return error; 1251 } 1252 1253 1254 1255 lldb_private::Error 1256 Platform::RunShellCommand (const char *command, // Shouldn't be NULL 1257 const char *working_dir, // Pass NULL to use the current working directory 1258 int *status_ptr, // Pass NULL if you don't want the process exit status 1259 int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit 1260 std::string *command_output, // Pass NULL if you don't want the command output 1261 uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish 1262 { 1263 if (IsHost()) 1264 return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); 1265 else 1266 return Error("unimplemented"); 1267 } 1268 1269 1270 bool 1271 Platform::CalculateMD5 (const FileSpec& file_spec, 1272 uint64_t &low, 1273 uint64_t &high) 1274 { 1275 if (IsHost()) 1276 return FileSystem::CalculateMD5(file_spec, low, high); 1277 else 1278 return false; 1279 } 1280 1281 Error 1282 Platform::LaunchNativeProcess ( 1283 ProcessLaunchInfo &launch_info, 1284 lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, 1285 NativeProcessProtocolSP &process_sp) 1286 { 1287 // Platforms should override this implementation if they want to 1288 // support lldb-gdbserver. 1289 return Error("unimplemented"); 1290 } 1291 1292 Error 1293 Platform::AttachNativeProcess (lldb::pid_t pid, 1294 lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, 1295 NativeProcessProtocolSP &process_sp) 1296 { 1297 // Platforms should override this implementation if they want to 1298 // support lldb-gdbserver. 1299 return Error("unimplemented"); 1300 } 1301 1302 void 1303 Platform::SetLocalCacheDirectory (const char* local) 1304 { 1305 m_local_cache_directory.assign(local); 1306 } 1307 1308 const char* 1309 Platform::GetLocalCacheDirectory () 1310 { 1311 return m_local_cache_directory.c_str(); 1312 } 1313 1314 static OptionDefinition 1315 g_rsync_option_table[] = 1316 { 1317 { LLDB_OPT_SET_ALL, false, "rsync" , 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Enable rsync." }, 1318 { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." }, 1319 { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." }, 1320 { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Do not automatically fill in the remote hostname when composing the rsync command." }, 1321 }; 1322 1323 static OptionDefinition 1324 g_ssh_option_table[] = 1325 { 1326 { LLDB_OPT_SET_ALL, false, "ssh" , 's', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Enable SSH." }, 1327 { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific options required for SSH to work." }, 1328 }; 1329 1330 static OptionDefinition 1331 g_caching_option_table[] = 1332 { 1333 { LLDB_OPT_SET_ALL, false, "local-cache-dir" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePath , "Path in which to store local copies of files." }, 1334 }; 1335 1336 OptionGroupPlatformRSync::OptionGroupPlatformRSync () 1337 { 1338 } 1339 1340 OptionGroupPlatformRSync::~OptionGroupPlatformRSync () 1341 { 1342 } 1343 1344 const lldb_private::OptionDefinition* 1345 OptionGroupPlatformRSync::GetDefinitions () 1346 { 1347 return g_rsync_option_table; 1348 } 1349 1350 void 1351 OptionGroupPlatformRSync::OptionParsingStarting (CommandInterpreter &interpreter) 1352 { 1353 m_rsync = false; 1354 m_rsync_opts.clear(); 1355 m_rsync_prefix.clear(); 1356 m_ignores_remote_hostname = false; 1357 } 1358 1359 lldb_private::Error 1360 OptionGroupPlatformRSync::SetOptionValue (CommandInterpreter &interpreter, 1361 uint32_t option_idx, 1362 const char *option_arg) 1363 { 1364 Error error; 1365 char short_option = (char) GetDefinitions()[option_idx].short_option; 1366 switch (short_option) 1367 { 1368 case 'r': 1369 m_rsync = true; 1370 break; 1371 1372 case 'R': 1373 m_rsync_opts.assign(option_arg); 1374 break; 1375 1376 case 'P': 1377 m_rsync_prefix.assign(option_arg); 1378 break; 1379 1380 case 'i': 1381 m_ignores_remote_hostname = true; 1382 break; 1383 1384 default: 1385 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1386 break; 1387 } 1388 1389 return error; 1390 } 1391 1392 uint32_t 1393 OptionGroupPlatformRSync::GetNumDefinitions () 1394 { 1395 return llvm::array_lengthof(g_rsync_option_table); 1396 } 1397 1398 lldb::BreakpointSP 1399 Platform::SetThreadCreationBreakpoint (lldb_private::Target &target) 1400 { 1401 return lldb::BreakpointSP(); 1402 } 1403 1404 OptionGroupPlatformSSH::OptionGroupPlatformSSH () 1405 { 1406 } 1407 1408 OptionGroupPlatformSSH::~OptionGroupPlatformSSH () 1409 { 1410 } 1411 1412 const lldb_private::OptionDefinition* 1413 OptionGroupPlatformSSH::GetDefinitions () 1414 { 1415 return g_ssh_option_table; 1416 } 1417 1418 void 1419 OptionGroupPlatformSSH::OptionParsingStarting (CommandInterpreter &interpreter) 1420 { 1421 m_ssh = false; 1422 m_ssh_opts.clear(); 1423 } 1424 1425 lldb_private::Error 1426 OptionGroupPlatformSSH::SetOptionValue (CommandInterpreter &interpreter, 1427 uint32_t option_idx, 1428 const char *option_arg) 1429 { 1430 Error error; 1431 char short_option = (char) GetDefinitions()[option_idx].short_option; 1432 switch (short_option) 1433 { 1434 case 's': 1435 m_ssh = true; 1436 break; 1437 1438 case 'S': 1439 m_ssh_opts.assign(option_arg); 1440 break; 1441 1442 default: 1443 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1444 break; 1445 } 1446 1447 return error; 1448 } 1449 1450 uint32_t 1451 OptionGroupPlatformSSH::GetNumDefinitions () 1452 { 1453 return llvm::array_lengthof(g_ssh_option_table); 1454 } 1455 1456 OptionGroupPlatformCaching::OptionGroupPlatformCaching () 1457 { 1458 } 1459 1460 OptionGroupPlatformCaching::~OptionGroupPlatformCaching () 1461 { 1462 } 1463 1464 const lldb_private::OptionDefinition* 1465 OptionGroupPlatformCaching::GetDefinitions () 1466 { 1467 return g_caching_option_table; 1468 } 1469 1470 void 1471 OptionGroupPlatformCaching::OptionParsingStarting (CommandInterpreter &interpreter) 1472 { 1473 m_cache_dir.clear(); 1474 } 1475 1476 lldb_private::Error 1477 OptionGroupPlatformCaching::SetOptionValue (CommandInterpreter &interpreter, 1478 uint32_t option_idx, 1479 const char *option_arg) 1480 { 1481 Error error; 1482 char short_option = (char) GetDefinitions()[option_idx].short_option; 1483 switch (short_option) 1484 { 1485 case 'c': 1486 m_cache_dir.assign(option_arg); 1487 break; 1488 1489 default: 1490 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1491 break; 1492 } 1493 1494 return error; 1495 } 1496 1497 uint32_t 1498 OptionGroupPlatformCaching::GetNumDefinitions () 1499 { 1500 return llvm::array_lengthof(g_caching_option_table); 1501 } 1502 1503 size_t 1504 Platform::GetEnvironment (StringList &environment) 1505 { 1506 environment.Clear(); 1507 return false; 1508 } 1509 1510 const std::vector<ConstString> & 1511 Platform::GetTrapHandlerSymbolNames () 1512 { 1513 if (!m_calculated_trap_handlers) 1514 { 1515 Mutex::Locker locker (m_trap_handler_mutex); 1516 if (!m_calculated_trap_handlers) 1517 { 1518 CalculateTrapHandlerSymbolNames(); 1519 m_calculated_trap_handlers = true; 1520 } 1521 } 1522 return m_trap_handlers; 1523 } 1524 1525