1dda28197Spatrick //===-- PlatformDarwinKernel.cpp ------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "PlatformDarwinKernel.h"
10061da546Spatrick 
11061da546Spatrick #if defined(__APPLE__) // This Plugin uses the Mac-specific
12061da546Spatrick                        // source/Host/macosx/cfcpp utilities
13061da546Spatrick 
14061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
15*f6aab3d8Srobert #include "lldb/Core/Debugger.h"
16061da546Spatrick #include "lldb/Core/Module.h"
17061da546Spatrick #include "lldb/Core/ModuleList.h"
18061da546Spatrick #include "lldb/Core/ModuleSpec.h"
19061da546Spatrick #include "lldb/Core/PluginManager.h"
20061da546Spatrick #include "lldb/Host/Host.h"
21dda28197Spatrick #include "lldb/Host/HostInfo.h"
22061da546Spatrick #include "lldb/Interpreter/OptionValueFileSpecList.h"
23061da546Spatrick #include "lldb/Interpreter/OptionValueProperties.h"
24061da546Spatrick #include "lldb/Interpreter/Property.h"
25061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
26061da546Spatrick #include "lldb/Target/Platform.h"
27061da546Spatrick #include "lldb/Target/Process.h"
28061da546Spatrick #include "lldb/Target/Target.h"
29061da546Spatrick #include "lldb/Utility/ArchSpec.h"
30*f6aab3d8Srobert #include "lldb/Utility/DataBufferHeap.h"
31061da546Spatrick #include "lldb/Utility/FileSpec.h"
32*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
33061da546Spatrick #include "lldb/Utility/Log.h"
34061da546Spatrick #include "lldb/Utility/Status.h"
35061da546Spatrick #include "lldb/Utility/StreamString.h"
36061da546Spatrick 
37061da546Spatrick #include "llvm/Support/FileSystem.h"
38061da546Spatrick 
39061da546Spatrick #include <CoreFoundation/CoreFoundation.h>
40061da546Spatrick 
41061da546Spatrick #include <memory>
42061da546Spatrick 
43061da546Spatrick #include "Host/macosx/cfcpp/CFCBundle.h"
44*f6aab3d8Srobert #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
45*f6aab3d8Srobert #include "Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.h"
46061da546Spatrick 
47061da546Spatrick using namespace lldb;
48061da546Spatrick using namespace lldb_private;
49061da546Spatrick 
50061da546Spatrick // Static Variables
51061da546Spatrick static uint32_t g_initialize_count = 0;
52061da546Spatrick 
53061da546Spatrick // Static Functions
Initialize()54061da546Spatrick void PlatformDarwinKernel::Initialize() {
55061da546Spatrick   PlatformDarwin::Initialize();
56061da546Spatrick 
57061da546Spatrick   if (g_initialize_count++ == 0) {
58061da546Spatrick     PluginManager::RegisterPlugin(PlatformDarwinKernel::GetPluginNameStatic(),
59061da546Spatrick                                   PlatformDarwinKernel::GetDescriptionStatic(),
60061da546Spatrick                                   PlatformDarwinKernel::CreateInstance,
61061da546Spatrick                                   PlatformDarwinKernel::DebuggerInitialize);
62061da546Spatrick   }
63061da546Spatrick }
64061da546Spatrick 
Terminate()65061da546Spatrick void PlatformDarwinKernel::Terminate() {
66061da546Spatrick   if (g_initialize_count > 0) {
67061da546Spatrick     if (--g_initialize_count == 0) {
68061da546Spatrick       PluginManager::UnregisterPlugin(PlatformDarwinKernel::CreateInstance);
69061da546Spatrick     }
70061da546Spatrick   }
71061da546Spatrick 
72061da546Spatrick   PlatformDarwin::Terminate();
73061da546Spatrick }
74061da546Spatrick 
CreateInstance(bool force,const ArchSpec * arch)75061da546Spatrick PlatformSP PlatformDarwinKernel::CreateInstance(bool force,
76061da546Spatrick                                                 const ArchSpec *arch) {
77*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Platform);
78061da546Spatrick   if (log) {
79061da546Spatrick     const char *arch_name;
80061da546Spatrick     if (arch && arch->GetArchitectureName())
81061da546Spatrick       arch_name = arch->GetArchitectureName();
82061da546Spatrick     else
83061da546Spatrick       arch_name = "<null>";
84061da546Spatrick 
85061da546Spatrick     const char *triple_cstr =
86061da546Spatrick         arch ? arch->GetTriple().getTriple().c_str() : "<null>";
87061da546Spatrick 
88061da546Spatrick     LLDB_LOGF(log, "PlatformDarwinKernel::%s(force=%s, arch={%s,%s})",
89061da546Spatrick               __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
90061da546Spatrick   }
91061da546Spatrick 
92061da546Spatrick   // This is a special plugin that we don't want to activate just based on an
93061da546Spatrick   // ArchSpec for normal userland debugging.  It is only useful in kernel debug
94061da546Spatrick   // sessions and the DynamicLoaderDarwinPlugin (or a user doing 'platform
95061da546Spatrick   // select') will force the creation of this Platform plugin.
96061da546Spatrick   if (!force) {
97061da546Spatrick     LLDB_LOGF(log,
98061da546Spatrick               "PlatformDarwinKernel::%s() aborting creation of platform "
99061da546Spatrick               "because force == false",
100061da546Spatrick               __FUNCTION__);
101061da546Spatrick     return PlatformSP();
102061da546Spatrick   }
103061da546Spatrick 
104061da546Spatrick   bool create = force;
105061da546Spatrick   LazyBool is_ios_debug_session = eLazyBoolCalculate;
106061da546Spatrick 
107061da546Spatrick   if (!create && arch && arch->IsValid()) {
108061da546Spatrick     const llvm::Triple &triple = arch->GetTriple();
109061da546Spatrick     switch (triple.getVendor()) {
110061da546Spatrick     case llvm::Triple::Apple:
111061da546Spatrick       create = true;
112061da546Spatrick       break;
113061da546Spatrick 
114061da546Spatrick     // Only accept "unknown" for vendor if the host is Apple and it "unknown"
115061da546Spatrick     // wasn't specified (it was just returned because it was NOT specified)
116061da546Spatrick     case llvm::Triple::UnknownVendor:
117061da546Spatrick       create = !arch->TripleVendorWasSpecified();
118061da546Spatrick       break;
119061da546Spatrick     default:
120061da546Spatrick       break;
121061da546Spatrick     }
122061da546Spatrick 
123061da546Spatrick     if (create) {
124061da546Spatrick       switch (triple.getOS()) {
125061da546Spatrick       case llvm::Triple::Darwin:
126061da546Spatrick       case llvm::Triple::MacOSX:
127061da546Spatrick       case llvm::Triple::IOS:
128061da546Spatrick       case llvm::Triple::WatchOS:
129061da546Spatrick       case llvm::Triple::TvOS:
130061da546Spatrick       // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS:
131061da546Spatrick         break;
132061da546Spatrick       // Only accept "vendor" for vendor if the host is Apple and it "unknown"
133061da546Spatrick       // wasn't specified (it was just returned because it was NOT specified)
134061da546Spatrick       case llvm::Triple::UnknownOS:
135061da546Spatrick         create = !arch->TripleOSWasSpecified();
136061da546Spatrick         break;
137061da546Spatrick       default:
138061da546Spatrick         create = false;
139061da546Spatrick         break;
140061da546Spatrick       }
141061da546Spatrick     }
142061da546Spatrick   }
143061da546Spatrick   if (arch && arch->IsValid()) {
144061da546Spatrick     switch (arch->GetMachine()) {
145061da546Spatrick     case llvm::Triple::x86:
146061da546Spatrick     case llvm::Triple::x86_64:
147061da546Spatrick     case llvm::Triple::ppc:
148061da546Spatrick     case llvm::Triple::ppc64:
149061da546Spatrick       is_ios_debug_session = eLazyBoolNo;
150061da546Spatrick       break;
151061da546Spatrick     case llvm::Triple::arm:
152061da546Spatrick     case llvm::Triple::aarch64:
153061da546Spatrick     case llvm::Triple::thumb:
154061da546Spatrick       is_ios_debug_session = eLazyBoolYes;
155061da546Spatrick       break;
156061da546Spatrick     default:
157061da546Spatrick       is_ios_debug_session = eLazyBoolCalculate;
158061da546Spatrick       break;
159061da546Spatrick     }
160061da546Spatrick   }
161061da546Spatrick   if (create) {
162061da546Spatrick     LLDB_LOGF(log, "PlatformDarwinKernel::%s() creating platform",
163061da546Spatrick               __FUNCTION__);
164061da546Spatrick 
165061da546Spatrick     return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session));
166061da546Spatrick   }
167061da546Spatrick 
168061da546Spatrick   LLDB_LOGF(log, "PlatformDarwinKernel::%s() aborting creation of platform",
169061da546Spatrick             __FUNCTION__);
170061da546Spatrick 
171061da546Spatrick   return PlatformSP();
172061da546Spatrick }
173061da546Spatrick 
GetDescriptionStatic()174*f6aab3d8Srobert llvm::StringRef PlatformDarwinKernel::GetDescriptionStatic() {
175061da546Spatrick   return "Darwin Kernel platform plug-in.";
176061da546Spatrick }
177061da546Spatrick 
178061da546Spatrick /// Code to handle the PlatformDarwinKernel settings
179061da546Spatrick 
180061da546Spatrick #define LLDB_PROPERTIES_platformdarwinkernel
181061da546Spatrick #include "PlatformMacOSXProperties.inc"
182061da546Spatrick 
183061da546Spatrick enum {
184061da546Spatrick #define LLDB_PROPERTIES_platformdarwinkernel
185061da546Spatrick #include "PlatformMacOSXPropertiesEnum.inc"
186061da546Spatrick };
187061da546Spatrick 
188061da546Spatrick class PlatformDarwinKernelProperties : public Properties {
189061da546Spatrick public:
GetSettingName()190061da546Spatrick   static ConstString &GetSettingName() {
191061da546Spatrick     static ConstString g_setting_name("darwin-kernel");
192061da546Spatrick     return g_setting_name;
193061da546Spatrick   }
194061da546Spatrick 
PlatformDarwinKernelProperties()195061da546Spatrick   PlatformDarwinKernelProperties() : Properties() {
196061da546Spatrick     m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
197061da546Spatrick     m_collection_sp->Initialize(g_platformdarwinkernel_properties);
198061da546Spatrick   }
199061da546Spatrick 
200*f6aab3d8Srobert   ~PlatformDarwinKernelProperties() override = default;
201061da546Spatrick 
GetKextDirectories() const202061da546Spatrick   FileSpecList GetKextDirectories() const {
203061da546Spatrick     const uint32_t idx = ePropertyKextDirectories;
204061da546Spatrick     const OptionValueFileSpecList *option_value =
205061da546Spatrick         m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(
206061da546Spatrick             NULL, false, idx);
207061da546Spatrick     assert(option_value);
208061da546Spatrick     return option_value->GetCurrentValue();
209061da546Spatrick   }
210061da546Spatrick };
211061da546Spatrick 
GetGlobalProperties()212*f6aab3d8Srobert static PlatformDarwinKernelProperties &GetGlobalProperties() {
213*f6aab3d8Srobert   static PlatformDarwinKernelProperties g_settings;
214*f6aab3d8Srobert   return g_settings;
215061da546Spatrick }
216061da546Spatrick 
DebuggerInitialize(lldb_private::Debugger & debugger)217061da546Spatrick void PlatformDarwinKernel::DebuggerInitialize(
218061da546Spatrick     lldb_private::Debugger &debugger) {
219061da546Spatrick   if (!PluginManager::GetSettingForPlatformPlugin(
220061da546Spatrick           debugger, PlatformDarwinKernelProperties::GetSettingName())) {
221061da546Spatrick     const bool is_global_setting = true;
222061da546Spatrick     PluginManager::CreateSettingForPlatformPlugin(
223*f6aab3d8Srobert         debugger, GetGlobalProperties().GetValueProperties(),
224061da546Spatrick         ConstString("Properties for the PlatformDarwinKernel plug-in."),
225061da546Spatrick         is_global_setting);
226061da546Spatrick   }
227061da546Spatrick }
228061da546Spatrick 
229061da546Spatrick /// Default Constructor
PlatformDarwinKernel(lldb_private::LazyBool is_ios_debug_session)230061da546Spatrick PlatformDarwinKernel::PlatformDarwinKernel(
231061da546Spatrick     lldb_private::LazyBool is_ios_debug_session)
232061da546Spatrick     : PlatformDarwin(false), // This is a remote platform
233061da546Spatrick       m_name_to_kext_path_map_with_dsyms(),
234061da546Spatrick       m_name_to_kext_path_map_without_dsyms(), m_search_directories(),
235061da546Spatrick       m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(),
236be691f3bSpatrick       m_kernel_binaries_without_dsyms(), m_kernel_dsyms_no_binaries(),
237be691f3bSpatrick       m_kernel_dsyms_yaas(), m_ios_debug_session(is_ios_debug_session)
238061da546Spatrick 
239061da546Spatrick {
240061da546Spatrick   CollectKextAndKernelDirectories();
241061da546Spatrick   SearchForKextsAndKernelsRecursively();
242061da546Spatrick }
243061da546Spatrick 
244061da546Spatrick /// Destructor.
245061da546Spatrick ///
246061da546Spatrick /// The destructor is virtual since this class is designed to be
247061da546Spatrick /// inherited from by the plug-in instance.
248be691f3bSpatrick PlatformDarwinKernel::~PlatformDarwinKernel() = default;
249061da546Spatrick 
GetStatus(Stream & strm)250061da546Spatrick void PlatformDarwinKernel::GetStatus(Stream &strm) {
251061da546Spatrick   Platform::GetStatus(strm);
252061da546Spatrick   strm.Printf(" Debug session type: ");
253061da546Spatrick   if (m_ios_debug_session == eLazyBoolYes)
254061da546Spatrick     strm.Printf("iOS kernel debugging\n");
255061da546Spatrick   else if (m_ios_debug_session == eLazyBoolNo)
256061da546Spatrick     strm.Printf("Mac OS X kernel debugging\n");
257061da546Spatrick   else
258061da546Spatrick     strm.Printf("unknown kernel debugging\n");
259061da546Spatrick 
260061da546Spatrick   strm.Printf("Directories searched recursively:\n");
261061da546Spatrick   const uint32_t num_kext_dirs = m_search_directories.size();
262061da546Spatrick   for (uint32_t i = 0; i < num_kext_dirs; ++i) {
263061da546Spatrick     strm.Printf("[%d] %s\n", i, m_search_directories[i].GetPath().c_str());
264061da546Spatrick   }
265061da546Spatrick 
266061da546Spatrick   strm.Printf("Directories not searched recursively:\n");
267061da546Spatrick   const uint32_t num_kext_dirs_no_recursion =
268061da546Spatrick       m_search_directories_no_recursing.size();
269061da546Spatrick   for (uint32_t i = 0; i < num_kext_dirs_no_recursion; i++) {
270061da546Spatrick     strm.Printf("[%d] %s\n", i,
271061da546Spatrick                 m_search_directories_no_recursing[i].GetPath().c_str());
272061da546Spatrick   }
273061da546Spatrick 
274061da546Spatrick   strm.Printf(" Number of kexts with dSYMs indexed: %d\n",
275061da546Spatrick               (int)m_name_to_kext_path_map_with_dsyms.size());
276061da546Spatrick   strm.Printf(" Number of kexts without dSYMs indexed: %d\n",
277061da546Spatrick               (int)m_name_to_kext_path_map_without_dsyms.size());
278061da546Spatrick   strm.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n",
279061da546Spatrick               (int)m_kernel_binaries_with_dsyms.size());
280061da546Spatrick   strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n",
281061da546Spatrick               (int)m_kernel_binaries_without_dsyms.size());
282be691f3bSpatrick   strm.Printf(" Number of Kernel dSYMs with no binaries indexed: %d\n",
283be691f3bSpatrick               (int)m_kernel_dsyms_no_binaries.size());
284be691f3bSpatrick   strm.Printf(" Number of Kernel dSYM.yaa's indexed: %d\n",
285be691f3bSpatrick               (int)m_kernel_dsyms_yaas.size());
286061da546Spatrick 
287*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Platform);
288061da546Spatrick   if (log) {
289061da546Spatrick     LLDB_LOGF(log, "\nkexts with dSYMs");
290061da546Spatrick     for (auto pos : m_name_to_kext_path_map_with_dsyms) {
291061da546Spatrick       LLDB_LOGF(log, "%s", pos.second.GetPath().c_str());
292061da546Spatrick     }
293061da546Spatrick     LLDB_LOGF(log, "\nkexts without dSYMs");
294061da546Spatrick 
295061da546Spatrick     for (auto pos : m_name_to_kext_path_map_without_dsyms) {
296061da546Spatrick       LLDB_LOGF(log, "%s", pos.second.GetPath().c_str());
297061da546Spatrick     }
298be691f3bSpatrick     LLDB_LOGF(log, "\nkernel binaries with dSYMS");
299061da546Spatrick     for (auto fs : m_kernel_binaries_with_dsyms) {
300061da546Spatrick       LLDB_LOGF(log, "%s", fs.GetPath().c_str());
301061da546Spatrick     }
302be691f3bSpatrick     LLDB_LOGF(log, "\nkernel binaries without dSYMS");
303061da546Spatrick     for (auto fs : m_kernel_binaries_without_dsyms) {
304061da546Spatrick       LLDB_LOGF(log, "%s", fs.GetPath().c_str());
305061da546Spatrick     }
306be691f3bSpatrick     LLDB_LOGF(log, "\nkernel dSYMS with no binaries");
307be691f3bSpatrick     for (auto fs : m_kernel_dsyms_no_binaries) {
308be691f3bSpatrick       LLDB_LOGF(log, "%s", fs.GetPath().c_str());
309be691f3bSpatrick     }
310be691f3bSpatrick     LLDB_LOGF(log, "\nkernels .dSYM.yaa's");
311be691f3bSpatrick     for (auto fs : m_kernel_dsyms_yaas) {
312be691f3bSpatrick       LLDB_LOGF(log, "%s", fs.GetPath().c_str());
313be691f3bSpatrick     }
314061da546Spatrick     LLDB_LOGF(log, "\n");
315061da546Spatrick   }
316061da546Spatrick }
317061da546Spatrick 
318061da546Spatrick // Populate the m_search_directories vector with directories we should search
319061da546Spatrick // for kernel & kext binaries.
320061da546Spatrick 
CollectKextAndKernelDirectories()321061da546Spatrick void PlatformDarwinKernel::CollectKextAndKernelDirectories() {
322061da546Spatrick   // Differentiate between "ios debug session" and "mac debug session" so we
323061da546Spatrick   // don't index kext bundles that won't be used in this debug session.  If
324061da546Spatrick   // this is an ios kext debug session, looking in /System/Library/Extensions
325061da546Spatrick   // is a waste of stat()s, for example.
326061da546Spatrick 
327061da546Spatrick   // DeveloperDirectory is something like
328061da546Spatrick   // "/Applications/Xcode.app/Contents/Developer"
329dda28197Spatrick   std::string developer_dir = HostInfo::GetXcodeDeveloperDirectory().GetPath();
330061da546Spatrick   if (developer_dir.empty())
331061da546Spatrick     developer_dir = "/Applications/Xcode.app/Contents/Developer";
332061da546Spatrick 
333061da546Spatrick   if (m_ios_debug_session != eLazyBoolNo) {
334061da546Spatrick     AddSDKSubdirsToSearchPaths(developer_dir +
335061da546Spatrick                                "/Platforms/iPhoneOS.platform/Developer/SDKs");
336061da546Spatrick     AddSDKSubdirsToSearchPaths(developer_dir +
337061da546Spatrick                                "/Platforms/AppleTVOS.platform/Developer/SDKs");
338061da546Spatrick     AddSDKSubdirsToSearchPaths(developer_dir +
339061da546Spatrick                                "/Platforms/WatchOS.platform/Developer/SDKs");
340061da546Spatrick     AddSDKSubdirsToSearchPaths(developer_dir +
341061da546Spatrick                                "/Platforms/BridgeOS.platform/Developer/SDKs");
342061da546Spatrick   }
343061da546Spatrick   if (m_ios_debug_session != eLazyBoolYes) {
344061da546Spatrick     AddSDKSubdirsToSearchPaths(developer_dir +
345061da546Spatrick                                "/Platforms/MacOSX.platform/Developer/SDKs");
346061da546Spatrick   }
347061da546Spatrick 
348061da546Spatrick   AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit");
349061da546Spatrick   AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs");
350061da546Spatrick   // The KDKs distributed from Apple installed on external developer systems
351061da546Spatrick   // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk
352061da546Spatrick   AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs");
353061da546Spatrick 
354061da546Spatrick   if (m_ios_debug_session != eLazyBoolNo) {
355061da546Spatrick   }
356061da546Spatrick   if (m_ios_debug_session != eLazyBoolYes) {
357061da546Spatrick     AddRootSubdirsToSearchPaths(this, "/");
358061da546Spatrick   }
359061da546Spatrick 
360061da546Spatrick   GetUserSpecifiedDirectoriesToSearch();
361061da546Spatrick 
362061da546Spatrick   // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols
363061da546Spatrick   FileSpec possible_dir(developer_dir + "/../Symbols");
364061da546Spatrick   FileSystem::Instance().Resolve(possible_dir);
365061da546Spatrick   if (FileSystem::Instance().IsDirectory(possible_dir))
366061da546Spatrick     m_search_directories.push_back(possible_dir);
367061da546Spatrick 
368061da546Spatrick   // Add simple directory of the current working directory
369061da546Spatrick   FileSpec cwd(".");
370061da546Spatrick   FileSystem::Instance().Resolve(cwd);
371061da546Spatrick   m_search_directories_no_recursing.push_back(cwd);
372061da546Spatrick }
373061da546Spatrick 
GetUserSpecifiedDirectoriesToSearch()374061da546Spatrick void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() {
375*f6aab3d8Srobert   FileSpecList user_dirs(GetGlobalProperties().GetKextDirectories());
376061da546Spatrick   std::vector<FileSpec> possible_sdk_dirs;
377061da546Spatrick 
378061da546Spatrick   const uint32_t user_dirs_count = user_dirs.GetSize();
379061da546Spatrick   for (uint32_t i = 0; i < user_dirs_count; i++) {
380061da546Spatrick     FileSpec dir = user_dirs.GetFileSpecAtIndex(i);
381061da546Spatrick     FileSystem::Instance().Resolve(dir);
382061da546Spatrick     if (FileSystem::Instance().IsDirectory(dir)) {
383061da546Spatrick       m_search_directories.push_back(dir);
384061da546Spatrick     }
385061da546Spatrick   }
386061da546Spatrick }
387061da546Spatrick 
AddRootSubdirsToSearchPaths(PlatformDarwinKernel * thisp,const std::string & dir)388061da546Spatrick void PlatformDarwinKernel::AddRootSubdirsToSearchPaths(
389061da546Spatrick     PlatformDarwinKernel *thisp, const std::string &dir) {
390061da546Spatrick   const char *subdirs[] = {
391061da546Spatrick       "/System/Library/Extensions", "/Library/Extensions",
392061da546Spatrick       "/System/Library/Kernels",
393061da546Spatrick       "/System/Library/Extensions/KDK", // this one probably only exist in
394061da546Spatrick                                         // /AppleInternal/Developer/KDKs/*.kdk/...
395061da546Spatrick       nullptr};
396061da546Spatrick   for (int i = 0; subdirs[i] != nullptr; i++) {
397061da546Spatrick     FileSpec testdir(dir + subdirs[i]);
398061da546Spatrick     FileSystem::Instance().Resolve(testdir);
399061da546Spatrick     if (FileSystem::Instance().IsDirectory(testdir))
400061da546Spatrick       thisp->m_search_directories.push_back(testdir);
401061da546Spatrick   }
402061da546Spatrick 
403061da546Spatrick   // Look for kernel binaries in the top level directory, without any recursion
404061da546Spatrick   thisp->m_search_directories_no_recursing.push_back(FileSpec(dir + "/"));
405061da546Spatrick }
406061da546Spatrick 
407061da546Spatrick // Given a directory path dir, look for any subdirs named *.kdk and *.sdk
AddSDKSubdirsToSearchPaths(const std::string & dir)408061da546Spatrick void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) {
409061da546Spatrick   // Look for *.kdk and *.sdk in dir
410061da546Spatrick   const bool find_directories = true;
411061da546Spatrick   const bool find_files = false;
412061da546Spatrick   const bool find_other = false;
413061da546Spatrick   FileSystem::Instance().EnumerateDirectory(
414061da546Spatrick       dir.c_str(), find_directories, find_files, find_other,
415061da546Spatrick       FindKDKandSDKDirectoriesInDirectory, this);
416061da546Spatrick }
417061da546Spatrick 
418061da546Spatrick // Helper function to find *.sdk and *.kdk directories in a given directory.
419061da546Spatrick FileSystem::EnumerateDirectoryResult
FindKDKandSDKDirectoriesInDirectory(void * baton,llvm::sys::fs::file_type ft,llvm::StringRef path)420061da546Spatrick PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory(
421061da546Spatrick     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
422061da546Spatrick   static ConstString g_sdk_suffix = ConstString(".sdk");
423061da546Spatrick   static ConstString g_kdk_suffix = ConstString(".kdk");
424061da546Spatrick 
425061da546Spatrick   PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
426061da546Spatrick   FileSpec file_spec(path);
427061da546Spatrick   if (ft == llvm::sys::fs::file_type::directory_file &&
428061da546Spatrick       (file_spec.GetFileNameExtension() == g_sdk_suffix ||
429061da546Spatrick        file_spec.GetFileNameExtension() == g_kdk_suffix)) {
430061da546Spatrick     AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath());
431061da546Spatrick   }
432061da546Spatrick   return FileSystem::eEnumerateDirectoryResultNext;
433061da546Spatrick }
434061da546Spatrick 
435061da546Spatrick // Recursively search trough m_search_directories looking for kext and kernel
436061da546Spatrick // binaries, adding files found to the appropriate lists.
SearchForKextsAndKernelsRecursively()437061da546Spatrick void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() {
438061da546Spatrick   const uint32_t num_dirs = m_search_directories.size();
439061da546Spatrick   for (uint32_t i = 0; i < num_dirs; i++) {
440061da546Spatrick     const FileSpec &dir = m_search_directories[i];
441061da546Spatrick     const bool find_directories = true;
442061da546Spatrick     const bool find_files = true;
443061da546Spatrick     const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
444061da546Spatrick     FileSystem::Instance().EnumerateDirectory(
445061da546Spatrick         dir.GetPath().c_str(), find_directories, find_files, find_other,
446061da546Spatrick         GetKernelsAndKextsInDirectoryWithRecursion, this);
447061da546Spatrick   }
448061da546Spatrick   const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size();
449061da546Spatrick   for (uint32_t i = 0; i < num_dirs_no_recurse; i++) {
450061da546Spatrick     const FileSpec &dir = m_search_directories_no_recursing[i];
451061da546Spatrick     const bool find_directories = true;
452061da546Spatrick     const bool find_files = true;
453061da546Spatrick     const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
454061da546Spatrick     FileSystem::Instance().EnumerateDirectory(
455061da546Spatrick         dir.GetPath().c_str(), find_directories, find_files, find_other,
456061da546Spatrick         GetKernelsAndKextsInDirectoryNoRecursion, this);
457061da546Spatrick   }
458061da546Spatrick }
459061da546Spatrick 
460061da546Spatrick // We're only doing a filename match here.  We won't try opening the file to
461061da546Spatrick // see if it's really a kernel or not until we need to find a kernel of a given
462061da546Spatrick // UUID.  There's no cheap way to find the UUID of a file (or if it's a Mach-O
463061da546Spatrick // binary at all) without creating a whole Module for the file and throwing it
464061da546Spatrick // away if it's not wanted.
465061da546Spatrick //
466061da546Spatrick // Recurse into any subdirectories found.
467061da546Spatrick 
468061da546Spatrick FileSystem::EnumerateDirectoryResult
GetKernelsAndKextsInDirectoryWithRecursion(void * baton,llvm::sys::fs::file_type ft,llvm::StringRef path)469061da546Spatrick PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion(
470061da546Spatrick     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
471061da546Spatrick   return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, true);
472061da546Spatrick }
473061da546Spatrick 
474061da546Spatrick FileSystem::EnumerateDirectoryResult
GetKernelsAndKextsInDirectoryNoRecursion(void * baton,llvm::sys::fs::file_type ft,llvm::StringRef path)475061da546Spatrick PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion(
476061da546Spatrick     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
477061da546Spatrick   return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, false);
478061da546Spatrick }
479061da546Spatrick 
480061da546Spatrick FileSystem::EnumerateDirectoryResult
GetKernelsAndKextsInDirectoryHelper(void * baton,llvm::sys::fs::file_type ft,llvm::StringRef path,bool recurse)481061da546Spatrick PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper(
482061da546Spatrick     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path,
483061da546Spatrick     bool recurse) {
484061da546Spatrick   static ConstString g_kext_suffix = ConstString(".kext");
485061da546Spatrick   static ConstString g_dsym_suffix = ConstString(".dSYM");
486061da546Spatrick   static ConstString g_bundle_suffix = ConstString("Bundle");
487061da546Spatrick 
488061da546Spatrick   FileSpec file_spec(path);
489061da546Spatrick   ConstString file_spec_extension = file_spec.GetFileNameExtension();
490061da546Spatrick 
491*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Platform);
492061da546Spatrick 
493*f6aab3d8Srobert   LLDB_LOGV(log, "PlatformDarwinKernel examining '{0}'", file_spec);
494061da546Spatrick 
495061da546Spatrick   PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
496be691f3bSpatrick 
497be691f3bSpatrick   llvm::StringRef filename = file_spec.GetFilename().GetStringRef();
498be691f3bSpatrick   bool is_kernel_filename =
499be691f3bSpatrick       filename.startswith("kernel") || filename.startswith("mach");
500be691f3bSpatrick   bool is_dsym_yaa = filename.endswith(".dSYM.yaa");
501be691f3bSpatrick 
502061da546Spatrick   if (ft == llvm::sys::fs::file_type::regular_file ||
503061da546Spatrick       ft == llvm::sys::fs::file_type::symlink_file) {
504be691f3bSpatrick     if (is_kernel_filename) {
505be691f3bSpatrick       if (file_spec_extension != g_dsym_suffix && !is_dsym_yaa) {
506be691f3bSpatrick         if (KernelHasdSYMSibling(file_spec)) {
507061da546Spatrick           LLDB_LOGF(log,
508061da546Spatrick                     "PlatformDarwinKernel registering kernel binary '%s' with "
509061da546Spatrick                     "dSYM sibling",
510061da546Spatrick                     file_spec.GetPath().c_str());
511061da546Spatrick           thisp->m_kernel_binaries_with_dsyms.push_back(file_spec);
512be691f3bSpatrick         } else {
513061da546Spatrick           LLDB_LOGF(
514be691f3bSpatrick               log,
515be691f3bSpatrick               "PlatformDarwinKernel registering kernel binary '%s', no dSYM",
516061da546Spatrick               file_spec.GetPath().c_str());
517061da546Spatrick           thisp->m_kernel_binaries_without_dsyms.push_back(file_spec);
518061da546Spatrick         }
519be691f3bSpatrick       }
520be691f3bSpatrick       if (is_dsym_yaa) {
521be691f3bSpatrick         LLDB_LOGF(log, "PlatformDarwinKernel registering kernel .dSYM.yaa '%s'",
522be691f3bSpatrick                   file_spec.GetPath().c_str());
523be691f3bSpatrick         thisp->m_kernel_dsyms_yaas.push_back(file_spec);
524be691f3bSpatrick       }
525061da546Spatrick       return FileSystem::eEnumerateDirectoryResultNext;
526061da546Spatrick     }
527be691f3bSpatrick   } else {
528be691f3bSpatrick     if (ft == llvm::sys::fs::file_type::directory_file) {
529be691f3bSpatrick       if (file_spec_extension == g_kext_suffix) {
530061da546Spatrick         AddKextToMap(thisp, file_spec);
531061da546Spatrick         // Look to see if there is a PlugIns subdir with more kexts
532061da546Spatrick         FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns");
533061da546Spatrick         std::string search_here_too;
534061da546Spatrick         if (FileSystem::Instance().IsDirectory(contents_plugins)) {
535061da546Spatrick           search_here_too = contents_plugins.GetPath();
536061da546Spatrick         } else {
537061da546Spatrick           FileSpec plugins(file_spec.GetPath() + "/PlugIns");
538061da546Spatrick           if (FileSystem::Instance().IsDirectory(plugins)) {
539061da546Spatrick             search_here_too = plugins.GetPath();
540061da546Spatrick           }
541061da546Spatrick         }
542061da546Spatrick 
543061da546Spatrick         if (!search_here_too.empty()) {
544061da546Spatrick           const bool find_directories = true;
545061da546Spatrick           const bool find_files = false;
546061da546Spatrick           const bool find_other = false;
547061da546Spatrick           FileSystem::Instance().EnumerateDirectory(
548061da546Spatrick               search_here_too.c_str(), find_directories, find_files, find_other,
549061da546Spatrick               recurse ? GetKernelsAndKextsInDirectoryWithRecursion
550061da546Spatrick                       : GetKernelsAndKextsInDirectoryNoRecursion,
551061da546Spatrick               baton);
552061da546Spatrick         }
553061da546Spatrick         return FileSystem::eEnumerateDirectoryResultNext;
554061da546Spatrick       }
555be691f3bSpatrick       // Do we have a kernel dSYM with no kernel binary?
556be691f3bSpatrick       if (is_kernel_filename && file_spec_extension == g_dsym_suffix) {
557be691f3bSpatrick         if (KerneldSYMHasNoSiblingBinary(file_spec)) {
558be691f3bSpatrick           LLDB_LOGF(log,
559be691f3bSpatrick                     "PlatformDarwinKernel registering kernel dSYM '%s' with "
560be691f3bSpatrick                     "no binary sibling",
561be691f3bSpatrick                     file_spec.GetPath().c_str());
562be691f3bSpatrick           thisp->m_kernel_dsyms_no_binaries.push_back(file_spec);
563be691f3bSpatrick           return FileSystem::eEnumerateDirectoryResultNext;
564be691f3bSpatrick         }
565be691f3bSpatrick       }
566be691f3bSpatrick     }
567be691f3bSpatrick   }
568be691f3bSpatrick 
569061da546Spatrick   // Don't recurse into dSYM/kext/bundle directories
570061da546Spatrick   if (recurse && file_spec_extension != g_dsym_suffix &&
571061da546Spatrick       file_spec_extension != g_kext_suffix &&
572061da546Spatrick       file_spec_extension != g_bundle_suffix) {
573*f6aab3d8Srobert     LLDB_LOGV(log, "PlatformDarwinKernel descending into directory '{0}'",
574*f6aab3d8Srobert               file_spec);
575061da546Spatrick     return FileSystem::eEnumerateDirectoryResultEnter;
576061da546Spatrick   } else {
577061da546Spatrick     return FileSystem::eEnumerateDirectoryResultNext;
578061da546Spatrick   }
579061da546Spatrick }
580061da546Spatrick 
AddKextToMap(PlatformDarwinKernel * thisp,const FileSpec & file_spec)581061da546Spatrick void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp,
582061da546Spatrick                                         const FileSpec &file_spec) {
583*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Platform);
584061da546Spatrick   CFCBundle bundle(file_spec.GetPath().c_str());
585061da546Spatrick   CFStringRef bundle_id(bundle.GetIdentifier());
586061da546Spatrick   if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) {
587061da546Spatrick     char bundle_id_buf[PATH_MAX];
588061da546Spatrick     if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf),
589061da546Spatrick                            kCFStringEncodingUTF8)) {
590061da546Spatrick       ConstString bundle_conststr(bundle_id_buf);
591061da546Spatrick       if (KextHasdSYMSibling(file_spec))
592061da546Spatrick       {
593061da546Spatrick         LLDB_LOGF(log,
594061da546Spatrick                   "PlatformDarwinKernel registering kext binary '%s' with dSYM "
595061da546Spatrick                   "sibling",
596061da546Spatrick                   file_spec.GetPath().c_str());
597061da546Spatrick         thisp->m_name_to_kext_path_map_with_dsyms.insert(
598061da546Spatrick             std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
599061da546Spatrick       }
600061da546Spatrick       else
601061da546Spatrick       {
602061da546Spatrick         LLDB_LOGF(log,
603061da546Spatrick                   "PlatformDarwinKernel registering kext binary '%s', no dSYM",
604061da546Spatrick                   file_spec.GetPath().c_str());
605061da546Spatrick         thisp->m_name_to_kext_path_map_without_dsyms.insert(
606061da546Spatrick             std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
607061da546Spatrick       }
608061da546Spatrick     }
609061da546Spatrick   }
610061da546Spatrick }
611061da546Spatrick 
612061da546Spatrick // Given a FileSpec of /dir/dir/foo.kext
613061da546Spatrick // Return true if any of these exist:
614061da546Spatrick //    /dir/dir/foo.kext.dSYM
615061da546Spatrick //    /dir/dir/foo.kext/Contents/MacOS/foo.dSYM
616061da546Spatrick //    /dir/dir/foo.kext/foo.dSYM
KextHasdSYMSibling(const FileSpec & kext_bundle_filepath)617061da546Spatrick bool PlatformDarwinKernel::KextHasdSYMSibling(
618061da546Spatrick     const FileSpec &kext_bundle_filepath) {
619061da546Spatrick   FileSpec dsym_fspec = kext_bundle_filepath;
620061da546Spatrick   std::string filename = dsym_fspec.GetFilename().AsCString();
621061da546Spatrick   filename += ".dSYM";
622*f6aab3d8Srobert   dsym_fspec.SetFilename(filename);
623061da546Spatrick   if (FileSystem::Instance().IsDirectory(dsym_fspec)) {
624061da546Spatrick     return true;
625061da546Spatrick   }
626061da546Spatrick   // Should probably get the CFBundleExecutable here or call
627061da546Spatrick   // CFBundleCopyExecutableURL
628061da546Spatrick 
629061da546Spatrick   // Look for a deep bundle foramt
630061da546Spatrick   ConstString executable_name =
631061da546Spatrick       kext_bundle_filepath.GetFileNameStrippingExtension();
632061da546Spatrick   std::string deep_bundle_str =
633061da546Spatrick       kext_bundle_filepath.GetPath() + "/Contents/MacOS/";
634061da546Spatrick   deep_bundle_str += executable_name.AsCString();
635061da546Spatrick   deep_bundle_str += ".dSYM";
636061da546Spatrick   dsym_fspec.SetFile(deep_bundle_str, FileSpec::Style::native);
637061da546Spatrick   FileSystem::Instance().Resolve(dsym_fspec);
638061da546Spatrick   if (FileSystem::Instance().IsDirectory(dsym_fspec)) {
639061da546Spatrick     return true;
640061da546Spatrick   }
641061da546Spatrick 
642061da546Spatrick   // look for a shallow bundle format
643061da546Spatrick   //
644061da546Spatrick   std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/";
645061da546Spatrick   shallow_bundle_str += executable_name.AsCString();
646061da546Spatrick   shallow_bundle_str += ".dSYM";
647061da546Spatrick   dsym_fspec.SetFile(shallow_bundle_str, FileSpec::Style::native);
648061da546Spatrick   FileSystem::Instance().Resolve(dsym_fspec);
649061da546Spatrick   return FileSystem::Instance().IsDirectory(dsym_fspec);
650061da546Spatrick }
651061da546Spatrick 
652061da546Spatrick // Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM
653061da546Spatrick // exists next to it:
654061da546Spatrick //    /dir/dir/mach.development.t7004.dSYM
KernelHasdSYMSibling(const FileSpec & kernel_binary)655061da546Spatrick bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) {
656061da546Spatrick   FileSpec kernel_dsym = kernel_binary;
657061da546Spatrick   std::string filename = kernel_binary.GetFilename().AsCString();
658061da546Spatrick   filename += ".dSYM";
659*f6aab3d8Srobert   kernel_dsym.SetFilename(filename);
660061da546Spatrick   return FileSystem::Instance().IsDirectory(kernel_dsym);
661061da546Spatrick }
662061da546Spatrick 
663be691f3bSpatrick // Given a FileSpec of /dir/dir/mach.development.t7004.dSYM
664be691f3bSpatrick // Return true if only the dSYM exists, no binary next to it.
665be691f3bSpatrick //    /dir/dir/mach.development.t7004.dSYM
666be691f3bSpatrick //    but no
667be691f3bSpatrick //    /dir/dir/mach.development.t7004
KerneldSYMHasNoSiblingBinary(const FileSpec & kernel_dsym)668be691f3bSpatrick bool PlatformDarwinKernel::KerneldSYMHasNoSiblingBinary(
669be691f3bSpatrick     const FileSpec &kernel_dsym) {
670be691f3bSpatrick   static ConstString g_dsym_suffix = ConstString(".dSYM");
671be691f3bSpatrick   std::string possible_path = kernel_dsym.GetPath();
672be691f3bSpatrick   if (kernel_dsym.GetFileNameExtension() != g_dsym_suffix)
673be691f3bSpatrick     return false;
674be691f3bSpatrick 
675be691f3bSpatrick   FileSpec binary_filespec = kernel_dsym;
676be691f3bSpatrick   // Chop off the '.dSYM' extension on the filename
677*f6aab3d8Srobert   binary_filespec.SetFilename(binary_filespec.GetFileNameStrippingExtension());
678be691f3bSpatrick 
679be691f3bSpatrick   // Is there a binary next to this this?  Then return false.
680be691f3bSpatrick   if (FileSystem::Instance().Exists(binary_filespec))
681be691f3bSpatrick     return false;
682be691f3bSpatrick 
683be691f3bSpatrick   // If we have at least one binary in the DWARF subdir, then
684be691f3bSpatrick   // this is a properly formed dSYM and it has no binary next
685be691f3bSpatrick   // to it.
686be691f3bSpatrick   if (GetDWARFBinaryInDSYMBundle(kernel_dsym).size() > 0)
687be691f3bSpatrick     return true;
688be691f3bSpatrick 
689be691f3bSpatrick   return false;
690be691f3bSpatrick }
691be691f3bSpatrick 
692be691f3bSpatrick // TODO: This method returns a vector of FileSpec's because a
693be691f3bSpatrick // dSYM bundle may contain multiple DWARF binaries, but it
694be691f3bSpatrick // only implements returning the base name binary for now;
695be691f3bSpatrick // it should iterate over every binary in the DWARF subdir
696be691f3bSpatrick // and return them all.
697be691f3bSpatrick std::vector<FileSpec>
GetDWARFBinaryInDSYMBundle(FileSpec dsym_bundle)698be691f3bSpatrick PlatformDarwinKernel::GetDWARFBinaryInDSYMBundle(FileSpec dsym_bundle) {
699be691f3bSpatrick   std::vector<FileSpec> results;
700be691f3bSpatrick   static ConstString g_dsym_suffix = ConstString(".dSYM");
701be691f3bSpatrick   if (dsym_bundle.GetFileNameExtension() != g_dsym_suffix) {
702be691f3bSpatrick     return results;
703be691f3bSpatrick   }
704be691f3bSpatrick   // Drop the '.dSYM' from the filename
705be691f3bSpatrick   std::string filename =
706be691f3bSpatrick       dsym_bundle.GetFileNameStrippingExtension().GetCString();
707be691f3bSpatrick   std::string dirname = dsym_bundle.GetDirectory().GetCString();
708be691f3bSpatrick 
709be691f3bSpatrick   std::string binary_filepath = dsym_bundle.GetPath();
710be691f3bSpatrick   binary_filepath += "/Contents/Resources/DWARF/";
711be691f3bSpatrick   binary_filepath += filename;
712be691f3bSpatrick 
713be691f3bSpatrick   FileSpec binary_fspec(binary_filepath);
714be691f3bSpatrick   if (FileSystem::Instance().Exists(binary_fspec))
715be691f3bSpatrick     results.push_back(binary_fspec);
716be691f3bSpatrick   return results;
717be691f3bSpatrick }
718be691f3bSpatrick 
GetSharedModule(const ModuleSpec & module_spec,Process * process,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<ModuleSP> * old_modules,bool * did_create_ptr)719061da546Spatrick Status PlatformDarwinKernel::GetSharedModule(
720061da546Spatrick     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
721dda28197Spatrick     const FileSpecList *module_search_paths_ptr,
722dda28197Spatrick     llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
723061da546Spatrick   Status error;
724061da546Spatrick   module_sp.reset();
725061da546Spatrick   const FileSpec &platform_file = module_spec.GetFileSpec();
726061da546Spatrick 
727061da546Spatrick   // Treat the file's path as a kext bundle ID (e.g.
728061da546Spatrick   // "com.apple.driver.AppleIRController") and search our kext index.
729061da546Spatrick   std::string kext_bundle_id = platform_file.GetPath();
730061da546Spatrick 
731*f6aab3d8Srobert   if (module_spec.GetUUID().IsValid()) {
732*f6aab3d8Srobert     // DynamicLoaderDarwinKernel uses the magic name mach_kernel,
733*f6aab3d8Srobert     // UUID search can get here with no name - and it may be a kernel.
734*f6aab3d8Srobert     if (kext_bundle_id == "mach_kernel" || kext_bundle_id.empty()) {
735*f6aab3d8Srobert       error = GetSharedModuleKernel(module_spec, process, module_sp,
736be691f3bSpatrick                                     module_search_paths_ptr, old_modules,
737be691f3bSpatrick                                     did_create_ptr);
738*f6aab3d8Srobert       if (error.Success() && module_sp) {
739*f6aab3d8Srobert         return error;
740*f6aab3d8Srobert       }
741be691f3bSpatrick     } else {
742be691f3bSpatrick       return GetSharedModuleKext(module_spec, process, module_sp,
743be691f3bSpatrick                                  module_search_paths_ptr, old_modules,
744be691f3bSpatrick                                  did_create_ptr);
745be691f3bSpatrick     }
746*f6aab3d8Srobert   }
747*f6aab3d8Srobert 
748be691f3bSpatrick   // Give the generic methods, including possibly calling into DebugSymbols
749be691f3bSpatrick   // framework on macOS systems, a chance.
750be691f3bSpatrick   return PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
751be691f3bSpatrick                                          module_search_paths_ptr, old_modules,
752be691f3bSpatrick                                          did_create_ptr);
753be691f3bSpatrick }
754be691f3bSpatrick 
GetSharedModuleKext(const ModuleSpec & module_spec,Process * process,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<ModuleSP> * old_modules,bool * did_create_ptr)755be691f3bSpatrick Status PlatformDarwinKernel::GetSharedModuleKext(
756be691f3bSpatrick     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
757be691f3bSpatrick     const FileSpecList *module_search_paths_ptr,
758be691f3bSpatrick     llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
759be691f3bSpatrick   Status error;
760be691f3bSpatrick   module_sp.reset();
761be691f3bSpatrick   const FileSpec &platform_file = module_spec.GetFileSpec();
762be691f3bSpatrick 
763be691f3bSpatrick   // Treat the file's path as a kext bundle ID (e.g.
764be691f3bSpatrick   // "com.apple.driver.AppleIRController") and search our kext index.
765be691f3bSpatrick   ConstString kext_bundle(platform_file.GetPath().c_str());
766061da546Spatrick   // First look through the kext bundles that had a dsym next to them
767be691f3bSpatrick   if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle) > 0) {
768be691f3bSpatrick     for (BundleIDToKextIterator it = m_name_to_kext_path_map_with_dsyms.begin();
769061da546Spatrick          it != m_name_to_kext_path_map_with_dsyms.end(); ++it) {
770be691f3bSpatrick       if (it->first == kext_bundle) {
771061da546Spatrick         error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(),
772061da546Spatrick                                            module_spec.GetArchitecture(),
773061da546Spatrick                                            module_sp);
774061da546Spatrick         if (module_sp.get()) {
775061da546Spatrick           return error;
776061da546Spatrick         }
777061da546Spatrick       }
778061da546Spatrick     }
779061da546Spatrick   }
780061da546Spatrick 
781061da546Spatrick   // Give the generic methods, including possibly calling into  DebugSymbols
782061da546Spatrick   // framework on macOS systems, a chance.
783061da546Spatrick   error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
784be691f3bSpatrick                                           module_search_paths_ptr, old_modules,
785be691f3bSpatrick                                           did_create_ptr);
786061da546Spatrick   if (error.Success() && module_sp.get()) {
787061da546Spatrick     return error;
788061da546Spatrick   }
789061da546Spatrick 
790061da546Spatrick   return error;
791061da546Spatrick }
792061da546Spatrick 
GetSharedModuleKernel(const ModuleSpec & module_spec,Process * process,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<ModuleSP> * old_modules,bool * did_create_ptr)793be691f3bSpatrick Status PlatformDarwinKernel::GetSharedModuleKernel(
794be691f3bSpatrick     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
795be691f3bSpatrick     const FileSpecList *module_search_paths_ptr,
796be691f3bSpatrick     llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
797be691f3bSpatrick   Status error;
798be691f3bSpatrick   module_sp.reset();
799be691f3bSpatrick 
800061da546Spatrick   // First try all kernel binaries that have a dSYM next to them
801061da546Spatrick   for (auto possible_kernel : m_kernel_binaries_with_dsyms) {
802061da546Spatrick     if (FileSystem::Instance().Exists(possible_kernel)) {
803061da546Spatrick       ModuleSpec kern_spec(possible_kernel);
804061da546Spatrick       kern_spec.GetUUID() = module_spec.GetUUID();
805be691f3bSpatrick       module_sp.reset(new Module(kern_spec));
806061da546Spatrick       if (module_sp && module_sp->GetObjectFile() &&
807061da546Spatrick           module_sp->MatchesModuleSpec(kern_spec)) {
808061da546Spatrick         // module_sp is an actual kernel binary we want to add.
809061da546Spatrick         if (process) {
810*f6aab3d8Srobert           const bool notify = false;
811*f6aab3d8Srobert           process->GetTarget().GetImages().AppendIfNeeded(module_sp, notify);
812061da546Spatrick           error.Clear();
813061da546Spatrick           return error;
814061da546Spatrick         } else {
815be691f3bSpatrick           error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr,
816be691f3bSpatrick                                               nullptr, nullptr);
817be691f3bSpatrick           if (module_sp && module_sp->GetObjectFile() &&
818be691f3bSpatrick               module_sp->GetObjectFile()->GetType() !=
819be691f3bSpatrick                   ObjectFile::Type::eTypeCoreFile) {
820be691f3bSpatrick             return error;
821be691f3bSpatrick           }
822be691f3bSpatrick           module_sp.reset();
823be691f3bSpatrick         }
824be691f3bSpatrick       }
825be691f3bSpatrick     }
826be691f3bSpatrick   }
827be691f3bSpatrick 
828be691f3bSpatrick   // Next try all dSYMs that have no kernel binary next to them (load
829be691f3bSpatrick   // the kernel DWARF stub as the main binary)
830be691f3bSpatrick   for (auto possible_kernel_dsym : m_kernel_dsyms_no_binaries) {
831be691f3bSpatrick     std::vector<FileSpec> objfile_names =
832be691f3bSpatrick         GetDWARFBinaryInDSYMBundle(possible_kernel_dsym);
833be691f3bSpatrick     for (FileSpec objfile : objfile_names) {
834be691f3bSpatrick       ModuleSpec kern_spec(objfile);
835be691f3bSpatrick       kern_spec.GetUUID() = module_spec.GetUUID();
836be691f3bSpatrick       kern_spec.GetSymbolFileSpec() = possible_kernel_dsym;
837be691f3bSpatrick 
838be691f3bSpatrick       module_sp.reset(new Module(kern_spec));
839be691f3bSpatrick       if (module_sp && module_sp->GetObjectFile() &&
840be691f3bSpatrick           module_sp->MatchesModuleSpec(kern_spec)) {
841be691f3bSpatrick         // module_sp is an actual kernel binary we want to add.
842be691f3bSpatrick         if (process) {
843*f6aab3d8Srobert           const bool notify = false;
844*f6aab3d8Srobert           process->GetTarget().GetImages().AppendIfNeeded(module_sp, notify);
845be691f3bSpatrick           error.Clear();
846be691f3bSpatrick           return error;
847be691f3bSpatrick         } else {
848be691f3bSpatrick           error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr,
849be691f3bSpatrick                                               nullptr, nullptr);
850061da546Spatrick           if (module_sp && module_sp->GetObjectFile() &&
851061da546Spatrick               module_sp->GetObjectFile()->GetType() !=
852061da546Spatrick                   ObjectFile::Type::eTypeCoreFile) {
853061da546Spatrick             return error;
854061da546Spatrick           }
855061da546Spatrick           module_sp.reset();
856061da546Spatrick         }
857061da546Spatrick       }
858061da546Spatrick     }
859061da546Spatrick   }
860061da546Spatrick 
861061da546Spatrick   // Give the generic methods, including possibly calling into  DebugSymbols
862061da546Spatrick   // framework on macOS systems, a chance.
863061da546Spatrick   error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
864be691f3bSpatrick                                           module_search_paths_ptr, old_modules,
865be691f3bSpatrick                                           did_create_ptr);
866061da546Spatrick   if (error.Success() && module_sp.get()) {
867061da546Spatrick     return error;
868061da546Spatrick   }
869061da546Spatrick 
870061da546Spatrick   return error;
871061da546Spatrick }
872061da546Spatrick 
873061da546Spatrick std::vector<lldb_private::FileSpec>
SearchForExecutablesRecursively(const std::string & dir)874061da546Spatrick PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string &dir) {
875061da546Spatrick   std::vector<FileSpec> executables;
876061da546Spatrick   std::error_code EC;
877061da546Spatrick   for (llvm::sys::fs::recursive_directory_iterator it(dir.c_str(), EC),
878061da546Spatrick        end;
879061da546Spatrick        it != end && !EC; it.increment(EC)) {
880061da546Spatrick     auto status = it->status();
881061da546Spatrick     if (!status)
882061da546Spatrick       break;
883061da546Spatrick     if (llvm::sys::fs::is_regular_file(*status) &&
884061da546Spatrick         llvm::sys::fs::can_execute(it->path()))
885061da546Spatrick       executables.emplace_back(it->path());
886061da546Spatrick   }
887061da546Spatrick   return executables;
888061da546Spatrick }
889061da546Spatrick 
ExamineKextForMatchingUUID(const FileSpec & kext_bundle_path,const lldb_private::UUID & uuid,const ArchSpec & arch,ModuleSP & exe_module_sp)890061da546Spatrick Status PlatformDarwinKernel::ExamineKextForMatchingUUID(
891061da546Spatrick     const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid,
892061da546Spatrick     const ArchSpec &arch, ModuleSP &exe_module_sp) {
893061da546Spatrick   for (const auto &exe_file :
894061da546Spatrick        SearchForExecutablesRecursively(kext_bundle_path.GetPath())) {
895061da546Spatrick     if (FileSystem::Instance().Exists(exe_file)) {
896061da546Spatrick       ModuleSpec exe_spec(exe_file);
897061da546Spatrick       exe_spec.GetUUID() = uuid;
898061da546Spatrick       if (!uuid.IsValid()) {
899061da546Spatrick         exe_spec.GetArchitecture() = arch;
900061da546Spatrick       }
901061da546Spatrick 
902061da546Spatrick       // First try to create a ModuleSP with the file / arch and see if the UUID
903061da546Spatrick       // matches. If that fails (this exec file doesn't have the correct uuid),
904061da546Spatrick       // don't call GetSharedModule (which may call in to the DebugSymbols
905061da546Spatrick       // framework and therefore can be slow.)
906061da546Spatrick       ModuleSP module_sp(new Module(exe_spec));
907061da546Spatrick       if (module_sp && module_sp->GetObjectFile() &&
908061da546Spatrick           module_sp->MatchesModuleSpec(exe_spec)) {
909061da546Spatrick         Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp,
910061da546Spatrick                                                    NULL, NULL, NULL);
911061da546Spatrick         if (exe_module_sp && exe_module_sp->GetObjectFile()) {
912061da546Spatrick           return error;
913061da546Spatrick         }
914061da546Spatrick       }
915061da546Spatrick       exe_module_sp.reset();
916061da546Spatrick     }
917061da546Spatrick   }
918061da546Spatrick 
919061da546Spatrick   return {};
920061da546Spatrick }
921061da546Spatrick 
find_kernel_in_macho_fileset(Process * process,addr_t input_addr)922*f6aab3d8Srobert static addr_t find_kernel_in_macho_fileset(Process *process,
923*f6aab3d8Srobert                                            addr_t input_addr) {
924*f6aab3d8Srobert   Status error;
925*f6aab3d8Srobert   WritableDataBufferSP header_data(new DataBufferHeap(512, 0));
926*f6aab3d8Srobert   if (!process->ReadMemory(input_addr, header_data->GetBytes(),
927*f6aab3d8Srobert                            header_data->GetByteSize(), error) ||
928*f6aab3d8Srobert       !error.Success())
929*f6aab3d8Srobert     return LLDB_INVALID_ADDRESS;
930*f6aab3d8Srobert   ModuleSP module_sp(new Module(ModuleSpec()));
931*f6aab3d8Srobert   ObjectContainerSP container_sp(
932*f6aab3d8Srobert       ObjectContainerMachOFileset::CreateMemoryInstance(
933*f6aab3d8Srobert           module_sp, header_data, process->shared_from_this(), input_addr));
934*f6aab3d8Srobert   if (!container_sp)
935*f6aab3d8Srobert     return LLDB_INVALID_ADDRESS;
936*f6aab3d8Srobert 
937*f6aab3d8Srobert   ObjectContainerMachOFileset *fileset_container =
938*f6aab3d8Srobert       static_cast<ObjectContainerMachOFileset *>(container_sp.get());
939*f6aab3d8Srobert   ObjectContainerMachOFileset::Entry *entry =
940*f6aab3d8Srobert       fileset_container->FindEntry("com.apple.kernel");
941*f6aab3d8Srobert   if (entry)
942*f6aab3d8Srobert     return entry->vmaddr;
943*f6aab3d8Srobert   return LLDB_INVALID_ADDRESS;
944*f6aab3d8Srobert }
945*f6aab3d8Srobert 
LoadPlatformBinaryAndSetup(Process * process,lldb::addr_t input_addr,bool notify)946*f6aab3d8Srobert bool PlatformDarwinKernel::LoadPlatformBinaryAndSetup(Process *process,
947*f6aab3d8Srobert                                                       lldb::addr_t input_addr,
948*f6aab3d8Srobert                                                       bool notify) {
949*f6aab3d8Srobert   Log *log =
950*f6aab3d8Srobert       GetLog(LLDBLog::Platform | LLDBLog::DynamicLoader | LLDBLog::Process);
951*f6aab3d8Srobert 
952*f6aab3d8Srobert   if (!process)
953*f6aab3d8Srobert     return false;
954*f6aab3d8Srobert 
955*f6aab3d8Srobert   addr_t actual_address = find_kernel_in_macho_fileset(process, input_addr);
956*f6aab3d8Srobert 
957*f6aab3d8Srobert   LLDB_LOGF(log,
958*f6aab3d8Srobert             "PlatformDarwinKernel::%s check address 0x%" PRIx64 " for "
959*f6aab3d8Srobert             "a macho fileset, got back kernel address 0x%" PRIx64,
960*f6aab3d8Srobert             __FUNCTION__, input_addr, actual_address);
961*f6aab3d8Srobert 
962*f6aab3d8Srobert   if (actual_address == LLDB_INVALID_ADDRESS)
963*f6aab3d8Srobert     return false;
964*f6aab3d8Srobert 
965*f6aab3d8Srobert   // We have a xnu kernel binary, this is a kernel debug session.
966*f6aab3d8Srobert   // Set the Target's Platform to be PlatformDarwinKernel, and the
967*f6aab3d8Srobert   // Process' DynamicLoader to be DynamicLoaderDarwinKernel.
968*f6aab3d8Srobert 
969*f6aab3d8Srobert   PlatformSP platform_sp =
970*f6aab3d8Srobert       process->GetTarget().GetDebugger().GetPlatformList().Create(
971*f6aab3d8Srobert           PlatformDarwinKernel::GetPluginNameStatic());
972*f6aab3d8Srobert   if (platform_sp)
973*f6aab3d8Srobert     process->GetTarget().SetPlatform(platform_sp);
974*f6aab3d8Srobert 
975*f6aab3d8Srobert   DynamicLoaderUP dyld_up =
976*f6aab3d8Srobert       std::make_unique<DynamicLoaderDarwinKernel>(process, actual_address);
977*f6aab3d8Srobert   if (!dyld_up)
978*f6aab3d8Srobert     return false;
979*f6aab3d8Srobert 
980*f6aab3d8Srobert   // Process owns it now
981*f6aab3d8Srobert   process->SetDynamicLoader(std::move(dyld_up));
982*f6aab3d8Srobert 
983*f6aab3d8Srobert   return true;
984*f6aab3d8Srobert }
985*f6aab3d8Srobert 
GetSupportedArchitectures(const ArchSpec & process_host_arch)986*f6aab3d8Srobert std::vector<ArchSpec> PlatformDarwinKernel::GetSupportedArchitectures(
987*f6aab3d8Srobert     const ArchSpec &process_host_arch) {
988*f6aab3d8Srobert   std::vector<ArchSpec> result;
989*f6aab3d8Srobert   ARMGetSupportedArchitectures(result);
990*f6aab3d8Srobert   x86GetSupportedArchitectures(result);
991*f6aab3d8Srobert   return result;
992061da546Spatrick }
993061da546Spatrick 
CalculateTrapHandlerSymbolNames()994061da546Spatrick void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() {
995061da546Spatrick   m_trap_handlers.push_back(ConstString("trap_from_kernel"));
996061da546Spatrick   m_trap_handlers.push_back(ConstString("hndl_machine_check"));
997061da546Spatrick   m_trap_handlers.push_back(ConstString("hndl_double_fault"));
998061da546Spatrick   m_trap_handlers.push_back(ConstString("hndl_allintrs"));
999061da546Spatrick   m_trap_handlers.push_back(ConstString("hndl_alltraps"));
1000061da546Spatrick   m_trap_handlers.push_back(ConstString("interrupt"));
1001061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_prefabt"));
1002061da546Spatrick   m_trap_handlers.push_back(ConstString("ExceptionVectorsBase"));
1003061da546Spatrick   m_trap_handlers.push_back(ConstString("ExceptionVectorsTable"));
1004061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_undef"));
1005061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_dataabt"));
1006061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_irq"));
1007061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_decirq"));
1008061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_fiq_generic"));
1009061da546Spatrick   m_trap_handlers.push_back(ConstString("fleh_dec"));
1010061da546Spatrick }
1011061da546Spatrick 
1012061da546Spatrick #endif // __APPLE__
1013