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 break; 133 // Only accept "vendor" for vendor if the host is Apple and it "unknown" 134 // wasn't specified (it was just returned because it was NOT specified) 135 case llvm::Triple::UnknownOS: 136 create = !arch->TripleOSWasSpecified(); 137 break; 138 default: 139 create = false; 140 break; 141 } 142 } 143 } 144 if (arch && arch->IsValid()) { 145 switch (arch->GetMachine()) { 146 case llvm::Triple::x86: 147 case llvm::Triple::x86_64: 148 case llvm::Triple::ppc: 149 case llvm::Triple::ppc64: 150 is_ios_debug_session = eLazyBoolNo; 151 break; 152 case llvm::Triple::arm: 153 case llvm::Triple::aarch64: 154 case llvm::Triple::thumb: 155 is_ios_debug_session = eLazyBoolYes; 156 break; 157 default: 158 is_ios_debug_session = eLazyBoolCalculate; 159 break; 160 } 161 } 162 if (create) { 163 if (log) 164 log->Printf("PlatformDarwinKernel::%s() creating platform", __FUNCTION__); 165 166 return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session)); 167 } 168 169 if (log) 170 log->Printf("PlatformDarwinKernel::%s() aborting creation of platform", 171 __FUNCTION__); 172 173 return PlatformSP(); 174 } 175 176 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { 177 static ConstString g_name("darwin-kernel"); 178 return g_name; 179 } 180 181 const char *PlatformDarwinKernel::GetDescriptionStatic() { 182 return "Darwin Kernel platform plug-in."; 183 } 184 185 //------------------------------------------------------------------ 186 /// Code to handle the PlatformDarwinKernel settings 187 //------------------------------------------------------------------ 188 189 static PropertyDefinition g_properties[] = { 190 {"search-locally-for-kexts", OptionValue::eTypeBoolean, true, true, NULL, 191 NULL, "Automatically search for kexts on the local system when doing " 192 "kernel debugging."}, 193 {"kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, NULL, 194 "Directories/KDKs to search for kexts in when starting a kernel debug " 195 "session."}, 196 {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; 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 } 358 if (m_ios_debug_session != eLazyBoolYes) { 359 AddSDKSubdirsToSearchPaths(developer_dir + 360 "/Platforms/MacOSX.platform/Developer/SDKs"); 361 } 362 363 AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit"); 364 AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs"); 365 // The KDKs distributed from Apple installed on external developer systems 366 // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk 367 AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs"); 368 369 if (m_ios_debug_session != eLazyBoolNo) { 370 } 371 if (m_ios_debug_session != eLazyBoolYes) { 372 AddRootSubdirsToSearchPaths(this, "/"); 373 } 374 375 GetUserSpecifiedDirectoriesToSearch(); 376 377 // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols 378 FileSpec possible_dir(developer_dir + "/../Symbols", true); 379 if (llvm::sys::fs::is_directory(possible_dir.GetPath())) 380 m_search_directories.push_back(possible_dir); 381 382 // Add simple directory of the current working directory 383 m_search_directories_no_recursing.push_back(FileSpec(".", true)); 384 } 385 386 void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() { 387 FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories()); 388 std::vector<FileSpec> possible_sdk_dirs; 389 390 const uint32_t user_dirs_count = user_dirs.GetSize(); 391 for (uint32_t i = 0; i < user_dirs_count; i++) { 392 FileSpec dir = user_dirs.GetFileSpecAtIndex(i); 393 dir.ResolvePath(); 394 if (llvm::sys::fs::is_directory(dir.GetPath())) { 395 m_search_directories.push_back(dir); 396 } 397 } 398 } 399 400 void PlatformDarwinKernel::AddRootSubdirsToSearchPaths( 401 PlatformDarwinKernel *thisp, const std::string &dir) { 402 const char *subdirs[] = { 403 "/System/Library/Extensions", "/Library/Extensions", 404 "/System/Library/Kernels", 405 "/System/Library/Extensions/KDK", // this one probably only exist in 406 // /AppleInternal/Developer/KDKs/*.kdk/... 407 nullptr}; 408 for (int i = 0; subdirs[i] != nullptr; i++) { 409 FileSpec testdir(dir + subdirs[i], true); 410 if (llvm::sys::fs::is_directory(testdir.GetPath())) 411 thisp->m_search_directories.push_back(testdir); 412 } 413 414 // Look for kernel binaries in the top level directory, without any recursion 415 thisp->m_search_directories_no_recursing.push_back( 416 FileSpec(dir + "/", false)); 417 } 418 419 // Given a directory path dir, look for any subdirs named *.kdk and *.sdk 420 void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) { 421 // Look for *.kdk and *.sdk in dir 422 const bool find_directories = true; 423 const bool find_files = false; 424 const bool find_other = false; 425 FileSpec::EnumerateDirectory(dir.c_str(), find_directories, find_files, 426 find_other, FindKDKandSDKDirectoriesInDirectory, 427 this); 428 } 429 430 // Helper function to find *.sdk and *.kdk directories in a given directory. 431 FileSpec::EnumerateDirectoryResult 432 PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( 433 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 434 static ConstString g_sdk_suffix = ConstString("sdk"); 435 static ConstString g_kdk_suffix = ConstString("kdk"); 436 437 PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; 438 if (ft == llvm::sys::fs::file_type::directory_file && 439 (file_spec.GetFileNameExtension() == g_sdk_suffix || 440 file_spec.GetFileNameExtension() == g_kdk_suffix)) { 441 AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath()); 442 } 443 return FileSpec::eEnumerateDirectoryResultNext; 444 } 445 446 // Recursively search trough m_search_directories looking for kext and kernel 447 // binaries, adding files found to the appropriate lists. 448 void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { 449 const uint32_t num_dirs = m_search_directories.size(); 450 for (uint32_t i = 0; i < num_dirs; i++) { 451 const FileSpec &dir = m_search_directories[i]; 452 const bool find_directories = true; 453 const bool find_files = true; 454 const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. 455 FileSpec::EnumerateDirectory( 456 dir.GetPath().c_str(), find_directories, find_files, find_other, 457 GetKernelsAndKextsInDirectoryWithRecursion, this); 458 } 459 const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size(); 460 for (uint32_t i = 0; i < num_dirs_no_recurse; i++) { 461 const FileSpec &dir = m_search_directories_no_recursing[i]; 462 const bool find_directories = true; 463 const bool find_files = true; 464 const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. 465 FileSpec::EnumerateDirectory( 466 dir.GetPath().c_str(), find_directories, find_files, find_other, 467 GetKernelsAndKextsInDirectoryNoRecursion, this); 468 } 469 } 470 471 // We're only doing a filename match here. We won't try opening the file to 472 // see if it's really a kernel or not until we need to find a kernel of a given 473 // UUID. There's no cheap way to find the UUID of a file (or if it's a Mach-O 474 // binary at all) without creating a whole Module for the file and throwing it 475 // away if it's not wanted. 476 // 477 // Recurse into any subdirectories found. 478 479 FileSpec::EnumerateDirectoryResult 480 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion( 481 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 482 return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, true); 483 } 484 485 FileSpec::EnumerateDirectoryResult 486 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion( 487 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { 488 return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, false); 489 } 490 491 FileSpec::EnumerateDirectoryResult 492 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( 493 void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec, 494 bool recurse) { 495 static ConstString g_kext_suffix = ConstString("kext"); 496 static ConstString g_dsym_suffix = ConstString("dSYM"); 497 static ConstString g_bundle_suffix = ConstString("Bundle"); 498 ConstString file_spec_extension = file_spec.GetFileNameExtension(); 499 500 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 501 Log *log_verbose(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM | LLDB_LOG_OPTION_VERBOSE)); 502 503 if (log_verbose) 504 log_verbose->Printf ("PlatformDarwinKernel examining '%s'", file_spec.GetPath().c_str()); 505 506 PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; 507 if (ft == llvm::sys::fs::file_type::regular_file || 508 ft == llvm::sys::fs::file_type::symlink_file) { 509 ConstString filename = file_spec.GetFilename(); 510 if ((strncmp(filename.GetCString(), "kernel", 6) == 0 || 511 strncmp(filename.GetCString(), "mach", 4) == 0) && 512 file_spec_extension != g_dsym_suffix) { 513 if (KernelHasdSYMSibling(file_spec)) 514 { 515 if (log) 516 { 517 log->Printf ("PlatformDarwinKernel registering kernel binary '%s' with dSYM sibling", file_spec.GetPath().c_str()); 518 } 519 thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); 520 } 521 else 522 { 523 if (log) 524 { 525 log->Printf ("PlatformDarwinKernel registering kernel binary '%s', no dSYM", file_spec.GetPath().c_str()); 526 } 527 thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); 528 } 529 return FileSpec::eEnumerateDirectoryResultNext; 530 } 531 } else if (ft == llvm::sys::fs::file_type::directory_file && 532 file_spec_extension == g_kext_suffix) { 533 AddKextToMap(thisp, file_spec); 534 // Look to see if there is a PlugIns subdir with more kexts 535 FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns", false); 536 std::string search_here_too; 537 if (llvm::sys::fs::is_directory(contents_plugins.GetPath())) { 538 search_here_too = contents_plugins.GetPath(); 539 } else { 540 FileSpec plugins(file_spec.GetPath() + "/PlugIns", false); 541 if (llvm::sys::fs::is_directory(plugins.GetPath())) { 542 search_here_too = plugins.GetPath(); 543 } 544 } 545 546 if (!search_here_too.empty()) { 547 const bool find_directories = true; 548 const bool find_files = false; 549 const bool find_other = false; 550 FileSpec::EnumerateDirectory( 551 search_here_too.c_str(), find_directories, find_files, find_other, 552 recurse ? GetKernelsAndKextsInDirectoryWithRecursion 553 : GetKernelsAndKextsInDirectoryNoRecursion, 554 baton); 555 } 556 return FileSpec::eEnumerateDirectoryResultNext; 557 } 558 // Don't recurse into dSYM/kext/bundle directories 559 if (recurse && file_spec_extension != g_dsym_suffix && 560 file_spec_extension != g_kext_suffix && 561 file_spec_extension != g_bundle_suffix) { 562 if (log_verbose) 563 log_verbose->Printf ("PlatformDarwinKernel descending into directory '%s'", file_spec.GetPath().c_str()); 564 return FileSpec::eEnumerateDirectoryResultEnter; 565 } else { 566 return FileSpec::eEnumerateDirectoryResultNext; 567 } 568 } 569 570 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp, 571 const FileSpec &file_spec) { 572 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 573 CFCBundle bundle(file_spec.GetPath().c_str()); 574 CFStringRef bundle_id(bundle.GetIdentifier()); 575 if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) { 576 char bundle_id_buf[PATH_MAX]; 577 if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf), 578 kCFStringEncodingUTF8)) { 579 ConstString bundle_conststr(bundle_id_buf); 580 if (KextHasdSYMSibling(file_spec)) 581 { 582 if (log) 583 { 584 log->Printf ("PlatformDarwinKernel registering kext binary '%s' with dSYM sibling", file_spec.GetPath().c_str()); 585 } 586 thisp->m_name_to_kext_path_map_with_dsyms.insert( 587 std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); 588 } 589 else 590 { 591 if (log) 592 { 593 log->Printf ("PlatformDarwinKernel registering kext binary '%s', no dSYM", file_spec.GetPath().c_str()); 594 } 595 thisp->m_name_to_kext_path_map_without_dsyms.insert( 596 std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); 597 } 598 } 599 } 600 } 601 602 // Given a FileSpec of /dir/dir/foo.kext 603 // Return true if any of these exist: 604 // /dir/dir/foo.kext.dSYM 605 // /dir/dir/foo.kext/Contents/MacOS/foo.dSYM 606 // /dir/dir/foo.kext/foo.dSYM 607 bool PlatformDarwinKernel::KextHasdSYMSibling( 608 const FileSpec &kext_bundle_filepath) { 609 FileSpec dsym_fspec = kext_bundle_filepath; 610 std::string filename = dsym_fspec.GetFilename().AsCString(); 611 filename += ".dSYM"; 612 dsym_fspec.GetFilename() = ConstString(filename); 613 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 614 return true; 615 } 616 // Should probably get the CFBundleExecutable here or call 617 // CFBundleCopyExecutableURL 618 619 // Look for a deep bundle foramt 620 ConstString executable_name = 621 kext_bundle_filepath.GetFileNameStrippingExtension(); 622 std::string deep_bundle_str = 623 kext_bundle_filepath.GetPath() + "/Contents/MacOS/"; 624 deep_bundle_str += executable_name.AsCString(); 625 deep_bundle_str += ".dSYM"; 626 dsym_fspec.SetFile(deep_bundle_str, true); 627 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 628 return true; 629 } 630 631 // look for a shallow bundle format 632 // 633 std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/"; 634 shallow_bundle_str += executable_name.AsCString(); 635 shallow_bundle_str += ".dSYM"; 636 dsym_fspec.SetFile(shallow_bundle_str, true); 637 if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { 638 return true; 639 } 640 return false; 641 } 642 643 // Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM 644 // exists next to it: 645 // /dir/dir/mach.development.t7004.dSYM 646 bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { 647 FileSpec kernel_dsym = kernel_binary; 648 std::string filename = kernel_binary.GetFilename().AsCString(); 649 filename += ".dSYM"; 650 kernel_dsym.GetFilename() = ConstString(filename); 651 if (llvm::sys::fs::is_directory(kernel_dsym.GetPath())) { 652 return true; 653 } 654 return false; 655 } 656 657 Status PlatformDarwinKernel::GetSharedModule( 658 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, 659 const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, 660 bool *did_create_ptr) { 661 Status error; 662 module_sp.reset(); 663 const FileSpec &platform_file = module_spec.GetFileSpec(); 664 665 // Treat the file's path as a kext bundle ID (e.g. 666 // "com.apple.driver.AppleIRController") and search our kext index. 667 std::string kext_bundle_id = platform_file.GetPath(); 668 if (!kext_bundle_id.empty()) { 669 ConstString kext_bundle_cs(kext_bundle_id.c_str()); 670 671 // First look through the kext bundles that had a dsym next to them 672 if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) { 673 for (BundleIDToKextIterator it = 674 m_name_to_kext_path_map_with_dsyms.begin(); 675 it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { 676 if (it->first == kext_bundle_cs) { 677 error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), 678 module_spec.GetArchitecture(), 679 module_sp); 680 if (module_sp.get()) { 681 return error; 682 } 683 } 684 } 685 } 686 687 // Give the generic methods, including possibly calling into DebugSymbols 688 // framework on macOS systems, a chance. 689 error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, 690 module_search_paths_ptr, 691 old_module_sp_ptr, did_create_ptr); 692 if (error.Success() && module_sp.get()) { 693 return error; 694 } 695 696 // Lastly, look through the kext binarys without dSYMs 697 if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) { 698 for (BundleIDToKextIterator it = 699 m_name_to_kext_path_map_without_dsyms.begin(); 700 it != m_name_to_kext_path_map_without_dsyms.end(); ++it) { 701 if (it->first == kext_bundle_cs) { 702 error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), 703 module_spec.GetArchitecture(), 704 module_sp); 705 if (module_sp.get()) { 706 return error; 707 } 708 } 709 } 710 } 711 } 712 713 if (kext_bundle_id.compare("mach_kernel") == 0 && 714 module_spec.GetUUID().IsValid()) { 715 // First try all kernel binaries that have a dSYM next to them 716 for (auto possible_kernel : m_kernel_binaries_with_dsyms) { 717 if (possible_kernel.Exists()) { 718 ModuleSpec kern_spec(possible_kernel); 719 kern_spec.GetUUID() = module_spec.GetUUID(); 720 ModuleSP module_sp(new Module(kern_spec)); 721 if (module_sp && module_sp->GetObjectFile() && 722 module_sp->MatchesModuleSpec(kern_spec)) { 723 // module_sp is an actual kernel binary we want to add. 724 if (process) { 725 process->GetTarget().GetImages().AppendIfNeeded(module_sp); 726 error.Clear(); 727 return error; 728 } else { 729 error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, 730 NULL, NULL); 731 if (module_sp && module_sp->GetObjectFile() && 732 module_sp->GetObjectFile()->GetType() != 733 ObjectFile::Type::eTypeCoreFile) { 734 return error; 735 } 736 module_sp.reset(); 737 } 738 } 739 } 740 } 741 742 // Give the generic methods, including possibly calling into DebugSymbols 743 // framework on macOS systems, a chance. 744 error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, 745 module_search_paths_ptr, 746 old_module_sp_ptr, did_create_ptr); 747 if (error.Success() && module_sp.get()) { 748 return error; 749 } 750 751 // Next try all kernel binaries that don't have a dSYM 752 for (auto possible_kernel : m_kernel_binaries_without_dsyms) { 753 if (possible_kernel.Exists()) { 754 ModuleSpec kern_spec(possible_kernel); 755 kern_spec.GetUUID() = module_spec.GetUUID(); 756 ModuleSP module_sp(new Module(kern_spec)); 757 if (module_sp && module_sp->GetObjectFile() && 758 module_sp->MatchesModuleSpec(kern_spec)) { 759 // module_sp is an actual kernel binary we want to add. 760 if (process) { 761 process->GetTarget().GetImages().AppendIfNeeded(module_sp); 762 error.Clear(); 763 return error; 764 } else { 765 error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, 766 NULL, NULL); 767 if (module_sp && module_sp->GetObjectFile() && 768 module_sp->GetObjectFile()->GetType() != 769 ObjectFile::Type::eTypeCoreFile) { 770 return error; 771 } 772 module_sp.reset(); 773 } 774 } 775 } 776 } 777 } 778 779 return error; 780 } 781 782 Status PlatformDarwinKernel::ExamineKextForMatchingUUID( 783 const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, 784 const ArchSpec &arch, ModuleSP &exe_module_sp) { 785 Status error; 786 FileSpec exe_file = kext_bundle_path; 787 Host::ResolveExecutableInBundle(exe_file); 788 if (exe_file.Exists()) { 789 ModuleSpec exe_spec(exe_file); 790 exe_spec.GetUUID() = uuid; 791 if (!uuid.IsValid()) { 792 exe_spec.GetArchitecture() = arch; 793 } 794 795 // First try to create a ModuleSP with the file / arch and see if the UUID 796 // matches. If that fails (this exec file doesn't have the correct uuid), 797 // don't call GetSharedModule (which may call in to the DebugSymbols 798 // framework and therefore can be slow.) 799 ModuleSP module_sp(new Module(exe_spec)); 800 if (module_sp && module_sp->GetObjectFile() && 801 module_sp->MatchesModuleSpec(exe_spec)) { 802 error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL, 803 NULL); 804 if (exe_module_sp && exe_module_sp->GetObjectFile()) { 805 return error; 806 } 807 } 808 exe_module_sp.reset(); 809 } 810 return error; 811 } 812 813 bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx, 814 ArchSpec &arch) { 815 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 816 return ARMGetSupportedArchitectureAtIndex(idx, arch); 817 #else 818 return x86GetSupportedArchitectureAtIndex(idx, arch); 819 #endif 820 } 821 822 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() { 823 m_trap_handlers.push_back(ConstString("trap_from_kernel")); 824 m_trap_handlers.push_back(ConstString("hndl_machine_check")); 825 m_trap_handlers.push_back(ConstString("hndl_double_fault")); 826 m_trap_handlers.push_back(ConstString("hndl_allintrs")); 827 m_trap_handlers.push_back(ConstString("hndl_alltraps")); 828 m_trap_handlers.push_back(ConstString("interrupt")); 829 m_trap_handlers.push_back(ConstString("fleh_prefabt")); 830 m_trap_handlers.push_back(ConstString("ExceptionVectorsBase")); 831 m_trap_handlers.push_back(ConstString("ExceptionVectorsTable")); 832 m_trap_handlers.push_back(ConstString("fleh_undef")); 833 m_trap_handlers.push_back(ConstString("fleh_dataabt")); 834 m_trap_handlers.push_back(ConstString("fleh_irq")); 835 m_trap_handlers.push_back(ConstString("fleh_decirq")); 836 m_trap_handlers.push_back(ConstString("fleh_fiq_generic")); 837 m_trap_handlers.push_back(ConstString("fleh_dec")); 838 } 839 840 #else // __APPLE__ 841 842 // Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies 843 // on PlatformDarwinKernel for the plug-in name, we compile just the plug-in 844 // name in here to avoid issues. We are tracking an internal bug to resolve 845 // this issue by either not compiling in DynamicLoaderDarwinKernel for non- 846 // apple builds, or to make PlatformDarwinKernel build on all systems. 847 // PlatformDarwinKernel is currently not compiled on other platforms due to the 848 // use of the Mac-specific source/Host/macosx/cfcpp utilities. 849 850 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { 851 static lldb_private::ConstString g_name("darwin-kernel"); 852 return g_name; 853 } 854 855 #endif // __APPLE__ 856