1//===-- HostInfoMacOSX.mm ---------------------------------------*- C++ -*-===// 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 "lldb/Host/macosx/HostInfoMacOSX.h" 10#include "Utility/UuidCompatibility.h" 11#include "lldb/Host/FileSystem.h" 12#include "lldb/Host/Host.h" 13#include "lldb/Host/HostInfo.h" 14#include "lldb/Utility/Args.h" 15#include "lldb/Utility/LLDBLog.h" 16#include "lldb/Utility/Log.h" 17#include "lldb/Utility/Timer.h" 18 19#include "llvm/ADT/ScopeExit.h" 20#include "llvm/ADT/SmallString.h" 21#include "llvm/ADT/StringMap.h" 22#include "llvm/Support/FileSystem.h" 23#include "llvm/Support/Path.h" 24#include "llvm/Support/raw_ostream.h" 25 26// C++ Includes 27#include <optional> 28#include <string> 29 30// C inclues 31#include <cstdlib> 32#include <sys/sysctl.h> 33#include <sys/syslimits.h> 34#include <sys/types.h> 35 36// Objective-C/C++ includes 37#include <CoreFoundation/CoreFoundation.h> 38#include <Foundation/Foundation.h> 39#include <mach-o/dyld.h> 40#if __has_include(<mach-o/dyld_introspection.h>) 41#include <mach-o/dyld_introspection.h> 42#define SDK_HAS_NEW_DYLD_INTROSPECTION_SPIS 43#endif 44#include <objc/objc-auto.h> 45 46// These are needed when compiling on systems 47// that do not yet have these definitions 48#include <AvailabilityMacros.h> 49#ifndef CPU_SUBTYPE_X86_64_H 50#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) 51#endif 52#ifndef CPU_TYPE_ARM64 53#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) 54#endif 55 56#ifndef CPU_TYPE_ARM64_32 57#define CPU_ARCH_ABI64_32 0x02000000 58#define CPU_TYPE_ARM64_32 (CPU_TYPE_ARM | CPU_ARCH_ABI64_32) 59#endif 60 61#include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH 62 63using namespace lldb_private; 64 65std::optional<std::string> HostInfoMacOSX::GetOSBuildString() { 66 int mib[2] = {CTL_KERN, KERN_OSVERSION}; 67 char cstr[PATH_MAX]; 68 size_t cstr_len = sizeof(cstr); 69 if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) 70 return std::string(cstr, cstr_len - 1); 71 72 return std::nullopt; 73} 74 75static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) { 76 @autoreleasepool { 77 NSDictionary *version_info = 78 [NSDictionary dictionaryWithContentsOfFile: 79 @"/System/Library/CoreServices/SystemVersion.plist"]; 80 NSString *version_value = [version_info objectForKey: Key]; 81 const char *version_str = [version_value UTF8String]; 82 version.tryParse(version_str); 83 } 84} 85 86llvm::VersionTuple HostInfoMacOSX::GetOSVersion() { 87 static llvm::VersionTuple g_version; 88 if (g_version.empty()) 89 ParseOSVersion(g_version, @"ProductVersion"); 90 return g_version; 91} 92 93llvm::VersionTuple HostInfoMacOSX::GetMacCatalystVersion() { 94 static llvm::VersionTuple g_version; 95 if (g_version.empty()) 96 ParseOSVersion(g_version, @"iOSSupportVersion"); 97 return g_version; 98} 99 100 101FileSpec HostInfoMacOSX::GetProgramFileSpec() { 102 static FileSpec g_program_filespec; 103 if (!g_program_filespec) { 104 char program_fullpath[PATH_MAX]; 105 // If DST is NULL, then return the number of bytes needed. 106 uint32_t len = sizeof(program_fullpath); 107 int err = _NSGetExecutablePath(program_fullpath, &len); 108 if (err == 0) 109 g_program_filespec.SetFile(program_fullpath, FileSpec::Style::native); 110 else if (err == -1) { 111 char *large_program_fullpath = (char *)::malloc(len + 1); 112 113 err = _NSGetExecutablePath(large_program_fullpath, &len); 114 if (err == 0) 115 g_program_filespec.SetFile(large_program_fullpath, 116 FileSpec::Style::native); 117 118 ::free(large_program_fullpath); 119 } 120 } 121 return g_program_filespec; 122} 123 124bool HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec) { 125 FileSpec lldb_file_spec = GetShlibDir(); 126 if (!lldb_file_spec) 127 return false; 128 129 std::string raw_path = lldb_file_spec.GetPath(); 130 131 size_t framework_pos = raw_path.find("LLDB.framework"); 132 if (framework_pos != std::string::npos) { 133 framework_pos += strlen("LLDB.framework"); 134#if TARGET_OS_IPHONE 135 // Shallow bundle 136 raw_path.resize(framework_pos); 137#else 138 // Normal bundle 139 raw_path.resize(framework_pos); 140 raw_path.append("/Resources"); 141#endif 142 } else { 143 // Find the bin path relative to the lib path where the cmake-based 144 // OS X .dylib lives. This is not going to work if the bin and lib 145 // dir are not both in the same dir. 146 // 147 // It is not going to work to do it by the executable path either, 148 // as in the case of a python script, the executable is python, not 149 // the lldb driver. 150 raw_path.append("/../bin"); 151 FileSpec support_dir_spec(raw_path); 152 FileSystem::Instance().Resolve(support_dir_spec); 153 if (!FileSystem::Instance().IsDirectory(support_dir_spec)) { 154 Log *log = GetLog(LLDBLog::Host); 155 LLDB_LOGF(log, "HostInfoMacOSX::%s(): failed to find support directory", 156 __FUNCTION__); 157 return false; 158 } 159 160 // Get normalization from support_dir_spec. Note the FileSpec resolve 161 // does not remove '..' in the path. 162 char *const dir_realpath = 163 realpath(support_dir_spec.GetPath().c_str(), NULL); 164 if (dir_realpath) { 165 raw_path = dir_realpath; 166 free(dir_realpath); 167 } else { 168 raw_path = support_dir_spec.GetPath(); 169 } 170 } 171 172 file_spec.SetDirectory(raw_path); 173 return (bool)file_spec.GetDirectory(); 174} 175 176bool HostInfoMacOSX::ComputeHeaderDirectory(FileSpec &file_spec) { 177 FileSpec lldb_file_spec = GetShlibDir(); 178 if (!lldb_file_spec) 179 return false; 180 181 std::string raw_path = lldb_file_spec.GetPath(); 182 183 size_t framework_pos = raw_path.find("LLDB.framework"); 184 if (framework_pos != std::string::npos) { 185 framework_pos += strlen("LLDB.framework"); 186 raw_path.resize(framework_pos); 187 raw_path.append("/Headers"); 188 } 189 file_spec.SetDirectory(raw_path); 190 return true; 191} 192 193bool HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { 194 FileSpec lldb_file_spec = GetShlibDir(); 195 if (!lldb_file_spec) 196 return false; 197 198 std::string raw_path = lldb_file_spec.GetPath(); 199 200 size_t framework_pos = raw_path.find("LLDB.framework"); 201 if (framework_pos == std::string::npos) 202 return false; 203 204 framework_pos += strlen("LLDB.framework"); 205 raw_path.resize(framework_pos); 206 raw_path.append("/Resources/PlugIns"); 207 file_spec.SetDirectory(raw_path); 208 return true; 209} 210 211bool HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec) { 212 FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns"); 213 FileSystem::Instance().Resolve(temp_file); 214 file_spec.SetDirectory(temp_file.GetPathAsConstString()); 215 return true; 216} 217 218void HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32, 219 ArchSpec &arch_64) { 220 // All apple systems support 32 bit execution. 221 uint32_t cputype, cpusubtype; 222 uint32_t is_64_bit_capable = false; 223 size_t len = sizeof(cputype); 224 ArchSpec host_arch; 225 // These will tell us about the kernel architecture, which even on a 64 226 // bit machine can be 32 bit... 227 if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0) { 228 len = sizeof(cpusubtype); 229 if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0) 230 cpusubtype = CPU_TYPE_ANY; 231 232 len = sizeof(is_64_bit_capable); 233 ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0); 234 235 if (cputype == CPU_TYPE_ARM64 && cpusubtype == CPU_SUBTYPE_ARM64E) { 236 // The arm64e architecture is a preview. Pretend the host architecture 237 // is arm64. 238 cpusubtype = CPU_SUBTYPE_ARM64_ALL; 239 } 240 241 if (is_64_bit_capable) { 242 if (cputype & CPU_ARCH_ABI64) { 243 // We have a 64 bit kernel on a 64 bit system 244 arch_64.SetArchitecture(eArchTypeMachO, cputype, cpusubtype); 245 } else { 246 // We have a 64 bit kernel that is returning a 32 bit cputype, the 247 // cpusubtype will be correct as if it were for a 64 bit architecture 248 arch_64.SetArchitecture(eArchTypeMachO, cputype | CPU_ARCH_ABI64, 249 cpusubtype); 250 } 251 252 // Now we need modify the cpusubtype for the 32 bit slices. 253 uint32_t cpusubtype32 = cpusubtype; 254#if defined(__i386__) || defined(__x86_64__) 255 if (cpusubtype == CPU_SUBTYPE_486 || cpusubtype == CPU_SUBTYPE_X86_64_H) 256 cpusubtype32 = CPU_SUBTYPE_I386_ALL; 257#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 258 if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) 259 cpusubtype32 = CPU_SUBTYPE_ARM_V7S; 260#endif 261 arch_32.SetArchitecture(eArchTypeMachO, cputype & ~(CPU_ARCH_MASK), 262 cpusubtype32); 263 264 if (cputype == CPU_TYPE_ARM || 265 cputype == CPU_TYPE_ARM64 || 266 cputype == CPU_TYPE_ARM64_32) { 267// When running on a watch or tv, report the host os correctly 268#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 269 arch_32.GetTriple().setOS(llvm::Triple::TvOS); 270 arch_64.GetTriple().setOS(llvm::Triple::TvOS); 271#elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1 272 arch_32.GetTriple().setOS(llvm::Triple::BridgeOS); 273 arch_64.GetTriple().setOS(llvm::Triple::BridgeOS); 274#elif defined(TARGET_OS_WATCHOS) && TARGET_OS_WATCHOS == 1 275 arch_32.GetTriple().setOS(llvm::Triple::WatchOS); 276 arch_64.GetTriple().setOS(llvm::Triple::WatchOS); 277#elif defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1 278 arch_32.GetTriple().setOS(llvm::Triple::MacOSX); 279 arch_64.GetTriple().setOS(llvm::Triple::MacOSX); 280#else 281 arch_32.GetTriple().setOS(llvm::Triple::IOS); 282 arch_64.GetTriple().setOS(llvm::Triple::IOS); 283#endif 284 } else { 285 arch_32.GetTriple().setOS(llvm::Triple::MacOSX); 286 arch_64.GetTriple().setOS(llvm::Triple::MacOSX); 287 } 288 } else { 289 // We have a 32 bit kernel on a 32 bit system 290 arch_32.SetArchitecture(eArchTypeMachO, cputype, cpusubtype); 291#if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 292 arch_32.GetTriple().setOS(llvm::Triple::WatchOS); 293#else 294 arch_32.GetTriple().setOS(llvm::Triple::IOS); 295#endif 296 arch_64.Clear(); 297 } 298 } 299} 300 301/// Return and cache $DEVELOPER_DIR if it is set and exists. 302static std::string GetEnvDeveloperDir() { 303 static std::string g_env_developer_dir; 304 static std::once_flag g_once_flag; 305 std::call_once(g_once_flag, [&]() { 306 if (const char *developer_dir_env_var = getenv("DEVELOPER_DIR")) { 307 FileSpec fspec(developer_dir_env_var); 308 if (FileSystem::Instance().Exists(fspec)) 309 g_env_developer_dir = fspec.GetPath(); 310 }}); 311 return g_env_developer_dir; 312} 313 314FileSpec HostInfoMacOSX::GetXcodeContentsDirectory() { 315 static FileSpec g_xcode_contents_path; 316 static std::once_flag g_once_flag; 317 std::call_once(g_once_flag, [&]() { 318 // Try the shlib dir first. 319 if (FileSpec fspec = HostInfo::GetShlibDir()) { 320 if (FileSystem::Instance().Exists(fspec)) { 321 std::string xcode_contents_dir = 322 XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath()); 323 if (!xcode_contents_dir.empty()) { 324 g_xcode_contents_path = FileSpec(xcode_contents_dir); 325 return; 326 } 327 } 328 } 329 330 llvm::SmallString<128> env_developer_dir(GetEnvDeveloperDir()); 331 if (!env_developer_dir.empty()) { 332 llvm::sys::path::append(env_developer_dir, "Contents"); 333 std::string xcode_contents_dir = 334 XcodeSDK::FindXcodeContentsDirectoryInPath(env_developer_dir); 335 if (!xcode_contents_dir.empty()) { 336 g_xcode_contents_path = FileSpec(xcode_contents_dir); 337 return; 338 } 339 } 340 341 auto sdk_path_or_err = HostInfo::GetXcodeSDKPath(XcodeSDK::GetAnyMacOS()); 342 if (!sdk_path_or_err) { 343 Log *log = GetLog(LLDBLog::Host); 344 LLDB_LOGF(log, "Error while searching for Xcode SDK: %s", 345 toString(sdk_path_or_err.takeError()).c_str()); 346 return; 347 } 348 FileSpec fspec(*sdk_path_or_err); 349 if (fspec) { 350 if (FileSystem::Instance().Exists(fspec)) { 351 std::string xcode_contents_dir = 352 XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath()); 353 if (!xcode_contents_dir.empty()) { 354 g_xcode_contents_path = FileSpec(xcode_contents_dir); 355 return; 356 } 357 } 358 } 359 }); 360 return g_xcode_contents_path; 361} 362 363lldb_private::FileSpec HostInfoMacOSX::GetXcodeDeveloperDirectory() { 364 static lldb_private::FileSpec g_developer_directory; 365 static llvm::once_flag g_once_flag; 366 llvm::call_once(g_once_flag, []() { 367 if (FileSpec fspec = GetXcodeContentsDirectory()) { 368 fspec.AppendPathComponent("Developer"); 369 if (FileSystem::Instance().Exists(fspec)) 370 g_developer_directory = fspec; 371 } 372 }); 373 return g_developer_directory; 374} 375 376llvm::Expected<std::string> GetXcodeSDK(XcodeSDK sdk) { 377 XcodeSDK::Info info = sdk.Parse(); 378 std::string sdk_name = XcodeSDK::GetCanonicalName(info); 379 if (sdk_name.empty()) 380 return llvm::createStringError(llvm::inconvertibleErrorCode(), 381 "Unrecognized SDK type: " + sdk.GetString()); 382 383 Log *log = GetLog(LLDBLog::Host); 384 385 auto xcrun = [](const std::string &sdk, 386 llvm::StringRef developer_dir = 387 "") -> llvm::Expected<std::string> { 388 Args args; 389 if (!developer_dir.empty()) { 390 args.AppendArgument("/usr/bin/env"); 391 args.AppendArgument("DEVELOPER_DIR=" + developer_dir.str()); 392 } 393 args.AppendArgument("/usr/bin/xcrun"); 394 args.AppendArgument("--show-sdk-path"); 395 args.AppendArgument("--sdk"); 396 args.AppendArgument(sdk); 397 398 Log *log = GetLog(LLDBLog::Host); 399 if (log) { 400 std::string cmdstr; 401 args.GetCommandString(cmdstr); 402 log->Printf("GetXcodeSDK() running shell cmd '%s'", cmdstr.c_str()); 403 } 404 405 int status = 0; 406 int signo = 0; 407 std::string output_str; 408 // The first time after Xcode was updated or freshly installed, 409 // xcrun can take surprisingly long to build up its database. 410 auto timeout = std::chrono::seconds(60); 411 bool run_in_shell = false; 412 lldb_private::Status error = Host::RunShellCommand( 413 args, FileSpec(), &status, &signo, &output_str, timeout, run_in_shell); 414 415 // Check that xcrun returned something useful. 416 if (error.Fail()) { 417 // Catastrophic error. 418 LLDB_LOG(log, "xcrun failed to execute: %s", error.AsCString()); 419 return error.ToError(); 420 } 421 if (status != 0) { 422 // xcrun didn't find a matching SDK. Not an error, we'll try 423 // different spellings. 424 LLDB_LOG(log, "xcrun returned exit code %d", status); 425 return ""; 426 } 427 if (output_str.empty()) { 428 LLDB_LOG(log, "xcrun returned no results"); 429 return ""; 430 } 431 432 // Convert to a StringRef so we can manipulate the string without modifying 433 // the underlying data. 434 llvm::StringRef output(output_str); 435 436 // Remove any trailing newline characters. 437 output = output.rtrim(); 438 439 // Strip any leading newline characters and everything before them. 440 const size_t last_newline = output.rfind('\n'); 441 if (last_newline != llvm::StringRef::npos) 442 output = output.substr(last_newline + 1); 443 444 return output.str(); 445 }; 446 447 auto find_sdk = 448 [&xcrun](const std::string &sdk_name) -> llvm::Expected<std::string> { 449 // Invoke xcrun with the developer dir specified in the environment. 450 std::string developer_dir = GetEnvDeveloperDir(); 451 if (!developer_dir.empty()) { 452 // Don't fallback if DEVELOPER_DIR was set. 453 return xcrun(sdk_name, developer_dir); 454 } 455 456 // Invoke xcrun with the shlib dir. 457 if (FileSpec fspec = HostInfo::GetShlibDir()) { 458 if (FileSystem::Instance().Exists(fspec)) { 459 std::string contents_dir = 460 XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath()); 461 llvm::StringRef shlib_developer_dir = 462 llvm::sys::path::parent_path(contents_dir); 463 if (!shlib_developer_dir.empty()) { 464 auto sdk = xcrun(sdk_name, std::move(shlib_developer_dir)); 465 if (!sdk) 466 return sdk.takeError(); 467 if (!sdk->empty()) 468 return sdk; 469 } 470 } 471 } 472 473 // Invoke xcrun without a developer dir as a last resort. 474 return xcrun(sdk_name); 475 }; 476 477 auto path_or_err = find_sdk(sdk_name); 478 if (!path_or_err) 479 return path_or_err.takeError(); 480 std::string path = *path_or_err; 481 while (path.empty()) { 482 // Try an alternate spelling of the name ("macosx10.9internal"). 483 if (info.type == XcodeSDK::Type::MacOSX && !info.version.empty() && 484 info.internal) { 485 llvm::StringRef fixed(sdk_name); 486 if (fixed.consume_back(".internal")) 487 sdk_name = fixed.str() + "internal"; 488 path_or_err = find_sdk(sdk_name); 489 if (!path_or_err) 490 return path_or_err.takeError(); 491 path = *path_or_err; 492 if (!path.empty()) 493 break; 494 } 495 LLDB_LOGF(log, "Couldn't find SDK %s on host", sdk_name.c_str()); 496 497 // Try without the version. 498 if (!info.version.empty()) { 499 info.version = {}; 500 sdk_name = XcodeSDK::GetCanonicalName(info); 501 path_or_err = find_sdk(sdk_name); 502 if (!path_or_err) 503 return path_or_err.takeError(); 504 path = *path_or_err; 505 if (!path.empty()) 506 break; 507 } 508 509 LLDB_LOGF(log, "Couldn't find any matching SDK on host"); 510 return ""; 511 } 512 513 // Whatever is left in output should be a valid path. 514 if (!FileSystem::Instance().Exists(path)) { 515 LLDB_LOGF(log, "SDK returned by xcrun doesn't exist"); 516 return llvm::createStringError(llvm::inconvertibleErrorCode(), 517 "SDK returned by xcrun doesn't exist"); 518 } 519 return path; 520} 521 522llvm::Expected<llvm::StringRef> HostInfoMacOSX::GetXcodeSDKPath(XcodeSDK sdk) { 523 struct ErrorOrPath { 524 std::string str; 525 bool is_error; 526 }; 527 static llvm::StringMap<ErrorOrPath> g_sdk_path; 528 static std::mutex g_sdk_path_mutex; 529 530 std::lock_guard<std::mutex> guard(g_sdk_path_mutex); 531 LLDB_SCOPED_TIMER(); 532 533 auto key = sdk.GetString(); 534 auto it = g_sdk_path.find(key); 535 if (it != g_sdk_path.end()) { 536 if (it->second.is_error) 537 return llvm::createStringError(llvm::inconvertibleErrorCode(), 538 it->second.str); 539 else 540 return it->second.str; 541 } 542 auto path_or_err = GetXcodeSDK(sdk); 543 if (!path_or_err) { 544 std::string error = toString(path_or_err.takeError()); 545 g_sdk_path.insert({key, {error, true}}); 546 return llvm::createStringError(llvm::inconvertibleErrorCode(), error); 547 } 548 auto it_new = g_sdk_path.insert({key, {*path_or_err, false}}); 549 return it_new.first->second.str; 550} 551 552namespace { 553struct dyld_shared_cache_dylib_text_info { 554 uint64_t version; // current version 1 555 // following fields all exist in version 1 556 uint64_t loadAddressUnslid; 557 uint64_t textSegmentSize; 558 uuid_t dylibUuid; 559 const char *path; // pointer invalid at end of iterations 560 // following fields all exist in version 2 561 uint64_t textSegmentOffset; // offset from start of cache 562}; 563typedef struct dyld_shared_cache_dylib_text_info 564 dyld_shared_cache_dylib_text_info; 565} 566 567extern "C" int dyld_shared_cache_iterate_text( 568 const uuid_t cacheUuid, 569 void (^callback)(const dyld_shared_cache_dylib_text_info *info)); 570extern "C" uint8_t *_dyld_get_shared_cache_range(size_t *length); 571extern "C" bool _dyld_get_shared_cache_uuid(uuid_t uuid); 572 573namespace { 574class SharedCacheInfo { 575public: 576 const UUID &GetUUID() const { return m_uuid; } 577 const llvm::StringMap<SharedCacheImageInfo> &GetImages() const { 578 return m_images; 579 } 580 581 SharedCacheInfo(); 582 583private: 584 bool CreateSharedCacheInfoWithInstrospectionSPIs(); 585 586 llvm::StringMap<SharedCacheImageInfo> m_images; 587 UUID m_uuid; 588}; 589} 590 591bool SharedCacheInfo::CreateSharedCacheInfoWithInstrospectionSPIs() { 592#if defined(SDK_HAS_NEW_DYLD_INTROSPECTION_SPIS) 593 dyld_process_t dyld_process = dyld_process_create_for_current_task(); 594 if (!dyld_process) 595 return false; 596 597 dyld_process_snapshot_t snapshot = 598 dyld_process_snapshot_create_for_process(dyld_process, nullptr); 599 if (!snapshot) 600 return false; 601 602 auto on_exit = 603 llvm::make_scope_exit([&]() { dyld_process_snapshot_dispose(snapshot); }); 604 605 dyld_shared_cache_t shared_cache = 606 dyld_process_snapshot_get_shared_cache(snapshot); 607 if (!shared_cache) 608 return false; 609 610 dyld_shared_cache_for_each_image(shared_cache, ^(dyld_image_t image) { 611 __block uint64_t minVmAddr = UINT64_MAX; 612 __block uint64_t maxVmAddr = 0; 613 uuid_t uuidStore; 614 __block uuid_t *uuid = &uuidStore; 615 616 dyld_image_for_each_segment_info( 617 image, 618 ^(const char *segmentName, uint64_t vmAddr, uint64_t vmSize, int perm) { 619 minVmAddr = std::min(minVmAddr, vmAddr); 620 maxVmAddr = std::max(maxVmAddr, vmAddr + vmSize); 621 dyld_image_copy_uuid(image, uuid); 622 }); 623 assert(minVmAddr != UINT_MAX); 624 assert(maxVmAddr != 0); 625 m_images[dyld_image_get_installname(image)] = SharedCacheImageInfo{ 626 UUID(uuid, 16), std::make_shared<DataBufferUnowned>( 627 (uint8_t *)minVmAddr, maxVmAddr - minVmAddr)}; 628 }); 629 return true; 630#endif 631 return false; 632} 633 634SharedCacheInfo::SharedCacheInfo() { 635 if (CreateSharedCacheInfoWithInstrospectionSPIs()) 636 return; 637 638 size_t shared_cache_size; 639 uint8_t *shared_cache_start = 640 _dyld_get_shared_cache_range(&shared_cache_size); 641 uuid_t dsc_uuid; 642 _dyld_get_shared_cache_uuid(dsc_uuid); 643 m_uuid = UUID(dsc_uuid); 644 645 dyld_shared_cache_iterate_text( 646 dsc_uuid, ^(const dyld_shared_cache_dylib_text_info *info) { 647 m_images[info->path] = SharedCacheImageInfo{ 648 UUID(info->dylibUuid, 16), 649 std::make_shared<DataBufferUnowned>( 650 shared_cache_start + info->textSegmentOffset, 651 shared_cache_size - info->textSegmentOffset)}; 652 }); 653} 654 655SharedCacheImageInfo 656HostInfoMacOSX::GetSharedCacheImageInfo(llvm::StringRef image_name) { 657 static SharedCacheInfo g_shared_cache_info; 658 return g_shared_cache_info.GetImages().lookup(image_name); 659} 660