1 //===-- PlatformDarwinKernel.cpp -----------------------------------*- C++ 2 //-*-===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "PlatformDarwinKernel.h" 12 13 #if defined(__APPLE__) // This Plugin uses the Mac-specific 14 // source/Host/macosx/cfcpp utilities 15 16 // C Includes 17 // C++ Includes 18 // Other libraries and framework includes 19 // Project includes 20 #include "lldb/Breakpoint/BreakpointLocation.h" 21 #include "lldb/Core/ArchSpec.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/Host/Host.h" 27 #include "lldb/Interpreter/OptionValueFileSpecList.h" 28 #include "lldb/Interpreter/OptionValueProperties.h" 29 #include "lldb/Interpreter/Property.h" 30 #include "lldb/Symbol/ObjectFile.h" 31 #include "lldb/Target/Platform.h" 32 #include "lldb/Target/Process.h" 33 #include "lldb/Target/Target.h" 34 #include "lldb/Utility/Error.h" 35 #include "lldb/Utility/FileSpec.h" 36 #include "lldb/Utility/Log.h" 37 #include "lldb/Utility/StreamString.h" 38 39 #include "llvm/Support/FileSystem.h" 40 41 #include <CoreFoundation/CoreFoundation.h> 42 43 #include "Host/macosx/cfcpp/CFCBundle.h" 44 45 using namespace lldb; 46 using namespace lldb_private; 47 48 //------------------------------------------------------------------ 49 // Static Variables 50 //------------------------------------------------------------------ 51 static uint32_t g_initialize_count = 0; 52 53 //------------------------------------------------------------------ 54 // Static Functions 55 //------------------------------------------------------------------ 56 void PlatformDarwinKernel::Initialize() { 57 PlatformDarwin::Initialize(); 58 59 if (g_initialize_count++ == 0) { 60 PluginManager::RegisterPlugin(PlatformDarwinKernel::GetPluginNameStatic(), 61 PlatformDarwinKernel::GetDescriptionStatic(), 62 PlatformDarwinKernel::CreateInstance, 63 PlatformDarwinKernel::DebuggerInitialize); 64 } 65 } 66 67 void PlatformDarwinKernel::Terminate() { 68 if (g_initialize_count > 0) { 69 if (--g_initialize_count == 0) { 70 PluginManager::UnregisterPlugin(PlatformDarwinKernel::CreateInstance); 71 } 72 } 73 74 PlatformDarwin::Terminate(); 75 } 76 77 PlatformSP PlatformDarwinKernel::CreateInstance(bool force, 78 const ArchSpec *arch) { 79 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 80 if (log) { 81 const char *arch_name; 82 if (arch && arch->GetArchitectureName()) 83 arch_name = arch->GetArchitectureName(); 84 else 85 arch_name = "<null>"; 86 87 const char *triple_cstr = 88 arch ? arch->GetTriple().getTriple().c_str() : "<null>"; 89 90 log->Printf("PlatformDarwinKernel::%s(force=%s, arch={%s,%s})", 91 __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); 92 } 93 94 // This is a special plugin that we don't want to activate just based on an 95 // ArchSpec for normal 96 // userland debugging. It is only useful in kernel debug sessions and the 97 // DynamicLoaderDarwinPlugin 98 // (or a user doing 'platform select') will force the creation of this 99 // Platform plugin. 100 if (force == false) { 101 if (log) 102 log->Printf("PlatformDarwinKernel::%s() aborting creation of platform " 103 "because force == false", 104 __FUNCTION__); 105 return PlatformSP(); 106 } 107 108 bool create = force; 109 LazyBool is_ios_debug_session = eLazyBoolCalculate; 110 111 if (create == false && arch && arch->IsValid()) { 112 const llvm::Triple &triple = arch->GetTriple(); 113 switch (triple.getVendor()) { 114 case llvm::Triple::Apple: 115 create = true; 116 break; 117 118 // Only accept "unknown" for vendor if the host is Apple and 119 // it "unknown" wasn't specified (it was just returned because it 120 // was NOT specified) 121 case llvm::Triple::UnknownArch: 122 create = !arch->TripleVendorWasSpecified(); 123 break; 124 default: 125 break; 126 } 127 128 if (create) { 129 switch (triple.getOS()) { 130 case llvm::Triple::Darwin: 131 case llvm::Triple::MacOSX: 132 case llvm::Triple::IOS: 133 case llvm::Triple::WatchOS: 134 case llvm::Triple::TvOS: 135 break; 136 // Only accept "vendor" for vendor if the host is Apple and 137 // it "unknown" wasn't specified (it was just returned because it 138 // was NOT specified) 139 case llvm::Triple::UnknownOS: 140 create = !arch->TripleOSWasSpecified(); 141 break; 142 default: 143 create = false; 144 break; 145 } 146 } 147 } 148 if (arch && arch->IsValid()) { 149 switch (arch->GetMachine()) { 150 case llvm::Triple::x86: 151 case llvm::Triple::x86_64: 152 case llvm::Triple::ppc: 153 case llvm::Triple::ppc64: 154 is_ios_debug_session = eLazyBoolNo; 155 break; 156 case llvm::Triple::arm: 157 case llvm::Triple::aarch64: 158 case llvm::Triple::thumb: 159 is_ios_debug_session = eLazyBoolYes; 160 break; 161 default: 162 is_ios_debug_session = eLazyBoolCalculate; 163 break; 164 } 165 } 166 if (create) { 167 if (log) 168 log->Printf("PlatformDarwinKernel::%s() creating platform", __FUNCTION__); 169 170 return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session)); 171 } 172 173 if (log) 174 log->Printf("PlatformDarwinKernel::%s() aborting creation of platform", 175 __FUNCTION__); 176 177 return PlatformSP(); 178 } 179 180 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { 181 static ConstString g_name("darwin-kernel"); 182 return g_name; 183 } 184 185 const char *PlatformDarwinKernel::GetDescriptionStatic() { 186 return "Darwin Kernel platform plug-in."; 187 } 188 189 //------------------------------------------------------------------ 190 /// Code to handle the PlatformDarwinKernel settings 191 //------------------------------------------------------------------ 192 193 static PropertyDefinition g_properties[] = { 194 {"search-locally-for-kexts", OptionValue::eTypeBoolean, true, true, NULL, 195 NULL, "Automatically search for kexts on the local system when doing " 196 "kernel debugging."}, 197 {"kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, NULL, 198 "Directories/KDKs to search for kexts in when starting a kernel debug " 199 "session."}, 200 {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; 201 202 enum { ePropertySearchForKexts = 0, ePropertyKextDirectories }; 203 204 class PlatformDarwinKernelProperties : public Properties { 205 public: 206 static ConstString &GetSettingName() { 207 static ConstString g_setting_name("darwin-kernel"); 208 return g_setting_name; 209 } 210 211 PlatformDarwinKernelProperties() : Properties() { 212 m_collection_sp.reset(new OptionValueProperties(GetSettingName())); 213 m_collection_sp->Initialize(g_properties); 214 } 215 216 virtual ~PlatformDarwinKernelProperties() {} 217 218 bool GetSearchForKexts() const { 219 const uint32_t idx = ePropertySearchForKexts; 220 return m_collection_sp->GetPropertyAtIndexAsBoolean( 221 NULL, idx, g_properties[idx].default_uint_value != 0); 222 } 223 224 FileSpecList &GetKextDirectories() const { 225 const uint32_t idx = ePropertyKextDirectories; 226 OptionValueFileSpecList *option_value = 227 m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList( 228 NULL, false, idx); 229 assert(option_value); 230 return option_value->GetCurrentValue(); 231 } 232 }; 233 234 typedef std::shared_ptr<PlatformDarwinKernelProperties> 235 PlatformDarwinKernelPropertiesSP; 236 237 static const PlatformDarwinKernelPropertiesSP &GetGlobalProperties() { 238 static PlatformDarwinKernelPropertiesSP g_settings_sp; 239 if (!g_settings_sp) 240 g_settings_sp.reset(new PlatformDarwinKernelProperties()); 241 return g_settings_sp; 242 } 243 244 void PlatformDarwinKernel::DebuggerInitialize( 245 lldb_private::Debugger &debugger) { 246 if (!PluginManager::GetSettingForPlatformPlugin( 247 debugger, PlatformDarwinKernelProperties::GetSettingName())) { 248 const bool is_global_setting = true; 249 PluginManager::CreateSettingForPlatformPlugin( 250 debugger, GetGlobalProperties()->GetValueProperties(), 251 ConstString("Properties for the PlatformDarwinKernel plug-in."), 252 is_global_setting); 253 } 254 } 255 256 //------------------------------------------------------------------ 257 /// Default Constructor 258 //------------------------------------------------------------------ 259 PlatformDarwinKernel::PlatformDarwinKernel( 260 lldb_private::LazyBool is_ios_debug_session) 261 : PlatformDarwin(false), // This is a remote platform 262 m_name_to_kext_path_map_with_dsyms(), 263 m_name_to_kext_path_map_without_dsyms(), m_search_directories(), 264 m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(), 265 m_kernel_binaries_without_dsyms(), 266 m_ios_debug_session(is_ios_debug_session) 267 268 { 269 if (GetGlobalProperties()->GetSearchForKexts()) { 270 CollectKextAndKernelDirectories(); 271 SearchForKextsAndKernelsRecursively(); 272 } 273 } 274 275 //------------------------------------------------------------------ 276 /// Destructor. 277 /// 278 /// The destructor is virtual since this class is designed to be 279 /// inherited from by the plug-in instance. 280 //------------------------------------------------------------------ 281 PlatformDarwinKernel::~PlatformDarwinKernel() {} 282 283 void PlatformDarwinKernel::GetStatus(Stream &strm) { 284 Platform::GetStatus(strm); 285 strm.Printf(" Debug session type: "); 286 if (m_ios_debug_session == eLazyBoolYes) 287 strm.Printf("iOS kernel debugging\n"); 288 else if (m_ios_debug_session == eLazyBoolNo) 289 strm.Printf("Mac OS X kernel debugging\n"); 290 else 291 strm.Printf("unknown kernel debugging\n"); 292 293 strm.Printf("Directories searched recursively:\n"); 294 const uint32_t num_kext_dirs = m_search_directories.size(); 295 for (uint32_t i = 0; i < num_kext_dirs; ++i) { 296 strm.Printf("[%d] %s\n", i, m_search_directories[i].GetPath().c_str()); 297 } 298 299 strm.Printf("Directories not searched recursively:\n"); 300 const uint32_t num_kext_dirs_no_recursion = 301 m_search_directories_no_recursing.size(); 302 for (uint32_t i = 0; i < num_kext_dirs_no_recursion; i++) { 303 strm.Printf("[%d] %s\n", i, 304 m_search_directories_no_recursing[i].GetPath().c_str()); 305 } 306 307 strm.Printf(" Number of kexts with dSYMs indexed: %d\n", 308 (int)m_name_to_kext_path_map_with_dsyms.size()); 309 strm.Printf(" Number of kexts without dSYMs indexed: %d\n", 310 (int)m_name_to_kext_path_map_without_dsyms.size()); 311 strm.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n", 312 (int)m_kernel_binaries_with_dsyms.size()); 313 strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n", 314 (int)m_kernel_binaries_without_dsyms.size()); 315 316 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 317 if (log) { 318 log->Printf("\nkexts with dSYMs"); 319 for (auto pos : m_name_to_kext_path_map_with_dsyms) { 320 log->Printf("%s", pos.second.GetPath().c_str()); 321 } 322 log->Printf("\nkexts without dSYMs"); 323 324 for (auto pos : m_name_to_kext_path_map_without_dsyms) { 325 log->Printf("%s", pos.second.GetPath().c_str()); 326 } 327 log->Printf("\nkernels with dSYMS"); 328 for (auto fs : m_kernel_binaries_with_dsyms) { 329 log->Printf("%s", fs.GetPath().c_str()); 330 } 331 log->Printf("\nkernels without dSYMS"); 332 for (auto fs : m_kernel_binaries_without_dsyms) { 333 log->Printf("%s", fs.GetPath().c_str()); 334 } 335 log->Printf("\n"); 336 } 337 } 338 339 // Populate the m_search_directories vector with directories we should search 340 // for kernel & kext binaries. 341 342 void PlatformDarwinKernel::CollectKextAndKernelDirectories() { 343 // Differentiate between "ios debug session" and "mac debug session" so we 344 // don't index 345 // kext bundles that won't be used in this debug session. If this is an ios 346 // kext debug 347 // session, looking in /System/Library/Extensions is a waste of stat()s, for 348 // example. 349 350 // DeveloperDirectory is something like 351 // "/Applications/Xcode.app/Contents/Developer" 352 std::string developer_dir = GetDeveloperDirectory(); 353 if (developer_dir.empty()) 354 developer_dir = "/Applications/Xcode.app/Contents/Developer"; 355 356 if (m_ios_debug_session != eLazyBoolNo) { 357 AddSDKSubdirsToSearchPaths(developer_dir + 358 "/Platforms/iPhoneOS.platform/Developer/SDKs"); 359 AddSDKSubdirsToSearchPaths(developer_dir + 360 "/Platforms/AppleTVOS.platform/Developer/SDKs"); 361 AddSDKSubdirsToSearchPaths(developer_dir + 362 "/Platforms/WatchOS.platform/Developer/SDKs"); 363 } 364 if (m_ios_debug_session != eLazyBoolYes) { 365 AddSDKSubdirsToSearchPaths(developer_dir + 366 "/Platforms/MacOSX.platform/Developer/SDKs"); 367 } 368 369 AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit"); 370 AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs"); 371 // The KDKs distributed from Apple installed on external 372 // developer systems may be in directories like 373 // /Library/Developer/KDKs/KDK_10.10_14A298i.kdk 374 AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs"); 375 376 if (m_ios_debug_session != eLazyBoolNo) { 377 } 378 if (m_ios_debug_session != eLazyBoolYes) { 379 AddRootSubdirsToSearchPaths(this, "/"); 380 } 381 382 GetUserSpecifiedDirectoriesToSearch(); 383 384 // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols 385 FileSpec possible_dir(developer_dir + "/../Symbols", true); 386 if (llvm::sys::fs::is_directory(possible_dir.GetPath())) 387 m_search_directories.push_back(possible_dir); 388 389 // Add simple directory of the current working directory 390 m_search_directories_no_recursing.push_back(FileSpec(".", true)); 391 } 392 393 void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() { 394 FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories()); 395 std::vector<FileSpec> possible_sdk_dirs; 396 397 const uint32_t user_dirs_count = user_dirs.GetSize(); 398 for (uint32_t i = 0; i < user_dirs_count; i++) { 399 FileSpec dir = user_dirs.GetFileSpecAtIndex(i); 400 dir.ResolvePath(); 401 if (llvm::sys::fs::is_directory(dir.GetPath())) { 402 m_search_directories.push_back(dir); 403 } 404 } 405 } 406 407 void PlatformDarwinKernel::AddRootSubdirsToSearchPaths( 408 PlatformDarwinKernel *thisp, const std::string &dir) { 409 const char *subdirs[] = { 410 "/System/Library/Extensions", "/Library/Extensions", 411 "/System/Library/Kernels", 412 "/System/Library/Extensions/KDK", // this one probably only exist in 413 // /AppleInternal/Developer/KDKs/*.kdk/... 414 nullptr}; 415 for (int i = 0; subdirs[i] != nullptr; i++) { 416 FileSpec testdir(dir + subdirs[i], true); 417 if (llvm::sys::fs::is_directory(testdir.GetPath())) 418 thisp->m_search_directories.push_back(testdir); 419 } 420 421 // Look for kernel binaries in the top level directory, without any recursion 422 thisp->m_search_directories_no_recursing.push_back( 423 FileSpec(dir + "/", false)); 424 } 425 426 // Given a directory path dir, look for any subdirs named *.kdk and *.sdk 427 void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) { 428 // Look for *.kdk and *.sdk in dir 429 const bool find_directories = true; 430 const bool find_files = false; 431 const bool find_other = false; 432 FileSpec::EnumerateDirectory(dir.c_str(), find_directories, find_files, 433 find_other, FindKDKandSDKDirectoriesInDirectory, 434 this); 435 } 436 437 // Helper function to find *.sdk and *.kdk directories in a given directory. 438 FileSpec::EnumerateDirectoryResult 439 PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( 440 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 441 static ConstString g_sdk_suffix = ConstString("sdk"); 442 static ConstString g_kdk_suffix = ConstString("kdk"); 443 444 PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; 445 if (ft == llvm::sys::fs::file_type::directory_file && 446 (file_spec.GetFileNameExtension() == g_sdk_suffix || 447 file_spec.GetFileNameExtension() == g_kdk_suffix)) { 448 AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath()); 449 } 450 return FileSpec::eEnumerateDirectoryResultNext; 451 } 452 453 // Recursively search trough m_search_directories looking for 454 // kext and kernel binaries, adding files found to the appropriate 455 // lists. 456 void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { 457 const uint32_t num_dirs = m_search_directories.size(); 458 for (uint32_t i = 0; i < num_dirs; i++) { 459 const FileSpec &dir = m_search_directories[i]; 460 const bool find_directories = true; 461 const bool find_files = true; 462 const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. 463 FileSpec::EnumerateDirectory( 464 dir.GetPath().c_str(), find_directories, find_files, find_other, 465 GetKernelsAndKextsInDirectoryWithRecursion, this); 466 } 467 const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size(); 468 for (uint32_t i = 0; i < num_dirs_no_recurse; i++) { 469 const FileSpec &dir = m_search_directories_no_recursing[i]; 470 const bool find_directories = true; 471 const bool find_files = true; 472 const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. 473 FileSpec::EnumerateDirectory( 474 dir.GetPath().c_str(), find_directories, find_files, find_other, 475 GetKernelsAndKextsInDirectoryNoRecursion, this); 476 } 477 } 478 479 // We're only doing a filename match here. We won't try opening the file to see 480 // if it's really 481 // a kernel or not until we need to find a kernel of a given UUID. There's no 482 // cheap way to find 483 // the UUID of a file (or if it's a Mach-O binary at all) without creating a 484 // whole Module for 485 // the file and throwing it away if it's not wanted. 486 // 487 // Recurse into any subdirectories found. 488 489 FileSpec::EnumerateDirectoryResult 490 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion( 491 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 492 return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, true); 493 } 494 495 FileSpec::EnumerateDirectoryResult 496 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion( 497 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 498 return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, false); 499 } 500 501 FileSpec::EnumerateDirectoryResult 502 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( 503 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec, 504 bool recurse) { 505 static ConstString g_kext_suffix = ConstString("kext"); 506 static ConstString g_dsym_suffix = ConstString("dSYM"); 507 static ConstString g_bundle_suffix = ConstString("Bundle"); 508 ConstString file_spec_extension = file_spec.GetFileNameExtension(); 509 510 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 511 if (log) 512 log->Printf("PlatformDarwinKernel examining %s", 513 file_spec.GetPath().c_str()); 514 515 PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; 516 if (ft == llvm::sys::fs::file_type::regular_file || 517 ft == llvm::sys::fs::file_type::symlink_file) { 518 ConstString filename = file_spec.GetFilename(); 519 if ((strncmp(filename.GetCString(), "kernel", 6) == 0 || 520 strncmp(filename.GetCString(), "mach", 4) == 0) && 521 file_spec_extension != g_dsym_suffix) { 522 if (KernelHasdSYMSibling(file_spec)) 523 thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); 524 else 525 thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); 526 return FileSpec::eEnumerateDirectoryResultNext; 527 } 528 } else if (ft == llvm::sys::fs::file_type::directory_file && 529 file_spec_extension == g_kext_suffix) { 530 AddKextToMap(thisp, file_spec); 531 // Look to see if there is a PlugIns subdir with more kexts 532 FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns", false); 533 std::string search_here_too; 534 if (llvm::sys::fs::is_directory(contents_plugins.GetPath())) { 535 search_here_too = contents_plugins.GetPath(); 536 } else { 537 FileSpec plugins(file_spec.GetPath() + "/PlugIns", false); 538 if (llvm::sys::fs::is_directory(plugins.GetPath())) { 539 search_here_too = plugins.GetPath(); 540 } 541 } 542 543 if (!search_here_too.empty()) { 544 const bool find_directories = true; 545 const bool find_files = false; 546 const bool find_other = false; 547 FileSpec::EnumerateDirectory( 548 search_here_too.c_str(), find_directories, find_files, find_other, 549 recurse ? GetKernelsAndKextsInDirectoryWithRecursion 550 : GetKernelsAndKextsInDirectoryNoRecursion, 551 baton); 552 } 553 return FileSpec::eEnumerateDirectoryResultNext; 554 } 555 // Don't recurse into dSYM/kext/bundle directories 556 if (recurse && file_spec_extension != g_dsym_suffix && 557 file_spec_extension != g_kext_suffix && 558 file_spec_extension != g_bundle_suffix) { 559 return FileSpec::eEnumerateDirectoryResultEnter; 560 } else { 561 return FileSpec::eEnumerateDirectoryResultNext; 562 } 563 } 564 565 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp, 566 const FileSpec &file_spec) { 567 CFCBundle bundle(file_spec.GetPath().c_str()); 568 CFStringRef bundle_id(bundle.GetIdentifier()); 569 if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) { 570 char bundle_id_buf[PATH_MAX]; 571 if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf), 572 kCFStringEncodingUTF8)) { 573 ConstString bundle_conststr(bundle_id_buf); 574 if (KextHasdSYMSibling(file_spec)) 575 thisp->m_name_to_kext_path_map_with_dsyms.insert( 576 std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); 577 else 578 thisp->m_name_to_kext_path_map_without_dsyms.insert( 579 std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); 580 } 581 } 582 } 583 584 // Given a FileSpec of /dir/dir/foo.kext 585 // Return true if any of these exist: 586 // /dir/dir/foo.kext.dSYM 587 // /dir/dir/foo.kext/Contents/MacOS/foo.dSYM 588 // /dir/dir/foo.kext/foo.dSYM 589 bool PlatformDarwinKernel::KextHasdSYMSibling( 590 const FileSpec &kext_bundle_filepath) { 591 FileSpec dsym_fspec = kext_bundle_filepath; 592 std::string filename = dsym_fspec.GetFilename().AsCString(); 593 filename += ".dSYM"; 594 dsym_fspec.GetFilename() = ConstString(filename); 595 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 596 return true; 597 } 598 // Should probably get the CFBundleExecutable here or call 599 // CFBundleCopyExecutableURL 600 601 // Look for a deep bundle foramt 602 ConstString executable_name = 603 kext_bundle_filepath.GetFileNameStrippingExtension(); 604 std::string deep_bundle_str = 605 kext_bundle_filepath.GetPath() + "/Contents/MacOS/"; 606 deep_bundle_str += executable_name.AsCString(); 607 deep_bundle_str += ".dSYM"; 608 dsym_fspec.SetFile(deep_bundle_str, true); 609 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 610 return true; 611 } 612 613 // look for a shallow bundle format 614 // 615 std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/"; 616 shallow_bundle_str += executable_name.AsCString(); 617 shallow_bundle_str += ".dSYM"; 618 dsym_fspec.SetFile(shallow_bundle_str, true); 619 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 620 return true; 621 } 622 return false; 623 } 624 625 // Given a FileSpec of /dir/dir/mach.development.t7004 626 // Return true if a dSYM exists next to it: 627 // /dir/dir/mach.development.t7004.dSYM 628 bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { 629 FileSpec kernel_dsym = kernel_binary; 630 std::string filename = kernel_binary.GetFilename().AsCString(); 631 filename += ".dSYM"; 632 kernel_dsym.GetFilename() = ConstString(filename); 633 if (llvm::sys::fs::is_directory(kernel_dsym.GetPath())) { 634 return true; 635 } 636 return false; 637 } 638 639 Error PlatformDarwinKernel::GetSharedModule( 640 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, 641 const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, 642 bool *did_create_ptr) { 643 Error error; 644 module_sp.reset(); 645 const FileSpec &platform_file = module_spec.GetFileSpec(); 646 647 // Treat the file's path as a kext bundle ID (e.g. 648 // "com.apple.driver.AppleIRController") and search our kext index. 649 std::string kext_bundle_id = platform_file.GetPath(); 650 if (!kext_bundle_id.empty()) { 651 ConstString kext_bundle_cs(kext_bundle_id.c_str()); 652 653 // First look through the kext bundles that had a dsym next to them 654 if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) { 655 for (BundleIDToKextIterator it = 656 m_name_to_kext_path_map_with_dsyms.begin(); 657 it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { 658 if (it->first == kext_bundle_cs) { 659 error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), 660 module_spec.GetArchitecture(), 661 module_sp); 662 if (module_sp.get()) { 663 return error; 664 } 665 } 666 } 667 } 668 669 // Second look through the kext binarys without dSYMs 670 if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) { 671 for (BundleIDToKextIterator it = 672 m_name_to_kext_path_map_without_dsyms.begin(); 673 it != m_name_to_kext_path_map_without_dsyms.end(); ++it) { 674 if (it->first == kext_bundle_cs) { 675 error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), 676 module_spec.GetArchitecture(), 677 module_sp); 678 if (module_sp.get()) { 679 return error; 680 } 681 } 682 } 683 } 684 } 685 686 if (kext_bundle_id.compare("mach_kernel") == 0 && 687 module_spec.GetUUID().IsValid()) { 688 // First try all kernel binaries that have a dSYM next to them 689 for (auto possible_kernel : m_kernel_binaries_with_dsyms) { 690 if (possible_kernel.Exists()) { 691 ModuleSpec kern_spec(possible_kernel); 692 kern_spec.GetUUID() = module_spec.GetUUID(); 693 ModuleSP module_sp(new Module(kern_spec)); 694 if (module_sp && module_sp->GetObjectFile() && 695 module_sp->MatchesModuleSpec(kern_spec)) { 696 // module_sp is an actual kernel binary we want to add. 697 if (process) { 698 process->GetTarget().GetImages().AppendIfNeeded(module_sp); 699 error.Clear(); 700 return error; 701 } else { 702 error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, 703 NULL, NULL); 704 if (module_sp && module_sp->GetObjectFile() && 705 module_sp->GetObjectFile()->GetType() != 706 ObjectFile::Type::eTypeCoreFile) { 707 return error; 708 } 709 module_sp.reset(); 710 } 711 } 712 } 713 } 714 // Second try all kernel binaries that don't have a dSYM 715 for (auto possible_kernel : m_kernel_binaries_without_dsyms) { 716 if (possible_kernel.Exists()) { 717 ModuleSpec kern_spec(possible_kernel); 718 kern_spec.GetUUID() = module_spec.GetUUID(); 719 ModuleSP module_sp(new Module(kern_spec)); 720 if (module_sp && module_sp->GetObjectFile() && 721 module_sp->MatchesModuleSpec(kern_spec)) { 722 // module_sp is an actual kernel binary we want to add. 723 if (process) { 724 process->GetTarget().GetImages().AppendIfNeeded(module_sp); 725 error.Clear(); 726 return error; 727 } else { 728 error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, 729 NULL, NULL); 730 if (module_sp && module_sp->GetObjectFile() && 731 module_sp->GetObjectFile()->GetType() != 732 ObjectFile::Type::eTypeCoreFile) { 733 return error; 734 } 735 module_sp.reset(); 736 } 737 } 738 } 739 } 740 } 741 742 // Else fall back to treating the file's path as an actual file path - defer 743 // to PlatformDarwin's GetSharedModule. 744 return PlatformDarwin::GetSharedModule(module_spec, process, module_sp, 745 module_search_paths_ptr, 746 old_module_sp_ptr, did_create_ptr); 747 } 748 749 Error PlatformDarwinKernel::ExamineKextForMatchingUUID( 750 const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, 751 const ArchSpec &arch, ModuleSP &exe_module_sp) { 752 Error error; 753 FileSpec exe_file = kext_bundle_path; 754 Host::ResolveExecutableInBundle(exe_file); 755 if (exe_file.Exists()) { 756 ModuleSpec exe_spec(exe_file); 757 exe_spec.GetUUID() = uuid; 758 if (!uuid.IsValid()) { 759 exe_spec.GetArchitecture() = arch; 760 } 761 762 // First try to create a ModuleSP with the file / arch and see if the UUID 763 // matches. 764 // If that fails (this exec file doesn't have the correct uuid), don't call 765 // GetSharedModule 766 // (which may call in to the DebugSymbols framework and therefore can be 767 // slow.) 768 ModuleSP module_sp(new Module(exe_spec)); 769 if (module_sp && module_sp->GetObjectFile() && 770 module_sp->MatchesModuleSpec(exe_spec)) { 771 error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL, 772 NULL); 773 if (exe_module_sp && exe_module_sp->GetObjectFile()) { 774 return error; 775 } 776 } 777 exe_module_sp.reset(); 778 } 779 return error; 780 } 781 782 bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx, 783 ArchSpec &arch) { 784 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 785 return ARMGetSupportedArchitectureAtIndex(idx, arch); 786 #else 787 return x86GetSupportedArchitectureAtIndex(idx, arch); 788 #endif 789 } 790 791 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() { 792 m_trap_handlers.push_back(ConstString("trap_from_kernel")); 793 m_trap_handlers.push_back(ConstString("hndl_machine_check")); 794 m_trap_handlers.push_back(ConstString("hndl_double_fault")); 795 m_trap_handlers.push_back(ConstString("hndl_allintrs")); 796 m_trap_handlers.push_back(ConstString("hndl_alltraps")); 797 m_trap_handlers.push_back(ConstString("interrupt")); 798 m_trap_handlers.push_back(ConstString("fleh_prefabt")); 799 m_trap_handlers.push_back(ConstString("ExceptionVectorsBase")); 800 m_trap_handlers.push_back(ConstString("ExceptionVectorsTable")); 801 m_trap_handlers.push_back(ConstString("fleh_undef")); 802 m_trap_handlers.push_back(ConstString("fleh_dataabt")); 803 m_trap_handlers.push_back(ConstString("fleh_irq")); 804 m_trap_handlers.push_back(ConstString("fleh_decirq")); 805 m_trap_handlers.push_back(ConstString("fleh_fiq_generic")); 806 m_trap_handlers.push_back(ConstString("fleh_dec")); 807 } 808 809 #else // __APPLE__ 810 811 // Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies on 812 // PlatformDarwinKernel for the plug-in name, we compile just the plug-in name 813 // in 814 // here to avoid issues. We are tracking an internal bug to resolve this issue 815 // by 816 // either not compiling in DynamicLoaderDarwinKernel for non-apple builds, or to 817 // make 818 // PlatformDarwinKernel build on all systems. PlatformDarwinKernel is currently 819 // not 820 // compiled on other platforms due to the use of the Mac-specific 821 // source/Host/macosx/cfcpp utilities. 822 823 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { 824 static lldb_private::ConstString g_name("darwin-kernel"); 825 return g_name; 826 } 827 828 #endif // __APPLE__ 829