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