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