LLDB  mainline
PlatformDarwinKernel.cpp
Go to the documentation of this file.
1 //===-- PlatformDarwinKernel.cpp ------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PlatformDarwinKernel.h"
10 
11 #if defined(__APPLE__) // This Plugin uses the Mac-specific
12  // source/Host/macosx/cfcpp utilities
13 
15 #include "lldb/Core/Module.h"
16 #include "lldb/Core/ModuleList.h"
17 #include "lldb/Core/ModuleSpec.h"
19 #include "lldb/Host/Host.h"
20 #include "lldb/Host/HostInfo.h"
24 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Target/Platform.h"
26 #include "lldb/Target/Process.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Utility/ArchSpec.h"
29 #include "lldb/Utility/FileSpec.h"
30 #include "lldb/Utility/LLDBLog.h"
31 #include "lldb/Utility/Log.h"
32 #include "lldb/Utility/Status.h"
34 
35 #include "llvm/Support/FileSystem.h"
36 
37 #include <CoreFoundation/CoreFoundation.h>
38 
39 #include <memory>
40 
42 
43 using namespace lldb;
44 using namespace lldb_private;
45 
46 // Static Variables
47 static uint32_t g_initialize_count = 0;
48 
49 // Static Functions
50 void PlatformDarwinKernel::Initialize() {
51  PlatformDarwin::Initialize();
52 
53  if (g_initialize_count++ == 0) {
54  PluginManager::RegisterPlugin(PlatformDarwinKernel::GetPluginNameStatic(),
55  PlatformDarwinKernel::GetDescriptionStatic(),
56  PlatformDarwinKernel::CreateInstance,
57  PlatformDarwinKernel::DebuggerInitialize);
58  }
59 }
60 
61 void PlatformDarwinKernel::Terminate() {
62  if (g_initialize_count > 0) {
63  if (--g_initialize_count == 0) {
64  PluginManager::UnregisterPlugin(PlatformDarwinKernel::CreateInstance);
65  }
66  }
67 
68  PlatformDarwin::Terminate();
69 }
70 
71 PlatformSP PlatformDarwinKernel::CreateInstance(bool force,
72  const ArchSpec *arch) {
73  Log *log = GetLog(LLDBLog::Platform);
74  if (log) {
75  const char *arch_name;
76  if (arch && arch->GetArchitectureName())
77  arch_name = arch->GetArchitectureName();
78  else
79  arch_name = "<null>";
80 
81  const char *triple_cstr =
82  arch ? arch->GetTriple().getTriple().c_str() : "<null>";
83 
84  LLDB_LOGF(log, "PlatformDarwinKernel::%s(force=%s, arch={%s,%s})",
85  __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
86  }
87 
88  // This is a special plugin that we don't want to activate just based on an
89  // ArchSpec for normal userland debugging. It is only useful in kernel debug
90  // sessions and the DynamicLoaderDarwinPlugin (or a user doing 'platform
91  // select') will force the creation of this Platform plugin.
92  if (!force) {
93  LLDB_LOGF(log,
94  "PlatformDarwinKernel::%s() aborting creation of platform "
95  "because force == false",
96  __FUNCTION__);
97  return PlatformSP();
98  }
99 
100  bool create = force;
101  LazyBool is_ios_debug_session = eLazyBoolCalculate;
102 
103  if (!create && arch && arch->IsValid()) {
104  const llvm::Triple &triple = arch->GetTriple();
105  switch (triple.getVendor()) {
106  case llvm::Triple::Apple:
107  create = true;
108  break;
109 
110  // Only accept "unknown" for vendor if the host is Apple and it "unknown"
111  // wasn't specified (it was just returned because it was NOT specified)
112  case llvm::Triple::UnknownVendor:
113  create = !arch->TripleVendorWasSpecified();
114  break;
115  default:
116  break;
117  }
118 
119  if (create) {
120  switch (triple.getOS()) {
121  case llvm::Triple::Darwin:
122  case llvm::Triple::MacOSX:
123  case llvm::Triple::IOS:
124  case llvm::Triple::WatchOS:
125  case llvm::Triple::TvOS:
126  // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS:
127  break;
128  // Only accept "vendor" for vendor if the host is Apple and it "unknown"
129  // wasn't specified (it was just returned because it was NOT specified)
130  case llvm::Triple::UnknownOS:
131  create = !arch->TripleOSWasSpecified();
132  break;
133  default:
134  create = false;
135  break;
136  }
137  }
138  }
139  if (arch && arch->IsValid()) {
140  switch (arch->GetMachine()) {
141  case llvm::Triple::x86:
142  case llvm::Triple::x86_64:
143  case llvm::Triple::ppc:
144  case llvm::Triple::ppc64:
145  is_ios_debug_session = eLazyBoolNo;
146  break;
147  case llvm::Triple::arm:
148  case llvm::Triple::aarch64:
149  case llvm::Triple::thumb:
150  is_ios_debug_session = eLazyBoolYes;
151  break;
152  default:
153  is_ios_debug_session = eLazyBoolCalculate;
154  break;
155  }
156  }
157  if (create) {
158  LLDB_LOGF(log, "PlatformDarwinKernel::%s() creating platform",
159  __FUNCTION__);
160 
161  return PlatformSP(new PlatformDarwinKernel(is_ios_debug_session));
162  }
163 
164  LLDB_LOGF(log, "PlatformDarwinKernel::%s() aborting creation of platform",
165  __FUNCTION__);
166 
167  return PlatformSP();
168 }
169 
170 llvm::StringRef PlatformDarwinKernel::GetDescriptionStatic() {
171  return "Darwin Kernel platform plug-in.";
172 }
173 
174 /// Code to handle the PlatformDarwinKernel settings
175 
176 #define LLDB_PROPERTIES_platformdarwinkernel
177 #include "PlatformMacOSXProperties.inc"
178 
179 enum {
180 #define LLDB_PROPERTIES_platformdarwinkernel
181 #include "PlatformMacOSXPropertiesEnum.inc"
182 };
183 
184 class PlatformDarwinKernelProperties : public Properties {
185 public:
186  static ConstString &GetSettingName() {
187  static ConstString g_setting_name("darwin-kernel");
188  return g_setting_name;
189  }
190 
191  PlatformDarwinKernelProperties() : Properties() {
192  m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
193  m_collection_sp->Initialize(g_platformdarwinkernel_properties);
194  }
195 
196  ~PlatformDarwinKernelProperties() override = default;
197 
198  FileSpecList GetKextDirectories() const {
199  const uint32_t idx = ePropertyKextDirectories;
200  const OptionValueFileSpecList *option_value =
201  m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(
202  NULL, false, idx);
203  assert(option_value);
204  return option_value->GetCurrentValue();
205  }
206 };
207 
208 static PlatformDarwinKernelProperties &GetGlobalProperties() {
209  static PlatformDarwinKernelProperties g_settings;
210  return g_settings;
211 }
212 
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  ConstString("Properties for the PlatformDarwinKernel plug-in."),
221  is_global_setting);
222  }
223 }
224 
225 /// Default Constructor
226 PlatformDarwinKernel::PlatformDarwinKernel(
227  lldb_private::LazyBool is_ios_debug_session)
228  : PlatformDarwin(false), // This is a remote platform
229  m_name_to_kext_path_map_with_dsyms(),
230  m_name_to_kext_path_map_without_dsyms(), m_search_directories(),
231  m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(),
232  m_kernel_binaries_without_dsyms(), m_kernel_dsyms_no_binaries(),
233  m_kernel_dsyms_yaas(), m_ios_debug_session(is_ios_debug_session)
234 
235 {
236  CollectKextAndKernelDirectories();
237  SearchForKextsAndKernelsRecursively();
238 }
239 
240 /// Destructor.
241 ///
242 /// The destructor is virtual since this class is designed to be
243 /// inherited from by the plug-in instance.
244 PlatformDarwinKernel::~PlatformDarwinKernel() = default;
245 
246 void PlatformDarwinKernel::GetStatus(Stream &strm) {
247  Platform::GetStatus(strm);
248  strm.Printf(" Debug session type: ");
249  if (m_ios_debug_session == eLazyBoolYes)
250  strm.Printf("iOS kernel debugging\n");
251  else if (m_ios_debug_session == eLazyBoolNo)
252  strm.Printf("Mac OS X kernel debugging\n");
253  else
254  strm.Printf("unknown kernel debugging\n");
255 
256  strm.Printf("Directories searched recursively:\n");
257  const uint32_t num_kext_dirs = m_search_directories.size();
258  for (uint32_t i = 0; i < num_kext_dirs; ++i) {
259  strm.Printf("[%d] %s\n", i, m_search_directories[i].GetPath().c_str());
260  }
261 
262  strm.Printf("Directories not searched recursively:\n");
263  const uint32_t num_kext_dirs_no_recursion =
264  m_search_directories_no_recursing.size();
265  for (uint32_t i = 0; i < num_kext_dirs_no_recursion; i++) {
266  strm.Printf("[%d] %s\n", i,
267  m_search_directories_no_recursing[i].GetPath().c_str());
268  }
269 
270  strm.Printf(" Number of kexts with dSYMs indexed: %d\n",
271  (int)m_name_to_kext_path_map_with_dsyms.size());
272  strm.Printf(" Number of kexts without dSYMs indexed: %d\n",
273  (int)m_name_to_kext_path_map_without_dsyms.size());
274  strm.Printf(" Number of Kernel binaries with dSYMs indexed: %d\n",
275  (int)m_kernel_binaries_with_dsyms.size());
276  strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n",
277  (int)m_kernel_binaries_without_dsyms.size());
278  strm.Printf(" Number of Kernel dSYMs with no binaries indexed: %d\n",
279  (int)m_kernel_dsyms_no_binaries.size());
280  strm.Printf(" Number of Kernel dSYM.yaa's indexed: %d\n",
281  (int)m_kernel_dsyms_yaas.size());
282 
283  Log *log = GetLog(LLDBLog::Platform);
284  if (log) {
285  LLDB_LOGF(log, "\nkexts with dSYMs");
286  for (auto pos : m_name_to_kext_path_map_with_dsyms) {
287  LLDB_LOGF(log, "%s", pos.second.GetPath().c_str());
288  }
289  LLDB_LOGF(log, "\nkexts without dSYMs");
290 
291  for (auto pos : m_name_to_kext_path_map_without_dsyms) {
292  LLDB_LOGF(log, "%s", pos.second.GetPath().c_str());
293  }
294  LLDB_LOGF(log, "\nkernel binaries with dSYMS");
295  for (auto fs : m_kernel_binaries_with_dsyms) {
296  LLDB_LOGF(log, "%s", fs.GetPath().c_str());
297  }
298  LLDB_LOGF(log, "\nkernel binaries without dSYMS");
299  for (auto fs : m_kernel_binaries_without_dsyms) {
300  LLDB_LOGF(log, "%s", fs.GetPath().c_str());
301  }
302  LLDB_LOGF(log, "\nkernel dSYMS with no binaries");
303  for (auto fs : m_kernel_dsyms_no_binaries) {
304  LLDB_LOGF(log, "%s", fs.GetPath().c_str());
305  }
306  LLDB_LOGF(log, "\nkernels .dSYM.yaa's");
307  for (auto fs : m_kernel_dsyms_yaas) {
308  LLDB_LOGF(log, "%s", fs.GetPath().c_str());
309  }
310  LLDB_LOGF(log, "\n");
311  }
312 }
313 
314 // Populate the m_search_directories vector with directories we should search
315 // for kernel & kext binaries.
316 
317 void PlatformDarwinKernel::CollectKextAndKernelDirectories() {
318  // Differentiate between "ios debug session" and "mac debug session" so we
319  // don't index kext bundles that won't be used in this debug session. If
320  // this is an ios kext debug session, looking in /System/Library/Extensions
321  // is a waste of stat()s, for example.
322 
323  // DeveloperDirectory is something like
324  // "/Applications/Xcode.app/Contents/Developer"
325  std::string developer_dir = HostInfo::GetXcodeDeveloperDirectory().GetPath();
326  if (developer_dir.empty())
327  developer_dir = "/Applications/Xcode.app/Contents/Developer";
328 
329  if (m_ios_debug_session != eLazyBoolNo) {
330  AddSDKSubdirsToSearchPaths(developer_dir +
331  "/Platforms/iPhoneOS.platform/Developer/SDKs");
332  AddSDKSubdirsToSearchPaths(developer_dir +
333  "/Platforms/AppleTVOS.platform/Developer/SDKs");
334  AddSDKSubdirsToSearchPaths(developer_dir +
335  "/Platforms/WatchOS.platform/Developer/SDKs");
336  AddSDKSubdirsToSearchPaths(developer_dir +
337  "/Platforms/BridgeOS.platform/Developer/SDKs");
338  }
339  if (m_ios_debug_session != eLazyBoolYes) {
340  AddSDKSubdirsToSearchPaths(developer_dir +
341  "/Platforms/MacOSX.platform/Developer/SDKs");
342  }
343 
344  AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit");
345  AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs");
346  // The KDKs distributed from Apple installed on external developer systems
347  // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk
348  AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs");
349 
350  if (m_ios_debug_session != eLazyBoolNo) {
351  }
352  if (m_ios_debug_session != eLazyBoolYes) {
353  AddRootSubdirsToSearchPaths(this, "/");
354  }
355 
356  GetUserSpecifiedDirectoriesToSearch();
357 
358  // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols
359  FileSpec possible_dir(developer_dir + "/../Symbols");
360  FileSystem::Instance().Resolve(possible_dir);
361  if (FileSystem::Instance().IsDirectory(possible_dir))
362  m_search_directories.push_back(possible_dir);
363 
364  // Add simple directory of the current working directory
365  FileSpec cwd(".");
367  m_search_directories_no_recursing.push_back(cwd);
368 }
369 
370 void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() {
371  FileSpecList user_dirs(GetGlobalProperties().GetKextDirectories());
372  std::vector<FileSpec> possible_sdk_dirs;
373 
374  const uint32_t user_dirs_count = user_dirs.GetSize();
375  for (uint32_t i = 0; i < user_dirs_count; i++) {
376  FileSpec dir = user_dirs.GetFileSpecAtIndex(i);
378  if (FileSystem::Instance().IsDirectory(dir)) {
379  m_search_directories.push_back(dir);
380  }
381  }
382 }
383 
384 void PlatformDarwinKernel::AddRootSubdirsToSearchPaths(
385  PlatformDarwinKernel *thisp, const std::string &dir) {
386  const char *subdirs[] = {
387  "/System/Library/Extensions", "/Library/Extensions",
388  "/System/Library/Kernels",
389  "/System/Library/Extensions/KDK", // this one probably only exist in
390  // /AppleInternal/Developer/KDKs/*.kdk/...
391  nullptr};
392  for (int i = 0; subdirs[i] != nullptr; i++) {
393  FileSpec testdir(dir + subdirs[i]);
394  FileSystem::Instance().Resolve(testdir);
395  if (FileSystem::Instance().IsDirectory(testdir))
396  thisp->m_search_directories.push_back(testdir);
397  }
398 
399  // Look for kernel binaries in the top level directory, without any recursion
400  thisp->m_search_directories_no_recursing.push_back(FileSpec(dir + "/"));
401 }
402 
403 // Given a directory path dir, look for any subdirs named *.kdk and *.sdk
404 void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) {
405  // Look for *.kdk and *.sdk in dir
406  const bool find_directories = true;
407  const bool find_files = false;
408  const bool find_other = false;
410  dir.c_str(), find_directories, find_files, find_other,
411  FindKDKandSDKDirectoriesInDirectory, this);
412 }
413 
414 // Helper function to find *.sdk and *.kdk directories in a given directory.
416 PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory(
417  void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
418  static ConstString g_sdk_suffix = ConstString(".sdk");
419  static ConstString g_kdk_suffix = ConstString(".kdk");
420 
421  PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
422  FileSpec file_spec(path);
423  if (ft == llvm::sys::fs::file_type::directory_file &&
424  (file_spec.GetFileNameExtension() == g_sdk_suffix ||
425  file_spec.GetFileNameExtension() == g_kdk_suffix)) {
426  AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath());
427  }
429 }
430 
431 // Recursively search trough m_search_directories looking for kext and kernel
432 // binaries, adding files found to the appropriate lists.
433 void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() {
434  const uint32_t num_dirs = m_search_directories.size();
435  for (uint32_t i = 0; i < num_dirs; i++) {
436  const FileSpec &dir = m_search_directories[i];
437  const bool find_directories = true;
438  const bool find_files = true;
439  const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
441  dir.GetPath().c_str(), find_directories, find_files, find_other,
442  GetKernelsAndKextsInDirectoryWithRecursion, this);
443  }
444  const uint32_t num_dirs_no_recurse = m_search_directories_no_recursing.size();
445  for (uint32_t i = 0; i < num_dirs_no_recurse; i++) {
446  const FileSpec &dir = m_search_directories_no_recursing[i];
447  const bool find_directories = true;
448  const bool find_files = true;
449  const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
451  dir.GetPath().c_str(), find_directories, find_files, find_other,
452  GetKernelsAndKextsInDirectoryNoRecursion, this);
453  }
454 }
455 
456 // We're only doing a filename match here. We won't try opening the file to
457 // see if it's really a kernel or not until we need to find a kernel of a given
458 // UUID. There's no cheap way to find the UUID of a file (or if it's a Mach-O
459 // binary at all) without creating a whole Module for the file and throwing it
460 // away if it's not wanted.
461 //
462 // Recurse into any subdirectories found.
463 
465 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion(
466  void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
467  return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, true);
468 }
469 
471 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion(
472  void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
473  return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, false);
474 }
475 
477 PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper(
478  void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path,
479  bool recurse) {
480  static ConstString g_kext_suffix = ConstString(".kext");
481  static ConstString g_dsym_suffix = ConstString(".dSYM");
482  static ConstString g_bundle_suffix = ConstString("Bundle");
483 
484  FileSpec file_spec(path);
485  ConstString file_spec_extension = file_spec.GetFileNameExtension();
486 
487  Log *log = GetLog(LLDBLog::Platform);
488 
489  LLDB_LOGV(log, "PlatformDarwinKernel examining '{0}'", file_spec);
490 
491  PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton;
492 
493  llvm::StringRef filename = file_spec.GetFilename().GetStringRef();
494  bool is_kernel_filename =
495  filename.startswith("kernel") || filename.startswith("mach");
496  bool is_dsym_yaa = filename.endswith(".dSYM.yaa");
497 
498  if (ft == llvm::sys::fs::file_type::regular_file ||
499  ft == llvm::sys::fs::file_type::symlink_file) {
500  if (is_kernel_filename) {
501  if (file_spec_extension != g_dsym_suffix && !is_dsym_yaa) {
502  if (KernelHasdSYMSibling(file_spec)) {
503  LLDB_LOGF(log,
504  "PlatformDarwinKernel registering kernel binary '%s' with "
505  "dSYM sibling",
506  file_spec.GetPath().c_str());
507  thisp->m_kernel_binaries_with_dsyms.push_back(file_spec);
508  } else {
509  LLDB_LOGF(
510  log,
511  "PlatformDarwinKernel registering kernel binary '%s', no dSYM",
512  file_spec.GetPath().c_str());
513  thisp->m_kernel_binaries_without_dsyms.push_back(file_spec);
514  }
515  }
516  if (is_dsym_yaa) {
517  LLDB_LOGF(log, "PlatformDarwinKernel registering kernel .dSYM.yaa '%s'",
518  file_spec.GetPath().c_str());
519  thisp->m_kernel_dsyms_yaas.push_back(file_spec);
520  }
522  }
523  } else {
524  if (ft == llvm::sys::fs::file_type::directory_file) {
525  if (file_spec_extension == g_kext_suffix) {
526  AddKextToMap(thisp, file_spec);
527  // Look to see if there is a PlugIns subdir with more kexts
528  FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns");
529  std::string search_here_too;
530  if (FileSystem::Instance().IsDirectory(contents_plugins)) {
531  search_here_too = contents_plugins.GetPath();
532  } else {
533  FileSpec plugins(file_spec.GetPath() + "/PlugIns");
534  if (FileSystem::Instance().IsDirectory(plugins)) {
535  search_here_too = plugins.GetPath();
536  }
537  }
538 
539  if (!search_here_too.empty()) {
540  const bool find_directories = true;
541  const bool find_files = false;
542  const bool find_other = false;
544  search_here_too.c_str(), find_directories, find_files, find_other,
545  recurse ? GetKernelsAndKextsInDirectoryWithRecursion
546  : GetKernelsAndKextsInDirectoryNoRecursion,
547  baton);
548  }
550  }
551  // Do we have a kernel dSYM with no kernel binary?
552  if (is_kernel_filename && file_spec_extension == g_dsym_suffix) {
553  if (KerneldSYMHasNoSiblingBinary(file_spec)) {
554  LLDB_LOGF(log,
555  "PlatformDarwinKernel registering kernel dSYM '%s' with "
556  "no binary sibling",
557  file_spec.GetPath().c_str());
558  thisp->m_kernel_dsyms_no_binaries.push_back(file_spec);
560  }
561  }
562  }
563  }
564 
565  // Don't recurse into dSYM/kext/bundle directories
566  if (recurse && file_spec_extension != g_dsym_suffix &&
567  file_spec_extension != g_kext_suffix &&
568  file_spec_extension != g_bundle_suffix) {
569  LLDB_LOGV(log, "PlatformDarwinKernel descending into directory '{0}'",
570  file_spec);
572  } else {
574  }
575 }
576 
577 void PlatformDarwinKernel::AddKextToMap(PlatformDarwinKernel *thisp,
578  const FileSpec &file_spec) {
579  Log *log = GetLog(LLDBLog::Platform);
580  CFCBundle bundle(file_spec.GetPath().c_str());
581  CFStringRef bundle_id(bundle.GetIdentifier());
582  if (bundle_id && CFGetTypeID(bundle_id) == CFStringGetTypeID()) {
583  char bundle_id_buf[PATH_MAX];
584  if (CFStringGetCString(bundle_id, bundle_id_buf, sizeof(bundle_id_buf),
585  kCFStringEncodingUTF8)) {
586  ConstString bundle_conststr(bundle_id_buf);
587  if (KextHasdSYMSibling(file_spec))
588  {
589  LLDB_LOGF(log,
590  "PlatformDarwinKernel registering kext binary '%s' with dSYM "
591  "sibling",
592  file_spec.GetPath().c_str());
593  thisp->m_name_to_kext_path_map_with_dsyms.insert(
594  std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
595  }
596  else
597  {
598  LLDB_LOGF(log,
599  "PlatformDarwinKernel registering kext binary '%s', no dSYM",
600  file_spec.GetPath().c_str());
601  thisp->m_name_to_kext_path_map_without_dsyms.insert(
602  std::pair<ConstString, FileSpec>(bundle_conststr, file_spec));
603  }
604  }
605  }
606 }
607 
608 // Given a FileSpec of /dir/dir/foo.kext
609 // Return true if any of these exist:
610 // /dir/dir/foo.kext.dSYM
611 // /dir/dir/foo.kext/Contents/MacOS/foo.dSYM
612 // /dir/dir/foo.kext/foo.dSYM
613 bool PlatformDarwinKernel::KextHasdSYMSibling(
614  const FileSpec &kext_bundle_filepath) {
615  FileSpec dsym_fspec = kext_bundle_filepath;
616  std::string filename = dsym_fspec.GetFilename().AsCString();
617  filename += ".dSYM";
618  dsym_fspec.GetFilename() = ConstString(filename);
619  if (FileSystem::Instance().IsDirectory(dsym_fspec)) {
620  return true;
621  }
622  // Should probably get the CFBundleExecutable here or call
623  // CFBundleCopyExecutableURL
624 
625  // Look for a deep bundle foramt
626  ConstString executable_name =
627  kext_bundle_filepath.GetFileNameStrippingExtension();
628  std::string deep_bundle_str =
629  kext_bundle_filepath.GetPath() + "/Contents/MacOS/";
630  deep_bundle_str += executable_name.AsCString();
631  deep_bundle_str += ".dSYM";
632  dsym_fspec.SetFile(deep_bundle_str, FileSpec::Style::native);
633  FileSystem::Instance().Resolve(dsym_fspec);
634  if (FileSystem::Instance().IsDirectory(dsym_fspec)) {
635  return true;
636  }
637 
638  // look for a shallow bundle format
639  //
640  std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/";
641  shallow_bundle_str += executable_name.AsCString();
642  shallow_bundle_str += ".dSYM";
643  dsym_fspec.SetFile(shallow_bundle_str, FileSpec::Style::native);
644  FileSystem::Instance().Resolve(dsym_fspec);
645  return FileSystem::Instance().IsDirectory(dsym_fspec);
646 }
647 
648 // Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM
649 // exists next to it:
650 // /dir/dir/mach.development.t7004.dSYM
651 bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) {
652  FileSpec kernel_dsym = kernel_binary;
653  std::string filename = kernel_binary.GetFilename().AsCString();
654  filename += ".dSYM";
655  kernel_dsym.GetFilename() = ConstString(filename);
656  return FileSystem::Instance().IsDirectory(kernel_dsym);
657 }
658 
659 // Given a FileSpec of /dir/dir/mach.development.t7004.dSYM
660 // Return true if only the dSYM exists, no binary next to it.
661 // /dir/dir/mach.development.t7004.dSYM
662 // but no
663 // /dir/dir/mach.development.t7004
664 bool PlatformDarwinKernel::KerneldSYMHasNoSiblingBinary(
665  const FileSpec &kernel_dsym) {
666  static ConstString g_dsym_suffix = ConstString(".dSYM");
667  std::string possible_path = kernel_dsym.GetPath();
668  if (kernel_dsym.GetFileNameExtension() != g_dsym_suffix)
669  return false;
670 
671  FileSpec binary_filespec = kernel_dsym;
672  // Chop off the '.dSYM' extension on the filename
673  binary_filespec.GetFilename() =
674  binary_filespec.GetFileNameStrippingExtension();
675 
676  // Is there a binary next to this this? Then return false.
677  if (FileSystem::Instance().Exists(binary_filespec))
678  return false;
679 
680  // If we have at least one binary in the DWARF subdir, then
681  // this is a properly formed dSYM and it has no binary next
682  // to it.
683  if (GetDWARFBinaryInDSYMBundle(kernel_dsym).size() > 0)
684  return true;
685 
686  return false;
687 }
688 
689 // TODO: This method returns a vector of FileSpec's because a
690 // dSYM bundle may contain multiple DWARF binaries, but it
691 // only implements returning the base name binary for now;
692 // it should iterate over every binary in the DWARF subdir
693 // and return them all.
694 std::vector<FileSpec>
695 PlatformDarwinKernel::GetDWARFBinaryInDSYMBundle(FileSpec dsym_bundle) {
696  std::vector<FileSpec> results;
697  static ConstString g_dsym_suffix = ConstString(".dSYM");
698  if (dsym_bundle.GetFileNameExtension() != g_dsym_suffix) {
699  return results;
700  }
701  // Drop the '.dSYM' from the filename
702  std::string filename =
704  std::string dirname = dsym_bundle.GetDirectory().GetCString();
705 
706  std::string binary_filepath = dsym_bundle.GetPath();
707  binary_filepath += "/Contents/Resources/DWARF/";
708  binary_filepath += filename;
709 
710  FileSpec binary_fspec(binary_filepath);
711  if (FileSystem::Instance().Exists(binary_fspec))
712  results.push_back(binary_fspec);
713  return results;
714 }
715 
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) {
720  Status error;
721  module_sp.reset();
722  const FileSpec &platform_file = module_spec.GetFileSpec();
723 
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();
727 
728  if (!kext_bundle_id.empty() && module_spec.GetUUID().IsValid()) {
729  if (kext_bundle_id == "mach_kernel") {
730  return GetSharedModuleKernel(module_spec, process, module_sp,
731  module_search_paths_ptr, old_modules,
732  did_create_ptr);
733  } else {
734  return GetSharedModuleKext(module_spec, process, module_sp,
735  module_search_paths_ptr, old_modules,
736  did_create_ptr);
737  }
738  } else {
739  // Give the generic methods, including possibly calling into DebugSymbols
740  // framework on macOS systems, a chance.
741  return PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
742  module_search_paths_ptr, old_modules,
743  did_create_ptr);
744  }
745 }
746 
747 Status PlatformDarwinKernel::GetSharedModuleKext(
748  const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
749  const FileSpecList *module_search_paths_ptr,
750  llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
751  Status error;
752  module_sp.reset();
753  const FileSpec &platform_file = module_spec.GetFileSpec();
754 
755  // Treat the file's path as a kext bundle ID (e.g.
756  // "com.apple.driver.AppleIRController") and search our kext index.
757  ConstString kext_bundle(platform_file.GetPath().c_str());
758  // First look through the kext bundles that had a dsym next to them
759  if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle) > 0) {
760  for (BundleIDToKextIterator it = m_name_to_kext_path_map_with_dsyms.begin();
761  it != m_name_to_kext_path_map_with_dsyms.end(); ++it) {
762  if (it->first == kext_bundle) {
763  error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(),
764  module_spec.GetArchitecture(),
765  module_sp);
766  if (module_sp.get()) {
767  return error;
768  }
769  }
770  }
771  }
772 
773  // Give the generic methods, including possibly calling into DebugSymbols
774  // framework on macOS systems, a chance.
775  error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
776  module_search_paths_ptr, old_modules,
777  did_create_ptr);
778  if (error.Success() && module_sp.get()) {
779  return error;
780  }
781 
782  return error;
783 }
784 
785 Status PlatformDarwinKernel::GetSharedModuleKernel(
786  const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
787  const FileSpecList *module_search_paths_ptr,
788  llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
789  Status error;
790  module_sp.reset();
791 
792  // First try all kernel binaries that have a dSYM next to them
793  for (auto possible_kernel : m_kernel_binaries_with_dsyms) {
794  if (FileSystem::Instance().Exists(possible_kernel)) {
795  ModuleSpec kern_spec(possible_kernel);
796  kern_spec.GetUUID() = module_spec.GetUUID();
797  module_sp.reset(new Module(kern_spec));
798  if (module_sp && module_sp->GetObjectFile() &&
799  module_sp->MatchesModuleSpec(kern_spec)) {
800  // module_sp is an actual kernel binary we want to add.
801  if (process) {
802  process->GetTarget().GetImages().AppendIfNeeded(module_sp);
803  error.Clear();
804  return error;
805  } else {
806  error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr,
807  nullptr, nullptr);
808  if (module_sp && module_sp->GetObjectFile() &&
809  module_sp->GetObjectFile()->GetType() !=
810  ObjectFile::Type::eTypeCoreFile) {
811  return error;
812  }
813  module_sp.reset();
814  }
815  }
816  }
817  }
818 
819  // Next try all dSYMs that have no kernel binary next to them (load
820  // the kernel DWARF stub as the main binary)
821  for (auto possible_kernel_dsym : m_kernel_dsyms_no_binaries) {
822  std::vector<FileSpec> objfile_names =
823  GetDWARFBinaryInDSYMBundle(possible_kernel_dsym);
824  for (FileSpec objfile : objfile_names) {
825  ModuleSpec kern_spec(objfile);
826  kern_spec.GetUUID() = module_spec.GetUUID();
827  kern_spec.GetSymbolFileSpec() = possible_kernel_dsym;
828 
829  module_sp.reset(new Module(kern_spec));
830  if (module_sp && module_sp->GetObjectFile() &&
831  module_sp->MatchesModuleSpec(kern_spec)) {
832  // module_sp is an actual kernel binary we want to add.
833  if (process) {
834  process->GetTarget().GetImages().AppendIfNeeded(module_sp);
835  error.Clear();
836  return error;
837  } else {
838  error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr,
839  nullptr, nullptr);
840  if (module_sp && module_sp->GetObjectFile() &&
841  module_sp->GetObjectFile()->GetType() !=
842  ObjectFile::Type::eTypeCoreFile) {
843  return error;
844  }
845  module_sp.reset();
846  }
847  }
848  }
849  }
850 
851  // Give the generic methods, including possibly calling into DebugSymbols
852  // framework on macOS systems, a chance.
853  error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
854  module_search_paths_ptr, old_modules,
855  did_create_ptr);
856  if (error.Success() && module_sp.get()) {
857  return error;
858  }
859 
860  return error;
861 }
862 
863 std::vector<lldb_private::FileSpec>
864 PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string &dir) {
865  std::vector<FileSpec> executables;
866  std::error_code EC;
867  for (llvm::sys::fs::recursive_directory_iterator it(dir.c_str(), EC),
868  end;
869  it != end && !EC; it.increment(EC)) {
870  auto status = it->status();
871  if (!status)
872  break;
873  if (llvm::sys::fs::is_regular_file(*status) &&
874  llvm::sys::fs::can_execute(it->path()))
875  executables.emplace_back(it->path());
876  }
877  return executables;
878 }
879 
880 Status PlatformDarwinKernel::ExamineKextForMatchingUUID(
881  const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid,
882  const ArchSpec &arch, ModuleSP &exe_module_sp) {
883  for (const auto &exe_file :
884  SearchForExecutablesRecursively(kext_bundle_path.GetPath())) {
885  if (FileSystem::Instance().Exists(exe_file)) {
886  ModuleSpec exe_spec(exe_file);
887  exe_spec.GetUUID() = uuid;
888  if (!uuid.IsValid()) {
889  exe_spec.GetArchitecture() = arch;
890  }
891 
892  // First try to create a ModuleSP with the file / arch and see if the UUID
893  // matches. If that fails (this exec file doesn't have the correct uuid),
894  // don't call GetSharedModule (which may call in to the DebugSymbols
895  // framework and therefore can be slow.)
896  ModuleSP module_sp(new Module(exe_spec));
897  if (module_sp && module_sp->GetObjectFile() &&
898  module_sp->MatchesModuleSpec(exe_spec)) {
899  Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp,
900  NULL, NULL, NULL);
901  if (exe_module_sp && exe_module_sp->GetObjectFile()) {
902  return error;
903  }
904  }
905  exe_module_sp.reset();
906  }
907  }
908 
909  return {};
910 }
911 
912 std::vector<ArchSpec> PlatformDarwinKernel::GetSupportedArchitectures(
913  const ArchSpec &process_host_arch) {
914  std::vector<ArchSpec> result;
915 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
916  ARMGetSupportedArchitectures(result);
917 #else
918  x86GetSupportedArchitectures(result);
919 #endif
920  return result;
921 }
922 
923 void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() {
924  m_trap_handlers.push_back(ConstString("trap_from_kernel"));
925  m_trap_handlers.push_back(ConstString("hndl_machine_check"));
926  m_trap_handlers.push_back(ConstString("hndl_double_fault"));
927  m_trap_handlers.push_back(ConstString("hndl_allintrs"));
928  m_trap_handlers.push_back(ConstString("hndl_alltraps"));
929  m_trap_handlers.push_back(ConstString("interrupt"));
930  m_trap_handlers.push_back(ConstString("fleh_prefabt"));
931  m_trap_handlers.push_back(ConstString("ExceptionVectorsBase"));
932  m_trap_handlers.push_back(ConstString("ExceptionVectorsTable"));
933  m_trap_handlers.push_back(ConstString("fleh_undef"));
934  m_trap_handlers.push_back(ConstString("fleh_dataabt"));
935  m_trap_handlers.push_back(ConstString("fleh_irq"));
936  m_trap_handlers.push_back(ConstString("fleh_decirq"));
937  m_trap_handlers.push_back(ConstString("fleh_fiq_generic"));
938  m_trap_handlers.push_back(ConstString("fleh_dec"));
939 }
940 
941 #endif // __APPLE__
lldb_private::UUID
Definition: UUID.h:23
lldb_private::ArchSpec
Definition: ArchSpec.h:33
lldb_private::ArchSpec::TripleVendorWasSpecified
bool TripleVendorWasSpecified() const
Definition: ArchSpec.h:358
lldb_private::ArchSpec::GetMachine
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:668
ModuleSpec.h
Host.h
lldb_private::UUID::IsValid
bool IsValid() const
Definition: UUID.h:79
lldb_private::eLazyBoolYes
@ eLazyBoolYes
Definition: lldb-private-enumerations.h:115
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:343
lldb_private::Process
Definition: Process.h:338
Module.h
BreakpointLocation.h
lldb_private::Process::GetTarget
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1206
lldb_private::FileSystem::IsDirectory
bool IsDirectory(const FileSpec &file_spec) const
Returns whether the given path is a directory.
Definition: common/FileSystem.cpp:169
lldb_private::Module
Definition: Module.h:85
lldb_private::ConstString::AsCString
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:193
CFCBundle.h
lldb_private::Stream
Definition: Stream.h:28
lldb_private::ArchSpec::GetTriple
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:455
lldb_private::LazyBool
LazyBool
Definition: lldb-private-enumerations.h:115
LLDB_LOGV
#define LLDB_LOGV(log,...)
Definition: Log.h:350
lldb_private::Target::GetImages
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:947
Process.h
Target.h
lldb_private::ModuleSpec::GetUUID
UUID & GetUUID()
Definition: ModuleSpec.h:99
lldb_private::Properties
Definition: UserSettingsController.h:33
Platform.h
lldb_private::FileSpec
Definition: FileSpec.h:56
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
ModuleList.h
Log.h
StreamString.h
lldb_private::FileSystem::EnumerateDirectoryResult
EnumerateDirectoryResult
Definition: FileSystem.h:166
Property.h
lldb_private::ConstString
Definition: ConstString.h:40
lldb_private::ArchSpec::TripleOSWasSpecified
bool TripleOSWasSpecified() const
Definition: ArchSpec.h:362
lldb_private::Debugger
Definition: Debugger.h:74
HostInfo.h
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::FileSystem::Resolve
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
Definition: common/FileSystem.cpp:235
lldb_private::ArchSpec::IsValid
bool IsValid() const
Tests if this ArchSpec is valid.
Definition: ArchSpec.h:353
CFCBundle
Definition: CFCBundle.h:14
OptionValueProperties.h
lldb_private::PlatformDarwin::GetSharedModule
Status GetSharedModule(const ModuleSpec &module_spec, Process *process, lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr) override
Definition: PlatformDarwin.cpp:332
ObjectFile.h
lldb_private::ModuleSpec::GetFileSpec
FileSpec & GetFileSpec()
Definition: ModuleSpec.h:53
lldb_private::ModuleSpec
Definition: ModuleSpec.h:27
lldb_private::FileSystem::eEnumerateDirectoryResultNext
@ eEnumerateDirectoryResultNext
Enumerate next entry in the current directory.
Definition: FileSystem.h:168
lldb_private::Status
Definition: Status.h:44
lldb_private::ArchSpec::GetArchitectureName
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition: ArchSpec.cpp:539
lldb_private::OptionValueFileSpecList::GetCurrentValue
FileSpecList GetCurrentValue() const
Definition: OptionValueFileSpecList.h:50
uint32_t
lldb_private::eLazyBoolNo
@ eLazyBoolNo
Definition: lldb-private-enumerations.h:115
lldb_private::FileSystem::eEnumerateDirectoryResultEnter
@ eEnumerateDirectoryResultEnter
Recurse into the current entry if it is a directory or symlink, or next if not.
Definition: FileSystem.h:171
PlatformDarwinKernel.h
lldb_private::ModuleList::AppendIfNeeded
bool AppendIfNeeded(const lldb::ModuleSP &new_module, bool notify=true)
Append a module to the module list, if it is not already there.
lldb_private::FileSystem::EnumerateDirectory
void EnumerateDirectory(llvm::Twine path, bool find_directories, bool find_files, bool find_other, EnumerateDirectoryCallbackType callback, void *callback_baton)
Definition: common/FileSystem.cpp:183
ArchSpec.h
PluginManager.h
lldb_private::ConstString::GetCString
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:216
lldb_private::ModuleSpec::GetArchitecture
ArchSpec & GetArchitecture()
Definition: ModuleSpec.h:89
lldb_private::PlatformDarwinKernel
Definition: PlatformDarwinKernel.h:208
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
lldb_private::OptionValueFileSpecList
Definition: OptionValueFileSpecList.h:19
lldb_private::FileSystem::Instance
static FileSystem & Instance()
Definition: common/FileSystem.cpp:46
Status.h
lldb_private::LLDBLog::Platform
@ Platform
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::eLazyBoolCalculate
@ eLazyBoolCalculate
Definition: lldb-private-enumerations.h:115
FileSpec.h
GetGlobalProperties
static DynamicLoaderDarwinKernelProperties & GetGlobalProperties()
Definition: DynamicLoaderDarwinKernel.cpp:128
lldb_private::FileSpec::GetDirectory
ConstString & GetDirectory()
Directory string get accessor.
Definition: FileSpec.cpp:334
OptionValueFileSpecList.h
lldb_private::Platform::GetStatus
virtual void GetStatus(Stream &strm)
Report the current status for this platform.
Definition: Platform.cpp:285
lldb_private::Log
Definition: Log.h:115
lldb_private::FileSpec::SetFile
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:172
llvm::SmallVectorImpl
Definition: Disassembler.h:42
PATH_MAX
#define PATH_MAX
Definition: windows/PosixApi.h:25
lldb_private::GetLog
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:308
lldb_private::FileSpec::GetPath
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:347
g_initialize_count
static uint32_t g_initialize_count
Definition: PlatformAndroid.cpp:31
lldb
Definition: SBAddress.h:15
lldb_private::FileSpec::GetFileNameExtension
ConstString GetFileNameExtension() const
Extract the extension of the file.
Definition: FileSpec.cpp:383
lldb_private::ModuleList::GetSharedModule
static Status GetSharedModule(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr, bool always_create=false)
Definition: ModuleList.cpp:777
lldb_private::PlatformDarwin
Definition: PlatformDarwin.h:45
lldb_private::FileSpec::GetFilename
ConstString & GetFilename()
Filename string get accessor.
Definition: FileSpec.cpp:340
LLDBLog.h
lldb_private::FileSpec::GetFileNameStrippingExtension
ConstString GetFileNameStrippingExtension() const
Return the filename without the extension part.
Definition: FileSpec.cpp:388