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