diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp | 860 |
1 files changed, 860 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp new file mode 100644 index 00000000000..7ca5397595c --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -0,0 +1,860 @@ +//===-- PlatformDarwinKernel.cpp -----------------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PlatformDarwinKernel.h" + +#if defined(__APPLE__) // This Plugin uses the Mac-specific + // source/Host/macosx/cfcpp utilities + +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Host.h" +#include "lldb/Interpreter/OptionValueFileSpecList.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Property.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +#include "llvm/Support/FileSystem.h" + +#include <CoreFoundation/CoreFoundation.h> + +#include <memory> + +#include "Host/macosx/cfcpp/CFCBundle.h" + +using namespace lldb; +using namespace lldb_private; + +// Static Variables +static uint32_t g_initialize_count = 0; + +// Static Functions +void PlatformDarwinKernel::Initialize() { + PlatformDarwin::Initialize(); + + if (g_initialize_count++ == 0) { + PluginManager::RegisterPlugin(PlatformDarwinKernel::GetPluginNameStatic(), + PlatformDarwinKernel::GetDescriptionStatic(), + PlatformDarwinKernel::CreateInstance, + PlatformDarwinKernel::DebuggerInitialize); + } +} + +void PlatformDarwinKernel::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformDarwinKernel::CreateInstance); + } + } + + PlatformDarwin::Terminate(); +} + +PlatformSP PlatformDarwinKernel::CreateInstance(bool force, + const ArchSpec *arch) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + const char *arch_name; + if (arch && arch->GetArchitectureName()) + arch_name = arch->GetArchitectureName(); + else + arch_name = "<null>"; + + const char *triple_cstr = + arch ? arch->GetTriple().getTriple().c_str() : "<null>"; + + LLDB_LOGF(log, "PlatformDarwinKernel::%s(force=%s, arch={%s,%s})", + __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); + } + + // This is a special plugin that we don't want to activate just based on an + // ArchSpec for normal userland debugging. It is only useful in kernel debug + // sessions and the DynamicLoaderDarwinPlugin (or a user doing 'platform + // select') will force the creation of this Platform plugin. + if (!force) { + LLDB_LOGF(log, + "PlatformDarwinKernel::%s() aborting creation of platform " + "because force == false", + __FUNCTION__); + return PlatformSP(); + } + + bool create = force; + LazyBool is_ios_debug_session = eLazyBoolCalculate; + + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getVendor()) { + case llvm::Triple::Apple: + create = true; + break; + + // Only accept "unknown" for vendor if the host is Apple and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) + case llvm::Triple::UnknownVendor: + create = !arch->TripleVendorWasSpecified(); + break; + default: + break; + } + + if (create) { + switch (triple.getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: + case llvm::Triple::WatchOS: + case llvm::Triple::TvOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: + break; + // Only accept "vendor" for vendor if the host is Apple and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) + case llvm::Triple::UnknownOS: + create = !arch->TripleOSWasSpecified(); + break; + default: + create = false; + break; + } + } + } + if (arch && arch->IsValid()) { + switch (arch->GetMachine()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + is_ios_debug_session = eLazyBoolNo; + break; + case llvm::Triple::arm: + case llvm::Triple::aarch64: + case llvm::Triple::thumb: + is_ios_debug_session = eLazyBoolYes; + break; + default: + is_ios_debug_session = eLazyBoolCalculate; + break; + } + } + if (create) { + LLDB_LOGF(log, "PlatformDarwinKernel::%s() creating platform", + __FUNCTION__); + + return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session)); + } + + LLDB_LOGF(log, "PlatformDarwinKernel::%s() aborting creation of platform", + __FUNCTION__); + + return PlatformSP(); +} + +lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { + static ConstString g_name("darwin-kernel"); + return g_name; +} + +const char *PlatformDarwinKernel::GetDescriptionStatic() { + return "Darwin Kernel platform plug-in."; +} + +/// Code to handle the PlatformDarwinKernel settings + +#define LLDB_PROPERTIES_platformdarwinkernel +#include "PlatformMacOSXProperties.inc" + +enum { +#define LLDB_PROPERTIES_platformdarwinkernel +#include "PlatformMacOSXPropertiesEnum.inc" +}; + +class PlatformDarwinKernelProperties : public Properties { +public: + static ConstString &GetSettingName() { + static ConstString g_setting_name("darwin-kernel"); + return g_setting_name; + } + + PlatformDarwinKernelProperties() : Properties() { + m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); + m_collection_sp->Initialize(g_platformdarwinkernel_properties); + } + + virtual ~PlatformDarwinKernelProperties() {} + + bool GetSearchForKexts() const { + const uint32_t idx = ePropertySearchForKexts; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + NULL, idx, + g_platformdarwinkernel_properties[idx].default_uint_value != 0); + } + + FileSpecList GetKextDirectories() const { + const uint32_t idx = ePropertyKextDirectories; + const OptionValueFileSpecList *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList( + NULL, false, idx); + assert(option_value); + return option_value->GetCurrentValue(); + } +}; + +typedef std::shared_ptr<PlatformDarwinKernelProperties> + PlatformDarwinKernelPropertiesSP; + +static const PlatformDarwinKernelPropertiesSP &GetGlobalProperties() { + static PlatformDarwinKernelPropertiesSP g_settings_sp; + if (!g_settings_sp) + g_settings_sp = std::make_shared<PlatformDarwinKernelProperties>(); + return g_settings_sp; +} + +void PlatformDarwinKernel::DebuggerInitialize( + lldb_private::Debugger &debugger) { + if (!PluginManager::GetSettingForPlatformPlugin( + debugger, PlatformDarwinKernelProperties::GetSettingName())) { + const bool is_global_setting = true; + PluginManager::CreateSettingForPlatformPlugin( + debugger, GetGlobalProperties()->GetValueProperties(), + ConstString("Properties for the PlatformDarwinKernel plug-in."), + is_global_setting); + } +} + +/// Default Constructor +PlatformDarwinKernel::PlatformDarwinKernel( + lldb_private::LazyBool is_ios_debug_session) + : PlatformDarwin(false), // This is a remote platform + m_name_to_kext_path_map_with_dsyms(), + m_name_to_kext_path_map_without_dsyms(), m_search_directories(), + m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(), + m_kernel_binaries_without_dsyms(), + m_ios_debug_session(is_ios_debug_session) + +{ + if (GetGlobalProperties()->GetSearchForKexts()) { + CollectKextAndKernelDirectories(); + SearchForKextsAndKernelsRecursively(); + } +} + +/// Destructor. +/// +/// The destructor is virtual since this class is designed to be +/// inherited from by the plug-in instance. +PlatformDarwinKernel::~PlatformDarwinKernel() {} + +void PlatformDarwinKernel::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + strm.Printf(" Debug session type: "); + if (m_ios_debug_session == eLazyBoolYes) + strm.Printf("iOS kernel debugging\n"); + else if (m_ios_debug_session == eLazyBoolNo) + strm.Printf("Mac OS X kernel debugging\n"); + else + strm.Printf("unknown kernel debugging\n"); + + strm.Printf("Directories searched recursively:\n"); + const uint32_t num_kext_dirs = m_search_directories.size(); + for (uint32_t i = 0; i < num_kext_dirs; ++i) { + strm.Printf("[%d] %s\n", i, m_search_directories[i].GetPath().c_str()); + } + + strm.Printf("Directories not searched recursively:\n"); + const uint32_t num_kext_dirs_no_recursion = + m_search_directories_no_recursing.size(); + for (uint32_t i = 0; i < num_kext_dirs_no_recursion; i++) { + strm.Printf("[%d] %s\n", i, + m_search_directories_no_recursing[i].GetPath().c_str()); + } + + strm.Printf(" Number of kexts with dSYMs indexed: %d\n", + (int)m_name_to_kext_path_map_with_dsyms.size()); + strm.Printf(" Number of kexts without dSYMs indexed: %d\n", + (int)m_name_to_kext_path_map_without_dsyms.size()); + strm.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n", + (int)m_kernel_binaries_with_dsyms.size()); + strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n", + (int)m_kernel_binaries_without_dsyms.size()); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "\nkexts with dSYMs"); + for (auto pos : m_name_to_kext_path_map_with_dsyms) { + LLDB_LOGF(log, "%s", pos.second.GetPath().c_str()); + } + LLDB_LOGF(log, "\nkexts without dSYMs"); + + for (auto pos : m_name_to_kext_path_map_without_dsyms) { + LLDB_LOGF(log, "%s", pos.second.GetPath().c_str()); + } + LLDB_LOGF(log, "\nkernels with dSYMS"); + for (auto fs : m_kernel_binaries_with_dsyms) { + LLDB_LOGF(log, "%s", fs.GetPath().c_str()); + } + LLDB_LOGF(log, "\nkernels without dSYMS"); + for (auto fs : m_kernel_binaries_without_dsyms) { + LLDB_LOGF(log, "%s", fs.GetPath().c_str()); + } + LLDB_LOGF(log, "\n"); + } +} + +// Populate the m_search_directories vector with directories we should search +// for kernel & kext binaries. + +void PlatformDarwinKernel::CollectKextAndKernelDirectories() { + // Differentiate between "ios debug session" and "mac debug session" so we + // don't index kext bundles that won't be used in this debug session. If + // this is an ios kext debug session, looking in /System/Library/Extensions + // is a waste of stat()s, for example. + + // DeveloperDirectory is something like + // "/Applications/Xcode.app/Contents/Developer" + std::string developer_dir = GetDeveloperDirectory(); + if (developer_dir.empty()) + developer_dir = "/Applications/Xcode.app/Contents/Developer"; + + if (m_ios_debug_session != eLazyBoolNo) { + AddSDKSubdirsToSearchPaths(developer_dir + + "/Platforms/iPhoneOS.platform/Developer/SDKs"); + AddSDKSubdirsToSearchPaths(developer_dir + + "/Platforms/AppleTVOS.platform/Developer/SDKs"); + AddSDKSubdirsToSearchPaths(developer_dir + + "/Platforms/WatchOS.platform/Developer/SDKs"); + AddSDKSubdirsToSearchPaths(developer_dir + + "/Platforms/BridgeOS.platform/Developer/SDKs"); + } + if (m_ios_debug_session != eLazyBoolYes) { + AddSDKSubdirsToSearchPaths(developer_dir + + "/Platforms/MacOSX.platform/Developer/SDKs"); + } + + AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit"); + AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs"); + // The KDKs distributed from Apple installed on external developer systems + // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk + AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs"); + + if (m_ios_debug_session != eLazyBoolNo) { + } + if (m_ios_debug_session != eLazyBoolYes) { + AddRootSubdirsToSearchPaths(this, "/"); + } + + GetUserSpecifiedDirectoriesToSearch(); + + // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols + FileSpec possible_dir(developer_dir + "/../Symbols"); + FileSystem::Instance().Resolve(possible_dir); + if (FileSystem::Instance().IsDirectory(possible_dir)) + m_search_directories.push_back(possible_dir); + + // Add simple directory of the current working directory + FileSpec cwd("."); + FileSystem::Instance().Resolve(cwd); + m_search_directories_no_recursing.push_back(cwd); +} + +void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() { + FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories()); + std::vector<FileSpec> possible_sdk_dirs; + + const uint32_t user_dirs_count = user_dirs.GetSize(); + for (uint32_t i = 0; i < user_dirs_count; i++) { + FileSpec dir = user_dirs.GetFileSpecAtIndex(i); + FileSystem::Instance().Resolve(dir); + if (FileSystem::Instance().IsDirectory(dir)) { + m_search_directories.push_back(dir); + } + } +} + +void PlatformDarwinKernel::AddRootSubdirsToSearchPaths( + PlatformDarwinKernel *thisp, const std::string &dir) { + const char *subdirs[] = { + "/System/Library/Extensions", "/Library/Extensions", + "/System/Library/Kernels", + "/System/Library/Extensions/KDK", // this one probably only exist in + // /AppleInternal/Developer/KDKs/*.kdk/... + nullptr}; + for (int i = 0; subdirs[i] != nullptr; i++) { + FileSpec testdir(dir + subdirs[i]); + FileSystem::Instance().Resolve(testdir); + if (FileSystem::Instance().IsDirectory(testdir)) + thisp->m_search_directories.push_back(testdir); + } + + // Look for kernel binaries in the top level directory, without any recursion + thisp->m_search_directories_no_recursing.push_back(FileSpec(dir + "/")); +} + +// Given a directory path dir, look for any subdirs named *.kdk and *.sdk +void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) { + // Look for *.kdk and *.sdk in dir + const bool find_directories = true; + const bool find_files = false; + const bool find_other = false; + FileSystem::Instance().EnumerateDirectory( + dir.c_str(), find_directories, find_files, find_other, + FindKDKandSDKDirectoriesInDirectory, this); +} + +// Helper function to find *.sdk and *.kdk directories in a given directory. +FileSystem::EnumerateDirectoryResult +PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { + static ConstString g_sdk_suffix = ConstString(".sdk"); + static ConstString g_kdk_suffix = ConstString(".kdk"); + + PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; + FileSpec file_spec(path); + if (ft == llvm::sys::fs::file_type::directory_file && + (file_spec.GetFileNameExtension() == g_sdk_suffix || + file_spec.GetFileNameExtension() == g_kdk_suffix)) { + AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath()); + } + return FileSystem::eEnumerateDirectoryResultNext; +} + +// Recursively search trough m_search_directories looking for kext and kernel +// binaries, adding files found to the appropriate lists. +void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { + const uint32_t num_dirs = m_search_directories.size(); + for (uint32_t i = 0; i < num_dirs; i++) { + const FileSpec &dir = m_search_directories[i]; + const bool find_directories = true; + const bool find_files = true; + const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. + FileSystem::Instance().EnumerateDirectory( + dir.GetPath().c_str(), find_directories, find_files, find_other, + GetKernelsAndKextsInDirectoryWithRecursion, this); + } + const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size(); + for (uint32_t i = 0; i < num_dirs_no_recurse; i++) { + const FileSpec &dir = m_search_directories_no_recursing[i]; + const bool find_directories = true; + const bool find_files = true; + const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. + FileSystem::Instance().EnumerateDirectory( + dir.GetPath().c_str(), find_directories, find_files, find_other, + GetKernelsAndKextsInDirectoryNoRecursion, this); + } +} + +// We're only doing a filename match here. We won't try opening the file to +// see if it's really a kernel or not until we need to find a kernel of a given +// UUID. There's no cheap way to find the UUID of a file (or if it's a Mach-O +// binary at all) without creating a whole Module for the file and throwing it +// away if it's not wanted. +// +// Recurse into any subdirectories found. + +FileSystem::EnumerateDirectoryResult +PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion( + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { + return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, true); +} + +FileSystem::EnumerateDirectoryResult +PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion( + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { + return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, false); +} + +FileSystem::EnumerateDirectoryResult +PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path, + bool recurse) { + static ConstString g_kext_suffix = ConstString(".kext"); + static ConstString g_dsym_suffix = ConstString(".dSYM"); + static ConstString g_bundle_suffix = ConstString("Bundle"); + + FileSpec file_spec(path); + ConstString file_spec_extension = file_spec.GetFileNameExtension(); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + Log *log_verbose(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM | LLDB_LOG_OPTION_VERBOSE)); + + LLDB_LOGF(log_verbose, "PlatformDarwinKernel examining '%s'", + file_spec.GetPath().c_str()); + + PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; + if (ft == llvm::sys::fs::file_type::regular_file || + ft == llvm::sys::fs::file_type::symlink_file) { + ConstString filename = file_spec.GetFilename(); + if ((strncmp(filename.GetCString(), "kernel", 6) == 0 || + strncmp(filename.GetCString(), "mach", 4) == 0) && + file_spec_extension != g_dsym_suffix) { + if (KernelHasdSYMSibling(file_spec)) + { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kernel binary '%s' with " + "dSYM sibling", + file_spec.GetPath().c_str()); + thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); + } + else + { + LLDB_LOGF( + log, "PlatformDarwinKernel registering kernel binary '%s', no dSYM", + file_spec.GetPath().c_str()); + thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); + } + return FileSystem::eEnumerateDirectoryResultNext; + } + } else if (ft == llvm::sys::fs::file_type::directory_file && + file_spec_extension == g_kext_suffix) { + AddKextToMap(thisp, file_spec); + // Look to see if there is a PlugIns subdir with more kexts + FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns"); + std::string search_here_too; + if (FileSystem::Instance().IsDirectory(contents_plugins)) { + search_here_too = contents_plugins.GetPath(); + } else { + FileSpec plugins(file_spec.GetPath() + "/PlugIns"); + if (FileSystem::Instance().IsDirectory(plugins)) { + search_here_too = plugins.GetPath(); + } + } + + if (!search_here_too.empty()) { + const bool find_directories = true; + const bool find_files = false; + const bool find_other = false; + FileSystem::Instance().EnumerateDirectory( + search_here_too.c_str(), find_directories, find_files, find_other, + recurse ? GetKernelsAndKextsInDirectoryWithRecursion + : GetKernelsAndKextsInDirectoryNoRecursion, + baton); + } + return FileSystem::eEnumerateDirectoryResultNext; + } + // Don't recurse into dSYM/kext/bundle directories + if (recurse && file_spec_extension != g_dsym_suffix && + file_spec_extension != g_kext_suffix && + file_spec_extension != g_bundle_suffix) { + LLDB_LOGF(log_verbose, + "PlatformDarwinKernel descending into directory '%s'", + file_spec.GetPath().c_str()); + return FileSystem::eEnumerateDirectoryResultEnter; + } else { + return FileSystem::eEnumerateDirectoryResultNext; + } +} + +void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp, + const FileSpec &file_spec) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + CFCBundle bundle(file_spec.GetPath().c_str()); + CFStringRef bundle_id(bundle.GetIdentifier()); + if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) { + char bundle_id_buf[PATH_MAX]; + if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf), + kCFStringEncodingUTF8)) { + ConstString bundle_conststr(bundle_id_buf); + if (KextHasdSYMSibling(file_spec)) + { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kext binary '%s' with dSYM " + "sibling", + file_spec.GetPath().c_str()); + thisp->m_name_to_kext_path_map_with_dsyms.insert( + std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); + } + else + { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kext binary '%s', no dSYM", + file_spec.GetPath().c_str()); + thisp->m_name_to_kext_path_map_without_dsyms.insert( + std::pair<ConstString, FileSpec>(bundle_conststr, file_spec)); + } + } + } +} + +// Given a FileSpec of /dir/dir/foo.kext +// Return true if any of these exist: +// /dir/dir/foo.kext.dSYM +// /dir/dir/foo.kext/Contents/MacOS/foo.dSYM +// /dir/dir/foo.kext/foo.dSYM +bool PlatformDarwinKernel::KextHasdSYMSibling( + const FileSpec &kext_bundle_filepath) { + FileSpec dsym_fspec = kext_bundle_filepath; + std::string filename = dsym_fspec.GetFilename().AsCString(); + filename += ".dSYM"; + dsym_fspec.GetFilename() = ConstString(filename); + if (FileSystem::Instance().IsDirectory(dsym_fspec)) { + return true; + } + // Should probably get the CFBundleExecutable here or call + // CFBundleCopyExecutableURL + + // Look for a deep bundle foramt + ConstString executable_name = + kext_bundle_filepath.GetFileNameStrippingExtension(); + std::string deep_bundle_str = + kext_bundle_filepath.GetPath() + "/Contents/MacOS/"; + deep_bundle_str += executable_name.AsCString(); + deep_bundle_str += ".dSYM"; + dsym_fspec.SetFile(deep_bundle_str, FileSpec::Style::native); + FileSystem::Instance().Resolve(dsym_fspec); + if (FileSystem::Instance().IsDirectory(dsym_fspec)) { + return true; + } + + // look for a shallow bundle format + // + std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/"; + shallow_bundle_str += executable_name.AsCString(); + shallow_bundle_str += ".dSYM"; + dsym_fspec.SetFile(shallow_bundle_str, FileSpec::Style::native); + FileSystem::Instance().Resolve(dsym_fspec); + return FileSystem::Instance().IsDirectory(dsym_fspec); +} + +// Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM +// exists next to it: +// /dir/dir/mach.development.t7004.dSYM +bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { + FileSpec kernel_dsym = kernel_binary; + std::string filename = kernel_binary.GetFilename().AsCString(); + filename += ".dSYM"; + kernel_dsym.GetFilename() = ConstString(filename); + return FileSystem::Instance().IsDirectory(kernel_dsym); +} + +Status PlatformDarwinKernel::GetSharedModule( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) { + Status error; + module_sp.reset(); + const FileSpec &platform_file = module_spec.GetFileSpec(); + + // Treat the file's path as a kext bundle ID (e.g. + // "com.apple.driver.AppleIRController") and search our kext index. + std::string kext_bundle_id = platform_file.GetPath(); + if (!kext_bundle_id.empty()) { + ConstString kext_bundle_cs(kext_bundle_id.c_str()); + + // First look through the kext bundles that had a dsym next to them + if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) { + for (BundleIDToKextIterator it = + m_name_to_kext_path_map_with_dsyms.begin(); + it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { + if (it->first == kext_bundle_cs) { + error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), + module_spec.GetArchitecture(), + module_sp); + if (module_sp.get()) { + return error; + } + } + } + } + + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. + error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, + old_module_sp_ptr, did_create_ptr); + if (error.Success() && module_sp.get()) { + return error; + } + + // Lastly, look through the kext binarys without dSYMs + if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) { + for (BundleIDToKextIterator it = + m_name_to_kext_path_map_without_dsyms.begin(); + it != m_name_to_kext_path_map_without_dsyms.end(); ++it) { + if (it->first == kext_bundle_cs) { + error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), + module_spec.GetArchitecture(), + module_sp); + if (module_sp.get()) { + return error; + } + } + } + } + } + + if (kext_bundle_id == "mach_kernel" && module_spec.GetUUID().IsValid()) { + // First try all kernel binaries that have a dSYM next to them + for (auto possible_kernel : m_kernel_binaries_with_dsyms) { + if (FileSystem::Instance().Exists(possible_kernel)) { + ModuleSpec kern_spec(possible_kernel); + kern_spec.GetUUID() = module_spec.GetUUID(); + ModuleSP module_sp(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, + NULL, NULL); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { + return error; + } + module_sp.reset(); + } + } + } + } + + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. + error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, + old_module_sp_ptr, did_create_ptr); + if (error.Success() && module_sp.get()) { + return error; + } + + // Next try all kernel binaries that don't have a dSYM + for (auto possible_kernel : m_kernel_binaries_without_dsyms) { + if (FileSystem::Instance().Exists(possible_kernel)) { + ModuleSpec kern_spec(possible_kernel); + kern_spec.GetUUID() = module_spec.GetUUID(); + ModuleSP module_sp(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, + NULL, NULL); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { + return error; + } + module_sp.reset(); + } + } + } + } + } + + return error; +} + +std::vector<lldb_private::FileSpec> +PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string &dir) { + std::vector<FileSpec> executables; + std::error_code EC; + for (llvm::sys::fs::recursive_directory_iterator it(dir.c_str(), EC), + end; + it != end && !EC; it.increment(EC)) { + auto status = it->status(); + if (!status) + break; + if (llvm::sys::fs::is_regular_file(*status) && + llvm::sys::fs::can_execute(it->path())) + executables.emplace_back(it->path()); + } + return executables; +} + +Status PlatformDarwinKernel::ExamineKextForMatchingUUID( + const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, + const ArchSpec &arch, ModuleSP &exe_module_sp) { + for (const auto &exe_file : + SearchForExecutablesRecursively(kext_bundle_path.GetPath())) { + if (FileSystem::Instance().Exists(exe_file)) { + ModuleSpec exe_spec(exe_file); + exe_spec.GetUUID() = uuid; + if (!uuid.IsValid()) { + exe_spec.GetArchitecture() = arch; + } + + // First try to create a ModuleSP with the file / arch and see if the UUID + // matches. If that fails (this exec file doesn't have the correct uuid), + // don't call GetSharedModule (which may call in to the DebugSymbols + // framework and therefore can be slow.) + ModuleSP module_sp(new Module(exe_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(exe_spec)) { + Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, + NULL, NULL, NULL); + if (exe_module_sp && exe_module_sp->GetObjectFile()) { + return error; + } + } + exe_module_sp.reset(); + } + } + + return {}; +} + +bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx, + ArchSpec &arch) { +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + return ARMGetSupportedArchitectureAtIndex(idx, arch); +#else + return x86GetSupportedArchitectureAtIndex(idx, arch); +#endif +} + +void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() { + m_trap_handlers.push_back(ConstString("trap_from_kernel")); + m_trap_handlers.push_back(ConstString("hndl_machine_check")); + m_trap_handlers.push_back(ConstString("hndl_double_fault")); + m_trap_handlers.push_back(ConstString("hndl_allintrs")); + m_trap_handlers.push_back(ConstString("hndl_alltraps")); + m_trap_handlers.push_back(ConstString("interrupt")); + m_trap_handlers.push_back(ConstString("fleh_prefabt")); + m_trap_handlers.push_back(ConstString("ExceptionVectorsBase")); + m_trap_handlers.push_back(ConstString("ExceptionVectorsTable")); + m_trap_handlers.push_back(ConstString("fleh_undef")); + m_trap_handlers.push_back(ConstString("fleh_dataabt")); + m_trap_handlers.push_back(ConstString("fleh_irq")); + m_trap_handlers.push_back(ConstString("fleh_decirq")); + m_trap_handlers.push_back(ConstString("fleh_fiq_generic")); + m_trap_handlers.push_back(ConstString("fleh_dec")); +} + +#else // __APPLE__ + +// Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies +// on PlatformDarwinKernel for the plug-in name, we compile just the plug-in +// name in here to avoid issues. We are tracking an internal bug to resolve +// this issue by either not compiling in DynamicLoaderDarwinKernel for non- +// apple builds, or to make PlatformDarwinKernel build on all systems. +// PlatformDarwinKernel is currently not compiled on other platforms due to the +// use of the Mac-specific source/Host/macosx/cfcpp utilities. + +lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { + static lldb_private::ConstString g_name("darwin-kernel"); + return g_name; +} + +#endif // __APPLE__ |