brintos

brintos / llvm-project-archived public Read only

0
0
Text · 36.8 KiB · 04e87b9 Raw
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