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