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