1 //===-- PlatformDarwinKernel.cpp ------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "PlatformDarwinKernel.h"
11 #if defined(__APPLE__) // This Plugin uses the Mac-specific
12 // source/Host/macosx/cfcpp utilities
14 #include "lldb/Breakpoint/BreakpointLocation.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Core/Module.h"
17 #include "lldb/Core/ModuleList.h"
18 #include "lldb/Core/ModuleSpec.h"
19 #include "lldb/Core/PluginManager.h"
20 #include "lldb/Host/Host.h"
21 #include "lldb/Host/HostInfo.h"
22 #include "lldb/Interpreter/OptionValueFileSpecList.h"
23 #include "lldb/Interpreter/OptionValueProperties.h"
24 #include "lldb/Interpreter/Property.h"
25 #include "lldb/Symbol/ObjectFile.h"
26 #include "lldb/Target/Platform.h"
27 #include "lldb/Target/Process.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Utility/ArchSpec.h"
30 #include "lldb/Utility/DataBufferHeap.h"
31 #include "lldb/Utility/FileSpec.h"
32 #include "lldb/Utility/LLDBLog.h"
33 #include "lldb/Utility/Log.h"
34 #include "lldb/Utility/Status.h"
35 #include "lldb/Utility/StreamString.h"
37 #include "llvm/Support/FileSystem.h"
39 #include <CoreFoundation/CoreFoundation.h>
43 #include "Host/macosx/cfcpp/CFCBundle.h"
44 #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
45 #include "Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.h"
48 using namespace lldb_private
;
51 static uint32_t g_initialize_count
= 0;
54 void PlatformDarwinKernel::Initialize() {
55 PlatformDarwin::Initialize();
57 if (g_initialize_count
++ == 0) {
58 PluginManager::RegisterPlugin(PlatformDarwinKernel::GetPluginNameStatic(),
59 PlatformDarwinKernel::GetDescriptionStatic(),
60 PlatformDarwinKernel::CreateInstance
,
61 PlatformDarwinKernel::DebuggerInitialize
);
65 void PlatformDarwinKernel::Terminate() {
66 if (g_initialize_count
> 0) {
67 if (--g_initialize_count
== 0) {
68 PluginManager::UnregisterPlugin(PlatformDarwinKernel::CreateInstance
);
72 PlatformDarwin::Terminate();
75 PlatformSP
PlatformDarwinKernel::CreateInstance(bool force
,
76 const ArchSpec
*arch
) {
77 Log
*log
= GetLog(LLDBLog::Platform
);
79 const char *arch_name
;
80 if (arch
&& arch
->GetArchitectureName())
81 arch_name
= arch
->GetArchitectureName();
85 const char *triple_cstr
=
86 arch
? arch
->GetTriple().getTriple().c_str() : "<null>";
88 LLDB_LOGF(log
, "PlatformDarwinKernel::%s(force=%s, arch={%s,%s})",
89 __FUNCTION__
, force
? "true" : "false", arch_name
, triple_cstr
);
92 // This is a special plugin that we don't want to activate just based on an
93 // ArchSpec for normal userland debugging. It is only useful in kernel debug
94 // sessions and the DynamicLoaderDarwinPlugin (or a user doing 'platform
95 // select') will force the creation of this Platform plugin.
98 "PlatformDarwinKernel::%s() aborting creation of platform "
99 "because force == false",
105 LazyBool is_ios_debug_session
= eLazyBoolCalculate
;
107 if (!create
&& arch
&& arch
->IsValid()) {
108 const llvm::Triple
&triple
= arch
->GetTriple();
109 switch (triple
.getVendor()) {
110 case llvm::Triple::Apple
:
114 // Only accept "unknown" for vendor if the host is Apple and it "unknown"
115 // wasn't specified (it was just returned because it was NOT specified)
116 case llvm::Triple::UnknownVendor
:
117 create
= !arch
->TripleVendorWasSpecified();
124 switch (triple
.getOS()) {
125 case llvm::Triple::Darwin
:
126 case llvm::Triple::MacOSX
:
127 case llvm::Triple::IOS
:
128 case llvm::Triple::WatchOS
:
129 case llvm::Triple::TvOS
:
130 case llvm::Triple::BridgeOS
:
132 // Only accept "vendor" for vendor if the host is Apple and it "unknown"
133 // wasn't specified (it was just returned because it was NOT specified)
134 case llvm::Triple::UnknownOS
:
135 create
= !arch
->TripleOSWasSpecified();
143 if (arch
&& arch
->IsValid()) {
144 switch (arch
->GetMachine()) {
145 case llvm::Triple::x86
:
146 case llvm::Triple::x86_64
:
147 case llvm::Triple::ppc
:
148 case llvm::Triple::ppc64
:
149 is_ios_debug_session
= eLazyBoolNo
;
151 case llvm::Triple::arm
:
152 case llvm::Triple::aarch64
:
153 case llvm::Triple::thumb
:
154 is_ios_debug_session
= eLazyBoolYes
;
157 is_ios_debug_session
= eLazyBoolCalculate
;
162 LLDB_LOGF(log
, "PlatformDarwinKernel::%s() creating platform",
165 return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session
));
168 LLDB_LOGF(log
, "PlatformDarwinKernel::%s() aborting creation of platform",
174 llvm::StringRef
PlatformDarwinKernel::GetDescriptionStatic() {
175 return "Darwin Kernel platform plug-in.";
178 /// Code to handle the PlatformDarwinKernel settings
180 #define LLDB_PROPERTIES_platformdarwinkernel
181 #include "PlatformMacOSXProperties.inc"
184 #define LLDB_PROPERTIES_platformdarwinkernel
185 #include "PlatformMacOSXPropertiesEnum.inc"
188 class PlatformDarwinKernelProperties
: public Properties
{
190 static llvm::StringRef
GetSettingName() {
191 static constexpr llvm::StringLiteral
g_setting_name("darwin-kernel");
192 return g_setting_name
;
195 PlatformDarwinKernelProperties() : Properties() {
196 m_collection_sp
= std::make_shared
<OptionValueProperties
>(GetSettingName());
197 m_collection_sp
->Initialize(g_platformdarwinkernel_properties
);
200 ~PlatformDarwinKernelProperties() override
= default;
202 FileSpecList
GetKextDirectories() const {
203 const uint32_t idx
= ePropertyKextDirectories
;
204 return GetPropertyAtIndexAs
<FileSpecList
>(idx
, {});
208 static PlatformDarwinKernelProperties
&GetGlobalProperties() {
209 static PlatformDarwinKernelProperties g_settings
;
213 void PlatformDarwinKernel::DebuggerInitialize(
214 lldb_private::Debugger
&debugger
) {
215 if (!PluginManager::GetSettingForPlatformPlugin(
216 debugger
, PlatformDarwinKernelProperties::GetSettingName())) {
217 const bool is_global_setting
= true;
218 PluginManager::CreateSettingForPlatformPlugin(
219 debugger
, GetGlobalProperties().GetValueProperties(),
220 "Properties for the PlatformDarwinKernel plug-in.", is_global_setting
);
224 /// Default Constructor
225 PlatformDarwinKernel::PlatformDarwinKernel(
226 lldb_private::LazyBool is_ios_debug_session
)
227 : PlatformDarwin(false), // This is a remote platform
228 m_name_to_kext_path_map_with_dsyms(),
229 m_name_to_kext_path_map_without_dsyms(), m_search_directories(),
230 m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(),
231 m_kernel_binaries_without_dsyms(), m_kernel_dsyms_no_binaries(),
232 m_kernel_dsyms_yaas(), m_ios_debug_session(is_ios_debug_session
),
233 m_kext_scan_flag() {}
237 /// The destructor is virtual since this class is designed to be
238 /// inherited from by the plug-in instance.
239 PlatformDarwinKernel::~PlatformDarwinKernel() = default;
241 void PlatformDarwinKernel::GetStatus(Stream
&strm
) {
242 UpdateKextandKernelsLocalScan();
243 Platform::GetStatus(strm
);
244 strm
.Printf(" Debug session type: ");
245 if (m_ios_debug_session
== eLazyBoolYes
)
246 strm
.Printf("iOS kernel debugging\n");
247 else if (m_ios_debug_session
== eLazyBoolNo
)
248 strm
.Printf("Mac OS X kernel debugging\n");
250 strm
.Printf("unknown kernel debugging\n");
252 strm
.Printf("Directories searched recursively:\n");
253 const uint32_t num_kext_dirs
= m_search_directories
.size();
254 for (uint32_t i
= 0; i
< num_kext_dirs
; ++i
) {
255 strm
.Printf("[%d] %s\n", i
, m_search_directories
[i
].GetPath().c_str());
258 strm
.Printf("Directories not searched recursively:\n");
259 const uint32_t num_kext_dirs_no_recursion
=
260 m_search_directories_no_recursing
.size();
261 for (uint32_t i
= 0; i
< num_kext_dirs_no_recursion
; i
++) {
262 strm
.Printf("[%d] %s\n", i
,
263 m_search_directories_no_recursing
[i
].GetPath().c_str());
266 strm
.Printf(" Number of kexts with dSYMs indexed: %d\n",
267 (int)m_name_to_kext_path_map_with_dsyms
.size());
268 strm
.Printf(" Number of kexts without dSYMs indexed: %d\n",
269 (int)m_name_to_kext_path_map_without_dsyms
.size());
270 strm
.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n",
271 (int)m_kernel_binaries_with_dsyms
.size());
272 strm
.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n",
273 (int)m_kernel_binaries_without_dsyms
.size());
274 strm
.Printf(" Number of Kernel dSYMs with no binaries indexed: %d\n",
275 (int)m_kernel_dsyms_no_binaries
.size());
276 strm
.Printf(" Number of Kernel dSYM.yaa's indexed: %d\n",
277 (int)m_kernel_dsyms_yaas
.size());
279 Log
*log
= GetLog(LLDBLog::Platform
);
281 LLDB_LOGF(log
, "\nkexts with dSYMs");
282 for (auto pos
: m_name_to_kext_path_map_with_dsyms
) {
283 LLDB_LOGF(log
, "%s", pos
.second
.GetPath().c_str());
285 LLDB_LOGF(log
, "\nkexts without dSYMs");
287 for (auto pos
: m_name_to_kext_path_map_without_dsyms
) {
288 LLDB_LOGF(log
, "%s", pos
.second
.GetPath().c_str());
290 LLDB_LOGF(log
, "\nkernel binaries with dSYMS");
291 for (auto fs
: m_kernel_binaries_with_dsyms
) {
292 LLDB_LOGF(log
, "%s", fs
.GetPath().c_str());
294 LLDB_LOGF(log
, "\nkernel binaries without dSYMS");
295 for (auto fs
: m_kernel_binaries_without_dsyms
) {
296 LLDB_LOGF(log
, "%s", fs
.GetPath().c_str());
298 LLDB_LOGF(log
, "\nkernel dSYMS with no binaries");
299 for (auto fs
: m_kernel_dsyms_no_binaries
) {
300 LLDB_LOGF(log
, "%s", fs
.GetPath().c_str());
302 LLDB_LOGF(log
, "\nkernels .dSYM.yaa's");
303 for (auto fs
: m_kernel_dsyms_yaas
) {
304 LLDB_LOGF(log
, "%s", fs
.GetPath().c_str());
306 LLDB_LOGF(log
, "\n");
310 // Populate the m_search_directories vector with directories we should search
311 // for kernel & kext binaries.
313 void PlatformDarwinKernel::CollectKextAndKernelDirectories() {
314 // Differentiate between "ios debug session" and "mac debug session" so we
315 // don't index kext bundles that won't be used in this debug session. If
316 // this is an ios kext debug session, looking in /System/Library/Extensions
317 // is a waste of stat()s, for example.
319 // DeveloperDirectory is something like
320 // "/Applications/Xcode.app/Contents/Developer"
321 std::string developer_dir
= HostInfo::GetXcodeDeveloperDirectory().GetPath();
322 if (developer_dir
.empty())
323 developer_dir
= "/Applications/Xcode.app/Contents/Developer";
325 if (m_ios_debug_session
!= eLazyBoolNo
) {
326 AddSDKSubdirsToSearchPaths(developer_dir
+
327 "/Platforms/iPhoneOS.platform/Developer/SDKs");
328 AddSDKSubdirsToSearchPaths(developer_dir
+
329 "/Platforms/AppleTVOS.platform/Developer/SDKs");
330 AddSDKSubdirsToSearchPaths(developer_dir
+
331 "/Platforms/WatchOS.platform/Developer/SDKs");
332 AddSDKSubdirsToSearchPaths(developer_dir
+
333 "/Platforms/BridgeOS.platform/Developer/SDKs");
335 if (m_ios_debug_session
!= eLazyBoolYes
) {
336 AddSDKSubdirsToSearchPaths(developer_dir
+
337 "/Platforms/MacOSX.platform/Developer/SDKs");
340 AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit");
341 AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs");
342 // The KDKs distributed from Apple installed on external developer systems
343 // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk
344 AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs");
346 if (m_ios_debug_session
!= eLazyBoolNo
) {
348 if (m_ios_debug_session
!= eLazyBoolYes
) {
349 AddRootSubdirsToSearchPaths(this, "/");
352 GetUserSpecifiedDirectoriesToSearch();
354 // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols
355 FileSpec
possible_dir(developer_dir
+ "/../Symbols");
356 FileSystem::Instance().Resolve(possible_dir
);
357 if (FileSystem::Instance().IsDirectory(possible_dir
))
358 m_search_directories
.push_back(possible_dir
);
360 // Add simple directory of the current working directory
362 FileSystem::Instance().Resolve(cwd
);
363 m_search_directories_no_recursing
.push_back(cwd
);
366 void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() {
367 FileSpecList
user_dirs(GetGlobalProperties().GetKextDirectories());
368 std::vector
<FileSpec
> possible_sdk_dirs
;
370 const uint32_t user_dirs_count
= user_dirs
.GetSize();
371 for (uint32_t i
= 0; i
< user_dirs_count
; i
++) {
372 FileSpec dir
= user_dirs
.GetFileSpecAtIndex(i
);
373 FileSystem::Instance().Resolve(dir
);
374 if (FileSystem::Instance().IsDirectory(dir
)) {
375 m_search_directories
.push_back(dir
);
380 void PlatformDarwinKernel::AddRootSubdirsToSearchPaths(
381 PlatformDarwinKernel
*thisp
, const std::string
&dir
) {
382 const char *subdirs
[] = {
383 "/System/Library/Extensions", "/Library/Extensions",
384 "/System/Library/Kernels",
385 "/System/Library/Extensions/KDK", // this one probably only exist in
386 // /AppleInternal/Developer/KDKs/*.kdk/...
388 for (int i
= 0; subdirs
[i
] != nullptr; i
++) {
389 FileSpec
testdir(dir
+ subdirs
[i
]);
390 FileSystem::Instance().Resolve(testdir
);
391 if (FileSystem::Instance().IsDirectory(testdir
))
392 thisp
->m_search_directories
.push_back(testdir
);
395 // Look for kernel binaries in the top level directory, without any recursion
396 thisp
->m_search_directories_no_recursing
.push_back(FileSpec(dir
+ "/"));
399 // Given a directory path dir, look for any subdirs named *.kdk and *.sdk
400 void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string
&dir
) {
401 // Look for *.kdk and *.sdk in dir
402 const bool find_directories
= true;
403 const bool find_files
= false;
404 const bool find_other
= false;
405 FileSystem::Instance().EnumerateDirectory(
406 dir
.c_str(), find_directories
, find_files
, find_other
,
407 FindKDKandSDKDirectoriesInDirectory
, this);
410 // Helper function to find *.sdk and *.kdk directories in a given directory.
411 FileSystem::EnumerateDirectoryResult
412 PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory(
413 void *baton
, llvm::sys::fs::file_type ft
, llvm::StringRef path
) {
414 static constexpr llvm::StringLiteral g_sdk_suffix
= ".sdk";
415 static constexpr llvm::StringLiteral g_kdk_suffix
= ".kdk";
417 PlatformDarwinKernel
*thisp
= (PlatformDarwinKernel
*)baton
;
418 const FileSpec
file_spec(path
);
419 if (ft
== llvm::sys::fs::file_type::directory_file
&&
420 (file_spec
.GetFileNameExtension() == g_sdk_suffix
||
421 file_spec
.GetFileNameExtension() == g_kdk_suffix
)) {
422 AddRootSubdirsToSearchPaths(thisp
, file_spec
.GetPath());
424 return FileSystem::eEnumerateDirectoryResultNext
;
427 // Recursively search trough m_search_directories looking for kext and kernel
428 // binaries, adding files found to the appropriate lists.
429 void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() {
430 const uint32_t num_dirs
= m_search_directories
.size();
431 for (uint32_t i
= 0; i
< num_dirs
; i
++) {
432 const FileSpec
&dir
= m_search_directories
[i
];
433 const bool find_directories
= true;
434 const bool find_files
= true;
435 const bool find_other
= true; // I think eFileTypeSymbolicLink are "other"s.
436 FileSystem::Instance().EnumerateDirectory(
437 dir
.GetPath().c_str(), find_directories
, find_files
, find_other
,
438 GetKernelsAndKextsInDirectoryWithRecursion
, this);
440 const uint32_t num_dirs_no_recurse
= m_search_directories_no_recursing
.size();
441 for (uint32_t i
= 0; i
< num_dirs_no_recurse
; i
++) {
442 const FileSpec
&dir
= m_search_directories_no_recursing
[i
];
443 const bool find_directories
= true;
444 const bool find_files
= true;
445 const bool find_other
= true; // I think eFileTypeSymbolicLink are "other"s.
446 FileSystem::Instance().EnumerateDirectory(
447 dir
.GetPath().c_str(), find_directories
, find_files
, find_other
,
448 GetKernelsAndKextsInDirectoryNoRecursion
, this);
452 // We're only doing a filename match here. We won't try opening the file to
453 // see if it's really a kernel or not until we need to find a kernel of a given
454 // UUID. There's no cheap way to find the UUID of a file (or if it's a Mach-O
455 // binary at all) without creating a whole Module for the file and throwing it
456 // away if it's not wanted.
458 // Recurse into any subdirectories found.
460 FileSystem::EnumerateDirectoryResult
461 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion(
462 void *baton
, llvm::sys::fs::file_type ft
, llvm::StringRef path
) {
463 return GetKernelsAndKextsInDirectoryHelper(baton
, ft
, path
, true);
466 FileSystem::EnumerateDirectoryResult
467 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion(
468 void *baton
, llvm::sys::fs::file_type ft
, llvm::StringRef path
) {
469 return GetKernelsAndKextsInDirectoryHelper(baton
, ft
, path
, false);
472 FileSystem::EnumerateDirectoryResult
473 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper(
474 void *baton
, llvm::sys::fs::file_type ft
, llvm::StringRef path
,
476 static constexpr llvm::StringLiteral g_kext_suffix
= ".kext";
477 static constexpr llvm::StringLiteral g_dsym_suffix
= ".dSYM";
479 const FileSpec
file_spec(path
);
480 llvm::StringRef file_spec_extension
= file_spec
.GetFileNameExtension();
482 Log
*log
= GetLog(LLDBLog::Platform
);
484 LLDB_LOGV(log
, "PlatformDarwinKernel examining '{0}'", file_spec
);
486 PlatformDarwinKernel
*thisp
= (PlatformDarwinKernel
*)baton
;
488 llvm::StringRef filename
= file_spec
.GetFilename().GetStringRef();
489 bool is_kernel_filename
=
490 filename
.starts_with("kernel") || filename
.starts_with("mach");
491 bool is_dsym_yaa
= filename
.ends_with(".dSYM.yaa");
493 if (ft
== llvm::sys::fs::file_type::regular_file
||
494 ft
== llvm::sys::fs::file_type::symlink_file
) {
495 if (is_kernel_filename
) {
496 if (file_spec_extension
!= g_dsym_suffix
&& !is_dsym_yaa
) {
497 if (KernelHasdSYMSibling(file_spec
)) {
499 "PlatformDarwinKernel registering kernel binary '%s' with "
501 file_spec
.GetPath().c_str());
502 thisp
->m_kernel_binaries_with_dsyms
.push_back(file_spec
);
506 "PlatformDarwinKernel registering kernel binary '%s', no dSYM",
507 file_spec
.GetPath().c_str());
508 thisp
->m_kernel_binaries_without_dsyms
.push_back(file_spec
);
512 LLDB_LOGF(log
, "PlatformDarwinKernel registering kernel .dSYM.yaa '%s'",
513 file_spec
.GetPath().c_str());
514 thisp
->m_kernel_dsyms_yaas
.push_back(file_spec
);
516 return FileSystem::eEnumerateDirectoryResultNext
;
519 if (ft
== llvm::sys::fs::file_type::directory_file
) {
520 if (file_spec_extension
== g_kext_suffix
) {
521 AddKextToMap(thisp
, file_spec
);
522 // Look to see if there is a PlugIns subdir with more kexts
523 FileSpec
contents_plugins(file_spec
.GetPath() + "/Contents/PlugIns");
524 std::string search_here_too
;
525 if (FileSystem::Instance().IsDirectory(contents_plugins
)) {
526 search_here_too
= contents_plugins
.GetPath();
528 FileSpec
plugins(file_spec
.GetPath() + "/PlugIns");
529 if (FileSystem::Instance().IsDirectory(plugins
)) {
530 search_here_too
= plugins
.GetPath();
534 if (!search_here_too
.empty()) {
535 const bool find_directories
= true;
536 const bool find_files
= false;
537 const bool find_other
= true;
538 FileSystem::Instance().EnumerateDirectory(
539 search_here_too
.c_str(), find_directories
, find_files
, find_other
,
540 recurse
? GetKernelsAndKextsInDirectoryWithRecursion
541 : GetKernelsAndKextsInDirectoryNoRecursion
,
544 return FileSystem::eEnumerateDirectoryResultNext
;
546 // Do we have a kernel dSYM with no kernel binary?
547 if (is_kernel_filename
&& file_spec_extension
== g_dsym_suffix
) {
548 if (KerneldSYMHasNoSiblingBinary(file_spec
)) {
550 "PlatformDarwinKernel registering kernel dSYM '%s' with "
552 file_spec
.GetPath().c_str());
553 thisp
->m_kernel_dsyms_no_binaries
.push_back(file_spec
);
554 return FileSystem::eEnumerateDirectoryResultNext
;
560 // Don't recurse into dSYM/kext/bundle directories
561 if (recurse
&& file_spec_extension
!= g_dsym_suffix
&&
562 file_spec_extension
!= g_kext_suffix
) {
563 LLDB_LOGV(log
, "PlatformDarwinKernel descending into directory '{0}'",
565 return FileSystem::eEnumerateDirectoryResultEnter
;
567 return FileSystem::eEnumerateDirectoryResultNext
;
571 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel
*thisp
,
572 const FileSpec
&file_spec
) {
573 Log
*log
= GetLog(LLDBLog::Platform
);
574 CFCBundle
bundle(file_spec
.GetPath().c_str());
575 CFStringRef
bundle_id(bundle
.GetIdentifier());
576 if (bundle_id
&& CFGetTypeID(bundle_id
) == CFStringGetTypeID()) {
577 char bundle_id_buf
[PATH_MAX
];
578 if (CFStringGetCString(bundle_id
, bundle_id_buf
, sizeof(bundle_id_buf
),
579 kCFStringEncodingUTF8
)) {
580 ConstString
bundle_conststr(bundle_id_buf
);
581 if (KextHasdSYMSibling(file_spec
))
584 "PlatformDarwinKernel registering kext binary '%s' with dSYM "
586 file_spec
.GetPath().c_str());
587 thisp
->m_name_to_kext_path_map_with_dsyms
.insert(
588 std::pair
<ConstString
, FileSpec
>(bundle_conststr
, file_spec
));
593 "PlatformDarwinKernel registering kext binary '%s', no dSYM",
594 file_spec
.GetPath().c_str());
595 thisp
->m_name_to_kext_path_map_without_dsyms
.insert(
596 std::pair
<ConstString
, FileSpec
>(bundle_conststr
, file_spec
));
602 // Given a FileSpec of /dir/dir/foo.kext
603 // Return true if any of these exist:
604 // /dir/dir/foo.kext.dSYM
605 // /dir/dir/foo.kext/Contents/MacOS/foo.dSYM
606 // /dir/dir/foo.kext/foo.dSYM
607 bool PlatformDarwinKernel::KextHasdSYMSibling(
608 const FileSpec
&kext_bundle_filepath
) {
609 FileSpec dsym_fspec
= kext_bundle_filepath
;
610 std::string filename
= dsym_fspec
.GetFilename().AsCString();
612 dsym_fspec
.SetFilename(filename
);
613 if (FileSystem::Instance().IsDirectory(dsym_fspec
)) {
616 // Should probably get the CFBundleExecutable here or call
617 // CFBundleCopyExecutableURL
619 // Look for a deep bundle foramt
620 ConstString executable_name
=
621 kext_bundle_filepath
.GetFileNameStrippingExtension();
622 std::string deep_bundle_str
=
623 kext_bundle_filepath
.GetPath() + "/Contents/MacOS/";
624 deep_bundle_str
+= executable_name
.AsCString();
625 deep_bundle_str
+= ".dSYM";
626 dsym_fspec
.SetFile(deep_bundle_str
, FileSpec::Style::native
);
627 FileSystem::Instance().Resolve(dsym_fspec
);
628 if (FileSystem::Instance().IsDirectory(dsym_fspec
)) {
632 // look for a shallow bundle format
634 std::string shallow_bundle_str
= kext_bundle_filepath
.GetPath() + "/";
635 shallow_bundle_str
+= executable_name
.AsCString();
636 shallow_bundle_str
+= ".dSYM";
637 dsym_fspec
.SetFile(shallow_bundle_str
, FileSpec::Style::native
);
638 FileSystem::Instance().Resolve(dsym_fspec
);
639 return FileSystem::Instance().IsDirectory(dsym_fspec
);
642 // Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM
643 // exists next to it:
644 // /dir/dir/mach.development.t7004.dSYM
645 bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec
&kernel_binary
) {
646 FileSpec kernel_dsym
= kernel_binary
;
647 std::string filename
= kernel_binary
.GetFilename().AsCString();
649 kernel_dsym
.SetFilename(filename
);
650 return FileSystem::Instance().IsDirectory(kernel_dsym
);
653 // Given a FileSpec of /dir/dir/mach.development.t7004.dSYM
654 // Return true if only the dSYM exists, no binary next to it.
655 // /dir/dir/mach.development.t7004.dSYM
657 // /dir/dir/mach.development.t7004
658 bool PlatformDarwinKernel::KerneldSYMHasNoSiblingBinary(
659 const FileSpec
&kernel_dsym
) {
660 static constexpr llvm::StringLiteral g_dsym_suffix
= ".dSYM";
661 std::string possible_path
= kernel_dsym
.GetPath();
662 if (kernel_dsym
.GetFileNameExtension() != g_dsym_suffix
)
665 FileSpec binary_filespec
= kernel_dsym
;
666 // Chop off the '.dSYM' extension on the filename
667 binary_filespec
.SetFilename(binary_filespec
.GetFileNameStrippingExtension());
669 // Is there a binary next to this this? Then return false.
670 if (FileSystem::Instance().Exists(binary_filespec
))
673 // If we have at least one binary in the DWARF subdir, then
674 // this is a properly formed dSYM and it has no binary next
676 if (GetDWARFBinaryInDSYMBundle(kernel_dsym
).size() > 0)
682 // TODO: This method returns a vector of FileSpec's because a
683 // dSYM bundle may contain multiple DWARF binaries, but it
684 // only implements returning the base name binary for now;
685 // it should iterate over every binary in the DWARF subdir
686 // and return them all.
687 std::vector
<FileSpec
>
688 PlatformDarwinKernel::GetDWARFBinaryInDSYMBundle(const FileSpec
&dsym_bundle
) {
689 std::vector
<FileSpec
> results
;
690 static constexpr llvm::StringLiteral g_dsym_suffix
= ".dSYM";
691 if (dsym_bundle
.GetFileNameExtension() != g_dsym_suffix
) {
694 // Drop the '.dSYM' from the filename
695 std::string filename
=
696 dsym_bundle
.GetFileNameStrippingExtension().GetCString();
697 std::string dirname
= dsym_bundle
.GetDirectory().GetCString();
699 std::string binary_filepath
= dsym_bundle
.GetPath();
700 binary_filepath
+= "/Contents/Resources/DWARF/";
701 binary_filepath
+= filename
;
703 FileSpec
binary_fspec(binary_filepath
);
704 if (FileSystem::Instance().Exists(binary_fspec
))
705 results
.push_back(binary_fspec
);
709 void PlatformDarwinKernel::UpdateKextandKernelsLocalScan() {
710 std::call_once(m_kext_scan_flag
, [this]() {
711 CollectKextAndKernelDirectories();
712 SearchForKextsAndKernelsRecursively();
716 Status
PlatformDarwinKernel::GetSharedModule(
717 const ModuleSpec
&module_spec
, Process
*process
, ModuleSP
&module_sp
,
718 const FileSpecList
*module_search_paths_ptr
,
719 llvm::SmallVectorImpl
<ModuleSP
> *old_modules
, bool *did_create_ptr
) {
722 const FileSpec
&platform_file
= module_spec
.GetFileSpec();
724 // Treat the file's path as a kext bundle ID (e.g.
725 // "com.apple.driver.AppleIRController") and search our kext index.
726 std::string kext_bundle_id
= platform_file
.GetPath();
728 if (module_spec
.GetUUID().IsValid()) {
729 // DynamicLoaderDarwinKernel uses the magic name mach_kernel,
730 // UUID search can get here with no name - and it may be a kernel.
731 if (kext_bundle_id
== "mach_kernel" || kext_bundle_id
.empty()) {
732 error
= GetSharedModuleKernel(module_spec
, process
, module_sp
,
733 module_search_paths_ptr
, old_modules
,
735 if (error
.Success() && module_sp
) {
739 return GetSharedModuleKext(module_spec
, process
, module_sp
,
740 module_search_paths_ptr
, old_modules
,
745 // Give the generic methods, including possibly calling into DebugSymbols
746 // framework on macOS systems, a chance.
747 return PlatformDarwin::GetSharedModule(module_spec
, process
, module_sp
,
748 module_search_paths_ptr
, old_modules
,
752 Status
PlatformDarwinKernel::GetSharedModuleKext(
753 const ModuleSpec
&module_spec
, Process
*process
, ModuleSP
&module_sp
,
754 const FileSpecList
*module_search_paths_ptr
,
755 llvm::SmallVectorImpl
<ModuleSP
> *old_modules
, bool *did_create_ptr
) {
758 const FileSpec
&platform_file
= module_spec
.GetFileSpec();
760 // Treat the file's path as a kext bundle ID (e.g.
761 // "com.apple.driver.AppleIRController") and search our kext index.
762 ConstString
kext_bundle(platform_file
.GetPath().c_str());
763 // First look through the kext bundles that had a dsym next to them
764 if (m_name_to_kext_path_map_with_dsyms
.count(kext_bundle
) > 0) {
765 for (BundleIDToKextIterator it
= m_name_to_kext_path_map_with_dsyms
.begin();
766 it
!= m_name_to_kext_path_map_with_dsyms
.end(); ++it
) {
767 if (it
->first
== kext_bundle
) {
768 error
= ExamineKextForMatchingUUID(it
->second
, module_spec
.GetUUID(),
769 module_spec
.GetArchitecture(),
771 if (module_sp
.get()) {
778 // Give the generic methods, including possibly calling into DebugSymbols
779 // framework on macOS systems, a chance.
780 error
= PlatformDarwin::GetSharedModule(module_spec
, process
, module_sp
,
781 module_search_paths_ptr
, old_modules
,
783 if (error
.Success() && module_sp
.get()) {
790 Status
PlatformDarwinKernel::GetSharedModuleKernel(
791 const ModuleSpec
&module_spec
, Process
*process
, ModuleSP
&module_sp
,
792 const FileSpecList
*module_search_paths_ptr
,
793 llvm::SmallVectorImpl
<ModuleSP
> *old_modules
, bool *did_create_ptr
) {
794 assert(module_sp
.get() == nullptr);
795 UpdateKextandKernelsLocalScan();
797 *did_create_ptr
= false;
799 // First try all kernel binaries that have a dSYM next to them
800 for (auto possible_kernel
: m_kernel_binaries_with_dsyms
) {
801 if (FileSystem::Instance().Exists(possible_kernel
)) {
802 ModuleSpec
kern_spec(possible_kernel
);
803 kern_spec
.GetUUID() = module_spec
.GetUUID();
804 module_sp
.reset(new Module(kern_spec
));
805 if (module_sp
&& module_sp
->GetObjectFile() &&
806 module_sp
->MatchesModuleSpec(kern_spec
)) {
807 // The dSYM is next to the binary (that's the only
808 // way it ends up in the index), but it might be a
809 // .dSYM.yaa that needs to be expanded, don't just
810 // append ".dSYM" to the filename for the SymbolFile.
811 FileSpecList search_paths
=
812 process
->GetTarget().GetDebugFileSearchPaths();
813 FileSpec dsym_fspec
=
814 PluginManager::LocateExecutableSymbolFile(kern_spec
, search_paths
);
815 if (FileSystem::Instance().Exists(dsym_fspec
))
816 module_sp
->SetSymbolFileFileSpec(dsym_fspec
);
818 *did_create_ptr
= true;
824 // Next try all dSYMs that have no kernel binary next to them (load
825 // the kernel DWARF stub as the main binary)
826 for (auto possible_kernel_dsym
: m_kernel_dsyms_no_binaries
) {
827 std::vector
<FileSpec
> objfile_names
=
828 GetDWARFBinaryInDSYMBundle(possible_kernel_dsym
);
829 for (FileSpec objfile
: objfile_names
) {
830 ModuleSpec
kern_spec(objfile
);
831 kern_spec
.GetUUID() = module_spec
.GetUUID();
832 kern_spec
.GetSymbolFileSpec() = possible_kernel_dsym
;
834 module_sp
.reset(new Module(kern_spec
));
835 if (module_sp
&& module_sp
->GetObjectFile() &&
836 module_sp
->MatchesModuleSpec(kern_spec
)) {
838 *did_create_ptr
= true;
844 // Give the generic methods, including possibly calling into DebugSymbols
845 // framework on macOS systems, a chance.
846 return PlatformDarwin::GetSharedModule(module_spec
, process
, module_sp
,
847 module_search_paths_ptr
, old_modules
,
851 std::vector
<lldb_private::FileSpec
>
852 PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string
&dir
) {
853 std::vector
<FileSpec
> executables
;
855 for (llvm::sys::fs::recursive_directory_iterator
it(dir
.c_str(), EC
),
857 it
!= end
&& !EC
; it
.increment(EC
)) {
858 auto status
= it
->status();
861 if (llvm::sys::fs::is_regular_file(*status
) &&
862 llvm::sys::fs::can_execute(it
->path()))
863 executables
.emplace_back(it
->path());
868 Status
PlatformDarwinKernel::ExamineKextForMatchingUUID(
869 const FileSpec
&kext_bundle_path
, const lldb_private::UUID
&uuid
,
870 const ArchSpec
&arch
, ModuleSP
&exe_module_sp
) {
871 for (const auto &exe_file
:
872 SearchForExecutablesRecursively(kext_bundle_path
.GetPath())) {
873 if (FileSystem::Instance().Exists(exe_file
)) {
874 ModuleSpec
exe_spec(exe_file
);
875 exe_spec
.GetUUID() = uuid
;
876 if (!uuid
.IsValid()) {
877 exe_spec
.GetArchitecture() = arch
;
880 // First try to create a ModuleSP with the file / arch and see if the UUID
881 // matches. If that fails (this exec file doesn't have the correct uuid),
882 // don't call GetSharedModule (which may call in to the DebugSymbols
883 // framework and therefore can be slow.)
884 ModuleSP
module_sp(new Module(exe_spec
));
885 if (module_sp
&& module_sp
->GetObjectFile() &&
886 module_sp
->MatchesModuleSpec(exe_spec
)) {
887 Status error
= ModuleList::GetSharedModule(exe_spec
, exe_module_sp
,
889 if (exe_module_sp
&& exe_module_sp
->GetObjectFile()) {
893 exe_module_sp
.reset();
900 static addr_t
find_kernel_in_macho_fileset(Process
*process
,
903 WritableDataBufferSP
header_data(new DataBufferHeap(512, 0));
904 if (!process
->ReadMemory(input_addr
, header_data
->GetBytes(),
905 header_data
->GetByteSize(), error
) ||
907 return LLDB_INVALID_ADDRESS
;
908 ModuleSP
module_sp(new Module(ModuleSpec()));
909 ObjectContainerSP
container_sp(
910 ObjectContainerMachOFileset::CreateMemoryInstance(
911 module_sp
, header_data
, process
->shared_from_this(), input_addr
));
913 return LLDB_INVALID_ADDRESS
;
915 ObjectContainerMachOFileset
*fileset_container
=
916 static_cast<ObjectContainerMachOFileset
*>(container_sp
.get());
917 ObjectContainerMachOFileset::Entry
*entry
=
918 fileset_container
->FindEntry("com.apple.kernel");
920 return entry
->vmaddr
;
921 return LLDB_INVALID_ADDRESS
;
924 bool PlatformDarwinKernel::LoadPlatformBinaryAndSetup(Process
*process
,
925 lldb::addr_t input_addr
,
928 GetLog(LLDBLog::Platform
| LLDBLog::DynamicLoader
| LLDBLog::Process
);
933 addr_t actual_address
= find_kernel_in_macho_fileset(process
, input_addr
);
935 if (actual_address
== LLDB_INVALID_ADDRESS
)
939 "PlatformDarwinKernel::%s check address 0x%" PRIx64
" for "
940 "a macho fileset, got back kernel address 0x%" PRIx64
,
941 __FUNCTION__
, input_addr
, actual_address
);
943 // We have a xnu kernel binary, this is a kernel debug session.
944 // Set the Target's Platform to be PlatformDarwinKernel, and the
945 // Process' DynamicLoader to be DynamicLoaderDarwinKernel.
947 PlatformSP platform_sp
=
948 process
->GetTarget().GetDebugger().GetPlatformList().Create(
949 PlatformDarwinKernel::GetPluginNameStatic());
951 process
->GetTarget().SetPlatform(platform_sp
);
953 DynamicLoaderUP dyld_up
=
954 std::make_unique
<DynamicLoaderDarwinKernel
>(process
, actual_address
);
958 // Process owns it now
959 process
->SetDynamicLoader(std::move(dyld_up
));
964 std::vector
<ArchSpec
> PlatformDarwinKernel::GetSupportedArchitectures(
965 const ArchSpec
&process_host_arch
) {
966 std::vector
<ArchSpec
> result
;
967 ARMGetSupportedArchitectures(result
);
968 x86GetSupportedArchitectures(result
);
972 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() {
973 m_trap_handlers
.push_back(ConstString("trap_from_kernel"));
974 m_trap_handlers
.push_back(ConstString("hndl_machine_check"));
975 m_trap_handlers
.push_back(ConstString("hndl_double_fault"));
976 m_trap_handlers
.push_back(ConstString("hndl_allintrs"));
977 m_trap_handlers
.push_back(ConstString("hndl_alltraps"));
978 m_trap_handlers
.push_back(ConstString("interrupt"));
979 m_trap_handlers
.push_back(ConstString("fleh_prefabt"));
980 m_trap_handlers
.push_back(ConstString("ExceptionVectorsBase"));
981 m_trap_handlers
.push_back(ConstString("ExceptionVectorsTable"));
982 m_trap_handlers
.push_back(ConstString("fleh_undef"));
983 m_trap_handlers
.push_back(ConstString("fleh_dataabt"));
984 m_trap_handlers
.push_back(ConstString("fleh_irq"));
985 m_trap_handlers
.push_back(ConstString("fleh_decirq"));
986 m_trap_handlers
.push_back(ConstString("fleh_fiq_generic"));
987 m_trap_handlers
.push_back(ConstString("fleh_dec"));