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 96 // userland debugging. It is only useful in kernel debug sessions and the 97 // DynamicLoaderDarwinPlugin 98 // (or a user doing 'platform select') will force the creation of this 99 // Platform plugin. 100 if (force == false) { 101 if (log) 102 log->Printf("PlatformDarwinKernel::%s() aborting creation of platform " 103 "because force == false", 104 __FUNCTION__); 105 return PlatformSP(); 106 } 107 108 bool create = force; 109 LazyBool is_ios_debug_session = eLazyBoolCalculate; 110 111 if (create == false && arch && arch->IsValid()) { 112 const llvm::Triple &triple = arch->GetTriple(); 113 switch (triple.getVendor()) { 114 case llvm::Triple::Apple: 115 create = true; 116 break; 117 118 // Only accept "unknown" for vendor if the host is Apple and 119 // it "unknown" wasn't specified (it was just returned because it 120 // was NOT specified) 121 case llvm::Triple::UnknownArch: 122 create = !arch->TripleVendorWasSpecified(); 123 break; 124 default: 125 break; 126 } 127 128 if (create) { 129 switch (triple.getOS()) { 130 case llvm::Triple::Darwin: 131 case llvm::Triple::MacOSX: 132 case llvm::Triple::IOS: 133 case llvm::Triple::WatchOS: 134 case llvm::Triple::TvOS: 135 break; 136 // Only accept "vendor" for vendor if the host is Apple and 137 // it "unknown" wasn't specified (it was just returned because it 138 // was NOT specified) 139 case llvm::Triple::UnknownOS: 140 create = !arch->TripleOSWasSpecified(); 141 break; 142 default: 143 create = false; 144 break; 145 } 146 } 147 } 148 if (arch && arch->IsValid()) { 149 switch (arch->GetMachine()) { 150 case llvm::Triple::x86: 151 case llvm::Triple::x86_64: 152 case llvm::Triple::ppc: 153 case llvm::Triple::ppc64: 154 is_ios_debug_session = eLazyBoolNo; 155 break; 156 case llvm::Triple::arm: 157 case llvm::Triple::aarch64: 158 case llvm::Triple::thumb: 159 is_ios_debug_session = eLazyBoolYes; 160 break; 161 default: 162 is_ios_debug_session = eLazyBoolCalculate; 163 break; 164 } 165 } 166 if (create) { 167 if (log) 168 log->Printf("PlatformDarwinKernel::%s() creating platform", __FUNCTION__); 169 170 return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session)); 171 } 172 173 if (log) 174 log->Printf("PlatformDarwinKernel::%s() aborting creation of platform", 175 __FUNCTION__); 176 177 return PlatformSP(); 178 } 179 180 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { 181 static ConstString g_name("darwin-kernel"); 182 return g_name; 183 } 184 185 const char *PlatformDarwinKernel::GetDescriptionStatic() { 186 return "Darwin Kernel platform plug-in."; 187 } 188 189 //------------------------------------------------------------------ 190 /// Code to handle the PlatformDarwinKernel settings 191 //------------------------------------------------------------------ 192 193 static PropertyDefinition g_properties[] = { 194 {"search-locally-for-kexts", OptionValue::eTypeBoolean, true, true, NULL, 195 NULL, "Automatically search for kexts on the local system when doing " 196 "kernel debugging."}, 197 {"kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, NULL, 198 "Directories/KDKs to search for kexts in when starting a kernel debug " 199 "session."}, 200 {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; 201 202 enum { ePropertySearchForKexts = 0, ePropertyKextDirectories }; 203 204 class PlatformDarwinKernelProperties : public Properties { 205 public: 206 static ConstString &GetSettingName() { 207 static ConstString g_setting_name("darwin-kernel"); 208 return g_setting_name; 209 } 210 211 PlatformDarwinKernelProperties() : Properties() { 212 m_collection_sp.reset(new OptionValueProperties(GetSettingName())); 213 m_collection_sp->Initialize(g_properties); 214 } 215 216 virtual ~PlatformDarwinKernelProperties() {} 217 218 bool GetSearchForKexts() const { 219 const uint32_t idx = ePropertySearchForKexts; 220 return m_collection_sp->GetPropertyAtIndexAsBoolean( 221 NULL, idx, g_properties[idx].default_uint_value != 0); 222 } 223 224 FileSpecList &GetKextDirectories() const { 225 const uint32_t idx = ePropertyKextDirectories; 226 OptionValueFileSpecList *option_value = 227 m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList( 228 NULL, false, idx); 229 assert(option_value); 230 return option_value->GetCurrentValue(); 231 } 232 }; 233 234 typedef std::shared_ptr<PlatformDarwinKernelProperties> 235 PlatformDarwinKernelPropertiesSP; 236 237 static const PlatformDarwinKernelPropertiesSP &GetGlobalProperties() { 238 static PlatformDarwinKernelPropertiesSP g_settings_sp; 239 if (!g_settings_sp) 240 g_settings_sp.reset(new PlatformDarwinKernelProperties()); 241 return g_settings_sp; 242 } 243 244 void PlatformDarwinKernel::DebuggerInitialize( 245 lldb_private::Debugger &debugger) { 246 if (!PluginManager::GetSettingForPlatformPlugin( 247 debugger, PlatformDarwinKernelProperties::GetSettingName())) { 248 const bool is_global_setting = true; 249 PluginManager::CreateSettingForPlatformPlugin( 250 debugger, GetGlobalProperties()->GetValueProperties(), 251 ConstString("Properties for the PlatformDarwinKernel plug-in."), 252 is_global_setting); 253 } 254 } 255 256 //------------------------------------------------------------------ 257 /// Default Constructor 258 //------------------------------------------------------------------ 259 PlatformDarwinKernel::PlatformDarwinKernel( 260 lldb_private::LazyBool is_ios_debug_session) 261 : PlatformDarwin(false), // This is a remote platform 262 m_name_to_kext_path_map_with_dsyms(), 263 m_name_to_kext_path_map_without_dsyms(), m_search_directories(), 264 m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(), 265 m_kernel_binaries_without_dsyms(), 266 m_ios_debug_session(is_ios_debug_session) 267 268 { 269 if (GetGlobalProperties()->GetSearchForKexts()) { 270 CollectKextAndKernelDirectories(); 271 SearchForKextsAndKernelsRecursively(); 272 } 273 } 274 275 //------------------------------------------------------------------ 276 /// Destructor. 277 /// 278 /// The destructor is virtual since this class is designed to be 279 /// inherited from by the plug-in instance. 280 //------------------------------------------------------------------ 281 PlatformDarwinKernel::~PlatformDarwinKernel() {} 282 283 void PlatformDarwinKernel::GetStatus(Stream &strm) { 284 Platform::GetStatus(strm); 285 strm.Printf(" Debug session type: "); 286 if (m_ios_debug_session == eLazyBoolYes) 287 strm.Printf("iOS kernel debugging\n"); 288 else if (m_ios_debug_session == eLazyBoolNo) 289 strm.Printf("Mac OS X kernel debugging\n"); 290 else 291 strm.Printf("unknown kernel debugging\n"); 292 293 strm.Printf("Directories searched recursively:\n"); 294 const uint32_t num_kext_dirs = m_search_directories.size(); 295 for (uint32_t i = 0; i < num_kext_dirs; ++i) { 296 strm.Printf("[%d] %s\n", i, m_search_directories[i].GetPath().c_str()); 297 } 298 299 strm.Printf("Directories not searched recursively:\n"); 300 const uint32_t num_kext_dirs_no_recursion = 301 m_search_directories_no_recursing.size(); 302 for (uint32_t i = 0; i < num_kext_dirs_no_recursion; i++) { 303 strm.Printf("[%d] %s\n", i, 304 m_search_directories_no_recursing[i].GetPath().c_str()); 305 } 306 307 strm.Printf(" Number of kexts with dSYMs indexed: %d\n", 308 (int)m_name_to_kext_path_map_with_dsyms.size()); 309 strm.Printf(" Number of kexts without dSYMs indexed: %d\n", 310 (int)m_name_to_kext_path_map_without_dsyms.size()); 311 strm.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n", 312 (int)m_kernel_binaries_with_dsyms.size()); 313 strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n", 314 (int)m_kernel_binaries_without_dsyms.size()); 315 316 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 317 if (log) { 318 log->Printf("\nkexts with dSYMs"); 319 for (auto pos : m_name_to_kext_path_map_with_dsyms) { 320 log->Printf("%s", pos.second.GetPath().c_str()); 321 } 322 log->Printf("\nkexts without dSYMs"); 323 324 for (auto pos : m_name_to_kext_path_map_without_dsyms) { 325 log->Printf("%s", pos.second.GetPath().c_str()); 326 } 327 log->Printf("\nkernels with dSYMS"); 328 for (auto fs : m_kernel_binaries_with_dsyms) { 329 log->Printf("%s", fs.GetPath().c_str()); 330 } 331 log->Printf("\nkernels without dSYMS"); 332 for (auto fs : m_kernel_binaries_without_dsyms) { 333 log->Printf("%s", fs.GetPath().c_str()); 334 } 335 log->Printf("\n"); 336 } 337 } 338 339 // Populate the m_search_directories vector with directories we should search 340 // for kernel & kext binaries. 341 342 void PlatformDarwinKernel::CollectKextAndKernelDirectories() { 343 // Differentiate between "ios debug session" and "mac debug session" so we 344 // don't index 345 // kext bundles that won't be used in this debug session. If this is an ios 346 // kext debug 347 // session, looking in /System/Library/Extensions is a waste of stat()s, for 348 // example. 349 350 // DeveloperDirectory is something like 351 // "/Applications/Xcode.app/Contents/Developer" 352 std::string developer_dir = GetDeveloperDirectory(); 353 if (developer_dir.empty()) 354 developer_dir = "/Applications/Xcode.app/Contents/Developer"; 355 356 if (m_ios_debug_session != eLazyBoolNo) { 357 AddSDKSubdirsToSearchPaths(developer_dir + 358 "/Platforms/iPhoneOS.platform/Developer/SDKs"); 359 AddSDKSubdirsToSearchPaths(developer_dir + 360 "/Platforms/AppleTVOS.platform/Developer/SDKs"); 361 AddSDKSubdirsToSearchPaths(developer_dir + 362 "/Platforms/WatchOS.platform/Developer/SDKs"); 363 } 364 if (m_ios_debug_session != eLazyBoolYes) { 365 AddSDKSubdirsToSearchPaths(developer_dir + 366 "/Platforms/MacOSX.platform/Developer/SDKs"); 367 } 368 369 AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit"); 370 AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs"); 371 // The KDKs distributed from Apple installed on external 372 // developer systems may be in directories like 373 // /Library/Developer/KDKs/KDK_10.10_14A298i.kdk 374 AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs"); 375 376 if (m_ios_debug_session != eLazyBoolNo) { 377 } 378 if (m_ios_debug_session != eLazyBoolYes) { 379 AddRootSubdirsToSearchPaths(this, "/"); 380 } 381 382 GetUserSpecifiedDirectoriesToSearch(); 383 384 // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols 385 FileSpec possible_dir(developer_dir + "/../Symbols", true); 386 if (llvm::sys::fs::is_directory(possible_dir.GetPath())) 387 m_search_directories.push_back(possible_dir); 388 389 // Add simple directory of the current working directory 390 m_search_directories_no_recursing.push_back(FileSpec(".", true)); 391 } 392 393 void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() { 394 FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories()); 395 std::vector<FileSpec> possible_sdk_dirs; 396 397 const uint32_t user_dirs_count = user_dirs.GetSize(); 398 for (uint32_t i = 0; i < user_dirs_count; i++) { 399 FileSpec dir = user_dirs.GetFileSpecAtIndex(i); 400 dir.ResolvePath(); 401 if (llvm::sys::fs::is_directory(dir.GetPath())) { 402 m_search_directories.push_back(dir); 403 } 404 } 405 } 406 407 void PlatformDarwinKernel::AddRootSubdirsToSearchPaths( 408 PlatformDarwinKernel *thisp, const std::string &dir) { 409 const char *subdirs[] = { 410 "/System/Library/Extensions", "/Library/Extensions", 411 "/System/Library/Kernels", 412 "/System/Library/Extensions/KDK", // this one probably only exist in 413 // /AppleInternal/Developer/KDKs/*.kdk/... 414 nullptr}; 415 for (int i = 0; subdirs[i] != nullptr; i++) { 416 FileSpec testdir(dir + subdirs[i], true); 417 if (llvm::sys::fs::is_directory(testdir.GetPath())) 418 thisp->m_search_directories.push_back(testdir); 419 } 420 421 // Look for kernel binaries in the top level directory, without any recursion 422 thisp->m_search_directories_no_recursing.push_back( 423 FileSpec(dir + "/", false)); 424 } 425 426 // Given a directory path dir, look for any subdirs named *.kdk and *.sdk 427 void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) { 428 // Look for *.kdk and *.sdk in dir 429 const bool find_directories = true; 430 const bool find_files = false; 431 const bool find_other = false; 432 FileSpec::EnumerateDirectory(dir.c_str(), find_directories, find_files, 433 find_other, FindKDKandSDKDirectoriesInDirectory, 434 this); 435 } 436 437 // Helper function to find *.sdk and *.kdk directories in a given directory. 438 FileSpec::EnumerateDirectoryResult 439 PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( 440 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 441 static ConstString g_sdk_suffix = ConstString("sdk"); 442 static ConstString g_kdk_suffix = ConstString("kdk"); 443 444 PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; 445 if (ft == llvm::sys::fs::file_type::directory_file && 446 (file_spec.GetFileNameExtension() == g_sdk_suffix || 447 file_spec.GetFileNameExtension() == g_kdk_suffix)) { 448 AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath()); 449 } 450 return FileSpec::eEnumerateDirectoryResultNext; 451 } 452 453 // Recursively search trough m_search_directories looking for 454 // kext and kernel binaries, adding files found to the appropriate 455 // lists. 456 void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { 457 const uint32_t num_dirs = m_search_directories.size(); 458 for (uint32_t i = 0; i < num_dirs; i++) { 459 const FileSpec &dir = m_search_directories[i]; 460 const bool find_directories = true; 461 const bool find_files = true; 462 const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. 463 FileSpec::EnumerateDirectory( 464 dir.GetPath().c_str(), find_directories, find_files, find_other, 465 GetKernelsAndKextsInDirectoryWithRecursion, this); 466 } 467 const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size(); 468 for (uint32_t i = 0; i < num_dirs_no_recurse; i++) { 469 const FileSpec &dir = m_search_directories_no_recursing[i]; 470 const bool find_directories = true; 471 const bool find_files = true; 472 const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. 473 FileSpec::EnumerateDirectory( 474 dir.GetPath().c_str(), find_directories, find_files, find_other, 475 GetKernelsAndKextsInDirectoryNoRecursion, this); 476 } 477 } 478 479 // We're only doing a filename match here. We won't try opening the file to see 480 // if it's really 481 // a kernel or not until we need to find a kernel of a given UUID. There's no 482 // cheap way to find 483 // the UUID of a file (or if it's a Mach-O binary at all) without creating a 484 // whole Module for 485 // the file and throwing it away if it's not wanted. 486 // 487 // Recurse into any subdirectories found. 488 489 FileSpec::EnumerateDirectoryResult 490 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion( 491 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 492 return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, true); 493 } 494 495 FileSpec::EnumerateDirectoryResult 496 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion( 497 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 498 return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, false); 499 } 500 501 FileSpec::EnumerateDirectoryResult 502 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( 503 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec, 504 bool recurse) { 505 static ConstString g_kext_suffix = ConstString("kext"); 506 static ConstString g_dsym_suffix = ConstString("dSYM"); 507 static ConstString g_bundle_suffix = ConstString("Bundle"); 508 ConstString file_spec_extension = file_spec.GetFileNameExtension(); 509 510 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 511 Log *log_verbose(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM | LLDB_LOG_OPTION_VERBOSE)); 512 513 if (log_verbose) 514 log_verbose->Printf ("PlatformDarwinKernel examining '%s'", file_spec.GetPath().c_str()); 515 516 PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; 517 if (ft == llvm::sys::fs::file_type::regular_file || 518 ft == llvm::sys::fs::file_type::symlink_file) { 519 ConstString filename = file_spec.GetFilename(); 520 if ((strncmp(filename.GetCString(), "kernel", 6) == 0 || 521 strncmp(filename.GetCString(), "mach", 4) == 0) && 522 file_spec_extension != g_dsym_suffix) { 523 if (KernelHasdSYMSibling(file_spec)) 524 { 525 if (log) 526 { 527 log->Printf ("PlatformDarwinKernel registering kernel binary '%s' with dSYM sibling", file_spec.GetPath().c_str()); 528 } 529 thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); 530 } 531 else 532 { 533 if (log) 534 { 535 log->Printf ("PlatformDarwinKernel registering kernel binary '%s', no dSYM", file_spec.GetPath().c_str()); 536 } 537 thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); 538 } 539 return FileSpec::eEnumerateDirectoryResultNext; 540 } 541 } else if (ft == llvm::sys::fs::file_type::directory_file && 542 file_spec_extension == g_kext_suffix) { 543 AddKextToMap(thisp, file_spec); 544 // Look to see if there is a PlugIns subdir with more kexts 545 FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns", false); 546 std::string search_here_too; 547 if (llvm::sys::fs::is_directory(contents_plugins.GetPath())) { 548 search_here_too = contents_plugins.GetPath(); 549 } else { 550 FileSpec plugins(file_spec.GetPath() + "/PlugIns", false); 551 if (llvm::sys::fs::is_directory(plugins.GetPath())) { 552 search_here_too = plugins.GetPath(); 553 } 554 } 555 556 if (!search_here_too.empty()) { 557 const bool find_directories = true; 558 const bool find_files = false; 559 const bool find_other = false; 560 FileSpec::EnumerateDirectory( 561 search_here_too.c_str(), find_directories, find_files, find_other, 562 recurse ? GetKernelsAndKextsInDirectoryWithRecursion 563 : GetKernelsAndKextsInDirectoryNoRecursion, 564 baton); 565 } 566 return FileSpec::eEnumerateDirectoryResultNext; 567 } 568 // Don't recurse into dSYM/kext/bundle directories 569 if (recurse && file_spec_extension != g_dsym_suffix && 570 file_spec_extension != g_kext_suffix && 571 file_spec_extension != g_bundle_suffix) { 572 if (log_verbose) 573 log_verbose->Printf ("PlatformDarwinKernel descending into directory '%s'", file_spec.GetPath().c_str()); 574 return FileSpec::eEnumerateDirectoryResultEnter; 575 } else { 576 return FileSpec::eEnumerateDirectoryResultNext; 577 } 578 } 579 580 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp, 581 const FileSpec &file_spec) { 582 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 583 CFCBundle bundle(file_spec.GetPath().c_str()); 584 CFStringRef bundle_id(bundle.GetIdentifier()); 585 if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) { 586 char bundle_id_buf[PATH_MAX]; 587 if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf), 588 kCFStringEncodingUTF8)) { 589 ConstString bundle_conststr(bundle_id_buf); 590 if (KextHasdSYMSibling(file_spec)) 591 { 592 if (log) 593 { 594 log->Printf ("PlatformDarwinKernel registering kext binary '%s' with dSYM sibling", file_spec.GetPath().c_str()); 595 } 596 thisp->m_name_to_kext_path_map_with_dsyms.insert( 597 std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); 598 } 599 else 600 { 601 if (log) 602 { 603 log->Printf ("PlatformDarwinKernel registering kext binary '%s', no dSYM", file_spec.GetPath().c_str()); 604 } 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.GetFilename() = ConstString(filename); 623 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 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, true); 637 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 638 return true; 639 } 640 641 // look for a shallow bundle format 642 // 643 std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/"; 644 shallow_bundle_str += executable_name.AsCString(); 645 shallow_bundle_str += ".dSYM"; 646 dsym_fspec.SetFile(shallow_bundle_str, true); 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 654 // Return true if a dSYM 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 698 // DebugSymbols 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 (possible_kernel.Exists()) { 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 753 // DebugSymbols 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 (possible_kernel.Exists()) { 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 Status PlatformDarwinKernel::ExamineKextForMatchingUUID( 793 const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, 794 const ArchSpec &arch, ModuleSP &exe_module_sp) { 795 Status error; 796 FileSpec exe_file = kext_bundle_path; 797 Host::ResolveExecutableInBundle(exe_file); 798 if (exe_file.Exists()) { 799 ModuleSpec exe_spec(exe_file); 800 exe_spec.GetUUID() = uuid; 801 if (!uuid.IsValid()) { 802 exe_spec.GetArchitecture() = arch; 803 } 804 805 // First try to create a ModuleSP with the file / arch and see if the UUID 806 // matches. 807 // If that fails (this exec file doesn't have the correct uuid), don't call 808 // GetSharedModule 809 // (which may call in to the DebugSymbols framework and therefore can be 810 // slow.) 811 ModuleSP module_sp(new Module(exe_spec)); 812 if (module_sp && module_sp->GetObjectFile() && 813 module_sp->MatchesModuleSpec(exe_spec)) { 814 error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL, 815 NULL); 816 if (exe_module_sp && exe_module_sp->GetObjectFile()) { 817 return error; 818 } 819 } 820 exe_module_sp.reset(); 821 } 822 return error; 823 } 824 825 bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx, 826 ArchSpec &arch) { 827 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 828 return ARMGetSupportedArchitectureAtIndex(idx, arch); 829 #else 830 return x86GetSupportedArchitectureAtIndex(idx, arch); 831 #endif 832 } 833 834 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() { 835 m_trap_handlers.push_back(ConstString("trap_from_kernel")); 836 m_trap_handlers.push_back(ConstString("hndl_machine_check")); 837 m_trap_handlers.push_back(ConstString("hndl_double_fault")); 838 m_trap_handlers.push_back(ConstString("hndl_allintrs")); 839 m_trap_handlers.push_back(ConstString("hndl_alltraps")); 840 m_trap_handlers.push_back(ConstString("interrupt")); 841 m_trap_handlers.push_back(ConstString("fleh_prefabt")); 842 m_trap_handlers.push_back(ConstString("ExceptionVectorsBase")); 843 m_trap_handlers.push_back(ConstString("ExceptionVectorsTable")); 844 m_trap_handlers.push_back(ConstString("fleh_undef")); 845 m_trap_handlers.push_back(ConstString("fleh_dataabt")); 846 m_trap_handlers.push_back(ConstString("fleh_irq")); 847 m_trap_handlers.push_back(ConstString("fleh_decirq")); 848 m_trap_handlers.push_back(ConstString("fleh_fiq_generic")); 849 m_trap_handlers.push_back(ConstString("fleh_dec")); 850 } 851 852 #else // __APPLE__ 853 854 // Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies on 855 // PlatformDarwinKernel for the plug-in name, we compile just the plug-in name 856 // in 857 // here to avoid issues. We are tracking an internal bug to resolve this issue 858 // by 859 // either not compiling in DynamicLoaderDarwinKernel for non-apple builds, or to 860 // make 861 // PlatformDarwinKernel build on all systems. PlatformDarwinKernel is currently 862 // not 863 // compiled on other platforms due to the use of the Mac-specific 864 // source/Host/macosx/cfcpp utilities. 865 866 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { 867 static lldb_private::ConstString g_name("darwin-kernel"); 868 return g_name; 869 } 870 871 #endif // __APPLE__ 872