1 //===-- PlatformDarwinKernel.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 "PlatformDarwinKernel.h" 11 12 #if defined (__APPLE__) // This Plugin uses the Mac-specific source/Host/macosx/cfcpp utilities 13 14 15 // C Includes 16 // C++ Includes 17 // Other libraries and framework includes 18 // Project includes 19 #include "lldb/Breakpoint/BreakpointLocation.h" 20 #include "lldb/Core/ArchSpec.h" 21 #include "lldb/Core/Error.h" 22 #include "lldb/Core/Module.h" 23 #include "lldb/Core/ModuleList.h" 24 #include "lldb/Core/ModuleSpec.h" 25 #include "lldb/Core/PluginManager.h" 26 #include "lldb/Core/StreamString.h" 27 #include "lldb/Host/FileSpec.h" 28 #include "lldb/Host/Host.h" 29 #include "lldb/Interpreter/OptionValueFileSpecList.h" 30 #include "lldb/Interpreter/OptionValueProperties.h" 31 #include "lldb/Interpreter/Property.h" 32 #include "lldb/Target/Platform.h" 33 #include "lldb/Target/Process.h" 34 #include "lldb/Target/Target.h" 35 36 #include <CoreFoundation/CoreFoundation.h> 37 38 #include "Host/macosx/cfcpp/CFCBundle.h" 39 40 using namespace lldb; 41 using namespace lldb_private; 42 43 //------------------------------------------------------------------ 44 // Static Variables 45 //------------------------------------------------------------------ 46 static uint32_t g_initialize_count = 0; 47 48 //------------------------------------------------------------------ 49 // Static Functions 50 //------------------------------------------------------------------ 51 void 52 PlatformDarwinKernel::Initialize () 53 { 54 if (g_initialize_count++ == 0) 55 { 56 PluginManager::RegisterPlugin (PlatformDarwinKernel::GetShortPluginNameStatic(), 57 PlatformDarwinKernel::GetDescriptionStatic(), 58 PlatformDarwinKernel::CreateInstance, 59 PlatformDarwinKernel::DebuggerInitialize); 60 } 61 } 62 63 void 64 PlatformDarwinKernel::Terminate () 65 { 66 if (g_initialize_count > 0) 67 { 68 if (--g_initialize_count == 0) 69 { 70 PluginManager::UnregisterPlugin (PlatformDarwinKernel::CreateInstance); 71 } 72 } 73 } 74 75 Platform* 76 PlatformDarwinKernel::CreateInstance (bool force, const ArchSpec *arch) 77 { 78 // This is a special plugin that we don't want to activate just based on an ArchSpec for normal 79 // userlnad debugging. It is only useful in kernel debug sessions and the DynamicLoaderDarwinPlugin 80 // (or a user doing 'platform select') will force the creation of this Platform plugin. 81 if (force == false) 82 return NULL; 83 84 bool create = force; 85 LazyBool is_ios_debug_session = eLazyBoolCalculate; 86 87 if (create == false && arch && arch->IsValid()) 88 { 89 const llvm::Triple &triple = arch->GetTriple(); 90 switch (triple.getVendor()) 91 { 92 case llvm::Triple::Apple: 93 create = true; 94 break; 95 96 // Only accept "unknown" for vendor if the host is Apple and 97 // it "unknown" wasn't specified (it was just returned becasue it 98 // was NOT specified) 99 case llvm::Triple::UnknownArch: 100 create = !arch->TripleVendorWasSpecified(); 101 break; 102 default: 103 break; 104 } 105 106 if (create) 107 { 108 switch (triple.getOS()) 109 { 110 case llvm::Triple::Darwin: // Deprecated, but still support Darwin for historical reasons 111 case llvm::Triple::MacOSX: 112 break; 113 // Only accept "vendor" for vendor if the host is Apple and 114 // it "unknown" wasn't specified (it was just returned becasue it 115 // was NOT specified) 116 case llvm::Triple::UnknownOS: 117 create = !arch->TripleOSWasSpecified(); 118 break; 119 default: 120 create = false; 121 break; 122 } 123 } 124 } 125 if (arch && arch->IsValid()) 126 { 127 switch (arch->GetMachine()) 128 { 129 case llvm::Triple::x86: 130 case llvm::Triple::x86_64: 131 case llvm::Triple::ppc: 132 case llvm::Triple::ppc64: 133 is_ios_debug_session = eLazyBoolNo; 134 break; 135 case llvm::Triple::arm: 136 case llvm::Triple::thumb: 137 is_ios_debug_session = eLazyBoolYes; 138 break; 139 default: 140 is_ios_debug_session = eLazyBoolCalculate; 141 break; 142 } 143 } 144 if (create) 145 return new PlatformDarwinKernel (is_ios_debug_session); 146 return NULL; 147 } 148 149 150 const char * 151 PlatformDarwinKernel::GetPluginNameStatic () 152 { 153 return "PlatformDarwinKernel"; 154 } 155 156 const char * 157 PlatformDarwinKernel::GetShortPluginNameStatic() 158 { 159 return "darwin-kernel"; 160 } 161 162 const char * 163 PlatformDarwinKernel::GetDescriptionStatic() 164 { 165 return "Darwin Kernel platform plug-in."; 166 } 167 168 //------------------------------------------------------------------ 169 /// Code to handle the PlatformDarwinKernel settings 170 //------------------------------------------------------------------ 171 172 static PropertyDefinition 173 g_properties[] = 174 { 175 { "search-locally-for-kexts" , OptionValue::eTypeBoolean, true, true, NULL, NULL, "Automatically search for kexts on the local system when doing kernel debugging." }, 176 { "kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, NULL, "Directories/KDKs to search for kexts in when starting a kernel debug session." }, 177 { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL } 178 }; 179 180 enum { 181 ePropertySearchForKexts = 0, 182 ePropertyKextDirectories 183 }; 184 185 186 187 class PlatformDarwinKernelProperties : public Properties 188 { 189 public: 190 191 static ConstString & 192 GetSettingName () 193 { 194 static ConstString g_setting_name("darwin-kernel"); 195 return g_setting_name; 196 } 197 198 PlatformDarwinKernelProperties() : 199 Properties () 200 { 201 m_collection_sp.reset (new OptionValueProperties(GetSettingName())); 202 m_collection_sp->Initialize(g_properties); 203 } 204 205 virtual 206 ~PlatformDarwinKernelProperties() 207 { 208 } 209 210 bool 211 GetSearchForKexts() const 212 { 213 const uint32_t idx = ePropertySearchForKexts; 214 return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); 215 } 216 217 FileSpecList & 218 GetKextDirectories() const 219 { 220 const uint32_t idx = ePropertyKextDirectories; 221 OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList (NULL, false, idx); 222 assert(option_value); 223 return option_value->GetCurrentValue(); 224 } 225 }; 226 227 typedef std::shared_ptr<PlatformDarwinKernelProperties> PlatformDarwinKernelPropertiesSP; 228 229 static const PlatformDarwinKernelPropertiesSP & 230 GetGlobalProperties() 231 { 232 static PlatformDarwinKernelPropertiesSP g_settings_sp; 233 if (!g_settings_sp) 234 g_settings_sp.reset (new PlatformDarwinKernelProperties ()); 235 return g_settings_sp; 236 } 237 238 void 239 PlatformDarwinKernel::DebuggerInitialize (lldb_private::Debugger &debugger) 240 { 241 if (!PluginManager::GetSettingForPlatformPlugin (debugger, PlatformDarwinKernelProperties::GetSettingName())) 242 { 243 const bool is_global_setting = true; 244 PluginManager::CreateSettingForPlatformPlugin (debugger, 245 GetGlobalProperties()->GetValueProperties(), 246 ConstString ("Properties for the PlatformDarwinKernel plug-in."), 247 is_global_setting); 248 } 249 } 250 251 //------------------------------------------------------------------ 252 /// Default Constructor 253 //------------------------------------------------------------------ 254 PlatformDarwinKernel::PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_session) : 255 PlatformDarwin (false), // This is a remote platform 256 m_name_to_kext_path_map(), 257 m_directories_searched(), 258 m_ios_debug_session(is_ios_debug_session) 259 260 { 261 if (GetGlobalProperties()->GetSearchForKexts()) 262 { 263 SearchForKexts (); 264 } 265 } 266 267 //------------------------------------------------------------------ 268 /// Destructor. 269 /// 270 /// The destructor is virtual since this class is designed to be 271 /// inherited from by the plug-in instance. 272 //------------------------------------------------------------------ 273 PlatformDarwinKernel::~PlatformDarwinKernel() 274 { 275 } 276 277 278 void 279 PlatformDarwinKernel::GetStatus (Stream &strm) 280 { 281 Platform::GetStatus (strm); 282 strm.Printf (" Debug session type: "); 283 if (m_ios_debug_session == eLazyBoolYes) 284 strm.Printf ("iOS kernel debugging\n"); 285 else if (m_ios_debug_session == eLazyBoolNo) 286 strm.Printf ("Mac OS X kernel debugging\n"); 287 else 288 strm.Printf ("unknown kernel debugging\n"); 289 const uint32_t num_kext_dirs = m_directories_searched.size(); 290 for (uint32_t i=0; i<num_kext_dirs; ++i) 291 { 292 const FileSpec &kext_dir = m_directories_searched[i]; 293 strm.Printf (" Kext directories: [%2u] \"%s\"\n", i, kext_dir.GetPath().c_str()); 294 } 295 strm.Printf (" Total number of kexts indexed: %d\n", (int) m_name_to_kext_path_map.size()); 296 } 297 298 void 299 PlatformDarwinKernel::SearchForKexts () 300 { 301 // Differentiate between "ios debug session" and "mac debug session" so we don't index 302 // kext bundles that won't be used in this debug session. If this is an ios kext debug 303 // session, looking in /System/Library/Extensions is a waste of stat()s, for example. 304 305 // Build up a list of all SDKs we'll be searching for directories of kexts 306 // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk 307 std::vector<FileSpec> sdk_dirs; 308 if (m_ios_debug_session != eLazyBoolNo) 309 GetiOSSDKDirectoriesToSearch (sdk_dirs); 310 if (m_ios_debug_session != eLazyBoolYes) 311 GetMacSDKDirectoriesToSearch (sdk_dirs); 312 313 GetGenericSDKDirectoriesToSearch (sdk_dirs); 314 315 // Build up a list of directories that hold kext bundles on the system 316 // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/System/Library/Extensions 317 std::vector<FileSpec> kext_dirs; 318 SearchSDKsForKextDirectories (sdk_dirs, kext_dirs); 319 320 if (m_ios_debug_session != eLazyBoolNo) 321 GetiOSDirectoriesToSearch (kext_dirs); 322 if (m_ios_debug_session != eLazyBoolYes) 323 GetMacDirectoriesToSearch (kext_dirs); 324 325 GetGenericDirectoriesToSearch (kext_dirs); 326 327 GetUserSpecifiedDirectoriesToSearch (kext_dirs); 328 329 // We now have a complete list of directories that we will search for kext bundles 330 m_directories_searched = kext_dirs; 331 332 IndexKextsInDirectories (kext_dirs); 333 } 334 335 void 336 PlatformDarwinKernel::GetiOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 337 { 338 // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer" 339 const char *developer_dir = GetDeveloperDirectory(); 340 if (developer_dir == NULL) 341 developer_dir = "/Applications/Xcode.app/Contents/Developer"; 342 343 char pathbuf[PATH_MAX]; 344 ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/iPhoneOS.platform/Developer/SDKs", developer_dir); 345 FileSpec ios_sdk(pathbuf, true); 346 if (ios_sdk.Exists() && ios_sdk.IsDirectory()) 347 { 348 directories.push_back (ios_sdk); 349 } 350 } 351 352 void 353 PlatformDarwinKernel::GetMacSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 354 { 355 // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer" 356 const char *developer_dir = GetDeveloperDirectory(); 357 if (developer_dir == NULL) 358 developer_dir = "/Applications/Xcode.app/Contents/Developer"; 359 360 char pathbuf[PATH_MAX]; 361 ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/MacOSX.platform/Developer/SDKs", developer_dir); 362 FileSpec mac_sdk(pathbuf, true); 363 if (mac_sdk.Exists() && mac_sdk.IsDirectory()) 364 { 365 directories.push_back (mac_sdk); 366 } 367 } 368 369 void 370 PlatformDarwinKernel::GetGenericSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 371 { 372 FileSpec generic_sdk("/AppleInternal/Developer/KDKs", true); 373 if (generic_sdk.Exists() && generic_sdk.IsDirectory()) 374 { 375 directories.push_back (generic_sdk); 376 } 377 } 378 379 void 380 PlatformDarwinKernel::GetiOSDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 381 { 382 } 383 384 void 385 PlatformDarwinKernel::GetMacDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 386 { 387 FileSpec sle("/System/Library/Extensions", true); 388 if (sle.Exists() && sle.IsDirectory()) 389 { 390 directories.push_back(sle); 391 } 392 393 FileSpec le("/Library/Extensions", true); 394 if (le.Exists() && le.IsDirectory()) 395 { 396 directories.push_back(le); 397 } 398 399 FileSpec kdk("/Volumes/KernelDebugKit", true); 400 if (kdk.Exists() && kdk.IsDirectory()) 401 { 402 directories.push_back(kdk); 403 } 404 } 405 406 void 407 PlatformDarwinKernel::GetGenericDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 408 { 409 // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer" 410 const char *developer_dir = GetDeveloperDirectory(); 411 if (developer_dir == NULL) 412 developer_dir = "/Applications/Xcode.app/Contents/Developer"; 413 414 char pathbuf[PATH_MAX]; 415 ::snprintf (pathbuf, sizeof (pathbuf), "%s/../Symbols", developer_dir); 416 FileSpec symbols_dir (pathbuf, true); 417 if (symbols_dir.Exists() && symbols_dir.IsDirectory()) 418 { 419 directories.push_back (symbols_dir); 420 } 421 } 422 423 void 424 PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories) 425 { 426 FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories()); 427 std::vector<FileSpec> possible_sdk_dirs; 428 429 const uint32_t user_dirs_count = user_dirs.GetSize(); 430 for (uint32_t i = 0; i < user_dirs_count; i++) 431 { 432 FileSpec dir = user_dirs.GetFileSpecAtIndex (i); 433 dir.ResolvePath(); 434 if (dir.Exists() && dir.IsDirectory()) 435 { 436 directories.push_back (dir); 437 possible_sdk_dirs.push_back (dir); // does this directory have a *.sdk or *.kdk that we should look in? 438 439 // Is there a "System/Library/Extensions" subdir of this directory? 440 std::string dir_sle_path = dir.GetPath(); 441 dir_sle_path.append ("/System/Library/Extensions"); 442 FileSpec dir_sle(dir_sle_path.c_str(), true); 443 if (dir_sle.Exists() && dir_sle.IsDirectory()) 444 { 445 directories.push_back (dir_sle); 446 } 447 } 448 } 449 450 SearchSDKsForKextDirectories (possible_sdk_dirs, directories); 451 } 452 453 // Scan through the SDK directories, looking for directories where kexts are likely. 454 // Add those directories to kext_dirs. 455 void 456 PlatformDarwinKernel::SearchSDKsForKextDirectories (std::vector<lldb_private::FileSpec> sdk_dirs, std::vector<lldb_private::FileSpec> &kext_dirs) 457 { 458 const uint32_t num_sdks = sdk_dirs.size(); 459 for (uint32_t i = 0; i < num_sdks; i++) 460 { 461 const FileSpec &sdk_dir = sdk_dirs[i]; 462 std::string sdk_dir_path = sdk_dir.GetPath(); 463 if (!sdk_dir_path.empty()) 464 { 465 const bool find_directories = true; 466 const bool find_files = false; 467 const bool find_other = false; 468 FileSpec::EnumerateDirectory (sdk_dir_path.c_str(), 469 find_directories, 470 find_files, 471 find_other, 472 GetKextDirectoriesInSDK, 473 &kext_dirs); 474 } 475 } 476 } 477 478 // Callback for FileSpec::EnumerateDirectory(). 479 // Step through the entries in a directory like 480 // /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs 481 // looking for any subdirectories of the form MacOSX10.8.Internal.sdk/System/Library/Extensions 482 // Adds these to the vector of FileSpec's. 483 484 FileSpec::EnumerateDirectoryResult 485 PlatformDarwinKernel::GetKextDirectoriesInSDK (void *baton, 486 FileSpec::FileType file_type, 487 const FileSpec &file_spec) 488 { 489 if (file_type == FileSpec::eFileTypeDirectory 490 && (file_spec.GetFileNameExtension() == ConstString("sdk") 491 || file_spec.GetFileNameExtension() == ConstString("kdk"))) 492 { 493 std::string kext_directory_path = file_spec.GetPath(); 494 kext_directory_path.append ("/System/Library/Extensions"); 495 FileSpec kext_directory (kext_directory_path.c_str(), true); 496 if (kext_directory.Exists() && kext_directory.IsDirectory()) 497 { 498 ((std::vector<lldb_private::FileSpec> *)baton)->push_back(kext_directory); 499 } 500 } 501 return FileSpec::eEnumerateDirectoryResultNext; 502 } 503 504 void 505 PlatformDarwinKernel::IndexKextsInDirectories (std::vector<lldb_private::FileSpec> kext_dirs) 506 { 507 std::vector<FileSpec> kext_bundles; 508 509 const uint32_t num_dirs = kext_dirs.size(); 510 for (uint32_t i = 0; i < num_dirs; i++) 511 { 512 const FileSpec &dir = kext_dirs[i]; 513 const bool find_directories = true; 514 const bool find_files = false; 515 const bool find_other = false; 516 FileSpec::EnumerateDirectory (dir.GetPath().c_str(), 517 find_directories, 518 find_files, 519 find_other, 520 GetKextsInDirectory, 521 &kext_bundles); 522 } 523 524 const uint32_t num_kexts = kext_bundles.size(); 525 for (uint32_t i = 0; i < num_kexts; i++) 526 { 527 const FileSpec &kext = kext_bundles[i]; 528 CFCBundle bundle (kext.GetPath().c_str()); 529 CFStringRef bundle_id (bundle.GetIdentifier()); 530 if (bundle_id && CFGetTypeID (bundle_id) == CFStringGetTypeID ()) 531 { 532 char bundle_id_buf[PATH_MAX]; 533 if (CFStringGetCString (bundle_id, bundle_id_buf, sizeof (bundle_id_buf), kCFStringEncodingUTF8)) 534 { 535 ConstString bundle_conststr(bundle_id_buf); 536 m_name_to_kext_path_map.insert(std::pair<ConstString, FileSpec>(bundle_conststr, kext)); 537 } 538 } 539 } 540 } 541 542 // Callback for FileSpec::EnumerateDirectory(). 543 // Step through the entries in a directory like /System/Library/Extensions, find .kext bundles, add them 544 // to the vector of FileSpecs. 545 // If a .kext bundle has a Contents/PlugIns or PlugIns subdir, search for kexts in there too. 546 547 FileSpec::EnumerateDirectoryResult 548 PlatformDarwinKernel::GetKextsInDirectory (void *baton, 549 FileSpec::FileType file_type, 550 const FileSpec &file_spec) 551 { 552 if (file_type == FileSpec::eFileTypeDirectory && file_spec.GetFileNameExtension() == ConstString("kext")) 553 { 554 ((std::vector<lldb_private::FileSpec> *)baton)->push_back(file_spec); 555 std::string kext_bundle_path = file_spec.GetPath(); 556 std::string search_here_too; 557 std::string contents_plugins_path = kext_bundle_path + "/Contents/PlugIns"; 558 FileSpec contents_plugins (contents_plugins_path.c_str(), false); 559 if (contents_plugins.Exists() && contents_plugins.IsDirectory()) 560 { 561 search_here_too = contents_plugins_path; 562 } 563 else 564 { 565 std::string plugins_path = kext_bundle_path + "/PlugIns"; 566 FileSpec plugins (plugins_path.c_str(), false); 567 if (plugins.Exists() && plugins.IsDirectory()) 568 { 569 search_here_too = plugins_path; 570 } 571 } 572 573 if (!search_here_too.empty()) 574 { 575 const bool find_directories = true; 576 const bool find_files = false; 577 const bool find_other = false; 578 FileSpec::EnumerateDirectory (search_here_too.c_str(), 579 find_directories, 580 find_files, 581 find_other, 582 GetKextsInDirectory, 583 baton); 584 } 585 } 586 return FileSpec::eEnumerateDirectoryResultNext; 587 } 588 589 Error 590 PlatformDarwinKernel::GetSharedModule (const ModuleSpec &module_spec, 591 ModuleSP &module_sp, 592 const FileSpecList *module_search_paths_ptr, 593 ModuleSP *old_module_sp_ptr, 594 bool *did_create_ptr) 595 { 596 Error error; 597 module_sp.reset(); 598 const FileSpec &platform_file = module_spec.GetFileSpec(); 599 std::string kext_bundle_id = platform_file.GetPath(); 600 if (!kext_bundle_id.empty()) 601 { 602 ConstString kext_bundle_cs(kext_bundle_id.c_str()); 603 if (m_name_to_kext_path_map.count(kext_bundle_cs) > 0) 604 { 605 for (BundleIDToKextIterator it = m_name_to_kext_path_map.begin (); it != m_name_to_kext_path_map.end (); ++it) 606 { 607 if (it->first == kext_bundle_cs) 608 { 609 error = ExamineKextForMatchingUUID (it->second, module_spec.GetUUID(), module_spec.GetArchitecture(), module_sp); 610 if (module_sp.get()) 611 { 612 return error; 613 } 614 } 615 } 616 } 617 } 618 619 return error; 620 } 621 622 Error 623 PlatformDarwinKernel::ExamineKextForMatchingUUID (const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, const ArchSpec &arch, ModuleSP &exe_module_sp) 624 { 625 Error error; 626 FileSpec exe_file = kext_bundle_path; 627 Host::ResolveExecutableInBundle (exe_file); 628 if (exe_file.Exists()) 629 { 630 ModuleSpec exe_spec (exe_file); 631 exe_spec.GetUUID() = uuid; 632 exe_spec.GetArchitecture() = arch; 633 634 // First try to create a ModuleSP with the file / arch and see if the UUID matches. 635 // If that fails (this exec file doesn't have the correct uuid), don't call GetSharedModule 636 // (which may call in to the DebugSymbols framework and therefore can be slow.) 637 ModuleSP module_sp (new Module (exe_file, arch)); 638 if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec (exe_spec)) 639 { 640 error = ModuleList::GetSharedModule (exe_spec, exe_module_sp, NULL, NULL, NULL); 641 if (exe_module_sp && exe_module_sp->GetObjectFile()) 642 { 643 return error; 644 } 645 } 646 exe_module_sp.reset(); 647 } 648 return error; 649 } 650 651 bool 652 PlatformDarwinKernel::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 653 { 654 #if defined (__arm__) 655 return ARMGetSupportedArchitectureAtIndex (idx, arch); 656 #else 657 return x86GetSupportedArchitectureAtIndex (idx, arch); 658 #endif 659 } 660 661 #endif // __APPLE__ 662