xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp (revision 24bb5fcea3ed904bc467217bdaadb5dfc618d5bf)
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PlatformDarwinKernel.h"
10 
11 #if defined(__APPLE__) // This Plugin uses the Mac-specific
12                        // source/Host/macosx/cfcpp utilities
13 
14 #include "lldb/Breakpoint/BreakpointLocation.h"
15 #include "lldb/Core/Module.h"
16 #include "lldb/Core/ModuleList.h"
17 #include "lldb/Core/ModuleSpec.h"
18 #include "lldb/Core/PluginManager.h"
19 #include "lldb/Host/Host.h"
20 #include "lldb/Host/HostInfo.h"
21 #include "lldb/Interpreter/OptionValueFileSpecList.h"
22 #include "lldb/Interpreter/OptionValueProperties.h"
23 #include "lldb/Interpreter/Property.h"
24 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Target/Platform.h"
26 #include "lldb/Target/Process.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Utility/ArchSpec.h"
29 #include "lldb/Utility/FileSpec.h"
30 #include "lldb/Utility/Log.h"
31 #include "lldb/Utility/Status.h"
32 #include "lldb/Utility/StreamString.h"
33 
34 #include "llvm/Support/FileSystem.h"
35 
36 #include <CoreFoundation/CoreFoundation.h>
37 
38 #include <memory>
39 
40 #include "Host/macosx/cfcpp/CFCBundle.h"
41 
42 using namespace lldb;
43 using namespace lldb_private;
44 
45 // Static Variables
46 static uint32_t g_initialize_count = 0;
47 
48 // Static Functions
49 void PlatformDarwinKernel::Initialize() {
50   PlatformDarwin::Initialize();
51 
52   if (g_initialize_count++ == 0) {
53     PluginManager::RegisterPlugin(PlatformDarwinKernel::GetPluginNameStatic(),
54                                   PlatformDarwinKernel::GetDescriptionStatic(),
55                                   PlatformDarwinKernel::CreateInstance,
56                                   PlatformDarwinKernel::DebuggerInitialize);
57   }
58 }
59 
60 void PlatformDarwinKernel::Terminate() {
61   if (g_initialize_count > 0) {
62     if (--g_initialize_count == 0) {
63       PluginManager::UnregisterPlugin(PlatformDarwinKernel::CreateInstance);
64     }
65   }
66 
67   PlatformDarwin::Terminate();
68 }
69 
70 PlatformSP PlatformDarwinKernel::CreateInstance(bool force,
71                                                 const ArchSpec *arch) {
72   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
73   if (log) {
74     const char *arch_name;
75     if (arch && arch->GetArchitectureName())
76       arch_name = arch->GetArchitectureName();
77     else
78       arch_name = "<null>";
79 
80     const char *triple_cstr =
81         arch ? arch->GetTriple().getTriple().c_str() : "<null>";
82 
83     LLDB_LOGF(log, "PlatformDarwinKernel::%s(force=%s, arch={%s,%s})",
84               __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
85   }
86 
87   // This is a special plugin that we don't want to activate just based on an
88   // ArchSpec for normal userland debugging.  It is only useful in kernel debug
89   // sessions and the DynamicLoaderDarwinPlugin (or a user doing 'platform
90   // select') will force the creation of this Platform plugin.
91   if (!force) {
92     LLDB_LOGF(log,
93               "PlatformDarwinKernel::%s() aborting creation of platform "
94               "because force == false",
95               __FUNCTION__);
96     return PlatformSP();
97   }
98 
99   bool create = force;
100   LazyBool is_ios_debug_session = eLazyBoolCalculate;
101 
102   if (!create && arch && arch->IsValid()) {
103     const llvm::Triple &triple = arch->GetTriple();
104     switch (triple.getVendor()) {
105     case llvm::Triple::Apple:
106       create = true;
107       break;
108 
109     // Only accept "unknown" for vendor if the host is Apple and it "unknown"
110     // wasn't specified (it was just returned because it was NOT specified)
111     case llvm::Triple::UnknownVendor:
112       create = !arch->TripleVendorWasSpecified();
113       break;
114     default:
115       break;
116     }
117 
118     if (create) {
119       switch (triple.getOS()) {
120       case llvm::Triple::Darwin:
121       case llvm::Triple::MacOSX:
122       case llvm::Triple::IOS:
123       case llvm::Triple::WatchOS:
124       case llvm::Triple::TvOS:
125       // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS:
126         break;
127       // Only accept "vendor" for vendor if the host is Apple and it "unknown"
128       // wasn't specified (it was just returned because it was NOT specified)
129       case llvm::Triple::UnknownOS:
130         create = !arch->TripleOSWasSpecified();
131         break;
132       default:
133         create = false;
134         break;
135       }
136     }
137   }
138   if (arch && arch->IsValid()) {
139     switch (arch->GetMachine()) {
140     case llvm::Triple::x86:
141     case llvm::Triple::x86_64:
142     case llvm::Triple::ppc:
143     case llvm::Triple::ppc64:
144       is_ios_debug_session = eLazyBoolNo;
145       break;
146     case llvm::Triple::arm:
147     case llvm::Triple::aarch64:
148     case llvm::Triple::thumb:
149       is_ios_debug_session = eLazyBoolYes;
150       break;
151     default:
152       is_ios_debug_session = eLazyBoolCalculate;
153       break;
154     }
155   }
156   if (create) {
157     LLDB_LOGF(log, "PlatformDarwinKernel::%s() creating platform",
158               __FUNCTION__);
159 
160     return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session));
161   }
162 
163   LLDB_LOGF(log, "PlatformDarwinKernel::%s() aborting creation of platform",
164             __FUNCTION__);
165 
166   return PlatformSP();
167 }
168 
169 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() {
170   static ConstString g_name("darwin-kernel");
171   return g_name;
172 }
173 
174 const char *PlatformDarwinKernel::GetDescriptionStatic() {
175   return "Darwin Kernel platform plug-in.";
176 }
177 
178 /// Code to handle the PlatformDarwinKernel settings
179 
180 #define LLDB_PROPERTIES_platformdarwinkernel
181 #include "PlatformMacOSXProperties.inc"
182 
183 enum {
184 #define LLDB_PROPERTIES_platformdarwinkernel
185 #include "PlatformMacOSXPropertiesEnum.inc"
186 };
187 
188 class PlatformDarwinKernelProperties : public Properties {
189 public:
190   static ConstString &GetSettingName() {
191     static ConstString g_setting_name("darwin-kernel");
192     return g_setting_name;
193   }
194 
195   PlatformDarwinKernelProperties() : Properties() {
196     m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
197     m_collection_sp->Initialize(g_platformdarwinkernel_properties);
198   }
199 
200   virtual ~PlatformDarwinKernelProperties() {}
201 
202   bool GetSearchForKexts() const {
203     const uint32_t idx = ePropertySearchForKexts;
204     return m_collection_sp->GetPropertyAtIndexAsBoolean(
205         NULL, idx,
206         g_platformdarwinkernel_properties[idx].default_uint_value != 0);
207   }
208 
209   FileSpecList GetKextDirectories() const {
210     const uint32_t idx = ePropertyKextDirectories;
211     const OptionValueFileSpecList *option_value =
212         m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(
213             NULL, false, idx);
214     assert(option_value);
215     return option_value->GetCurrentValue();
216   }
217 };
218 
219 typedef std::shared_ptr<PlatformDarwinKernelProperties>
220     PlatformDarwinKernelPropertiesSP;
221 
222 static const PlatformDarwinKernelPropertiesSP &GetGlobalProperties() {
223   static PlatformDarwinKernelPropertiesSP g_settings_sp;
224   if (!g_settings_sp)
225     g_settings_sp = std::make_shared<PlatformDarwinKernelProperties>();
226   return g_settings_sp;
227 }
228 
229 void PlatformDarwinKernel::DebuggerInitialize(
230     lldb_private::Debugger &debugger) {
231   if (!PluginManager::GetSettingForPlatformPlugin(
232           debugger, PlatformDarwinKernelProperties::GetSettingName())) {
233     const bool is_global_setting = true;
234     PluginManager::CreateSettingForPlatformPlugin(
235         debugger, GetGlobalProperties()->GetValueProperties(),
236         ConstString("Properties for the PlatformDarwinKernel plug-in."),
237         is_global_setting);
238   }
239 }
240 
241 /// Default Constructor
242 PlatformDarwinKernel::PlatformDarwinKernel(
243     lldb_private::LazyBool is_ios_debug_session)
244     : PlatformDarwin(false), // This is a remote platform
245       m_name_to_kext_path_map_with_dsyms(),
246       m_name_to_kext_path_map_without_dsyms(), m_search_directories(),
247       m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(),
248       m_kernel_binaries_without_dsyms(),
249       m_ios_debug_session(is_ios_debug_session)
250 
251 {
252   if (GetGlobalProperties()->GetSearchForKexts()) {
253     CollectKextAndKernelDirectories();
254     SearchForKextsAndKernelsRecursively();
255   }
256 }
257 
258 /// Destructor.
259 ///
260 /// The destructor is virtual since this class is designed to be
261 /// inherited from by the plug-in instance.
262 PlatformDarwinKernel::~PlatformDarwinKernel() {}
263 
264 void PlatformDarwinKernel::GetStatus(Stream &strm) {
265   Platform::GetStatus(strm);
266   strm.Printf(" Debug session type: ");
267   if (m_ios_debug_session == eLazyBoolYes)
268     strm.Printf("iOS kernel debugging\n");
269   else if (m_ios_debug_session == eLazyBoolNo)
270     strm.Printf("Mac OS X kernel debugging\n");
271   else
272     strm.Printf("unknown kernel debugging\n");
273 
274   strm.Printf("Directories searched recursively:\n");
275   const uint32_t num_kext_dirs = m_search_directories.size();
276   for (uint32_t i = 0; i < num_kext_dirs; ++i) {
277     strm.Printf("[%d] %s\n", i, m_search_directories[i].GetPath().c_str());
278   }
279 
280   strm.Printf("Directories not searched recursively:\n");
281   const uint32_t num_kext_dirs_no_recursion =
282       m_search_directories_no_recursing.size();
283   for (uint32_t i = 0; i < num_kext_dirs_no_recursion; i++) {
284     strm.Printf("[%d] %s\n", i,
285                 m_search_directories_no_recursing[i].GetPath().c_str());
286   }
287 
288   strm.Printf(" Number of kexts with dSYMs indexed: %d\n",
289               (int)m_name_to_kext_path_map_with_dsyms.size());
290   strm.Printf(" Number of kexts without dSYMs indexed: %d\n",
291               (int)m_name_to_kext_path_map_without_dsyms.size());
292   strm.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n",
293               (int)m_kernel_binaries_with_dsyms.size());
294   strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n",
295               (int)m_kernel_binaries_without_dsyms.size());
296 
297   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
298   if (log) {
299     LLDB_LOGF(log, "\nkexts with dSYMs");
300     for (auto pos : m_name_to_kext_path_map_with_dsyms) {
301       LLDB_LOGF(log, "%s", pos.second.GetPath().c_str());
302     }
303     LLDB_LOGF(log, "\nkexts without dSYMs");
304 
305     for (auto pos : m_name_to_kext_path_map_without_dsyms) {
306       LLDB_LOGF(log, "%s", pos.second.GetPath().c_str());
307     }
308     LLDB_LOGF(log, "\nkernels with dSYMS");
309     for (auto fs : m_kernel_binaries_with_dsyms) {
310       LLDB_LOGF(log, "%s", fs.GetPath().c_str());
311     }
312     LLDB_LOGF(log, "\nkernels without dSYMS");
313     for (auto fs : m_kernel_binaries_without_dsyms) {
314       LLDB_LOGF(log, "%s", fs.GetPath().c_str());
315     }
316     LLDB_LOGF(log, "\n");
317   }
318 }
319 
320 // Populate the m_search_directories vector with directories we should search
321 // for kernel & kext binaries.
322 
323 void PlatformDarwinKernel::CollectKextAndKernelDirectories() {
324   // Differentiate between "ios debug session" and "mac debug session" so we
325   // don't index kext bundles that won't be used in this debug session.  If
326   // this is an ios kext debug session, looking in /System/Library/Extensions
327   // is a waste of stat()s, for example.
328 
329   // DeveloperDirectory is something like
330   // "/Applications/Xcode.app/Contents/Developer"
331   std::string developer_dir = HostInfo::GetXcodeDeveloperDirectory().GetPath();
332   if (developer_dir.empty())
333     developer_dir = "/Applications/Xcode.app/Contents/Developer";
334 
335   if (m_ios_debug_session != eLazyBoolNo) {
336     AddSDKSubdirsToSearchPaths(developer_dir +
337                                "/Platforms/iPhoneOS.platform/Developer/SDKs");
338     AddSDKSubdirsToSearchPaths(developer_dir +
339                                "/Platforms/AppleTVOS.platform/Developer/SDKs");
340     AddSDKSubdirsToSearchPaths(developer_dir +
341                                "/Platforms/WatchOS.platform/Developer/SDKs");
342     AddSDKSubdirsToSearchPaths(developer_dir +
343                                "/Platforms/BridgeOS.platform/Developer/SDKs");
344   }
345   if (m_ios_debug_session != eLazyBoolYes) {
346     AddSDKSubdirsToSearchPaths(developer_dir +
347                                "/Platforms/MacOSX.platform/Developer/SDKs");
348   }
349 
350   AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit");
351   AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs");
352   // The KDKs distributed from Apple installed on external developer systems
353   // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk
354   AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs");
355 
356   if (m_ios_debug_session != eLazyBoolNo) {
357   }
358   if (m_ios_debug_session != eLazyBoolYes) {
359     AddRootSubdirsToSearchPaths(this, "/");
360   }
361 
362   GetUserSpecifiedDirectoriesToSearch();
363 
364   // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols
365   FileSpec possible_dir(developer_dir + "/../Symbols");
366   FileSystem::Instance().Resolve(possible_dir);
367   if (FileSystem::Instance().IsDirectory(possible_dir))
368     m_search_directories.push_back(possible_dir);
369 
370   // Add simple directory of the current working directory
371   FileSpec cwd(".");
372   FileSystem::Instance().Resolve(cwd);
373   m_search_directories_no_recursing.push_back(cwd);
374 }
375 
376 void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() {
377   FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories());
378   std::vector<FileSpec> possible_sdk_dirs;
379 
380   const uint32_t user_dirs_count = user_dirs.GetSize();
381   for (uint32_t i = 0; i < user_dirs_count; i++) {
382     FileSpec dir = user_dirs.GetFileSpecAtIndex(i);
383     FileSystem::Instance().Resolve(dir);
384     if (FileSystem::Instance().IsDirectory(dir)) {
385       m_search_directories.push_back(dir);
386     }
387   }
388 }
389 
390 void PlatformDarwinKernel::AddRootSubdirsToSearchPaths(
391     PlatformDarwinKernel *thisp, const std::string &dir) {
392   const char *subdirs[] = {
393       "/System/Library/Extensions", "/Library/Extensions",
394       "/System/Library/Kernels",
395       "/System/Library/Extensions/KDK", // this one probably only exist in
396                                         // /AppleInternal/Developer/KDKs/*.kdk/...
397       nullptr};
398   for (int i = 0; subdirs[i] != nullptr; i++) {
399     FileSpec testdir(dir + subdirs[i]);
400     FileSystem::Instance().Resolve(testdir);
401     if (FileSystem::Instance().IsDirectory(testdir))
402       thisp->m_search_directories.push_back(testdir);
403   }
404 
405   // Look for kernel binaries in the top level directory, without any recursion
406   thisp->m_search_directories_no_recursing.push_back(FileSpec(dir + "/"));
407 }
408 
409 // Given a directory path dir, look for any subdirs named *.kdk and *.sdk
410 void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) {
411   // Look for *.kdk and *.sdk in dir
412   const bool find_directories = true;
413   const bool find_files = false;
414   const bool find_other = false;
415   FileSystem::Instance().EnumerateDirectory(
416       dir.c_str(), find_directories, find_files, find_other,
417       FindKDKandSDKDirectoriesInDirectory, this);
418 }
419 
420 // Helper function to find *.sdk and *.kdk directories in a given directory.
421 FileSystem::EnumerateDirectoryResult
422 PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory(
423     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
424   static ConstString g_sdk_suffix = ConstString(".sdk");
425   static ConstString g_kdk_suffix = ConstString(".kdk");
426 
427   PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
428   FileSpec file_spec(path);
429   if (ft == llvm::sys::fs::file_type::directory_file &&
430       (file_spec.GetFileNameExtension() == g_sdk_suffix ||
431        file_spec.GetFileNameExtension() == g_kdk_suffix)) {
432     AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath());
433   }
434   return FileSystem::eEnumerateDirectoryResultNext;
435 }
436 
437 // Recursively search trough m_search_directories looking for kext and kernel
438 // binaries, adding files found to the appropriate lists.
439 void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() {
440   const uint32_t num_dirs = m_search_directories.size();
441   for (uint32_t i = 0; i < num_dirs; i++) {
442     const FileSpec &dir = m_search_directories[i];
443     const bool find_directories = true;
444     const bool find_files = true;
445     const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
446     FileSystem::Instance().EnumerateDirectory(
447         dir.GetPath().c_str(), find_directories, find_files, find_other,
448         GetKernelsAndKextsInDirectoryWithRecursion, this);
449   }
450   const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size();
451   for (uint32_t i = 0; i < num_dirs_no_recurse; i++) {
452     const FileSpec &dir = m_search_directories_no_recursing[i];
453     const bool find_directories = true;
454     const bool find_files = true;
455     const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
456     FileSystem::Instance().EnumerateDirectory(
457         dir.GetPath().c_str(), find_directories, find_files, find_other,
458         GetKernelsAndKextsInDirectoryNoRecursion, this);
459   }
460 }
461 
462 // We're only doing a filename match here.  We won't try opening the file to
463 // see if it's really a kernel or not until we need to find a kernel of a given
464 // UUID.  There's no cheap way to find the UUID of a file (or if it's a Mach-O
465 // binary at all) without creating a whole Module for the file and throwing it
466 // away if it's not wanted.
467 //
468 // Recurse into any subdirectories found.
469 
470 FileSystem::EnumerateDirectoryResult
471 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion(
472     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
473   return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, true);
474 }
475 
476 FileSystem::EnumerateDirectoryResult
477 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion(
478     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
479   return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, false);
480 }
481 
482 FileSystem::EnumerateDirectoryResult
483 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper(
484     void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path,
485     bool recurse) {
486   static ConstString g_kext_suffix = ConstString(".kext");
487   static ConstString g_dsym_suffix = ConstString(".dSYM");
488   static ConstString g_bundle_suffix = ConstString("Bundle");
489 
490   FileSpec file_spec(path);
491   ConstString file_spec_extension = file_spec.GetFileNameExtension();
492 
493   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
494   Log *log_verbose(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM | LLDB_LOG_OPTION_VERBOSE));
495 
496   LLDB_LOGF(log_verbose, "PlatformDarwinKernel examining '%s'",
497             file_spec.GetPath().c_str());
498 
499   PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
500   if (ft == llvm::sys::fs::file_type::regular_file ||
501       ft == llvm::sys::fs::file_type::symlink_file) {
502     ConstString filename = file_spec.GetFilename();
503     if ((strncmp(filename.GetCString(), "kernel", 6) == 0 ||
504          strncmp(filename.GetCString(), "mach", 4) == 0) &&
505         file_spec_extension != g_dsym_suffix) {
506       if (KernelHasdSYMSibling(file_spec))
507       {
508         LLDB_LOGF(log,
509                   "PlatformDarwinKernel registering kernel binary '%s' with "
510                   "dSYM sibling",
511                   file_spec.GetPath().c_str());
512         thisp->m_kernel_binaries_with_dsyms.push_back(file_spec);
513       }
514       else
515       {
516         LLDB_LOGF(
517             log, "PlatformDarwinKernel registering kernel binary '%s', no dSYM",
518             file_spec.GetPath().c_str());
519         thisp->m_kernel_binaries_without_dsyms.push_back(file_spec);
520       }
521       return FileSystem::eEnumerateDirectoryResultNext;
522     }
523   } else if (ft == llvm::sys::fs::file_type::directory_file &&
524              file_spec_extension == g_kext_suffix) {
525     AddKextToMap(thisp, file_spec);
526     // Look to see if there is a PlugIns subdir with more kexts
527     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 = false;
542       FileSystem::Instance().EnumerateDirectory(
543           search_here_too.c_str(), find_directories, find_files, find_other,
544           recurse ? GetKernelsAndKextsInDirectoryWithRecursion
545                   : GetKernelsAndKextsInDirectoryNoRecursion,
546           baton);
547     }
548     return FileSystem::eEnumerateDirectoryResultNext;
549   }
550   // Don't recurse into dSYM/kext/bundle directories
551   if (recurse && file_spec_extension != g_dsym_suffix &&
552       file_spec_extension != g_kext_suffix &&
553       file_spec_extension != g_bundle_suffix) {
554     LLDB_LOGF(log_verbose,
555               "PlatformDarwinKernel descending into directory '%s'",
556               file_spec.GetPath().c_str());
557     return FileSystem::eEnumerateDirectoryResultEnter;
558   } else {
559     return FileSystem::eEnumerateDirectoryResultNext;
560   }
561 }
562 
563 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp,
564                                         const FileSpec &file_spec) {
565   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
566   CFCBundle bundle(file_spec.GetPath().c_str());
567   CFStringRef bundle_id(bundle.GetIdentifier());
568   if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) {
569     char bundle_id_buf[PATH_MAX];
570     if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf),
571                            kCFStringEncodingUTF8)) {
572       ConstString bundle_conststr(bundle_id_buf);
573       if (KextHasdSYMSibling(file_spec))
574       {
575         LLDB_LOGF(log,
576                   "PlatformDarwinKernel registering kext binary '%s' with dSYM "
577                   "sibling",
578                   file_spec.GetPath().c_str());
579         thisp->m_name_to_kext_path_map_with_dsyms.insert(
580             std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
581       }
582       else
583       {
584         LLDB_LOGF(log,
585                   "PlatformDarwinKernel registering kext binary '%s', no dSYM",
586                   file_spec.GetPath().c_str());
587         thisp->m_name_to_kext_path_map_without_dsyms.insert(
588             std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
589       }
590     }
591   }
592 }
593 
594 // Given a FileSpec of /dir/dir/foo.kext
595 // Return true if any of these exist:
596 //    /dir/dir/foo.kext.dSYM
597 //    /dir/dir/foo.kext/Contents/MacOS/foo.dSYM
598 //    /dir/dir/foo.kext/foo.dSYM
599 bool PlatformDarwinKernel::KextHasdSYMSibling(
600     const FileSpec &kext_bundle_filepath) {
601   FileSpec dsym_fspec = kext_bundle_filepath;
602   std::string filename = dsym_fspec.GetFilename().AsCString();
603   filename += ".dSYM";
604   dsym_fspec.GetFilename() = ConstString(filename);
605   if (FileSystem::Instance().IsDirectory(dsym_fspec)) {
606     return true;
607   }
608   // Should probably get the CFBundleExecutable here or call
609   // CFBundleCopyExecutableURL
610 
611   // Look for a deep bundle foramt
612   ConstString executable_name =
613       kext_bundle_filepath.GetFileNameStrippingExtension();
614   std::string deep_bundle_str =
615       kext_bundle_filepath.GetPath() + "/Contents/MacOS/";
616   deep_bundle_str += executable_name.AsCString();
617   deep_bundle_str += ".dSYM";
618   dsym_fspec.SetFile(deep_bundle_str, FileSpec::Style::native);
619   FileSystem::Instance().Resolve(dsym_fspec);
620   if (FileSystem::Instance().IsDirectory(dsym_fspec)) {
621     return true;
622   }
623 
624   // look for a shallow bundle format
625   //
626   std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/";
627   shallow_bundle_str += executable_name.AsCString();
628   shallow_bundle_str += ".dSYM";
629   dsym_fspec.SetFile(shallow_bundle_str, FileSpec::Style::native);
630   FileSystem::Instance().Resolve(dsym_fspec);
631   return FileSystem::Instance().IsDirectory(dsym_fspec);
632 }
633 
634 // Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM
635 // exists next to it:
636 //    /dir/dir/mach.development.t7004.dSYM
637 bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) {
638   FileSpec kernel_dsym = kernel_binary;
639   std::string filename = kernel_binary.GetFilename().AsCString();
640   filename += ".dSYM";
641   kernel_dsym.GetFilename() = ConstString(filename);
642   return FileSystem::Instance().IsDirectory(kernel_dsym);
643 }
644 
645 Status PlatformDarwinKernel::GetSharedModule(
646     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
647     const FileSpecList *module_search_paths_ptr,
648     llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
649   Status error;
650   module_sp.reset();
651   const FileSpec &platform_file = module_spec.GetFileSpec();
652 
653   // Treat the file's path as a kext bundle ID (e.g.
654   // "com.apple.driver.AppleIRController") and search our kext index.
655   std::string kext_bundle_id = platform_file.GetPath();
656   if (!kext_bundle_id.empty()) {
657     ConstString kext_bundle_cs(kext_bundle_id.c_str());
658 
659     // First look through the kext bundles that had a dsym next to them
660     if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) {
661       for (BundleIDToKextIterator it =
662                m_name_to_kext_path_map_with_dsyms.begin();
663            it != m_name_to_kext_path_map_with_dsyms.end(); ++it) {
664         if (it->first == kext_bundle_cs) {
665           error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(),
666                                              module_spec.GetArchitecture(),
667                                              module_sp);
668           if (module_sp.get()) {
669             return error;
670           }
671         }
672       }
673     }
674 
675     // Give the generic methods, including possibly calling into  DebugSymbols
676     // framework on macOS systems, a chance.
677     error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
678                                            module_search_paths_ptr,
679                                            old_modules, did_create_ptr);
680     if (error.Success() && module_sp.get()) {
681       return error;
682     }
683 
684     // Lastly, look through the kext binarys without dSYMs
685     if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) {
686       for (BundleIDToKextIterator it =
687                m_name_to_kext_path_map_without_dsyms.begin();
688            it != m_name_to_kext_path_map_without_dsyms.end(); ++it) {
689         if (it->first == kext_bundle_cs) {
690           error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(),
691                                              module_spec.GetArchitecture(),
692                                              module_sp);
693           if (module_sp.get()) {
694             return error;
695           }
696         }
697       }
698     }
699   }
700 
701   if (kext_bundle_id == "mach_kernel" && module_spec.GetUUID().IsValid()) {
702     // First try all kernel binaries that have a dSYM next to them
703     for (auto possible_kernel : m_kernel_binaries_with_dsyms) {
704       if (FileSystem::Instance().Exists(possible_kernel)) {
705         ModuleSpec kern_spec(possible_kernel);
706         kern_spec.GetUUID() = module_spec.GetUUID();
707         ModuleSP module_sp(new Module(kern_spec));
708         if (module_sp && module_sp->GetObjectFile() &&
709             module_sp->MatchesModuleSpec(kern_spec)) {
710           // module_sp is an actual kernel binary we want to add.
711           if (process) {
712             process->GetTarget().GetImages().AppendIfNeeded(module_sp);
713             error.Clear();
714             return error;
715           } else {
716             error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL,
717                                                 NULL, NULL);
718             if (module_sp && module_sp->GetObjectFile() &&
719                 module_sp->GetObjectFile()->GetType() !=
720                     ObjectFile::Type::eTypeCoreFile) {
721               return error;
722             }
723             module_sp.reset();
724           }
725         }
726       }
727     }
728 
729     // Give the generic methods, including possibly calling into  DebugSymbols
730     // framework on macOS systems, a chance.
731     error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
732                                             module_search_paths_ptr,
733                                             old_modules, did_create_ptr);
734     if (error.Success() && module_sp.get()) {
735       return error;
736     }
737 
738     // Next try all kernel binaries that don't have a dSYM
739     for (auto possible_kernel : m_kernel_binaries_without_dsyms) {
740       if (FileSystem::Instance().Exists(possible_kernel)) {
741         ModuleSpec kern_spec(possible_kernel);
742         kern_spec.GetUUID() = module_spec.GetUUID();
743         ModuleSP module_sp(new Module(kern_spec));
744         if (module_sp && module_sp->GetObjectFile() &&
745             module_sp->MatchesModuleSpec(kern_spec)) {
746           // module_sp is an actual kernel binary we want to add.
747           if (process) {
748             process->GetTarget().GetImages().AppendIfNeeded(module_sp);
749             error.Clear();
750             return error;
751           } else {
752             error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL,
753                                                 NULL, NULL);
754             if (module_sp && module_sp->GetObjectFile() &&
755                 module_sp->GetObjectFile()->GetType() !=
756                     ObjectFile::Type::eTypeCoreFile) {
757               return error;
758             }
759             module_sp.reset();
760           }
761         }
762       }
763     }
764   }
765 
766   return error;
767 }
768 
769 std::vector<lldb_private::FileSpec>
770 PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string &dir) {
771   std::vector<FileSpec> executables;
772   std::error_code EC;
773   for (llvm::sys::fs::recursive_directory_iterator it(dir.c_str(), EC),
774        end;
775        it != end && !EC; it.increment(EC)) {
776     auto status = it->status();
777     if (!status)
778       break;
779     if (llvm::sys::fs::is_regular_file(*status) &&
780         llvm::sys::fs::can_execute(it->path()))
781       executables.emplace_back(it->path());
782   }
783   return executables;
784 }
785 
786 Status PlatformDarwinKernel::ExamineKextForMatchingUUID(
787     const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid,
788     const ArchSpec &arch, ModuleSP &exe_module_sp) {
789   for (const auto &exe_file :
790        SearchForExecutablesRecursively(kext_bundle_path.GetPath())) {
791     if (FileSystem::Instance().Exists(exe_file)) {
792       ModuleSpec exe_spec(exe_file);
793       exe_spec.GetUUID() = uuid;
794       if (!uuid.IsValid()) {
795         exe_spec.GetArchitecture() = arch;
796       }
797 
798       // First try to create a ModuleSP with the file / arch and see if the UUID
799       // matches. If that fails (this exec file doesn't have the correct uuid),
800       // don't call GetSharedModule (which may call in to the DebugSymbols
801       // framework and therefore can be slow.)
802       ModuleSP module_sp(new Module(exe_spec));
803       if (module_sp && module_sp->GetObjectFile() &&
804           module_sp->MatchesModuleSpec(exe_spec)) {
805         Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp,
806                                                    NULL, NULL, NULL);
807         if (exe_module_sp && exe_module_sp->GetObjectFile()) {
808           return error;
809         }
810       }
811       exe_module_sp.reset();
812     }
813   }
814 
815   return {};
816 }
817 
818 bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx,
819                                                            ArchSpec &arch) {
820 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
821   return ARMGetSupportedArchitectureAtIndex(idx, arch);
822 #else
823   return x86GetSupportedArchitectureAtIndex(idx, arch);
824 #endif
825 }
826 
827 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() {
828   m_trap_handlers.push_back(ConstString("trap_from_kernel"));
829   m_trap_handlers.push_back(ConstString("hndl_machine_check"));
830   m_trap_handlers.push_back(ConstString("hndl_double_fault"));
831   m_trap_handlers.push_back(ConstString("hndl_allintrs"));
832   m_trap_handlers.push_back(ConstString("hndl_alltraps"));
833   m_trap_handlers.push_back(ConstString("interrupt"));
834   m_trap_handlers.push_back(ConstString("fleh_prefabt"));
835   m_trap_handlers.push_back(ConstString("ExceptionVectorsBase"));
836   m_trap_handlers.push_back(ConstString("ExceptionVectorsTable"));
837   m_trap_handlers.push_back(ConstString("fleh_undef"));
838   m_trap_handlers.push_back(ConstString("fleh_dataabt"));
839   m_trap_handlers.push_back(ConstString("fleh_irq"));
840   m_trap_handlers.push_back(ConstString("fleh_decirq"));
841   m_trap_handlers.push_back(ConstString("fleh_fiq_generic"));
842   m_trap_handlers.push_back(ConstString("fleh_dec"));
843 }
844 
845 #else // __APPLE__
846 
847 // Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies
848 // on PlatformDarwinKernel for the plug-in name, we compile just the plug-in
849 // name in here to avoid issues. We are tracking an internal bug to resolve
850 // this issue by either not compiling in DynamicLoaderDarwinKernel for non-
851 // apple builds, or to make PlatformDarwinKernel build on all systems.
852 // PlatformDarwinKernel is currently not compiled on other platforms due to the
853 // use of the Mac-specific source/Host/macosx/cfcpp utilities.
854 
855 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() {
856   static lldb_private::ConstString g_name("darwin-kernel");
857   return g_name;
858 }
859 
860 #endif // __APPLE__
861