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