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