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