1 //===-- Platform.cpp ------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <algorithm> 10 #include <csignal> 11 #include <fstream> 12 #include <memory> 13 #include <vector> 14 15 #include "lldb/Breakpoint/BreakpointIDList.h" 16 #include "lldb/Breakpoint/BreakpointLocation.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/ModuleSpec.h" 20 #include "lldb/Core/PluginManager.h" 21 #include "lldb/Core/StreamFile.h" 22 #include "lldb/Host/FileSystem.h" 23 #include "lldb/Host/Host.h" 24 #include "lldb/Host/HostInfo.h" 25 #include "lldb/Host/OptionParser.h" 26 #include "lldb/Interpreter/OptionValueFileSpec.h" 27 #include "lldb/Interpreter/OptionValueProperties.h" 28 #include "lldb/Interpreter/Property.h" 29 #include "lldb/Symbol/ObjectFile.h" 30 #include "lldb/Target/ModuleCache.h" 31 #include "lldb/Target/Platform.h" 32 #include "lldb/Target/Process.h" 33 #include "lldb/Target/Target.h" 34 #include "lldb/Target/UnixSignals.h" 35 #include "lldb/Utility/DataBufferHeap.h" 36 #include "lldb/Utility/FileSpec.h" 37 #include "lldb/Utility/LLDBLog.h" 38 #include "lldb/Utility/Log.h" 39 #include "lldb/Utility/Status.h" 40 #include "lldb/Utility/StructuredData.h" 41 #include "llvm/Support/FileSystem.h" 42 #include "llvm/Support/Path.h" 43 44 // Define these constants from POSIX mman.h rather than include the file so 45 // that they will be correct even when compiled on Linux. 46 #define MAP_PRIVATE 2 47 #define MAP_ANON 0x1000 48 49 using namespace lldb; 50 using namespace lldb_private; 51 52 // Use a singleton function for g_local_platform_sp to avoid init constructors 53 // since LLDB is often part of a shared library 54 static PlatformSP &GetHostPlatformSP() { 55 static PlatformSP g_platform_sp; 56 return g_platform_sp; 57 } 58 59 const char *Platform::GetHostPlatformName() { return "host"; } 60 61 namespace { 62 63 #define LLDB_PROPERTIES_platform 64 #include "TargetProperties.inc" 65 66 enum { 67 #define LLDB_PROPERTIES_platform 68 #include "TargetPropertiesEnum.inc" 69 }; 70 71 } // namespace 72 73 ConstString PlatformProperties::GetSettingName() { 74 static ConstString g_setting_name("platform"); 75 return g_setting_name; 76 } 77 78 PlatformProperties::PlatformProperties() { 79 m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); 80 m_collection_sp->Initialize(g_platform_properties); 81 82 auto module_cache_dir = GetModuleCacheDirectory(); 83 if (module_cache_dir) 84 return; 85 86 llvm::SmallString<64> user_home_dir; 87 if (!FileSystem::Instance().GetHomeDirectory(user_home_dir)) 88 return; 89 90 module_cache_dir = FileSpec(user_home_dir.c_str()); 91 module_cache_dir.AppendPathComponent(".lldb"); 92 module_cache_dir.AppendPathComponent("module_cache"); 93 SetDefaultModuleCacheDirectory(module_cache_dir); 94 SetModuleCacheDirectory(module_cache_dir); 95 } 96 97 bool PlatformProperties::GetUseModuleCache() const { 98 const auto idx = ePropertyUseModuleCache; 99 return m_collection_sp->GetPropertyAtIndexAsBoolean( 100 nullptr, idx, g_platform_properties[idx].default_uint_value != 0); 101 } 102 103 bool PlatformProperties::SetUseModuleCache(bool use_module_cache) { 104 return m_collection_sp->SetPropertyAtIndexAsBoolean( 105 nullptr, ePropertyUseModuleCache, use_module_cache); 106 } 107 108 FileSpec PlatformProperties::GetModuleCacheDirectory() const { 109 return m_collection_sp->GetPropertyAtIndexAsFileSpec( 110 nullptr, ePropertyModuleCacheDirectory); 111 } 112 113 bool PlatformProperties::SetModuleCacheDirectory(const FileSpec &dir_spec) { 114 return m_collection_sp->SetPropertyAtIndexAsFileSpec( 115 nullptr, ePropertyModuleCacheDirectory, dir_spec); 116 } 117 118 void PlatformProperties::SetDefaultModuleCacheDirectory( 119 const FileSpec &dir_spec) { 120 auto f_spec_opt = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec( 121 nullptr, false, ePropertyModuleCacheDirectory); 122 assert(f_spec_opt); 123 f_spec_opt->SetDefaultValue(dir_spec); 124 } 125 126 /// Get the native host platform plug-in. 127 /// 128 /// There should only be one of these for each host that LLDB runs 129 /// upon that should be statically compiled in and registered using 130 /// preprocessor macros or other similar build mechanisms. 131 /// 132 /// This platform will be used as the default platform when launching 133 /// or attaching to processes unless another platform is specified. 134 PlatformSP Platform::GetHostPlatform() { return GetHostPlatformSP(); } 135 136 void Platform::Initialize() {} 137 138 void Platform::Terminate() {} 139 140 PlatformProperties &Platform::GetGlobalPlatformProperties() { 141 static PlatformProperties g_settings; 142 return g_settings; 143 } 144 145 void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) { 146 // The native platform should use its static void Platform::Initialize() 147 // function to register itself as the native platform. 148 GetHostPlatformSP() = platform_sp; 149 } 150 151 Status Platform::GetFileWithUUID(const FileSpec &platform_file, 152 const UUID *uuid_ptr, FileSpec &local_file) { 153 // Default to the local case 154 local_file = platform_file; 155 return Status(); 156 } 157 158 FileSpecList 159 Platform::LocateExecutableScriptingResources(Target *target, Module &module, 160 Stream *feedback_stream) { 161 return FileSpecList(); 162 } 163 164 // PlatformSP 165 // Platform::FindPlugin (Process *process, ConstString plugin_name) 166 //{ 167 // PlatformCreateInstance create_callback = nullptr; 168 // if (plugin_name) 169 // { 170 // create_callback = 171 // PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); 172 // if (create_callback) 173 // { 174 // ArchSpec arch; 175 // if (process) 176 // { 177 // arch = process->GetTarget().GetArchitecture(); 178 // } 179 // PlatformSP platform_sp(create_callback(process, &arch)); 180 // if (platform_sp) 181 // return platform_sp; 182 // } 183 // } 184 // else 185 // { 186 // for (uint32_t idx = 0; (create_callback = 187 // PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != nullptr; 188 // ++idx) 189 // { 190 // PlatformSP platform_sp(create_callback(process, nullptr)); 191 // if (platform_sp) 192 // return platform_sp; 193 // } 194 // } 195 // return PlatformSP(); 196 //} 197 198 Status Platform::GetSharedModule( 199 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, 200 const FileSpecList *module_search_paths_ptr, 201 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) { 202 if (IsHost()) 203 return ModuleList::GetSharedModule(module_spec, module_sp, 204 module_search_paths_ptr, old_modules, 205 did_create_ptr, false); 206 207 // Module resolver lambda. 208 auto resolver = [&](const ModuleSpec &spec) { 209 Status error(eErrorTypeGeneric); 210 ModuleSpec resolved_spec; 211 // Check if we have sysroot set. 212 if (m_sdk_sysroot) { 213 // Prepend sysroot to module spec. 214 resolved_spec = spec; 215 resolved_spec.GetFileSpec().PrependPathComponent( 216 m_sdk_sysroot.GetStringRef()); 217 // Try to get shared module with resolved spec. 218 error = ModuleList::GetSharedModule(resolved_spec, module_sp, 219 module_search_paths_ptr, old_modules, 220 did_create_ptr, false); 221 } 222 // If we don't have sysroot or it didn't work then 223 // try original module spec. 224 if (!error.Success()) { 225 resolved_spec = spec; 226 error = ModuleList::GetSharedModule(resolved_spec, module_sp, 227 module_search_paths_ptr, old_modules, 228 did_create_ptr, false); 229 } 230 if (error.Success() && module_sp) 231 module_sp->SetPlatformFileSpec(resolved_spec.GetFileSpec()); 232 return error; 233 }; 234 235 return GetRemoteSharedModule(module_spec, process, module_sp, resolver, 236 did_create_ptr); 237 } 238 239 bool Platform::GetModuleSpec(const FileSpec &module_file_spec, 240 const ArchSpec &arch, ModuleSpec &module_spec) { 241 ModuleSpecList module_specs; 242 if (ObjectFile::GetModuleSpecifications(module_file_spec, 0, 0, 243 module_specs) == 0) 244 return false; 245 246 ModuleSpec matched_module_spec; 247 return module_specs.FindMatchingModuleSpec(ModuleSpec(module_file_spec, arch), 248 module_spec); 249 } 250 251 PlatformSP Platform::Create(llvm::StringRef name) { 252 lldb::PlatformSP platform_sp; 253 if (name == GetHostPlatformName()) 254 return GetHostPlatform(); 255 256 if (PlatformCreateInstance create_callback = 257 PluginManager::GetPlatformCreateCallbackForPluginName(name)) 258 return create_callback(true, nullptr); 259 return nullptr; 260 } 261 262 ArchSpec Platform::GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple) { 263 if (platform) 264 return platform->GetAugmentedArchSpec(triple); 265 return HostInfo::GetAugmentedArchSpec(triple); 266 } 267 268 /// Default Constructor 269 Platform::Platform(bool is_host) 270 : m_is_host(is_host), m_os_version_set_while_connected(false), 271 m_system_arch_set_while_connected(false), m_max_uid_name_len(0), 272 m_max_gid_name_len(0), m_supports_rsync(false), m_rsync_opts(), 273 m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(), 274 m_ignores_remote_hostname(false), m_trap_handlers(), 275 m_calculated_trap_handlers(false), 276 m_module_cache(std::make_unique<ModuleCache>()) { 277 Log *log = GetLog(LLDBLog::Object); 278 LLDB_LOGF(log, "%p Platform::Platform()", static_cast<void *>(this)); 279 } 280 281 Platform::~Platform() = default; 282 283 void Platform::GetStatus(Stream &strm) { 284 strm.Format(" Platform: {0}\n", GetPluginName()); 285 286 ArchSpec arch(GetSystemArchitecture()); 287 if (arch.IsValid()) { 288 if (!arch.GetTriple().str().empty()) { 289 strm.Printf(" Triple: "); 290 arch.DumpTriple(strm.AsRawOstream()); 291 strm.EOL(); 292 } 293 } 294 295 llvm::VersionTuple os_version = GetOSVersion(); 296 if (!os_version.empty()) { 297 strm.Format("OS Version: {0}", os_version.getAsString()); 298 299 if (llvm::Optional<std::string> s = GetOSBuildString()) 300 strm.Format(" ({0})", *s); 301 302 strm.EOL(); 303 } 304 305 if (IsHost()) { 306 strm.Printf(" Hostname: %s\n", GetHostname()); 307 } else { 308 const bool is_connected = IsConnected(); 309 if (is_connected) 310 strm.Printf(" Hostname: %s\n", GetHostname()); 311 strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); 312 } 313 314 if (GetSDKRootDirectory()) { 315 strm.Format(" Sysroot: {0}\n", GetSDKRootDirectory()); 316 } 317 if (GetWorkingDirectory()) { 318 strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); 319 } 320 if (!IsConnected()) 321 return; 322 323 std::string specific_info(GetPlatformSpecificConnectionInformation()); 324 325 if (!specific_info.empty()) 326 strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); 327 328 if (llvm::Optional<std::string> s = GetOSKernelDescription()) 329 strm.Format(" Kernel: {0}\n", *s); 330 } 331 332 llvm::VersionTuple Platform::GetOSVersion(Process *process) { 333 std::lock_guard<std::mutex> guard(m_mutex); 334 335 if (IsHost()) { 336 if (m_os_version.empty()) { 337 // We have a local host platform 338 m_os_version = HostInfo::GetOSVersion(); 339 m_os_version_set_while_connected = !m_os_version.empty(); 340 } 341 } else { 342 // We have a remote platform. We can only fetch the remote 343 // OS version if we are connected, and we don't want to do it 344 // more than once. 345 346 const bool is_connected = IsConnected(); 347 348 bool fetch = false; 349 if (!m_os_version.empty()) { 350 // We have valid OS version info, check to make sure it wasn't manually 351 // set prior to connecting. If it was manually set prior to connecting, 352 // then lets fetch the actual OS version info if we are now connected. 353 if (is_connected && !m_os_version_set_while_connected) 354 fetch = true; 355 } else { 356 // We don't have valid OS version info, fetch it if we are connected 357 fetch = is_connected; 358 } 359 360 if (fetch) 361 m_os_version_set_while_connected = GetRemoteOSVersion(); 362 } 363 364 if (!m_os_version.empty()) 365 return m_os_version; 366 if (process) { 367 // Check with the process in case it can answer the question if a process 368 // was provided 369 return process->GetHostOSVersion(); 370 } 371 return llvm::VersionTuple(); 372 } 373 374 llvm::Optional<std::string> Platform::GetOSBuildString() { 375 if (IsHost()) 376 return HostInfo::GetOSBuildString(); 377 return GetRemoteOSBuildString(); 378 } 379 380 llvm::Optional<std::string> Platform::GetOSKernelDescription() { 381 if (IsHost()) 382 return HostInfo::GetOSKernelDescription(); 383 return GetRemoteOSKernelDescription(); 384 } 385 386 void Platform::AddClangModuleCompilationOptions( 387 Target *target, std::vector<std::string> &options) { 388 std::vector<std::string> default_compilation_options = { 389 "-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc"}; 390 391 options.insert(options.end(), default_compilation_options.begin(), 392 default_compilation_options.end()); 393 } 394 395 FileSpec Platform::GetWorkingDirectory() { 396 if (IsHost()) { 397 llvm::SmallString<64> cwd; 398 if (llvm::sys::fs::current_path(cwd)) 399 return {}; 400 else { 401 FileSpec file_spec(cwd); 402 FileSystem::Instance().Resolve(file_spec); 403 return file_spec; 404 } 405 } else { 406 if (!m_working_dir) 407 m_working_dir = GetRemoteWorkingDirectory(); 408 return m_working_dir; 409 } 410 } 411 412 struct RecurseCopyBaton { 413 const FileSpec &dst; 414 Platform *platform_ptr; 415 Status error; 416 }; 417 418 static FileSystem::EnumerateDirectoryResult 419 RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, 420 llvm::StringRef path) { 421 RecurseCopyBaton *rc_baton = (RecurseCopyBaton *)baton; 422 FileSpec src(path); 423 namespace fs = llvm::sys::fs; 424 switch (ft) { 425 case fs::file_type::fifo_file: 426 case fs::file_type::socket_file: 427 // we have no way to copy pipes and sockets - ignore them and continue 428 return FileSystem::eEnumerateDirectoryResultNext; 429 break; 430 431 case fs::file_type::directory_file: { 432 // make the new directory and get in there 433 FileSpec dst_dir = rc_baton->dst; 434 if (!dst_dir.GetFilename()) 435 dst_dir.GetFilename() = src.GetLastPathComponent(); 436 Status error = rc_baton->platform_ptr->MakeDirectory( 437 dst_dir, lldb::eFilePermissionsDirectoryDefault); 438 if (error.Fail()) { 439 rc_baton->error.SetErrorStringWithFormat( 440 "unable to setup directory %s on remote end", dst_dir.GetCString()); 441 return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out 442 } 443 444 // now recurse 445 std::string src_dir_path(src.GetPath()); 446 447 // Make a filespec that only fills in the directory of a FileSpec so when 448 // we enumerate we can quickly fill in the filename for dst copies 449 FileSpec recurse_dst; 450 recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); 451 RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr, 452 Status()}; 453 FileSystem::Instance().EnumerateDirectory(src_dir_path, true, true, true, 454 RecurseCopy_Callback, &rc_baton2); 455 if (rc_baton2.error.Fail()) { 456 rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); 457 return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out 458 } 459 return FileSystem::eEnumerateDirectoryResultNext; 460 } break; 461 462 case fs::file_type::symlink_file: { 463 // copy the file and keep going 464 FileSpec dst_file = rc_baton->dst; 465 if (!dst_file.GetFilename()) 466 dst_file.GetFilename() = src.GetFilename(); 467 468 FileSpec src_resolved; 469 470 rc_baton->error = FileSystem::Instance().Readlink(src, src_resolved); 471 472 if (rc_baton->error.Fail()) 473 return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out 474 475 rc_baton->error = 476 rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved); 477 478 if (rc_baton->error.Fail()) 479 return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out 480 481 return FileSystem::eEnumerateDirectoryResultNext; 482 } break; 483 484 case fs::file_type::regular_file: { 485 // copy the file and keep going 486 FileSpec dst_file = rc_baton->dst; 487 if (!dst_file.GetFilename()) 488 dst_file.GetFilename() = src.GetFilename(); 489 Status err = rc_baton->platform_ptr->PutFile(src, dst_file); 490 if (err.Fail()) { 491 rc_baton->error.SetErrorString(err.AsCString()); 492 return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out 493 } 494 return FileSystem::eEnumerateDirectoryResultNext; 495 } break; 496 497 default: 498 rc_baton->error.SetErrorStringWithFormat( 499 "invalid file detected during copy: %s", src.GetPath().c_str()); 500 return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out 501 break; 502 } 503 llvm_unreachable("Unhandled file_type!"); 504 } 505 506 Status Platform::Install(const FileSpec &src, const FileSpec &dst) { 507 Status error; 508 509 Log *log = GetLog(LLDBLog::Platform); 510 LLDB_LOGF(log, "Platform::Install (src='%s', dst='%s')", 511 src.GetPath().c_str(), dst.GetPath().c_str()); 512 FileSpec fixed_dst(dst); 513 514 if (!fixed_dst.GetFilename()) 515 fixed_dst.GetFilename() = src.GetFilename(); 516 517 FileSpec working_dir = GetWorkingDirectory(); 518 519 if (dst) { 520 if (dst.GetDirectory()) { 521 const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; 522 if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') { 523 fixed_dst.GetDirectory() = dst.GetDirectory(); 524 } 525 // If the fixed destination file doesn't have a directory yet, then we 526 // must have a relative path. We will resolve this relative path against 527 // the platform's working directory 528 if (!fixed_dst.GetDirectory()) { 529 FileSpec relative_spec; 530 std::string path; 531 if (working_dir) { 532 relative_spec = working_dir; 533 relative_spec.AppendPathComponent(dst.GetPath()); 534 fixed_dst.GetDirectory() = relative_spec.GetDirectory(); 535 } else { 536 error.SetErrorStringWithFormat( 537 "platform working directory must be valid for relative path '%s'", 538 dst.GetPath().c_str()); 539 return error; 540 } 541 } 542 } else { 543 if (working_dir) { 544 fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); 545 } else { 546 error.SetErrorStringWithFormat( 547 "platform working directory must be valid for relative path '%s'", 548 dst.GetPath().c_str()); 549 return error; 550 } 551 } 552 } else { 553 if (working_dir) { 554 fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); 555 } else { 556 error.SetErrorStringWithFormat("platform working directory must be valid " 557 "when destination directory is empty"); 558 return error; 559 } 560 } 561 562 LLDB_LOGF(log, "Platform::Install (src='%s', dst='%s') fixed_dst='%s'", 563 src.GetPath().c_str(), dst.GetPath().c_str(), 564 fixed_dst.GetPath().c_str()); 565 566 if (GetSupportsRSync()) { 567 error = PutFile(src, dst); 568 } else { 569 namespace fs = llvm::sys::fs; 570 switch (fs::get_file_type(src.GetPath(), false)) { 571 case fs::file_type::directory_file: { 572 llvm::sys::fs::remove(fixed_dst.GetPath()); 573 uint32_t permissions = FileSystem::Instance().GetPermissions(src); 574 if (permissions == 0) 575 permissions = eFilePermissionsDirectoryDefault; 576 error = MakeDirectory(fixed_dst, permissions); 577 if (error.Success()) { 578 // Make a filespec that only fills in the directory of a FileSpec so 579 // when we enumerate we can quickly fill in the filename for dst copies 580 FileSpec recurse_dst; 581 recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString()); 582 std::string src_dir_path(src.GetPath()); 583 RecurseCopyBaton baton = {recurse_dst, this, Status()}; 584 FileSystem::Instance().EnumerateDirectory( 585 src_dir_path, true, true, true, RecurseCopy_Callback, &baton); 586 return baton.error; 587 } 588 } break; 589 590 case fs::file_type::regular_file: 591 llvm::sys::fs::remove(fixed_dst.GetPath()); 592 error = PutFile(src, fixed_dst); 593 break; 594 595 case fs::file_type::symlink_file: { 596 llvm::sys::fs::remove(fixed_dst.GetPath()); 597 FileSpec src_resolved; 598 error = FileSystem::Instance().Readlink(src, src_resolved); 599 if (error.Success()) 600 error = CreateSymlink(dst, src_resolved); 601 } break; 602 case fs::file_type::fifo_file: 603 error.SetErrorString("platform install doesn't handle pipes"); 604 break; 605 case fs::file_type::socket_file: 606 error.SetErrorString("platform install doesn't handle sockets"); 607 break; 608 default: 609 error.SetErrorString( 610 "platform install doesn't handle non file or directory items"); 611 break; 612 } 613 } 614 return error; 615 } 616 617 bool Platform::SetWorkingDirectory(const FileSpec &file_spec) { 618 if (IsHost()) { 619 Log *log = GetLog(LLDBLog::Platform); 620 LLDB_LOG(log, "{0}", file_spec); 621 if (std::error_code ec = llvm::sys::fs::set_current_path(file_spec.GetPath())) { 622 LLDB_LOG(log, "error: {0}", ec.message()); 623 return false; 624 } 625 return true; 626 } else { 627 m_working_dir.Clear(); 628 return SetRemoteWorkingDirectory(file_spec); 629 } 630 } 631 632 Status Platform::MakeDirectory(const FileSpec &file_spec, 633 uint32_t permissions) { 634 if (IsHost()) 635 return llvm::sys::fs::create_directory(file_spec.GetPath(), permissions); 636 else { 637 Status error; 638 error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}", 639 GetPluginName(), LLVM_PRETTY_FUNCTION); 640 return error; 641 } 642 } 643 644 Status Platform::GetFilePermissions(const FileSpec &file_spec, 645 uint32_t &file_permissions) { 646 if (IsHost()) { 647 auto Value = llvm::sys::fs::getPermissions(file_spec.GetPath()); 648 if (Value) 649 file_permissions = Value.get(); 650 return Status(Value.getError()); 651 } else { 652 Status error; 653 error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}", 654 GetPluginName(), LLVM_PRETTY_FUNCTION); 655 return error; 656 } 657 } 658 659 Status Platform::SetFilePermissions(const FileSpec &file_spec, 660 uint32_t file_permissions) { 661 if (IsHost()) { 662 auto Perms = static_cast<llvm::sys::fs::perms>(file_permissions); 663 return llvm::sys::fs::setPermissions(file_spec.GetPath(), Perms); 664 } else { 665 Status error; 666 error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}", 667 GetPluginName(), LLVM_PRETTY_FUNCTION); 668 return error; 669 } 670 } 671 672 const char *Platform::GetHostname() { 673 if (IsHost()) 674 return "127.0.0.1"; 675 676 if (m_hostname.empty()) 677 return nullptr; 678 return m_hostname.c_str(); 679 } 680 681 ConstString Platform::GetFullNameForDylib(ConstString basename) { 682 return basename; 683 } 684 685 bool Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) { 686 Log *log = GetLog(LLDBLog::Platform); 687 LLDB_LOGF(log, "Platform::SetRemoteWorkingDirectory('%s')", 688 working_dir.GetCString()); 689 m_working_dir = working_dir; 690 return true; 691 } 692 693 bool Platform::SetOSVersion(llvm::VersionTuple version) { 694 if (IsHost()) { 695 // We don't need anyone setting the OS version for the host platform, we 696 // should be able to figure it out by calling HostInfo::GetOSVersion(...). 697 return false; 698 } else { 699 // We have a remote platform, allow setting the target OS version if we 700 // aren't connected, since if we are connected, we should be able to 701 // request the remote OS version from the connected platform. 702 if (IsConnected()) 703 return false; 704 else { 705 // We aren't connected and we might want to set the OS version ahead of 706 // time before we connect so we can peruse files and use a local SDK or 707 // PDK cache of support files to disassemble or do other things. 708 m_os_version = version; 709 return true; 710 } 711 } 712 return false; 713 } 714 715 Status 716 Platform::ResolveExecutable(const ModuleSpec &module_spec, 717 lldb::ModuleSP &exe_module_sp, 718 const FileSpecList *module_search_paths_ptr) { 719 Status error; 720 721 if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { 722 if (module_spec.GetArchitecture().IsValid()) { 723 error = ModuleList::GetSharedModule(module_spec, exe_module_sp, 724 module_search_paths_ptr, nullptr, 725 nullptr); 726 } else { 727 // No valid architecture was specified, ask the platform for the 728 // architectures that we should be using (in the correct order) and see 729 // if we can find a match that way 730 ModuleSpec arch_module_spec(module_spec); 731 for (const ArchSpec &arch : GetSupportedArchitectures()) { 732 arch_module_spec.GetArchitecture() = arch; 733 error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp, 734 module_search_paths_ptr, nullptr, 735 nullptr); 736 // Did we find an executable using one of the 737 if (error.Success() && exe_module_sp) 738 break; 739 } 740 } 741 } else { 742 error.SetErrorStringWithFormat( 743 "'%s' does not exist", module_spec.GetFileSpec().GetPath().c_str()); 744 } 745 return error; 746 } 747 748 Status 749 Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec, 750 lldb::ModuleSP &exe_module_sp, 751 const FileSpecList *module_search_paths_ptr) { 752 Status error; 753 754 // We may connect to a process and use the provided executable (Don't use 755 // local $PATH). 756 ModuleSpec resolved_module_spec(module_spec); 757 758 // Resolve any executable within a bundle on MacOSX 759 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 760 761 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) || 762 module_spec.GetUUID().IsValid()) { 763 if (resolved_module_spec.GetArchitecture().IsValid() || 764 resolved_module_spec.GetUUID().IsValid()) { 765 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 766 module_search_paths_ptr, nullptr, 767 nullptr); 768 769 if (exe_module_sp && exe_module_sp->GetObjectFile()) 770 return error; 771 exe_module_sp.reset(); 772 } 773 // No valid architecture was specified or the exact arch wasn't found so 774 // ask the platform for the architectures that we should be using (in the 775 // correct order) and see if we can find a match that way 776 StreamString arch_names; 777 llvm::ListSeparator LS; 778 for (const ArchSpec &arch : GetSupportedArchitectures()) { 779 resolved_module_spec.GetArchitecture() = arch; 780 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 781 module_search_paths_ptr, nullptr, 782 nullptr); 783 // Did we find an executable using one of the 784 if (error.Success()) { 785 if (exe_module_sp && exe_module_sp->GetObjectFile()) 786 break; 787 else 788 error.SetErrorToGenericError(); 789 } 790 791 arch_names << LS << arch.GetArchitectureName(); 792 } 793 794 if (error.Fail() || !exe_module_sp) { 795 if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) { 796 error.SetErrorStringWithFormatv( 797 "'{0}' doesn't contain any '{1}' platform architectures: {2}", 798 resolved_module_spec.GetFileSpec(), GetPluginName(), 799 arch_names.GetData()); 800 } else { 801 error.SetErrorStringWithFormatv("'{0}' is not readable", 802 resolved_module_spec.GetFileSpec()); 803 } 804 } 805 } else { 806 error.SetErrorStringWithFormatv("'{0}' does not exist", 807 resolved_module_spec.GetFileSpec()); 808 } 809 810 return error; 811 } 812 813 Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, 814 FileSpec &sym_file) { 815 Status error; 816 if (FileSystem::Instance().Exists(sym_spec.GetSymbolFileSpec())) 817 sym_file = sym_spec.GetSymbolFileSpec(); 818 else 819 error.SetErrorString("unable to resolve symbol file"); 820 return error; 821 } 822 823 bool Platform::ResolveRemotePath(const FileSpec &platform_path, 824 FileSpec &resolved_platform_path) { 825 resolved_platform_path = platform_path; 826 FileSystem::Instance().Resolve(resolved_platform_path); 827 return true; 828 } 829 830 const ArchSpec &Platform::GetSystemArchitecture() { 831 if (IsHost()) { 832 if (!m_system_arch.IsValid()) { 833 // We have a local host platform 834 m_system_arch = HostInfo::GetArchitecture(); 835 m_system_arch_set_while_connected = m_system_arch.IsValid(); 836 } 837 } else { 838 // We have a remote platform. We can only fetch the remote system 839 // architecture if we are connected, and we don't want to do it more than 840 // once. 841 842 const bool is_connected = IsConnected(); 843 844 bool fetch = false; 845 if (m_system_arch.IsValid()) { 846 // We have valid OS version info, check to make sure it wasn't manually 847 // set prior to connecting. If it was manually set prior to connecting, 848 // then lets fetch the actual OS version info if we are now connected. 849 if (is_connected && !m_system_arch_set_while_connected) 850 fetch = true; 851 } else { 852 // We don't have valid OS version info, fetch it if we are connected 853 fetch = is_connected; 854 } 855 856 if (fetch) { 857 m_system_arch = GetRemoteSystemArchitecture(); 858 m_system_arch_set_while_connected = m_system_arch.IsValid(); 859 } 860 } 861 return m_system_arch; 862 } 863 864 ArchSpec Platform::GetAugmentedArchSpec(llvm::StringRef triple) { 865 if (triple.empty()) 866 return ArchSpec(); 867 llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); 868 if (!ArchSpec::ContainsOnlyArch(normalized_triple)) 869 return ArchSpec(triple); 870 871 if (auto kind = HostInfo::ParseArchitectureKind(triple)) 872 return HostInfo::GetArchitecture(*kind); 873 874 ArchSpec compatible_arch; 875 ArchSpec raw_arch(triple); 876 if (!IsCompatibleArchitecture(raw_arch, false, &compatible_arch)) 877 return raw_arch; 878 879 if (!compatible_arch.IsValid()) 880 return ArchSpec(normalized_triple); 881 882 const llvm::Triple &compatible_triple = compatible_arch.GetTriple(); 883 if (normalized_triple.getVendorName().empty()) 884 normalized_triple.setVendor(compatible_triple.getVendor()); 885 if (normalized_triple.getOSName().empty()) 886 normalized_triple.setOS(compatible_triple.getOS()); 887 if (normalized_triple.getEnvironmentName().empty()) 888 normalized_triple.setEnvironment(compatible_triple.getEnvironment()); 889 return ArchSpec(normalized_triple); 890 } 891 892 Status Platform::ConnectRemote(Args &args) { 893 Status error; 894 if (IsHost()) 895 error.SetErrorStringWithFormatv( 896 "The currently selected platform ({0}) is " 897 "the host platform and is always connected.", 898 GetPluginName()); 899 else 900 error.SetErrorStringWithFormatv( 901 "Platform::ConnectRemote() is not supported by {0}", GetPluginName()); 902 return error; 903 } 904 905 Status Platform::DisconnectRemote() { 906 Status error; 907 if (IsHost()) 908 error.SetErrorStringWithFormatv( 909 "The currently selected platform ({0}) is " 910 "the host platform and is always connected.", 911 GetPluginName()); 912 else 913 error.SetErrorStringWithFormatv( 914 "Platform::DisconnectRemote() is not supported by {0}", 915 GetPluginName()); 916 return error; 917 } 918 919 bool Platform::GetProcessInfo(lldb::pid_t pid, 920 ProcessInstanceInfo &process_info) { 921 // Take care of the host case so that each subclass can just call this 922 // function to get the host functionality. 923 if (IsHost()) 924 return Host::GetProcessInfo(pid, process_info); 925 return false; 926 } 927 928 uint32_t Platform::FindProcesses(const ProcessInstanceInfoMatch &match_info, 929 ProcessInstanceInfoList &process_infos) { 930 // Take care of the host case so that each subclass can just call this 931 // function to get the host functionality. 932 uint32_t match_count = 0; 933 if (IsHost()) 934 match_count = Host::FindProcesses(match_info, process_infos); 935 return match_count; 936 } 937 938 Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) { 939 Status error; 940 Log *log = GetLog(LLDBLog::Platform); 941 LLDB_LOGF(log, "Platform::%s()", __FUNCTION__); 942 943 // Take care of the host case so that each subclass can just call this 944 // function to get the host functionality. 945 if (IsHost()) { 946 if (::getenv("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY")) 947 launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); 948 949 if (launch_info.GetFlags().Test(eLaunchFlagLaunchInShell)) { 950 const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); 951 const bool first_arg_is_full_shell_command = false; 952 uint32_t num_resumes = GetResumeCountForLaunchInfo(launch_info); 953 if (log) { 954 const FileSpec &shell = launch_info.GetShell(); 955 std::string shell_str = (shell) ? shell.GetPath() : "<null>"; 956 LLDB_LOGF(log, 957 "Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 958 ", shell is '%s'", 959 __FUNCTION__, num_resumes, shell_str.c_str()); 960 } 961 962 if (!launch_info.ConvertArgumentsForLaunchingInShell( 963 error, will_debug, first_arg_is_full_shell_command, num_resumes)) 964 return error; 965 } else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { 966 error = ShellExpandArguments(launch_info); 967 if (error.Fail()) { 968 error.SetErrorStringWithFormat("shell expansion failed (reason: %s). " 969 "consider launching with 'process " 970 "launch'.", 971 error.AsCString("unknown")); 972 return error; 973 } 974 } 975 976 LLDB_LOGF(log, "Platform::%s final launch_info resume count: %" PRIu32, 977 __FUNCTION__, launch_info.GetResumeCount()); 978 979 error = Host::LaunchProcess(launch_info); 980 } else 981 error.SetErrorString( 982 "base lldb_private::Platform class can't launch remote processes"); 983 return error; 984 } 985 986 Status Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 987 if (IsHost()) 988 return Host::ShellExpandArguments(launch_info); 989 return Status("base lldb_private::Platform class can't expand arguments"); 990 } 991 992 Status Platform::KillProcess(const lldb::pid_t pid) { 993 Log *log = GetLog(LLDBLog::Platform); 994 LLDB_LOGF(log, "Platform::%s, pid %" PRIu64, __FUNCTION__, pid); 995 996 if (!IsHost()) { 997 return Status( 998 "base lldb_private::Platform class can't kill remote processes"); 999 } 1000 Host::Kill(pid, SIGKILL); 1001 return Status(); 1002 } 1003 1004 lldb::ProcessSP Platform::DebugProcess(ProcessLaunchInfo &launch_info, 1005 Debugger &debugger, Target &target, 1006 Status &error) { 1007 Log *log = GetLog(LLDBLog::Platform); 1008 LLDB_LOG(log, "target = {0})", &target); 1009 1010 ProcessSP process_sp; 1011 // Make sure we stop at the entry point 1012 launch_info.GetFlags().Set(eLaunchFlagDebug); 1013 // We always launch the process we are going to debug in a separate process 1014 // group, since then we can handle ^C interrupts ourselves w/o having to 1015 // worry about the target getting them as well. 1016 launch_info.SetLaunchInSeparateProcessGroup(true); 1017 1018 // Allow any StructuredData process-bound plugins to adjust the launch info 1019 // if needed 1020 size_t i = 0; 1021 bool iteration_complete = false; 1022 // Note iteration can't simply go until a nullptr callback is returned, as it 1023 // is valid for a plugin to not supply a filter. 1024 auto get_filter_func = PluginManager::GetStructuredDataFilterCallbackAtIndex; 1025 for (auto filter_callback = get_filter_func(i, iteration_complete); 1026 !iteration_complete; 1027 filter_callback = get_filter_func(++i, iteration_complete)) { 1028 if (filter_callback) { 1029 // Give this ProcessLaunchInfo filter a chance to adjust the launch info. 1030 error = (*filter_callback)(launch_info, &target); 1031 if (!error.Success()) { 1032 LLDB_LOGF(log, 1033 "Platform::%s() StructuredDataPlugin launch " 1034 "filter failed.", 1035 __FUNCTION__); 1036 return process_sp; 1037 } 1038 } 1039 } 1040 1041 error = LaunchProcess(launch_info); 1042 if (error.Success()) { 1043 LLDB_LOGF(log, 1044 "Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")", 1045 __FUNCTION__, launch_info.GetProcessID()); 1046 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { 1047 ProcessAttachInfo attach_info(launch_info); 1048 process_sp = Attach(attach_info, debugger, &target, error); 1049 if (process_sp) { 1050 LLDB_LOG(log, "Attach() succeeded, Process plugin: {0}", 1051 process_sp->GetPluginName()); 1052 launch_info.SetHijackListener(attach_info.GetHijackListener()); 1053 1054 // Since we attached to the process, it will think it needs to detach 1055 // if the process object just goes away without an explicit call to 1056 // Process::Kill() or Process::Detach(), so let it know to kill the 1057 // process if this happens. 1058 process_sp->SetShouldDetach(false); 1059 1060 // If we didn't have any file actions, the pseudo terminal might have 1061 // been used where the secondary side was given as the file to open for 1062 // stdin/out/err after we have already opened the primary so we can 1063 // read/write stdin/out/err. 1064 int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); 1065 if (pty_fd != PseudoTerminal::invalid_fd) { 1066 process_sp->SetSTDIOFileDescriptor(pty_fd); 1067 } 1068 } else { 1069 LLDB_LOGF(log, "Platform::%s Attach() failed: %s", __FUNCTION__, 1070 error.AsCString()); 1071 } 1072 } else { 1073 LLDB_LOGF(log, 1074 "Platform::%s LaunchProcess() returned launch_info with " 1075 "invalid process id", 1076 __FUNCTION__); 1077 } 1078 } else { 1079 LLDB_LOGF(log, "Platform::%s LaunchProcess() failed: %s", __FUNCTION__, 1080 error.AsCString()); 1081 } 1082 1083 return process_sp; 1084 } 1085 1086 std::vector<ArchSpec> 1087 Platform::CreateArchList(llvm::ArrayRef<llvm::Triple::ArchType> archs, 1088 llvm::Triple::OSType os) { 1089 std::vector<ArchSpec> list; 1090 for(auto arch : archs) { 1091 llvm::Triple triple; 1092 triple.setArch(arch); 1093 triple.setOS(os); 1094 list.push_back(ArchSpec(triple)); 1095 } 1096 return list; 1097 } 1098 1099 /// Lets a platform answer if it is compatible with a given 1100 /// architecture and the target triple contained within. 1101 bool Platform::IsCompatibleArchitecture(const ArchSpec &arch, 1102 bool exact_arch_match, 1103 ArchSpec *compatible_arch_ptr) { 1104 // If the architecture is invalid, we must answer true... 1105 if (arch.IsValid()) { 1106 ArchSpec platform_arch; 1107 auto match = exact_arch_match ? &ArchSpec::IsExactMatch 1108 : &ArchSpec::IsCompatibleMatch; 1109 for (const ArchSpec &platform_arch : GetSupportedArchitectures()) { 1110 if ((arch.*match)(platform_arch)) { 1111 if (compatible_arch_ptr) 1112 *compatible_arch_ptr = platform_arch; 1113 return true; 1114 } 1115 } 1116 } 1117 if (compatible_arch_ptr) 1118 compatible_arch_ptr->Clear(); 1119 return false; 1120 } 1121 1122 Status Platform::PutFile(const FileSpec &source, const FileSpec &destination, 1123 uint32_t uid, uint32_t gid) { 1124 Log *log = GetLog(LLDBLog::Platform); 1125 LLDB_LOGF(log, "[PutFile] Using block by block transfer....\n"); 1126 1127 auto source_open_options = 1128 File::eOpenOptionReadOnly | File::eOpenOptionCloseOnExec; 1129 namespace fs = llvm::sys::fs; 1130 if (fs::is_symlink_file(source.GetPath())) 1131 source_open_options |= File::eOpenOptionDontFollowSymlinks; 1132 1133 auto source_file = FileSystem::Instance().Open(source, source_open_options, 1134 lldb::eFilePermissionsUserRW); 1135 if (!source_file) 1136 return Status(source_file.takeError()); 1137 Status error; 1138 uint32_t permissions = source_file.get()->GetPermissions(error); 1139 if (permissions == 0) 1140 permissions = lldb::eFilePermissionsFileDefault; 1141 1142 lldb::user_id_t dest_file = OpenFile( 1143 destination, File::eOpenOptionCanCreate | File::eOpenOptionWriteOnly | 1144 File::eOpenOptionTruncate | File::eOpenOptionCloseOnExec, 1145 permissions, error); 1146 LLDB_LOGF(log, "dest_file = %" PRIu64 "\n", dest_file); 1147 1148 if (error.Fail()) 1149 return error; 1150 if (dest_file == UINT64_MAX) 1151 return Status("unable to open target file"); 1152 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024 * 16, 0)); 1153 uint64_t offset = 0; 1154 for (;;) { 1155 size_t bytes_read = buffer_sp->GetByteSize(); 1156 error = source_file.get()->Read(buffer_sp->GetBytes(), bytes_read); 1157 if (error.Fail() || bytes_read == 0) 1158 break; 1159 1160 const uint64_t bytes_written = 1161 WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); 1162 if (error.Fail()) 1163 break; 1164 1165 offset += bytes_written; 1166 if (bytes_written != bytes_read) { 1167 // We didn't write the correct number of bytes, so adjust the file 1168 // position in the source file we are reading from... 1169 source_file.get()->SeekFromStart(offset); 1170 } 1171 } 1172 CloseFile(dest_file, error); 1173 1174 if (uid == UINT32_MAX && gid == UINT32_MAX) 1175 return error; 1176 1177 // TODO: ChownFile? 1178 1179 return error; 1180 } 1181 1182 Status Platform::GetFile(const FileSpec &source, const FileSpec &destination) { 1183 Status error("unimplemented"); 1184 return error; 1185 } 1186 1187 Status 1188 Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src 1189 const FileSpec &dst) // The symlink points to dst 1190 { 1191 Status error("unimplemented"); 1192 return error; 1193 } 1194 1195 bool Platform::GetFileExists(const lldb_private::FileSpec &file_spec) { 1196 return false; 1197 } 1198 1199 Status Platform::Unlink(const FileSpec &path) { 1200 Status error("unimplemented"); 1201 return error; 1202 } 1203 1204 MmapArgList Platform::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, 1205 addr_t length, unsigned prot, 1206 unsigned flags, addr_t fd, 1207 addr_t offset) { 1208 uint64_t flags_platform = 0; 1209 if (flags & eMmapFlagsPrivate) 1210 flags_platform |= MAP_PRIVATE; 1211 if (flags & eMmapFlagsAnon) 1212 flags_platform |= MAP_ANON; 1213 1214 MmapArgList args({addr, length, prot, flags_platform, fd, offset}); 1215 return args; 1216 } 1217 1218 lldb_private::Status Platform::RunShellCommand( 1219 llvm::StringRef command, 1220 const FileSpec & 1221 working_dir, // Pass empty FileSpec to use the current working directory 1222 int *status_ptr, // Pass nullptr if you don't want the process exit status 1223 int *signo_ptr, // Pass nullptr if you don't want the signal that caused the 1224 // process to exit 1225 std::string 1226 *command_output, // Pass nullptr if you don't want the command output 1227 const Timeout<std::micro> &timeout) { 1228 return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr, 1229 signo_ptr, command_output, timeout); 1230 } 1231 1232 lldb_private::Status Platform::RunShellCommand( 1233 llvm::StringRef shell, // Pass empty if you want to use the default 1234 // shell interpreter 1235 llvm::StringRef command, // Shouldn't be empty 1236 const FileSpec & 1237 working_dir, // Pass empty FileSpec to use the current working directory 1238 int *status_ptr, // Pass nullptr if you don't want the process exit status 1239 int *signo_ptr, // Pass nullptr if you don't want the signal that caused the 1240 // process to exit 1241 std::string 1242 *command_output, // Pass nullptr if you don't want the command output 1243 const Timeout<std::micro> &timeout) { 1244 if (IsHost()) 1245 return Host::RunShellCommand(shell, command, working_dir, status_ptr, 1246 signo_ptr, command_output, timeout); 1247 else 1248 return Status("unimplemented"); 1249 } 1250 1251 bool Platform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, 1252 uint64_t &high) { 1253 if (!IsHost()) 1254 return false; 1255 auto Result = llvm::sys::fs::md5_contents(file_spec.GetPath()); 1256 if (!Result) 1257 return false; 1258 std::tie(high, low) = Result->words(); 1259 return true; 1260 } 1261 1262 void Platform::SetLocalCacheDirectory(const char *local) { 1263 m_local_cache_directory.assign(local); 1264 } 1265 1266 const char *Platform::GetLocalCacheDirectory() { 1267 return m_local_cache_directory.c_str(); 1268 } 1269 1270 static constexpr OptionDefinition g_rsync_option_table[] = { 1271 {LLDB_OPT_SET_ALL, false, "rsync", 'r', OptionParser::eNoArgument, nullptr, 1272 {}, 0, eArgTypeNone, "Enable rsync."}, 1273 {LLDB_OPT_SET_ALL, false, "rsync-opts", 'R', 1274 OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, 1275 "Platform-specific options required for rsync to work."}, 1276 {LLDB_OPT_SET_ALL, false, "rsync-prefix", 'P', 1277 OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, 1278 "Platform-specific rsync prefix put before the remote path."}, 1279 {LLDB_OPT_SET_ALL, false, "ignore-remote-hostname", 'i', 1280 OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, 1281 "Do not automatically fill in the remote hostname when composing the " 1282 "rsync command."}, 1283 }; 1284 1285 static constexpr OptionDefinition g_ssh_option_table[] = { 1286 {LLDB_OPT_SET_ALL, false, "ssh", 's', OptionParser::eNoArgument, nullptr, 1287 {}, 0, eArgTypeNone, "Enable SSH."}, 1288 {LLDB_OPT_SET_ALL, false, "ssh-opts", 'S', OptionParser::eRequiredArgument, 1289 nullptr, {}, 0, eArgTypeCommandName, 1290 "Platform-specific options required for SSH to work."}, 1291 }; 1292 1293 static constexpr OptionDefinition g_caching_option_table[] = { 1294 {LLDB_OPT_SET_ALL, false, "local-cache-dir", 'c', 1295 OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePath, 1296 "Path in which to store local copies of files."}, 1297 }; 1298 1299 llvm::ArrayRef<OptionDefinition> OptionGroupPlatformRSync::GetDefinitions() { 1300 return llvm::makeArrayRef(g_rsync_option_table); 1301 } 1302 1303 void OptionGroupPlatformRSync::OptionParsingStarting( 1304 ExecutionContext *execution_context) { 1305 m_rsync = false; 1306 m_rsync_opts.clear(); 1307 m_rsync_prefix.clear(); 1308 m_ignores_remote_hostname = false; 1309 } 1310 1311 lldb_private::Status 1312 OptionGroupPlatformRSync::SetOptionValue(uint32_t option_idx, 1313 llvm::StringRef option_arg, 1314 ExecutionContext *execution_context) { 1315 Status error; 1316 char short_option = (char)GetDefinitions()[option_idx].short_option; 1317 switch (short_option) { 1318 case 'r': 1319 m_rsync = true; 1320 break; 1321 1322 case 'R': 1323 m_rsync_opts.assign(std::string(option_arg)); 1324 break; 1325 1326 case 'P': 1327 m_rsync_prefix.assign(std::string(option_arg)); 1328 break; 1329 1330 case 'i': 1331 m_ignores_remote_hostname = true; 1332 break; 1333 1334 default: 1335 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 1336 break; 1337 } 1338 1339 return error; 1340 } 1341 1342 lldb::BreakpointSP 1343 Platform::SetThreadCreationBreakpoint(lldb_private::Target &target) { 1344 return lldb::BreakpointSP(); 1345 } 1346 1347 llvm::ArrayRef<OptionDefinition> OptionGroupPlatformSSH::GetDefinitions() { 1348 return llvm::makeArrayRef(g_ssh_option_table); 1349 } 1350 1351 void OptionGroupPlatformSSH::OptionParsingStarting( 1352 ExecutionContext *execution_context) { 1353 m_ssh = false; 1354 m_ssh_opts.clear(); 1355 } 1356 1357 lldb_private::Status 1358 OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx, 1359 llvm::StringRef option_arg, 1360 ExecutionContext *execution_context) { 1361 Status error; 1362 char short_option = (char)GetDefinitions()[option_idx].short_option; 1363 switch (short_option) { 1364 case 's': 1365 m_ssh = true; 1366 break; 1367 1368 case 'S': 1369 m_ssh_opts.assign(std::string(option_arg)); 1370 break; 1371 1372 default: 1373 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 1374 break; 1375 } 1376 1377 return error; 1378 } 1379 1380 llvm::ArrayRef<OptionDefinition> OptionGroupPlatformCaching::GetDefinitions() { 1381 return llvm::makeArrayRef(g_caching_option_table); 1382 } 1383 1384 void OptionGroupPlatformCaching::OptionParsingStarting( 1385 ExecutionContext *execution_context) { 1386 m_cache_dir.clear(); 1387 } 1388 1389 lldb_private::Status OptionGroupPlatformCaching::SetOptionValue( 1390 uint32_t option_idx, llvm::StringRef option_arg, 1391 ExecutionContext *execution_context) { 1392 Status error; 1393 char short_option = (char)GetDefinitions()[option_idx].short_option; 1394 switch (short_option) { 1395 case 'c': 1396 m_cache_dir.assign(std::string(option_arg)); 1397 break; 1398 1399 default: 1400 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 1401 break; 1402 } 1403 1404 return error; 1405 } 1406 1407 Environment Platform::GetEnvironment() { return Environment(); } 1408 1409 const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() { 1410 if (!m_calculated_trap_handlers) { 1411 std::lock_guard<std::mutex> guard(m_mutex); 1412 if (!m_calculated_trap_handlers) { 1413 CalculateTrapHandlerSymbolNames(); 1414 m_calculated_trap_handlers = true; 1415 } 1416 } 1417 return m_trap_handlers; 1418 } 1419 1420 Status 1421 Platform::GetCachedExecutable(ModuleSpec &module_spec, 1422 lldb::ModuleSP &module_sp, 1423 const FileSpecList *module_search_paths_ptr) { 1424 FileSpec platform_spec = module_spec.GetFileSpec(); 1425 Status error = GetRemoteSharedModule( 1426 module_spec, nullptr, module_sp, 1427 [&](const ModuleSpec &spec) { 1428 return ResolveRemoteExecutable(spec, module_sp, 1429 module_search_paths_ptr); 1430 }, 1431 nullptr); 1432 if (error.Success()) { 1433 module_spec.GetFileSpec() = module_sp->GetFileSpec(); 1434 module_spec.GetPlatformFileSpec() = platform_spec; 1435 } 1436 1437 return error; 1438 } 1439 1440 Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, 1441 Process *process, 1442 lldb::ModuleSP &module_sp, 1443 const ModuleResolver &module_resolver, 1444 bool *did_create_ptr) { 1445 // Get module information from a target. 1446 ModuleSpec resolved_module_spec; 1447 bool got_module_spec = false; 1448 if (process) { 1449 // Try to get module information from the process 1450 if (process->GetModuleSpec(module_spec.GetFileSpec(), 1451 module_spec.GetArchitecture(), 1452 resolved_module_spec)) { 1453 if (!module_spec.GetUUID().IsValid() || 1454 module_spec.GetUUID() == resolved_module_spec.GetUUID()) { 1455 got_module_spec = true; 1456 } 1457 } 1458 } 1459 1460 if (!module_spec.GetArchitecture().IsValid()) { 1461 Status error; 1462 // No valid architecture was specified, ask the platform for the 1463 // architectures that we should be using (in the correct order) and see if 1464 // we can find a match that way 1465 ModuleSpec arch_module_spec(module_spec); 1466 for (const ArchSpec &arch : GetSupportedArchitectures()) { 1467 arch_module_spec.GetArchitecture() = arch; 1468 error = ModuleList::GetSharedModule(arch_module_spec, module_sp, nullptr, 1469 nullptr, nullptr); 1470 // Did we find an executable using one of the 1471 if (error.Success() && module_sp) 1472 break; 1473 } 1474 if (module_sp) { 1475 resolved_module_spec = arch_module_spec; 1476 got_module_spec = true; 1477 } 1478 } 1479 1480 if (!got_module_spec) { 1481 // Get module information from a target. 1482 if (GetModuleSpec(module_spec.GetFileSpec(), module_spec.GetArchitecture(), 1483 resolved_module_spec)) { 1484 if (!module_spec.GetUUID().IsValid() || 1485 module_spec.GetUUID() == resolved_module_spec.GetUUID()) { 1486 got_module_spec = true; 1487 } 1488 } 1489 } 1490 1491 if (!got_module_spec) { 1492 // Fall back to the given module resolver, which may have its own 1493 // search logic. 1494 return module_resolver(module_spec); 1495 } 1496 1497 // If we are looking for a specific UUID, make sure resolved_module_spec has 1498 // the same one before we search. 1499 if (module_spec.GetUUID().IsValid()) { 1500 resolved_module_spec.GetUUID() = module_spec.GetUUID(); 1501 } 1502 1503 // Trying to find a module by UUID on local file system. 1504 const auto error = module_resolver(resolved_module_spec); 1505 if (error.Fail()) { 1506 if (GetCachedSharedModule(resolved_module_spec, module_sp, did_create_ptr)) 1507 return Status(); 1508 } 1509 1510 return error; 1511 } 1512 1513 bool Platform::GetCachedSharedModule(const ModuleSpec &module_spec, 1514 lldb::ModuleSP &module_sp, 1515 bool *did_create_ptr) { 1516 if (IsHost() || !GetGlobalPlatformProperties().GetUseModuleCache() || 1517 !GetGlobalPlatformProperties().GetModuleCacheDirectory()) 1518 return false; 1519 1520 Log *log = GetLog(LLDBLog::Platform); 1521 1522 // Check local cache for a module. 1523 auto error = m_module_cache->GetAndPut( 1524 GetModuleCacheRoot(), GetCacheHostname(), module_spec, 1525 [this](const ModuleSpec &module_spec, 1526 const FileSpec &tmp_download_file_spec) { 1527 return DownloadModuleSlice( 1528 module_spec.GetFileSpec(), module_spec.GetObjectOffset(), 1529 module_spec.GetObjectSize(), tmp_download_file_spec); 1530 1531 }, 1532 [this](const ModuleSP &module_sp, 1533 const FileSpec &tmp_download_file_spec) { 1534 return DownloadSymbolFile(module_sp, tmp_download_file_spec); 1535 }, 1536 module_sp, did_create_ptr); 1537 if (error.Success()) 1538 return true; 1539 1540 LLDB_LOGF(log, "Platform::%s - module %s not found in local cache: %s", 1541 __FUNCTION__, module_spec.GetUUID().GetAsString().c_str(), 1542 error.AsCString()); 1543 return false; 1544 } 1545 1546 Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec, 1547 const uint64_t src_offset, 1548 const uint64_t src_size, 1549 const FileSpec &dst_file_spec) { 1550 Status error; 1551 1552 std::error_code EC; 1553 llvm::raw_fd_ostream dst(dst_file_spec.GetPath(), EC, llvm::sys::fs::OF_None); 1554 if (EC) { 1555 error.SetErrorStringWithFormat("unable to open destination file: %s", 1556 dst_file_spec.GetPath().c_str()); 1557 return error; 1558 } 1559 1560 auto src_fd = OpenFile(src_file_spec, File::eOpenOptionReadOnly, 1561 lldb::eFilePermissionsFileDefault, error); 1562 1563 if (error.Fail()) { 1564 error.SetErrorStringWithFormat("unable to open source file: %s", 1565 error.AsCString()); 1566 return error; 1567 } 1568 1569 std::vector<char> buffer(1024); 1570 auto offset = src_offset; 1571 uint64_t total_bytes_read = 0; 1572 while (total_bytes_read < src_size) { 1573 const auto to_read = std::min(static_cast<uint64_t>(buffer.size()), 1574 src_size - total_bytes_read); 1575 const uint64_t n_read = 1576 ReadFile(src_fd, offset, &buffer[0], to_read, error); 1577 if (error.Fail()) 1578 break; 1579 if (n_read == 0) { 1580 error.SetErrorString("read 0 bytes"); 1581 break; 1582 } 1583 offset += n_read; 1584 total_bytes_read += n_read; 1585 dst.write(&buffer[0], n_read); 1586 } 1587 1588 Status close_error; 1589 CloseFile(src_fd, close_error); // Ignoring close error. 1590 1591 return error; 1592 } 1593 1594 Status Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp, 1595 const FileSpec &dst_file_spec) { 1596 return Status( 1597 "Symbol file downloading not supported by the default platform."); 1598 } 1599 1600 FileSpec Platform::GetModuleCacheRoot() { 1601 auto dir_spec = GetGlobalPlatformProperties().GetModuleCacheDirectory(); 1602 dir_spec.AppendPathComponent(GetPluginName()); 1603 return dir_spec; 1604 } 1605 1606 const char *Platform::GetCacheHostname() { return GetHostname(); } 1607 1608 const UnixSignalsSP &Platform::GetRemoteUnixSignals() { 1609 static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>(); 1610 return s_default_unix_signals_sp; 1611 } 1612 1613 UnixSignalsSP Platform::GetUnixSignals() { 1614 if (IsHost()) 1615 return UnixSignals::CreateForHost(); 1616 return GetRemoteUnixSignals(); 1617 } 1618 1619 uint32_t Platform::LoadImage(lldb_private::Process *process, 1620 const lldb_private::FileSpec &local_file, 1621 const lldb_private::FileSpec &remote_file, 1622 lldb_private::Status &error) { 1623 if (local_file && remote_file) { 1624 // Both local and remote file was specified. Install the local file to the 1625 // given location. 1626 if (IsRemote() || local_file != remote_file) { 1627 error = Install(local_file, remote_file); 1628 if (error.Fail()) 1629 return LLDB_INVALID_IMAGE_TOKEN; 1630 } 1631 return DoLoadImage(process, remote_file, nullptr, error); 1632 } 1633 1634 if (local_file) { 1635 // Only local file was specified. Install it to the current working 1636 // directory. 1637 FileSpec target_file = GetWorkingDirectory(); 1638 target_file.AppendPathComponent(local_file.GetFilename().AsCString()); 1639 if (IsRemote() || local_file != target_file) { 1640 error = Install(local_file, target_file); 1641 if (error.Fail()) 1642 return LLDB_INVALID_IMAGE_TOKEN; 1643 } 1644 return DoLoadImage(process, target_file, nullptr, error); 1645 } 1646 1647 if (remote_file) { 1648 // Only remote file was specified so we don't have to do any copying 1649 return DoLoadImage(process, remote_file, nullptr, error); 1650 } 1651 1652 error.SetErrorString("Neither local nor remote file was specified"); 1653 return LLDB_INVALID_IMAGE_TOKEN; 1654 } 1655 1656 uint32_t Platform::DoLoadImage(lldb_private::Process *process, 1657 const lldb_private::FileSpec &remote_file, 1658 const std::vector<std::string> *paths, 1659 lldb_private::Status &error, 1660 lldb_private::FileSpec *loaded_image) { 1661 error.SetErrorString("LoadImage is not supported on the current platform"); 1662 return LLDB_INVALID_IMAGE_TOKEN; 1663 } 1664 1665 uint32_t Platform::LoadImageUsingPaths(lldb_private::Process *process, 1666 const lldb_private::FileSpec &remote_filename, 1667 const std::vector<std::string> &paths, 1668 lldb_private::Status &error, 1669 lldb_private::FileSpec *loaded_path) 1670 { 1671 FileSpec file_to_use; 1672 if (remote_filename.IsAbsolute()) 1673 file_to_use = FileSpec(remote_filename.GetFilename().GetStringRef(), 1674 1675 remote_filename.GetPathStyle()); 1676 else 1677 file_to_use = remote_filename; 1678 1679 return DoLoadImage(process, file_to_use, &paths, error, loaded_path); 1680 } 1681 1682 Status Platform::UnloadImage(lldb_private::Process *process, 1683 uint32_t image_token) { 1684 return Status("UnloadImage is not supported on the current platform"); 1685 } 1686 1687 lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url, 1688 llvm::StringRef plugin_name, 1689 Debugger &debugger, Target *target, 1690 Status &error) { 1691 return DoConnectProcess(connect_url, plugin_name, debugger, nullptr, target, 1692 error); 1693 } 1694 1695 lldb::ProcessSP Platform::ConnectProcessSynchronous( 1696 llvm::StringRef connect_url, llvm::StringRef plugin_name, 1697 Debugger &debugger, Stream &stream, Target *target, Status &error) { 1698 return DoConnectProcess(connect_url, plugin_name, debugger, &stream, target, 1699 error); 1700 } 1701 1702 lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url, 1703 llvm::StringRef plugin_name, 1704 Debugger &debugger, Stream *stream, 1705 Target *target, Status &error) { 1706 error.Clear(); 1707 1708 if (!target) { 1709 ArchSpec arch; 1710 if (target && target->GetArchitecture().IsValid()) 1711 arch = target->GetArchitecture(); 1712 else 1713 arch = Target::GetDefaultArchitecture(); 1714 1715 const char *triple = ""; 1716 if (arch.IsValid()) 1717 triple = arch.GetTriple().getTriple().c_str(); 1718 1719 TargetSP new_target_sp; 1720 error = debugger.GetTargetList().CreateTarget( 1721 debugger, "", triple, eLoadDependentsNo, nullptr, new_target_sp); 1722 target = new_target_sp.get(); 1723 } 1724 1725 if (!target || error.Fail()) 1726 return nullptr; 1727 1728 lldb::ProcessSP process_sp = 1729 target->CreateProcess(debugger.GetListener(), plugin_name, nullptr, true); 1730 1731 if (!process_sp) 1732 return nullptr; 1733 1734 // If this private method is called with a stream we are synchronous. 1735 const bool synchronous = stream != nullptr; 1736 1737 ListenerSP listener_sp( 1738 Listener::MakeListener("lldb.Process.ConnectProcess.hijack")); 1739 if (synchronous) 1740 process_sp->HijackProcessEvents(listener_sp); 1741 1742 error = process_sp->ConnectRemote(connect_url); 1743 if (error.Fail()) { 1744 if (synchronous) 1745 process_sp->RestoreProcessEvents(); 1746 return nullptr; 1747 } 1748 1749 if (synchronous) { 1750 EventSP event_sp; 1751 process_sp->WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp, 1752 nullptr); 1753 process_sp->RestoreProcessEvents(); 1754 bool pop_process_io_handler = false; 1755 Process::HandleProcessStateChangedEvent(event_sp, stream, 1756 pop_process_io_handler); 1757 } 1758 1759 return process_sp; 1760 } 1761 1762 size_t Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger, 1763 lldb_private::Status &error) { 1764 error.Clear(); 1765 return 0; 1766 } 1767 1768 size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, 1769 BreakpointSite *bp_site) { 1770 ArchSpec arch = target.GetArchitecture(); 1771 assert(arch.IsValid()); 1772 const uint8_t *trap_opcode = nullptr; 1773 size_t trap_opcode_size = 0; 1774 1775 switch (arch.GetMachine()) { 1776 case llvm::Triple::aarch64_32: 1777 case llvm::Triple::aarch64: { 1778 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4}; 1779 trap_opcode = g_aarch64_opcode; 1780 trap_opcode_size = sizeof(g_aarch64_opcode); 1781 } break; 1782 1783 case llvm::Triple::arc: { 1784 static const uint8_t g_hex_opcode[] = { 0xff, 0x7f }; 1785 trap_opcode = g_hex_opcode; 1786 trap_opcode_size = sizeof(g_hex_opcode); 1787 } break; 1788 1789 // TODO: support big-endian arm and thumb trap codes. 1790 case llvm::Triple::arm: { 1791 // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the 1792 // linux kernel does otherwise. 1793 static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; 1794 static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; 1795 1796 lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); 1797 AddressClass addr_class = AddressClass::eUnknown; 1798 1799 if (bp_loc_sp) { 1800 addr_class = bp_loc_sp->GetAddress().GetAddressClass(); 1801 if (addr_class == AddressClass::eUnknown && 1802 (bp_loc_sp->GetAddress().GetFileAddress() & 1)) 1803 addr_class = AddressClass::eCodeAlternateISA; 1804 } 1805 1806 if (addr_class == AddressClass::eCodeAlternateISA) { 1807 trap_opcode = g_thumb_breakpoint_opcode; 1808 trap_opcode_size = sizeof(g_thumb_breakpoint_opcode); 1809 } else { 1810 trap_opcode = g_arm_breakpoint_opcode; 1811 trap_opcode_size = sizeof(g_arm_breakpoint_opcode); 1812 } 1813 } break; 1814 1815 case llvm::Triple::avr: { 1816 static const uint8_t g_hex_opcode[] = {0x98, 0x95}; 1817 trap_opcode = g_hex_opcode; 1818 trap_opcode_size = sizeof(g_hex_opcode); 1819 } break; 1820 1821 case llvm::Triple::mips: 1822 case llvm::Triple::mips64: { 1823 static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d}; 1824 trap_opcode = g_hex_opcode; 1825 trap_opcode_size = sizeof(g_hex_opcode); 1826 } break; 1827 1828 case llvm::Triple::mipsel: 1829 case llvm::Triple::mips64el: { 1830 static const uint8_t g_hex_opcode[] = {0x0d, 0x00, 0x00, 0x00}; 1831 trap_opcode = g_hex_opcode; 1832 trap_opcode_size = sizeof(g_hex_opcode); 1833 } break; 1834 1835 case llvm::Triple::systemz: { 1836 static const uint8_t g_hex_opcode[] = {0x00, 0x01}; 1837 trap_opcode = g_hex_opcode; 1838 trap_opcode_size = sizeof(g_hex_opcode); 1839 } break; 1840 1841 case llvm::Triple::hexagon: { 1842 static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54}; 1843 trap_opcode = g_hex_opcode; 1844 trap_opcode_size = sizeof(g_hex_opcode); 1845 } break; 1846 1847 case llvm::Triple::ppc: 1848 case llvm::Triple::ppc64: { 1849 static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; 1850 trap_opcode = g_ppc_opcode; 1851 trap_opcode_size = sizeof(g_ppc_opcode); 1852 } break; 1853 1854 case llvm::Triple::ppc64le: { 1855 static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap 1856 trap_opcode = g_ppc64le_opcode; 1857 trap_opcode_size = sizeof(g_ppc64le_opcode); 1858 } break; 1859 1860 case llvm::Triple::x86: 1861 case llvm::Triple::x86_64: { 1862 static const uint8_t g_i386_opcode[] = {0xCC}; 1863 trap_opcode = g_i386_opcode; 1864 trap_opcode_size = sizeof(g_i386_opcode); 1865 } break; 1866 1867 default: 1868 return 0; 1869 } 1870 1871 assert(bp_site); 1872 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 1873 return trap_opcode_size; 1874 1875 return 0; 1876 } 1877 1878 CompilerType Platform::GetSiginfoType(const llvm::Triple& triple) { 1879 return CompilerType(); 1880 } 1881 1882 PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) { 1883 std::lock_guard<std::recursive_mutex> guard(m_mutex); 1884 for (const PlatformSP &platform_sp : m_platforms) { 1885 if (platform_sp->GetName() == name) 1886 return platform_sp; 1887 } 1888 return Create(name); 1889 } 1890 1891 PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch, 1892 ArchSpec *platform_arch_ptr, 1893 Status &error) { 1894 std::lock_guard<std::recursive_mutex> guard(m_mutex); 1895 // First try exact arch matches across all platforms already created 1896 for (const auto &platform_sp : m_platforms) { 1897 if (platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr)) 1898 return platform_sp; 1899 } 1900 1901 // Next try compatible arch matches across all platforms already created 1902 for (const auto &platform_sp : m_platforms) { 1903 if (platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr)) 1904 return platform_sp; 1905 } 1906 1907 PlatformCreateInstance create_callback; 1908 // First try exact arch matches across all platform plug-ins 1909 uint32_t idx; 1910 for (idx = 0; 1911 (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); 1912 ++idx) { 1913 PlatformSP platform_sp = create_callback(false, &arch); 1914 if (platform_sp && 1915 platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr)) { 1916 m_platforms.push_back(platform_sp); 1917 return platform_sp; 1918 } 1919 } 1920 // Next try compatible arch matches across all platform plug-ins 1921 for (idx = 0; 1922 (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); 1923 ++idx) { 1924 PlatformSP platform_sp = create_callback(false, &arch); 1925 if (platform_sp && 1926 platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr)) { 1927 m_platforms.push_back(platform_sp); 1928 return platform_sp; 1929 } 1930 } 1931 if (platform_arch_ptr) 1932 platform_arch_ptr->Clear(); 1933 return nullptr; 1934 } 1935 1936 PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch, 1937 ArchSpec *platform_arch_ptr) { 1938 Status error; 1939 if (arch.IsValid()) 1940 return GetOrCreate(arch, platform_arch_ptr, error); 1941 return nullptr; 1942 } 1943 1944 PlatformSP PlatformList::Create(llvm::StringRef name) { 1945 std::lock_guard<std::recursive_mutex> guard(m_mutex); 1946 PlatformSP platform_sp = Platform::Create(name); 1947 m_platforms.push_back(platform_sp); 1948 return platform_sp; 1949 } 1950