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