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