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