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