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/Module.h"
22 #include "lldb/Core/ModuleList.h"
23 #include "lldb/Core/ModuleSpec.h"
24 #include "lldb/Core/PluginManager.h"
25 #include "lldb/Host/Host.h"
26 #include "lldb/Interpreter/OptionValueFileSpecList.h"
27 #include "lldb/Interpreter/OptionValueProperties.h"
28 #include "lldb/Interpreter/Property.h"
29 #include "lldb/Symbol/ObjectFile.h"
30 #include "lldb/Target/Platform.h"
31 #include "lldb/Target/Process.h"
32 #include "lldb/Target/Target.h"
33 #include "lldb/Utility/ArchSpec.h"
34 #include "lldb/Utility/FileSpec.h"
35 #include "lldb/Utility/Log.h"
36 #include "lldb/Utility/Status.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   Log *log_verbose(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM | LLDB_LOG_OPTION_VERBOSE));
512 
513   if (log_verbose)
514       log_verbose->Printf ("PlatformDarwinKernel examining '%s'", file_spec.GetPath().c_str());
515 
516   PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
517   if (ft == llvm::sys::fs::file_type::regular_file ||
518       ft == llvm::sys::fs::file_type::symlink_file) {
519     ConstString filename = file_spec.GetFilename();
520     if ((strncmp(filename.GetCString(), "kernel", 6) == 0 ||
521          strncmp(filename.GetCString(), "mach", 4) == 0) &&
522         file_spec_extension != g_dsym_suffix) {
523       if (KernelHasdSYMSibling(file_spec))
524       {
525         if (log)
526         {
527             log->Printf ("PlatformDarwinKernel registering kernel binary '%s' with dSYM sibling", file_spec.GetPath().c_str());
528         }
529         thisp->m_kernel_binaries_with_dsyms.push_back(file_spec);
530       }
531       else
532       {
533         if (log)
534         {
535             log->Printf ("PlatformDarwinKernel registering kernel binary '%s', no dSYM", file_spec.GetPath().c_str());
536         }
537         thisp->m_kernel_binaries_without_dsyms.push_back(file_spec);
538       }
539       return FileSpec::eEnumerateDirectoryResultNext;
540     }
541   } else if (ft == llvm::sys::fs::file_type::directory_file &&
542              file_spec_extension == g_kext_suffix) {
543     AddKextToMap(thisp, file_spec);
544     // Look to see if there is a PlugIns subdir with more kexts
545     FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns", false);
546     std::string search_here_too;
547     if (llvm::sys::fs::is_directory(contents_plugins.GetPath())) {
548       search_here_too = contents_plugins.GetPath();
549     } else {
550       FileSpec plugins(file_spec.GetPath() + "/PlugIns", false);
551       if (llvm::sys::fs::is_directory(plugins.GetPath())) {
552         search_here_too = plugins.GetPath();
553       }
554     }
555 
556     if (!search_here_too.empty()) {
557       const bool find_directories = true;
558       const bool find_files = false;
559       const bool find_other = false;
560       FileSpec::EnumerateDirectory(
561           search_here_too.c_str(), find_directories, find_files, find_other,
562           recurse ? GetKernelsAndKextsInDirectoryWithRecursion
563                   : GetKernelsAndKextsInDirectoryNoRecursion,
564           baton);
565     }
566     return FileSpec::eEnumerateDirectoryResultNext;
567   }
568   // Don't recurse into dSYM/kext/bundle directories
569   if (recurse && file_spec_extension != g_dsym_suffix &&
570       file_spec_extension != g_kext_suffix &&
571       file_spec_extension != g_bundle_suffix) {
572     if (log_verbose)
573         log_verbose->Printf ("PlatformDarwinKernel descending into directory '%s'", file_spec.GetPath().c_str());
574     return FileSpec::eEnumerateDirectoryResultEnter;
575   } else {
576     return FileSpec::eEnumerateDirectoryResultNext;
577   }
578 }
579 
580 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp,
581                                         const FileSpec &file_spec) {
582   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
583   CFCBundle bundle(file_spec.GetPath().c_str());
584   CFStringRef bundle_id(bundle.GetIdentifier());
585   if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) {
586     char bundle_id_buf[PATH_MAX];
587     if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf),
588                            kCFStringEncodingUTF8)) {
589       ConstString bundle_conststr(bundle_id_buf);
590       if (KextHasdSYMSibling(file_spec))
591       {
592         if (log)
593         {
594             log->Printf ("PlatformDarwinKernel registering kext binary '%s' with dSYM sibling", file_spec.GetPath().c_str());
595         }
596         thisp->m_name_to_kext_path_map_with_dsyms.insert(
597             std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
598       }
599       else
600       {
601         if (log)
602         {
603             log->Printf ("PlatformDarwinKernel registering kext binary '%s', no dSYM", file_spec.GetPath().c_str());
604         }
605         thisp->m_name_to_kext_path_map_without_dsyms.insert(
606             std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
607       }
608     }
609   }
610 }
611 
612 // Given a FileSpec of /dir/dir/foo.kext
613 // Return true if any of these exist:
614 //    /dir/dir/foo.kext.dSYM
615 //    /dir/dir/foo.kext/Contents/MacOS/foo.dSYM
616 //    /dir/dir/foo.kext/foo.dSYM
617 bool PlatformDarwinKernel::KextHasdSYMSibling(
618     const FileSpec &kext_bundle_filepath) {
619   FileSpec dsym_fspec = kext_bundle_filepath;
620   std::string filename = dsym_fspec.GetFilename().AsCString();
621   filename += ".dSYM";
622   dsym_fspec.GetFilename() = ConstString(filename);
623   if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) {
624     return true;
625   }
626   // Should probably get the CFBundleExecutable here or call
627   // CFBundleCopyExecutableURL
628 
629   // Look for a deep bundle foramt
630   ConstString executable_name =
631       kext_bundle_filepath.GetFileNameStrippingExtension();
632   std::string deep_bundle_str =
633       kext_bundle_filepath.GetPath() + "/Contents/MacOS/";
634   deep_bundle_str += executable_name.AsCString();
635   deep_bundle_str += ".dSYM";
636   dsym_fspec.SetFile(deep_bundle_str, true);
637   if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) {
638     return true;
639   }
640 
641   // look for a shallow bundle format
642   //
643   std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/";
644   shallow_bundle_str += executable_name.AsCString();
645   shallow_bundle_str += ".dSYM";
646   dsym_fspec.SetFile(shallow_bundle_str, true);
647   if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) {
648     return true;
649   }
650   return false;
651 }
652 
653 // Given a FileSpec of /dir/dir/mach.development.t7004
654 // Return true if a dSYM exists next to it:
655 //    /dir/dir/mach.development.t7004.dSYM
656 bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) {
657   FileSpec kernel_dsym = kernel_binary;
658   std::string filename = kernel_binary.GetFilename().AsCString();
659   filename += ".dSYM";
660   kernel_dsym.GetFilename() = ConstString(filename);
661   if (llvm::sys::fs::is_directory(kernel_dsym.GetPath())) {
662     return true;
663   }
664   return false;
665 }
666 
667 Status PlatformDarwinKernel::GetSharedModule(
668     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
669     const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr,
670     bool *did_create_ptr) {
671   Status error;
672   module_sp.reset();
673   const FileSpec &platform_file = module_spec.GetFileSpec();
674 
675   // Treat the file's path as a kext bundle ID (e.g.
676   // "com.apple.driver.AppleIRController") and search our kext index.
677   std::string kext_bundle_id = platform_file.GetPath();
678   if (!kext_bundle_id.empty()) {
679     ConstString kext_bundle_cs(kext_bundle_id.c_str());
680 
681     // First look through the kext bundles that had a dsym next to them
682     if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) {
683       for (BundleIDToKextIterator it =
684                m_name_to_kext_path_map_with_dsyms.begin();
685            it != m_name_to_kext_path_map_with_dsyms.end(); ++it) {
686         if (it->first == kext_bundle_cs) {
687           error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(),
688                                              module_spec.GetArchitecture(),
689                                              module_sp);
690           if (module_sp.get()) {
691             return error;
692           }
693         }
694       }
695     }
696 
697     // Give the generic methods, including possibly calling into
698     // DebugSymbols framework on macOS systems, a chance.
699     error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
700                                            module_search_paths_ptr,
701                                            old_module_sp_ptr, did_create_ptr);
702     if (error.Success() && module_sp.get()) {
703       return error;
704     }
705 
706     // Lastly, look through the kext binarys without dSYMs
707     if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) {
708       for (BundleIDToKextIterator it =
709                m_name_to_kext_path_map_without_dsyms.begin();
710            it != m_name_to_kext_path_map_without_dsyms.end(); ++it) {
711         if (it->first == kext_bundle_cs) {
712           error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(),
713                                              module_spec.GetArchitecture(),
714                                              module_sp);
715           if (module_sp.get()) {
716             return error;
717           }
718         }
719       }
720     }
721   }
722 
723   if (kext_bundle_id.compare("mach_kernel") == 0 &&
724       module_spec.GetUUID().IsValid()) {
725     // First try all kernel binaries that have a dSYM next to them
726     for (auto possible_kernel : m_kernel_binaries_with_dsyms) {
727       if (possible_kernel.Exists()) {
728         ModuleSpec kern_spec(possible_kernel);
729         kern_spec.GetUUID() = module_spec.GetUUID();
730         ModuleSP module_sp(new Module(kern_spec));
731         if (module_sp && module_sp->GetObjectFile() &&
732             module_sp->MatchesModuleSpec(kern_spec)) {
733           // module_sp is an actual kernel binary we want to add.
734           if (process) {
735             process->GetTarget().GetImages().AppendIfNeeded(module_sp);
736             error.Clear();
737             return error;
738           } else {
739             error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL,
740                                                 NULL, NULL);
741             if (module_sp && module_sp->GetObjectFile() &&
742                 module_sp->GetObjectFile()->GetType() !=
743                     ObjectFile::Type::eTypeCoreFile) {
744               return error;
745             }
746             module_sp.reset();
747           }
748         }
749       }
750     }
751 
752     // Give the generic methods, including possibly calling into
753     // DebugSymbols framework on macOS systems, a chance.
754     error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
755                                             module_search_paths_ptr,
756                                             old_module_sp_ptr, did_create_ptr);
757     if (error.Success() && module_sp.get()) {
758       return error;
759     }
760 
761     // Next try all kernel binaries that don't have a dSYM
762     for (auto possible_kernel : m_kernel_binaries_without_dsyms) {
763       if (possible_kernel.Exists()) {
764         ModuleSpec kern_spec(possible_kernel);
765         kern_spec.GetUUID() = module_spec.GetUUID();
766         ModuleSP module_sp(new Module(kern_spec));
767         if (module_sp && module_sp->GetObjectFile() &&
768             module_sp->MatchesModuleSpec(kern_spec)) {
769           // module_sp is an actual kernel binary we want to add.
770           if (process) {
771             process->GetTarget().GetImages().AppendIfNeeded(module_sp);
772             error.Clear();
773             return error;
774           } else {
775             error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL,
776                                                 NULL, NULL);
777             if (module_sp && module_sp->GetObjectFile() &&
778                 module_sp->GetObjectFile()->GetType() !=
779                     ObjectFile::Type::eTypeCoreFile) {
780               return error;
781             }
782             module_sp.reset();
783           }
784         }
785       }
786     }
787   }
788 
789   return error;
790 }
791 
792 Status PlatformDarwinKernel::ExamineKextForMatchingUUID(
793     const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid,
794     const ArchSpec &arch, ModuleSP &exe_module_sp) {
795   Status error;
796   FileSpec exe_file = kext_bundle_path;
797   Host::ResolveExecutableInBundle(exe_file);
798   if (exe_file.Exists()) {
799     ModuleSpec exe_spec(exe_file);
800     exe_spec.GetUUID() = uuid;
801     if (!uuid.IsValid()) {
802       exe_spec.GetArchitecture() = arch;
803     }
804 
805     // First try to create a ModuleSP with the file / arch and see if the UUID
806     // matches.
807     // If that fails (this exec file doesn't have the correct uuid), don't call
808     // GetSharedModule
809     // (which may call in to the DebugSymbols framework and therefore can be
810     // slow.)
811     ModuleSP module_sp(new Module(exe_spec));
812     if (module_sp && module_sp->GetObjectFile() &&
813         module_sp->MatchesModuleSpec(exe_spec)) {
814       error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL,
815                                           NULL);
816       if (exe_module_sp && exe_module_sp->GetObjectFile()) {
817         return error;
818       }
819     }
820     exe_module_sp.reset();
821   }
822   return error;
823 }
824 
825 bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx,
826                                                            ArchSpec &arch) {
827 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
828   return ARMGetSupportedArchitectureAtIndex(idx, arch);
829 #else
830   return x86GetSupportedArchitectureAtIndex(idx, arch);
831 #endif
832 }
833 
834 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() {
835   m_trap_handlers.push_back(ConstString("trap_from_kernel"));
836   m_trap_handlers.push_back(ConstString("hndl_machine_check"));
837   m_trap_handlers.push_back(ConstString("hndl_double_fault"));
838   m_trap_handlers.push_back(ConstString("hndl_allintrs"));
839   m_trap_handlers.push_back(ConstString("hndl_alltraps"));
840   m_trap_handlers.push_back(ConstString("interrupt"));
841   m_trap_handlers.push_back(ConstString("fleh_prefabt"));
842   m_trap_handlers.push_back(ConstString("ExceptionVectorsBase"));
843   m_trap_handlers.push_back(ConstString("ExceptionVectorsTable"));
844   m_trap_handlers.push_back(ConstString("fleh_undef"));
845   m_trap_handlers.push_back(ConstString("fleh_dataabt"));
846   m_trap_handlers.push_back(ConstString("fleh_irq"));
847   m_trap_handlers.push_back(ConstString("fleh_decirq"));
848   m_trap_handlers.push_back(ConstString("fleh_fiq_generic"));
849   m_trap_handlers.push_back(ConstString("fleh_dec"));
850 }
851 
852 #else // __APPLE__
853 
854 // Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies on
855 // PlatformDarwinKernel for the plug-in name, we compile just the plug-in name
856 // in
857 // here to avoid issues. We are tracking an internal bug to resolve this issue
858 // by
859 // either not compiling in DynamicLoaderDarwinKernel for non-apple builds, or to
860 // make
861 // PlatformDarwinKernel build on all systems. PlatformDarwinKernel is currently
862 // not
863 // compiled on other platforms due to the use of the Mac-specific
864 // source/Host/macosx/cfcpp utilities.
865 
866 lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() {
867   static lldb_private::ConstString g_name("darwin-kernel");
868   return g_name;
869 }
870 
871 #endif // __APPLE__
872