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