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