1 //===-- PlatformDarwin.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 "PlatformDarwin.h"
10
11 #include <string.h>
12
13 #include <algorithm>
14 #include <memory>
15 #include <mutex>
16
17 #include "lldb/Breakpoint/BreakpointLocation.h"
18 #include "lldb/Breakpoint/BreakpointSite.h"
19 #include "lldb/Core/Debugger.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/ModuleSpec.h"
22 #include "lldb/Core/Section.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Host/HostInfo.h"
25 #include "lldb/Host/XML.h"
26 #include "lldb/Interpreter/CommandInterpreter.h"
27 #include "lldb/Symbol/LocateSymbolFile.h"
28 #include "lldb/Symbol/ObjectFile.h"
29 #include "lldb/Symbol/SymbolFile.h"
30 #include "lldb/Symbol/SymbolVendor.h"
31 #include "lldb/Target/Platform.h"
32 #include "lldb/Target/Process.h"
33 #include "lldb/Target/Target.h"
34 #include "lldb/Utility/Log.h"
35 #include "lldb/Utility/ProcessInfo.h"
36 #include "lldb/Utility/Status.h"
37 #include "lldb/Utility/Timer.h"
38 #include "llvm/ADT/STLExtras.h"
39 #include "llvm/Support/FileSystem.h"
40 #include "llvm/Support/Threading.h"
41 #include "llvm/Support/VersionTuple.h"
42
43 #if defined(__APPLE__)
44 #include <TargetConditionals.h>
45 #endif
46
47 using namespace lldb;
48 using namespace lldb_private;
49
50 /// Default Constructor
PlatformDarwin(bool is_host)51 PlatformDarwin::PlatformDarwin(bool is_host) : PlatformPOSIX(is_host) {}
52
53 /// Destructor.
54 ///
55 /// The destructor is virtual since this class is designed to be
56 /// inherited from by the plug-in instance.
~PlatformDarwin()57 PlatformDarwin::~PlatformDarwin() {}
58
59 lldb_private::Status
PutFile(const lldb_private::FileSpec & source,const lldb_private::FileSpec & destination,uint32_t uid,uint32_t gid)60 PlatformDarwin::PutFile(const lldb_private::FileSpec &source,
61 const lldb_private::FileSpec &destination, uint32_t uid,
62 uint32_t gid) {
63 // Unconditionally unlink the destination. If it is an executable,
64 // simply opening it and truncating its contents would invalidate
65 // its cached code signature.
66 Unlink(destination);
67 return PlatformPOSIX::PutFile(source, destination, uid, gid);
68 }
69
LocateExecutableScriptingResources(Target * target,Module & module,Stream * feedback_stream)70 FileSpecList PlatformDarwin::LocateExecutableScriptingResources(
71 Target *target, Module &module, Stream *feedback_stream) {
72 FileSpecList file_list;
73 if (target &&
74 target->GetDebugger().GetScriptLanguage() == eScriptLanguagePython) {
75 // NB some extensions might be meaningful and should not be stripped -
76 // "this.binary.file"
77 // should not lose ".file" but GetFileNameStrippingExtension() will do
78 // precisely that. Ideally, we should have a per-platform list of
79 // extensions (".exe", ".app", ".dSYM", ".framework") which should be
80 // stripped while leaving "this.binary.file" as-is.
81
82 FileSpec module_spec = module.GetFileSpec();
83
84 if (module_spec) {
85 if (SymbolFile *symfile = module.GetSymbolFile()) {
86 ObjectFile *objfile = symfile->GetObjectFile();
87 if (objfile) {
88 FileSpec symfile_spec(objfile->GetFileSpec());
89 if (symfile_spec &&
90 strcasestr(symfile_spec.GetPath().c_str(),
91 ".dSYM/Contents/Resources/DWARF") != nullptr &&
92 FileSystem::Instance().Exists(symfile_spec)) {
93 while (module_spec.GetFilename()) {
94 std::string module_basename(
95 module_spec.GetFilename().GetCString());
96 std::string original_module_basename(module_basename);
97
98 bool was_keyword = false;
99
100 // FIXME: for Python, we cannot allow certain characters in
101 // module
102 // filenames we import. Theoretically, different scripting
103 // languages may have different sets of forbidden tokens in
104 // filenames, and that should be dealt with by each
105 // ScriptInterpreter. For now, we just replace dots with
106 // underscores, but if we ever support anything other than
107 // Python we will need to rework this
108 std::replace(module_basename.begin(), module_basename.end(), '.',
109 '_');
110 std::replace(module_basename.begin(), module_basename.end(), ' ',
111 '_');
112 std::replace(module_basename.begin(), module_basename.end(), '-',
113 '_');
114 ScriptInterpreter *script_interpreter =
115 target->GetDebugger().GetScriptInterpreter();
116 if (script_interpreter &&
117 script_interpreter->IsReservedWord(module_basename.c_str())) {
118 module_basename.insert(module_basename.begin(), '_');
119 was_keyword = true;
120 }
121
122 StreamString path_string;
123 StreamString original_path_string;
124 // for OSX we are going to be in
125 // .dSYM/Contents/Resources/DWARF/<basename> let us go to
126 // .dSYM/Contents/Resources/Python/<basename>.py and see if the
127 // file exists
128 path_string.Printf("%s/../Python/%s.py",
129 symfile_spec.GetDirectory().GetCString(),
130 module_basename.c_str());
131 original_path_string.Printf(
132 "%s/../Python/%s.py",
133 symfile_spec.GetDirectory().GetCString(),
134 original_module_basename.c_str());
135 FileSpec script_fspec(path_string.GetString());
136 FileSystem::Instance().Resolve(script_fspec);
137 FileSpec orig_script_fspec(original_path_string.GetString());
138 FileSystem::Instance().Resolve(orig_script_fspec);
139
140 // if we did some replacements of reserved characters, and a
141 // file with the untampered name exists, then warn the user
142 // that the file as-is shall not be loaded
143 if (feedback_stream) {
144 if (module_basename != original_module_basename &&
145 FileSystem::Instance().Exists(orig_script_fspec)) {
146 const char *reason_for_complaint =
147 was_keyword ? "conflicts with a keyword"
148 : "contains reserved characters";
149 if (FileSystem::Instance().Exists(script_fspec))
150 feedback_stream->Printf(
151 "warning: the symbol file '%s' contains a debug "
152 "script. However, its name"
153 " '%s' %s and as such cannot be loaded. LLDB will"
154 " load '%s' instead. Consider removing the file with "
155 "the malformed name to"
156 " eliminate this warning.\n",
157 symfile_spec.GetPath().c_str(),
158 original_path_string.GetData(), reason_for_complaint,
159 path_string.GetData());
160 else
161 feedback_stream->Printf(
162 "warning: the symbol file '%s' contains a debug "
163 "script. However, its name"
164 " %s and as such cannot be loaded. If you intend"
165 " to have this script loaded, please rename '%s' to "
166 "'%s' and retry.\n",
167 symfile_spec.GetPath().c_str(), reason_for_complaint,
168 original_path_string.GetData(), path_string.GetData());
169 }
170 }
171
172 if (FileSystem::Instance().Exists(script_fspec)) {
173 file_list.Append(script_fspec);
174 break;
175 }
176
177 // If we didn't find the python file, then keep stripping the
178 // extensions and try again
179 ConstString filename_no_extension(
180 module_spec.GetFileNameStrippingExtension());
181 if (module_spec.GetFilename() == filename_no_extension)
182 break;
183
184 module_spec.GetFilename() = filename_no_extension;
185 }
186 }
187 }
188 }
189 }
190 }
191 return file_list;
192 }
193
ResolveSymbolFile(Target & target,const ModuleSpec & sym_spec,FileSpec & sym_file)194 Status PlatformDarwin::ResolveSymbolFile(Target &target,
195 const ModuleSpec &sym_spec,
196 FileSpec &sym_file) {
197 sym_file = sym_spec.GetSymbolFileSpec();
198 if (FileSystem::Instance().IsDirectory(sym_file)) {
199 sym_file = Symbols::FindSymbolFileInBundle(sym_file, sym_spec.GetUUIDPtr(),
200 sym_spec.GetArchitecturePtr());
201 }
202 return {};
203 }
204
205 static lldb_private::Status
MakeCacheFolderForFile(const FileSpec & module_cache_spec)206 MakeCacheFolderForFile(const FileSpec &module_cache_spec) {
207 FileSpec module_cache_folder =
208 module_cache_spec.CopyByRemovingLastPathComponent();
209 return llvm::sys::fs::create_directory(module_cache_folder.GetPath());
210 }
211
212 static lldb_private::Status
BringInRemoteFile(Platform * platform,const lldb_private::ModuleSpec & module_spec,const FileSpec & module_cache_spec)213 BringInRemoteFile(Platform *platform,
214 const lldb_private::ModuleSpec &module_spec,
215 const FileSpec &module_cache_spec) {
216 MakeCacheFolderForFile(module_cache_spec);
217 Status err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
218 return err;
219 }
220
GetSharedModuleWithLocalCache(const lldb_private::ModuleSpec & module_spec,lldb::ModuleSP & module_sp,const lldb_private::FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<lldb::ModuleSP> * old_modules,bool * did_create_ptr)221 lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache(
222 const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
223 const lldb_private::FileSpecList *module_search_paths_ptr,
224 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
225
226 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
227 LLDB_LOGF(log,
228 "[%s] Trying to find module %s/%s - platform path %s/%s symbol "
229 "path %s/%s",
230 (IsHost() ? "host" : "remote"),
231 module_spec.GetFileSpec().GetDirectory().AsCString(),
232 module_spec.GetFileSpec().GetFilename().AsCString(),
233 module_spec.GetPlatformFileSpec().GetDirectory().AsCString(),
234 module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
235 module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
236 module_spec.GetSymbolFileSpec().GetFilename().AsCString());
237
238 Status err;
239
240 if (IsHost()) {
241 // When debugging on the host, we are most likely using the same shared
242 // cache as our inferior. The dylibs from the shared cache might not
243 // exist on the filesystem, so let's use the images in our own memory
244 // to create the modules.
245
246 // Check if the requested image is in our shared cache.
247 SharedCacheImageInfo image_info =
248 HostInfo::GetSharedCacheImageInfo(module_spec.GetFileSpec().GetPath());
249
250 // If we found it and it has the correct UUID, let's proceed with
251 // creating a module from the memory contents.
252 if (image_info.uuid &&
253 (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) {
254 ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
255 image_info.data_sp);
256 err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
257 module_search_paths_ptr, old_modules,
258 did_create_ptr);
259 if (module_sp)
260 return err;
261 }
262 }
263
264 err = ModuleList::GetSharedModule(module_spec, module_sp,
265 module_search_paths_ptr, old_modules,
266 did_create_ptr);
267 if (module_sp)
268 return err;
269
270 if (!IsHost()) {
271 std::string cache_path(GetLocalCacheDirectory());
272 // Only search for a locally cached file if we have a valid cache path
273 if (!cache_path.empty()) {
274 std::string module_path(module_spec.GetFileSpec().GetPath());
275 cache_path.append(module_path);
276 FileSpec module_cache_spec(cache_path);
277
278 // if rsync is supported, always bring in the file - rsync will be very
279 // efficient when files are the same on the local and remote end of the
280 // connection
281 if (this->GetSupportsRSync()) {
282 err = BringInRemoteFile(this, module_spec, module_cache_spec);
283 if (err.Fail())
284 return err;
285 if (FileSystem::Instance().Exists(module_cache_spec)) {
286 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
287 LLDB_LOGF(log, "[%s] module %s/%s was rsynced and is now there",
288 (IsHost() ? "host" : "remote"),
289 module_spec.GetFileSpec().GetDirectory().AsCString(),
290 module_spec.GetFileSpec().GetFilename().AsCString());
291 ModuleSpec local_spec(module_cache_spec,
292 module_spec.GetArchitecture());
293 module_sp = std::make_shared<Module>(local_spec);
294 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
295 return Status();
296 }
297 }
298
299 // try to find the module in the cache
300 if (FileSystem::Instance().Exists(module_cache_spec)) {
301 // get the local and remote MD5 and compare
302 if (m_remote_platform_sp) {
303 // when going over the *slow* GDB remote transfer mechanism we first
304 // check the hashes of the files - and only do the actual transfer if
305 // they differ
306 uint64_t high_local, high_remote, low_local, low_remote;
307 auto MD5 = llvm::sys::fs::md5_contents(module_cache_spec.GetPath());
308 if (!MD5)
309 return Status(MD5.getError());
310 std::tie(high_local, low_local) = MD5->words();
311
312 m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec(),
313 low_remote, high_remote);
314 if (low_local != low_remote || high_local != high_remote) {
315 // bring in the remote file
316 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
317 LLDB_LOGF(log,
318 "[%s] module %s/%s needs to be replaced from remote copy",
319 (IsHost() ? "host" : "remote"),
320 module_spec.GetFileSpec().GetDirectory().AsCString(),
321 module_spec.GetFileSpec().GetFilename().AsCString());
322 Status err =
323 BringInRemoteFile(this, module_spec, module_cache_spec);
324 if (err.Fail())
325 return err;
326 }
327 }
328
329 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
330 module_sp = std::make_shared<Module>(local_spec);
331 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
332 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
333 LLDB_LOGF(log, "[%s] module %s/%s was found in the cache",
334 (IsHost() ? "host" : "remote"),
335 module_spec.GetFileSpec().GetDirectory().AsCString(),
336 module_spec.GetFileSpec().GetFilename().AsCString());
337 return Status();
338 }
339
340 // bring in the remote module file
341 LLDB_LOGF(log, "[%s] module %s/%s needs to come in remotely",
342 (IsHost() ? "host" : "remote"),
343 module_spec.GetFileSpec().GetDirectory().AsCString(),
344 module_spec.GetFileSpec().GetFilename().AsCString());
345 Status err = BringInRemoteFile(this, module_spec, module_cache_spec);
346 if (err.Fail())
347 return err;
348 if (FileSystem::Instance().Exists(module_cache_spec)) {
349 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
350 LLDB_LOGF(log, "[%s] module %s/%s is now cached and fine",
351 (IsHost() ? "host" : "remote"),
352 module_spec.GetFileSpec().GetDirectory().AsCString(),
353 module_spec.GetFileSpec().GetFilename().AsCString());
354 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
355 module_sp = std::make_shared<Module>(local_spec);
356 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
357 return Status();
358 } else
359 return Status("unable to obtain valid module file");
360 } else
361 return Status("no cache path");
362 } else
363 return Status("unable to resolve module");
364 }
365
GetSharedModule(const ModuleSpec & module_spec,Process * process,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<ModuleSP> * old_modules,bool * did_create_ptr)366 Status PlatformDarwin::GetSharedModule(
367 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
368 const FileSpecList *module_search_paths_ptr,
369 llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
370 Status error;
371 module_sp.reset();
372
373 if (IsRemote()) {
374 // If we have a remote platform always, let it try and locate the shared
375 // module first.
376 if (m_remote_platform_sp) {
377 error = m_remote_platform_sp->GetSharedModule(
378 module_spec, process, module_sp, module_search_paths_ptr, old_modules,
379 did_create_ptr);
380 }
381 }
382
383 if (!module_sp) {
384 // Fall back to the local platform and find the file locally
385 error = Platform::GetSharedModule(module_spec, process, module_sp,
386 module_search_paths_ptr, old_modules,
387 did_create_ptr);
388
389 const FileSpec &platform_file = module_spec.GetFileSpec();
390 if (!module_sp && module_search_paths_ptr && platform_file) {
391 // We can try to pull off part of the file path up to the bundle
392 // directory level and try any module search paths...
393 FileSpec bundle_directory;
394 if (Host::GetBundleDirectory(platform_file, bundle_directory)) {
395 if (platform_file == bundle_directory) {
396 ModuleSpec new_module_spec(module_spec);
397 new_module_spec.GetFileSpec() = bundle_directory;
398 if (Host::ResolveExecutableInBundle(new_module_spec.GetFileSpec())) {
399 Status new_error(Platform::GetSharedModule(
400 new_module_spec, process, module_sp, nullptr, old_modules,
401 did_create_ptr));
402
403 if (module_sp)
404 return new_error;
405 }
406 } else {
407 char platform_path[PATH_MAX];
408 char bundle_dir[PATH_MAX];
409 platform_file.GetPath(platform_path, sizeof(platform_path));
410 const size_t bundle_directory_len =
411 bundle_directory.GetPath(bundle_dir, sizeof(bundle_dir));
412 char new_path[PATH_MAX];
413 size_t num_module_search_paths = module_search_paths_ptr->GetSize();
414 for (size_t i = 0; i < num_module_search_paths; ++i) {
415 const size_t search_path_len =
416 module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath(
417 new_path, sizeof(new_path));
418 if (search_path_len < sizeof(new_path)) {
419 snprintf(new_path + search_path_len,
420 sizeof(new_path) - search_path_len, "/%s",
421 platform_path + bundle_directory_len);
422 FileSpec new_file_spec(new_path);
423 if (FileSystem::Instance().Exists(new_file_spec)) {
424 ModuleSpec new_module_spec(module_spec);
425 new_module_spec.GetFileSpec() = new_file_spec;
426 Status new_error(Platform::GetSharedModule(
427 new_module_spec, process, module_sp, nullptr, old_modules,
428 did_create_ptr));
429
430 if (module_sp) {
431 module_sp->SetPlatformFileSpec(new_file_spec);
432 return new_error;
433 }
434 }
435 }
436 }
437 }
438 }
439 }
440 }
441 if (module_sp)
442 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
443 return error;
444 }
445
446 size_t
GetSoftwareBreakpointTrapOpcode(Target & target,BreakpointSite * bp_site)447 PlatformDarwin::GetSoftwareBreakpointTrapOpcode(Target &target,
448 BreakpointSite *bp_site) {
449 const uint8_t *trap_opcode = nullptr;
450 uint32_t trap_opcode_size = 0;
451 bool bp_is_thumb = false;
452
453 llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
454 switch (machine) {
455 case llvm::Triple::aarch64_32:
456 case llvm::Triple::aarch64: {
457 // 'brk #0' or 0xd4200000 in BE byte order
458 static const uint8_t g_arm64_breakpoint_opcode[] = {0x00, 0x00, 0x20, 0xD4};
459 trap_opcode = g_arm64_breakpoint_opcode;
460 trap_opcode_size = sizeof(g_arm64_breakpoint_opcode);
461 } break;
462
463 case llvm::Triple::thumb:
464 bp_is_thumb = true;
465 LLVM_FALLTHROUGH;
466 case llvm::Triple::arm: {
467 static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7};
468 static const uint8_t g_thumb_breakpooint_opcode[] = {0xFE, 0xDE};
469
470 // Auto detect arm/thumb if it wasn't explicitly specified
471 if (!bp_is_thumb) {
472 lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0));
473 if (bp_loc_sp)
474 bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass() ==
475 AddressClass::eCodeAlternateISA;
476 }
477 if (bp_is_thumb) {
478 trap_opcode = g_thumb_breakpooint_opcode;
479 trap_opcode_size = sizeof(g_thumb_breakpooint_opcode);
480 break;
481 }
482 trap_opcode = g_arm_breakpoint_opcode;
483 trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
484 } break;
485
486 case llvm::Triple::ppc:
487 case llvm::Triple::ppc64: {
488 static const uint8_t g_ppc_breakpoint_opcode[] = {0x7F, 0xC0, 0x00, 0x08};
489 trap_opcode = g_ppc_breakpoint_opcode;
490 trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
491 } break;
492
493 default:
494 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
495 }
496
497 if (trap_opcode && trap_opcode_size) {
498 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
499 return trap_opcode_size;
500 }
501 return 0;
502 }
503
ModuleIsExcludedForUnconstrainedSearches(lldb_private::Target & target,const lldb::ModuleSP & module_sp)504 bool PlatformDarwin::ModuleIsExcludedForUnconstrainedSearches(
505 lldb_private::Target &target, const lldb::ModuleSP &module_sp) {
506 if (!module_sp)
507 return false;
508
509 ObjectFile *obj_file = module_sp->GetObjectFile();
510 if (!obj_file)
511 return false;
512
513 ObjectFile::Type obj_type = obj_file->GetType();
514 return obj_type == ObjectFile::eTypeDynamicLinker;
515 }
516
x86GetSupportedArchitectureAtIndex(uint32_t idx,ArchSpec & arch)517 bool PlatformDarwin::x86GetSupportedArchitectureAtIndex(uint32_t idx,
518 ArchSpec &arch) {
519 ArchSpec host_arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
520 if (host_arch.GetCore() == ArchSpec::eCore_x86_64_x86_64h) {
521 switch (idx) {
522 case 0:
523 arch = host_arch;
524 return true;
525
526 case 1:
527 arch.SetTriple("x86_64-apple-macosx");
528 return true;
529
530 case 2:
531 arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
532 return true;
533
534 default:
535 return false;
536 }
537 } else {
538 if (idx == 0) {
539 arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
540 return arch.IsValid();
541 } else if (idx == 1) {
542 ArchSpec platform_arch(
543 HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
544 ArchSpec platform_arch64(
545 HostInfo::GetArchitecture(HostInfo::eArchKind64));
546 if (platform_arch.IsExactMatch(platform_arch64)) {
547 // This macosx platform supports both 32 and 64 bit. Since we already
548 // returned the 64 bit arch for idx == 0, return the 32 bit arch for
549 // idx == 1
550 arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
551 return arch.IsValid();
552 }
553 }
554 }
555 return false;
556 }
557
558 // The architecture selection rules for arm processors These cpu subtypes have
559 // distinct names (e.g. armv7f) but armv7 binaries run fine on an armv7f
560 // processor.
561
ARMGetSupportedArchitectureAtIndex(uint32_t idx,ArchSpec & arch)562 bool PlatformDarwin::ARMGetSupportedArchitectureAtIndex(uint32_t idx,
563 ArchSpec &arch) {
564 ArchSpec system_arch(GetSystemArchitecture());
565
566 // When lldb is running on a watch or tv, set the arch OS name appropriately.
567 #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
568 #define OSNAME "tvos"
569 #elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
570 #define OSNAME "watchos"
571 #elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1
572 #define OSNAME "bridgeos"
573 #else
574 #define OSNAME "ios"
575 #endif
576
577 #if TARGET_OS_OSX
578 if (IsHost()) {
579 if (idx == 0) {
580 arch.SetTriple("arm64e-apple-macosx");
581 return true;
582 } else if (idx == 1) {
583 arch.SetTriple("arm64-apple-macosx");
584 return true;
585 }
586 return false;
587 }
588 #endif
589
590 const ArchSpec::Core system_core = system_arch.GetCore();
591 switch (system_core) {
592 default:
593 switch (idx) {
594 case 0:
595 arch.SetTriple("arm64-apple-" OSNAME);
596 return true;
597 case 1:
598 arch.SetTriple("armv7-apple-" OSNAME);
599 return true;
600 case 2:
601 arch.SetTriple("armv7f-apple-" OSNAME);
602 return true;
603 case 3:
604 arch.SetTriple("armv7k-apple-" OSNAME);
605 return true;
606 case 4:
607 arch.SetTriple("armv7s-apple-" OSNAME);
608 return true;
609 case 5:
610 arch.SetTriple("armv7m-apple-" OSNAME);
611 return true;
612 case 6:
613 arch.SetTriple("armv7em-apple-" OSNAME);
614 return true;
615 case 7:
616 arch.SetTriple("armv6m-apple-" OSNAME);
617 return true;
618 case 8:
619 arch.SetTriple("armv6-apple-" OSNAME);
620 return true;
621 case 9:
622 arch.SetTriple("armv5-apple-" OSNAME);
623 return true;
624 case 10:
625 arch.SetTriple("armv4-apple-" OSNAME);
626 return true;
627 case 11:
628 arch.SetTriple("arm-apple-" OSNAME);
629 return true;
630 case 12:
631 arch.SetTriple("thumbv7-apple-" OSNAME);
632 return true;
633 case 13:
634 arch.SetTriple("thumbv7f-apple-" OSNAME);
635 return true;
636 case 14:
637 arch.SetTriple("thumbv7k-apple-" OSNAME);
638 return true;
639 case 15:
640 arch.SetTriple("thumbv7s-apple-" OSNAME);
641 return true;
642 case 16:
643 arch.SetTriple("thumbv7m-apple-" OSNAME);
644 return true;
645 case 17:
646 arch.SetTriple("thumbv7em-apple-" OSNAME);
647 return true;
648 case 18:
649 arch.SetTriple("thumbv6m-apple-" OSNAME);
650 return true;
651 case 19:
652 arch.SetTriple("thumbv6-apple-" OSNAME);
653 return true;
654 case 20:
655 arch.SetTriple("thumbv5-apple-" OSNAME);
656 return true;
657 case 21:
658 arch.SetTriple("thumbv4t-apple-" OSNAME);
659 return true;
660 case 22:
661 arch.SetTriple("thumb-apple-" OSNAME);
662 return true;
663 default:
664 break;
665 }
666 break;
667
668 case ArchSpec::eCore_arm_arm64:
669 switch (idx) {
670 case 0:
671 arch.SetTriple("arm64-apple-" OSNAME);
672 return true;
673 case 1:
674 arch.SetTriple("armv7s-apple-" OSNAME);
675 return true;
676 case 2:
677 arch.SetTriple("armv7f-apple-" OSNAME);
678 return true;
679 case 3:
680 arch.SetTriple("armv7m-apple-" OSNAME);
681 return true;
682 case 4:
683 arch.SetTriple("armv7em-apple-" OSNAME);
684 return true;
685 case 5:
686 arch.SetTriple("armv7-apple-" OSNAME);
687 return true;
688 case 6:
689 arch.SetTriple("armv6m-apple-" OSNAME);
690 return true;
691 case 7:
692 arch.SetTriple("armv6-apple-" OSNAME);
693 return true;
694 case 8:
695 arch.SetTriple("armv5-apple-" OSNAME);
696 return true;
697 case 9:
698 arch.SetTriple("armv4-apple-" OSNAME);
699 return true;
700 case 10:
701 arch.SetTriple("arm-apple-" OSNAME);
702 return true;
703 case 11:
704 arch.SetTriple("thumbv7-apple-" OSNAME);
705 return true;
706 case 12:
707 arch.SetTriple("thumbv7f-apple-" OSNAME);
708 return true;
709 case 13:
710 arch.SetTriple("thumbv7k-apple-" OSNAME);
711 return true;
712 case 14:
713 arch.SetTriple("thumbv7s-apple-" OSNAME);
714 return true;
715 case 15:
716 arch.SetTriple("thumbv7m-apple-" OSNAME);
717 return true;
718 case 16:
719 arch.SetTriple("thumbv7em-apple-" OSNAME);
720 return true;
721 case 17:
722 arch.SetTriple("thumbv6m-apple-" OSNAME);
723 return true;
724 case 18:
725 arch.SetTriple("thumbv6-apple-" OSNAME);
726 return true;
727 case 19:
728 arch.SetTriple("thumbv5-apple-" OSNAME);
729 return true;
730 case 20:
731 arch.SetTriple("thumbv4t-apple-" OSNAME);
732 return true;
733 case 21:
734 arch.SetTriple("thumb-apple-" OSNAME);
735 return true;
736 default:
737 break;
738 }
739 break;
740
741 case ArchSpec::eCore_arm_armv7f:
742 switch (idx) {
743 case 0:
744 arch.SetTriple("armv7f-apple-" OSNAME);
745 return true;
746 case 1:
747 arch.SetTriple("armv7-apple-" OSNAME);
748 return true;
749 case 2:
750 arch.SetTriple("armv6m-apple-" OSNAME);
751 return true;
752 case 3:
753 arch.SetTriple("armv6-apple-" OSNAME);
754 return true;
755 case 4:
756 arch.SetTriple("armv5-apple-" OSNAME);
757 return true;
758 case 5:
759 arch.SetTriple("armv4-apple-" OSNAME);
760 return true;
761 case 6:
762 arch.SetTriple("arm-apple-" OSNAME);
763 return true;
764 case 7:
765 arch.SetTriple("thumbv7f-apple-" OSNAME);
766 return true;
767 case 8:
768 arch.SetTriple("thumbv7-apple-" OSNAME);
769 return true;
770 case 9:
771 arch.SetTriple("thumbv6m-apple-" OSNAME);
772 return true;
773 case 10:
774 arch.SetTriple("thumbv6-apple-" OSNAME);
775 return true;
776 case 11:
777 arch.SetTriple("thumbv5-apple-" OSNAME);
778 return true;
779 case 12:
780 arch.SetTriple("thumbv4t-apple-" OSNAME);
781 return true;
782 case 13:
783 arch.SetTriple("thumb-apple-" OSNAME);
784 return true;
785 default:
786 break;
787 }
788 break;
789
790 case ArchSpec::eCore_arm_armv7k:
791 switch (idx) {
792 case 0:
793 arch.SetTriple("armv7k-apple-" OSNAME);
794 return true;
795 case 1:
796 arch.SetTriple("armv7-apple-" OSNAME);
797 return true;
798 case 2:
799 arch.SetTriple("armv6m-apple-" OSNAME);
800 return true;
801 case 3:
802 arch.SetTriple("armv6-apple-" OSNAME);
803 return true;
804 case 4:
805 arch.SetTriple("armv5-apple-" OSNAME);
806 return true;
807 case 5:
808 arch.SetTriple("armv4-apple-" OSNAME);
809 return true;
810 case 6:
811 arch.SetTriple("arm-apple-" OSNAME);
812 return true;
813 case 7:
814 arch.SetTriple("thumbv7k-apple-" OSNAME);
815 return true;
816 case 8:
817 arch.SetTriple("thumbv7-apple-" OSNAME);
818 return true;
819 case 9:
820 arch.SetTriple("thumbv6m-apple-" OSNAME);
821 return true;
822 case 10:
823 arch.SetTriple("thumbv6-apple-" OSNAME);
824 return true;
825 case 11:
826 arch.SetTriple("thumbv5-apple-" OSNAME);
827 return true;
828 case 12:
829 arch.SetTriple("thumbv4t-apple-" OSNAME);
830 return true;
831 case 13:
832 arch.SetTriple("thumb-apple-" OSNAME);
833 return true;
834 default:
835 break;
836 }
837 break;
838
839 case ArchSpec::eCore_arm_armv7s:
840 switch (idx) {
841 case 0:
842 arch.SetTriple("armv7s-apple-" OSNAME);
843 return true;
844 case 1:
845 arch.SetTriple("armv7-apple-" OSNAME);
846 return true;
847 case 2:
848 arch.SetTriple("armv6m-apple-" OSNAME);
849 return true;
850 case 3:
851 arch.SetTriple("armv6-apple-" OSNAME);
852 return true;
853 case 4:
854 arch.SetTriple("armv5-apple-" OSNAME);
855 return true;
856 case 5:
857 arch.SetTriple("armv4-apple-" OSNAME);
858 return true;
859 case 6:
860 arch.SetTriple("arm-apple-" OSNAME);
861 return true;
862 case 7:
863 arch.SetTriple("thumbv7s-apple-" OSNAME);
864 return true;
865 case 8:
866 arch.SetTriple("thumbv7-apple-" OSNAME);
867 return true;
868 case 9:
869 arch.SetTriple("thumbv6m-apple-" OSNAME);
870 return true;
871 case 10:
872 arch.SetTriple("thumbv6-apple-" OSNAME);
873 return true;
874 case 11:
875 arch.SetTriple("thumbv5-apple-" OSNAME);
876 return true;
877 case 12:
878 arch.SetTriple("thumbv4t-apple-" OSNAME);
879 return true;
880 case 13:
881 arch.SetTriple("thumb-apple-" OSNAME);
882 return true;
883 default:
884 break;
885 }
886 break;
887
888 case ArchSpec::eCore_arm_armv7m:
889 switch (idx) {
890 case 0:
891 arch.SetTriple("armv7m-apple-" OSNAME);
892 return true;
893 case 1:
894 arch.SetTriple("armv7-apple-" OSNAME);
895 return true;
896 case 2:
897 arch.SetTriple("armv6m-apple-" OSNAME);
898 return true;
899 case 3:
900 arch.SetTriple("armv6-apple-" OSNAME);
901 return true;
902 case 4:
903 arch.SetTriple("armv5-apple-" OSNAME);
904 return true;
905 case 5:
906 arch.SetTriple("armv4-apple-" OSNAME);
907 return true;
908 case 6:
909 arch.SetTriple("arm-apple-" OSNAME);
910 return true;
911 case 7:
912 arch.SetTriple("thumbv7m-apple-" OSNAME);
913 return true;
914 case 8:
915 arch.SetTriple("thumbv7-apple-" OSNAME);
916 return true;
917 case 9:
918 arch.SetTriple("thumbv6m-apple-" OSNAME);
919 return true;
920 case 10:
921 arch.SetTriple("thumbv6-apple-" OSNAME);
922 return true;
923 case 11:
924 arch.SetTriple("thumbv5-apple-" OSNAME);
925 return true;
926 case 12:
927 arch.SetTriple("thumbv4t-apple-" OSNAME);
928 return true;
929 case 13:
930 arch.SetTriple("thumb-apple-" OSNAME);
931 return true;
932 default:
933 break;
934 }
935 break;
936
937 case ArchSpec::eCore_arm_armv7em:
938 switch (idx) {
939 case 0:
940 arch.SetTriple("armv7em-apple-" OSNAME);
941 return true;
942 case 1:
943 arch.SetTriple("armv7-apple-" OSNAME);
944 return true;
945 case 2:
946 arch.SetTriple("armv6m-apple-" OSNAME);
947 return true;
948 case 3:
949 arch.SetTriple("armv6-apple-" OSNAME);
950 return true;
951 case 4:
952 arch.SetTriple("armv5-apple-" OSNAME);
953 return true;
954 case 5:
955 arch.SetTriple("armv4-apple-" OSNAME);
956 return true;
957 case 6:
958 arch.SetTriple("arm-apple-" OSNAME);
959 return true;
960 case 7:
961 arch.SetTriple("thumbv7em-apple-" OSNAME);
962 return true;
963 case 8:
964 arch.SetTriple("thumbv7-apple-" OSNAME);
965 return true;
966 case 9:
967 arch.SetTriple("thumbv6m-apple-" OSNAME);
968 return true;
969 case 10:
970 arch.SetTriple("thumbv6-apple-" OSNAME);
971 return true;
972 case 11:
973 arch.SetTriple("thumbv5-apple-" OSNAME);
974 return true;
975 case 12:
976 arch.SetTriple("thumbv4t-apple-" OSNAME);
977 return true;
978 case 13:
979 arch.SetTriple("thumb-apple-" OSNAME);
980 return true;
981 default:
982 break;
983 }
984 break;
985
986 case ArchSpec::eCore_arm_armv7:
987 switch (idx) {
988 case 0:
989 arch.SetTriple("armv7-apple-" OSNAME);
990 return true;
991 case 1:
992 arch.SetTriple("armv6m-apple-" OSNAME);
993 return true;
994 case 2:
995 arch.SetTriple("armv6-apple-" OSNAME);
996 return true;
997 case 3:
998 arch.SetTriple("armv5-apple-" OSNAME);
999 return true;
1000 case 4:
1001 arch.SetTriple("armv4-apple-" OSNAME);
1002 return true;
1003 case 5:
1004 arch.SetTriple("arm-apple-" OSNAME);
1005 return true;
1006 case 6:
1007 arch.SetTriple("thumbv7-apple-" OSNAME);
1008 return true;
1009 case 7:
1010 arch.SetTriple("thumbv6m-apple-" OSNAME);
1011 return true;
1012 case 8:
1013 arch.SetTriple("thumbv6-apple-" OSNAME);
1014 return true;
1015 case 9:
1016 arch.SetTriple("thumbv5-apple-" OSNAME);
1017 return true;
1018 case 10:
1019 arch.SetTriple("thumbv4t-apple-" OSNAME);
1020 return true;
1021 case 11:
1022 arch.SetTriple("thumb-apple-" OSNAME);
1023 return true;
1024 default:
1025 break;
1026 }
1027 break;
1028
1029 case ArchSpec::eCore_arm_armv6m:
1030 switch (idx) {
1031 case 0:
1032 arch.SetTriple("armv6m-apple-" OSNAME);
1033 return true;
1034 case 1:
1035 arch.SetTriple("armv6-apple-" OSNAME);
1036 return true;
1037 case 2:
1038 arch.SetTriple("armv5-apple-" OSNAME);
1039 return true;
1040 case 3:
1041 arch.SetTriple("armv4-apple-" OSNAME);
1042 return true;
1043 case 4:
1044 arch.SetTriple("arm-apple-" OSNAME);
1045 return true;
1046 case 5:
1047 arch.SetTriple("thumbv6m-apple-" OSNAME);
1048 return true;
1049 case 6:
1050 arch.SetTriple("thumbv6-apple-" OSNAME);
1051 return true;
1052 case 7:
1053 arch.SetTriple("thumbv5-apple-" OSNAME);
1054 return true;
1055 case 8:
1056 arch.SetTriple("thumbv4t-apple-" OSNAME);
1057 return true;
1058 case 9:
1059 arch.SetTriple("thumb-apple-" OSNAME);
1060 return true;
1061 default:
1062 break;
1063 }
1064 break;
1065
1066 case ArchSpec::eCore_arm_armv6:
1067 switch (idx) {
1068 case 0:
1069 arch.SetTriple("armv6-apple-" OSNAME);
1070 return true;
1071 case 1:
1072 arch.SetTriple("armv5-apple-" OSNAME);
1073 return true;
1074 case 2:
1075 arch.SetTriple("armv4-apple-" OSNAME);
1076 return true;
1077 case 3:
1078 arch.SetTriple("arm-apple-" OSNAME);
1079 return true;
1080 case 4:
1081 arch.SetTriple("thumbv6-apple-" OSNAME);
1082 return true;
1083 case 5:
1084 arch.SetTriple("thumbv5-apple-" OSNAME);
1085 return true;
1086 case 6:
1087 arch.SetTriple("thumbv4t-apple-" OSNAME);
1088 return true;
1089 case 7:
1090 arch.SetTriple("thumb-apple-" OSNAME);
1091 return true;
1092 default:
1093 break;
1094 }
1095 break;
1096
1097 case ArchSpec::eCore_arm_armv5:
1098 switch (idx) {
1099 case 0:
1100 arch.SetTriple("armv5-apple-" OSNAME);
1101 return true;
1102 case 1:
1103 arch.SetTriple("armv4-apple-" OSNAME);
1104 return true;
1105 case 2:
1106 arch.SetTriple("arm-apple-" OSNAME);
1107 return true;
1108 case 3:
1109 arch.SetTriple("thumbv5-apple-" OSNAME);
1110 return true;
1111 case 4:
1112 arch.SetTriple("thumbv4t-apple-" OSNAME);
1113 return true;
1114 case 5:
1115 arch.SetTriple("thumb-apple-" OSNAME);
1116 return true;
1117 default:
1118 break;
1119 }
1120 break;
1121
1122 case ArchSpec::eCore_arm_armv4:
1123 switch (idx) {
1124 case 0:
1125 arch.SetTriple("armv4-apple-" OSNAME);
1126 return true;
1127 case 1:
1128 arch.SetTriple("arm-apple-" OSNAME);
1129 return true;
1130 case 2:
1131 arch.SetTriple("thumbv4t-apple-" OSNAME);
1132 return true;
1133 case 3:
1134 arch.SetTriple("thumb-apple-" OSNAME);
1135 return true;
1136 default:
1137 break;
1138 }
1139 break;
1140 }
1141 arch.Clear();
1142 return false;
1143 }
1144
GetXcodeSelectPath()1145 static FileSpec GetXcodeSelectPath() {
1146 static FileSpec g_xcode_select_filespec;
1147
1148 if (!g_xcode_select_filespec) {
1149 FileSpec xcode_select_cmd("/usr/bin/xcode-select");
1150 if (FileSystem::Instance().Exists(xcode_select_cmd)) {
1151 int exit_status = -1;
1152 int signo = -1;
1153 std::string command_output;
1154 Status status =
1155 Host::RunShellCommand("/usr/bin/xcode-select --print-path",
1156 FileSpec(), // current working directory
1157 &exit_status, &signo, &command_output,
1158 std::chrono::seconds(2), // short timeout
1159 false); // don't run in a shell
1160 if (status.Success() && exit_status == 0 && !command_output.empty()) {
1161 size_t first_non_newline = command_output.find_last_not_of("\r\n");
1162 if (first_non_newline != std::string::npos) {
1163 command_output.erase(first_non_newline + 1);
1164 }
1165 g_xcode_select_filespec = FileSpec(command_output);
1166 }
1167 }
1168 }
1169
1170 return g_xcode_select_filespec;
1171 }
1172
SetThreadCreationBreakpoint(Target & target)1173 BreakpointSP PlatformDarwin::SetThreadCreationBreakpoint(Target &target) {
1174 BreakpointSP bp_sp;
1175 static const char *g_bp_names[] = {
1176 "start_wqthread", "_pthread_wqthread", "_pthread_start",
1177 };
1178
1179 static const char *g_bp_modules[] = {"libsystem_c.dylib",
1180 "libSystem.B.dylib"};
1181
1182 FileSpecList bp_modules;
1183 for (size_t i = 0; i < llvm::array_lengthof(g_bp_modules); i++) {
1184 const char *bp_module = g_bp_modules[i];
1185 bp_modules.EmplaceBack(bp_module);
1186 }
1187
1188 bool internal = true;
1189 bool hardware = false;
1190 LazyBool skip_prologue = eLazyBoolNo;
1191 bp_sp = target.CreateBreakpoint(&bp_modules, nullptr, g_bp_names,
1192 llvm::array_lengthof(g_bp_names),
1193 eFunctionNameTypeFull, eLanguageTypeUnknown,
1194 0, skip_prologue, internal, hardware);
1195 bp_sp->SetBreakpointKind("thread-creation");
1196
1197 return bp_sp;
1198 }
1199
1200 uint32_t
GetResumeCountForLaunchInfo(ProcessLaunchInfo & launch_info)1201 PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
1202 const FileSpec &shell = launch_info.GetShell();
1203 if (!shell)
1204 return 1;
1205
1206 std::string shell_string = shell.GetPath();
1207 const char *shell_name = strrchr(shell_string.c_str(), '/');
1208 if (shell_name == nullptr)
1209 shell_name = shell_string.c_str();
1210 else
1211 shell_name++;
1212
1213 if (strcmp(shell_name, "sh") == 0) {
1214 // /bin/sh re-exec's itself as /bin/bash requiring another resume. But it
1215 // only does this if the COMMAND_MODE environment variable is set to
1216 // "legacy".
1217 if (launch_info.GetEnvironment().lookup("COMMAND_MODE") == "legacy")
1218 return 2;
1219 return 1;
1220 } else if (strcmp(shell_name, "csh") == 0 ||
1221 strcmp(shell_name, "tcsh") == 0 ||
1222 strcmp(shell_name, "zsh") == 0) {
1223 // csh and tcsh always seem to re-exec themselves.
1224 return 2;
1225 } else
1226 return 1;
1227 }
1228
1229 lldb::ProcessSP
DebugProcess(ProcessLaunchInfo & launch_info,Debugger & debugger,Target * target,Status & error)1230 PlatformDarwin::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
1231 Target *target, // Can be NULL, if NULL create
1232 // a new target, else use existing
1233 // one
1234 Status &error) {
1235 ProcessSP process_sp;
1236
1237 if (IsHost()) {
1238 // We are going to hand this process off to debugserver which will be in
1239 // charge of setting the exit status. However, we still need to reap it
1240 // from lldb. So, make sure we use a exit callback which does not set exit
1241 // status.
1242 const bool monitor_signals = false;
1243 launch_info.SetMonitorProcessCallback(
1244 &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals);
1245 process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
1246 } else {
1247 if (m_remote_platform_sp)
1248 process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
1249 target, error);
1250 else
1251 error.SetErrorString("the platform is not currently connected");
1252 }
1253 return process_sp;
1254 }
1255
CalculateTrapHandlerSymbolNames()1256 void PlatformDarwin::CalculateTrapHandlerSymbolNames() {
1257 m_trap_handlers.push_back(ConstString("_sigtramp"));
1258 }
1259
GetCommandLineToolsLibraryPath()1260 static FileSpec GetCommandLineToolsLibraryPath() {
1261 static FileSpec g_command_line_tools_filespec;
1262
1263 if (!g_command_line_tools_filespec) {
1264 FileSpec command_line_tools_path(GetXcodeSelectPath());
1265 command_line_tools_path.AppendPathComponent("Library");
1266 if (FileSystem::Instance().Exists(command_line_tools_path)) {
1267 g_command_line_tools_filespec = command_line_tools_path;
1268 }
1269 }
1270
1271 return g_command_line_tools_filespec;
1272 }
1273
DirectoryEnumerator(void * baton,llvm::sys::fs::file_type file_type,llvm::StringRef path)1274 FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator(
1275 void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) {
1276 SDKEnumeratorInfo *enumerator_info = static_cast<SDKEnumeratorInfo *>(baton);
1277
1278 FileSpec spec(path);
1279 if (XcodeSDK::SDKSupportsModules(enumerator_info->sdk_type, spec)) {
1280 enumerator_info->found_path = spec;
1281 return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext;
1282 }
1283
1284 return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext;
1285 }
1286
FindSDKInXcodeForModules(XcodeSDK::Type sdk_type,const FileSpec & sdks_spec)1287 FileSpec PlatformDarwin::FindSDKInXcodeForModules(XcodeSDK::Type sdk_type,
1288 const FileSpec &sdks_spec) {
1289 // Look inside Xcode for the required installed iOS SDK version
1290
1291 if (!FileSystem::Instance().IsDirectory(sdks_spec)) {
1292 return FileSpec();
1293 }
1294
1295 const bool find_directories = true;
1296 const bool find_files = false;
1297 const bool find_other = true; // include symlinks
1298
1299 SDKEnumeratorInfo enumerator_info;
1300
1301 enumerator_info.sdk_type = sdk_type;
1302
1303 FileSystem::Instance().EnumerateDirectory(
1304 sdks_spec.GetPath(), find_directories, find_files, find_other,
1305 DirectoryEnumerator, &enumerator_info);
1306
1307 if (FileSystem::Instance().IsDirectory(enumerator_info.found_path))
1308 return enumerator_info.found_path;
1309 else
1310 return FileSpec();
1311 }
1312
GetSDKDirectoryForModules(XcodeSDK::Type sdk_type)1313 FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) {
1314 FileSpec sdks_spec = HostInfo::GetXcodeContentsDirectory();
1315 sdks_spec.AppendPathComponent("Developer");
1316 sdks_spec.AppendPathComponent("Platforms");
1317
1318 switch (sdk_type) {
1319 case XcodeSDK::Type::MacOSX:
1320 sdks_spec.AppendPathComponent("MacOSX.platform");
1321 break;
1322 case XcodeSDK::Type::iPhoneSimulator:
1323 sdks_spec.AppendPathComponent("iPhoneSimulator.platform");
1324 break;
1325 case XcodeSDK::Type::iPhoneOS:
1326 sdks_spec.AppendPathComponent("iPhoneOS.platform");
1327 break;
1328 case XcodeSDK::Type::WatchSimulator:
1329 sdks_spec.AppendPathComponent("WatchSimulator.platform");
1330 break;
1331 case XcodeSDK::Type::AppleTVSimulator:
1332 sdks_spec.AppendPathComponent("AppleTVSimulator.platform");
1333 break;
1334 default:
1335 llvm_unreachable("unsupported sdk");
1336 }
1337
1338 sdks_spec.AppendPathComponent("Developer");
1339 sdks_spec.AppendPathComponent("SDKs");
1340
1341 if (sdk_type == XcodeSDK::Type::MacOSX) {
1342 llvm::VersionTuple version = HostInfo::GetOSVersion();
1343
1344 if (!version.empty()) {
1345 if (XcodeSDK::SDKSupportsModules(XcodeSDK::Type::MacOSX, version)) {
1346 // If the Xcode SDKs are not available then try to use the
1347 // Command Line Tools one which is only for MacOSX.
1348 if (!FileSystem::Instance().Exists(sdks_spec)) {
1349 sdks_spec = GetCommandLineToolsLibraryPath();
1350 sdks_spec.AppendPathComponent("SDKs");
1351 }
1352
1353 // We slightly prefer the exact SDK for this machine. See if it is
1354 // there.
1355
1356 FileSpec native_sdk_spec = sdks_spec;
1357 StreamString native_sdk_name;
1358 native_sdk_name.Printf("MacOSX%u.%u.sdk", version.getMajor(),
1359 version.getMinor().getValueOr(0));
1360 native_sdk_spec.AppendPathComponent(native_sdk_name.GetString());
1361
1362 if (FileSystem::Instance().Exists(native_sdk_spec)) {
1363 return native_sdk_spec;
1364 }
1365 }
1366 }
1367 }
1368
1369 return FindSDKInXcodeForModules(sdk_type, sdks_spec);
1370 }
1371
1372 std::tuple<llvm::VersionTuple, llvm::StringRef>
ParseVersionBuildDir(llvm::StringRef dir)1373 PlatformDarwin::ParseVersionBuildDir(llvm::StringRef dir) {
1374 llvm::StringRef build;
1375 llvm::StringRef version_str;
1376 llvm::StringRef build_str;
1377 std::tie(version_str, build_str) = dir.split(' ');
1378 llvm::VersionTuple version;
1379 if (!version.tryParse(version_str) ||
1380 build_str.empty()) {
1381 if (build_str.consume_front("(")) {
1382 size_t pos = build_str.find(')');
1383 build = build_str.slice(0, pos);
1384 }
1385 }
1386
1387 return std::make_tuple(version, build);
1388 }
1389
1390 llvm::Expected<StructuredData::DictionarySP>
FetchExtendedCrashInformation(Process & process)1391 PlatformDarwin::FetchExtendedCrashInformation(Process &process) {
1392 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1393
1394 StructuredData::ArraySP annotations = ExtractCrashInfoAnnotations(process);
1395
1396 if (!annotations || !annotations->GetSize()) {
1397 LLDB_LOG(log, "Couldn't extract crash information annotations");
1398 return nullptr;
1399 }
1400
1401 StructuredData::DictionarySP extended_crash_info =
1402 std::make_shared<StructuredData::Dictionary>();
1403
1404 extended_crash_info->AddItem("crash-info annotations", annotations);
1405
1406 return extended_crash_info;
1407 }
1408
1409 StructuredData::ArraySP
ExtractCrashInfoAnnotations(Process & process)1410 PlatformDarwin::ExtractCrashInfoAnnotations(Process &process) {
1411 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1412
1413 ConstString section_name("__crash_info");
1414 Target &target = process.GetTarget();
1415 StructuredData::ArraySP array_sp = std::make_shared<StructuredData::Array>();
1416
1417 for (ModuleSP module : target.GetImages().Modules()) {
1418 SectionList *sections = module->GetSectionList();
1419
1420 std::string module_name = module->GetSpecificationDescription();
1421
1422 // The DYDL module is skipped since it's always loaded when running the
1423 // binary.
1424 if (module_name == "/usr/lib/dyld")
1425 continue;
1426
1427 if (!sections) {
1428 LLDB_LOG(log, "Module {0} doesn't have any section!", module_name);
1429 continue;
1430 }
1431
1432 SectionSP crash_info = sections->FindSectionByName(section_name);
1433 if (!crash_info) {
1434 LLDB_LOG(log, "Module {0} doesn't have section {1}!", module_name,
1435 section_name);
1436 continue;
1437 }
1438
1439 addr_t load_addr = crash_info->GetLoadBaseAddress(&target);
1440
1441 if (load_addr == LLDB_INVALID_ADDRESS) {
1442 LLDB_LOG(log, "Module {0} has an invalid '{1}' section load address: {2}",
1443 module_name, section_name, load_addr);
1444 continue;
1445 }
1446
1447 Status error;
1448 CrashInfoAnnotations annotations;
1449 size_t expected_size = sizeof(CrashInfoAnnotations);
1450 size_t bytes_read = process.ReadMemoryFromInferior(load_addr, &annotations,
1451 expected_size, error);
1452
1453 if (expected_size != bytes_read || error.Fail()) {
1454 LLDB_LOG(log, "Failed to read {0} section from memory in module {1}: {2}",
1455 section_name, module_name, error);
1456 continue;
1457 }
1458
1459 // initial support added for version 5
1460 if (annotations.version < 5) {
1461 LLDB_LOG(log,
1462 "Annotation version lower than 5 unsupported! Module {0} has "
1463 "version {1} instead.",
1464 module_name, annotations.version);
1465 continue;
1466 }
1467
1468 if (!annotations.message) {
1469 LLDB_LOG(log, "No message available for module {0}.", module_name);
1470 continue;
1471 }
1472
1473 std::string message;
1474 bytes_read =
1475 process.ReadCStringFromMemory(annotations.message, message, error);
1476
1477 if (message.empty() || bytes_read != message.size() || error.Fail()) {
1478 LLDB_LOG(log, "Failed to read the message from memory in module {0}: {1}",
1479 module_name, error);
1480 continue;
1481 }
1482
1483 // Remove trailing newline from message
1484 if (message.back() == '\n')
1485 message.pop_back();
1486
1487 if (!annotations.message2)
1488 LLDB_LOG(log, "No message2 available for module {0}.", module_name);
1489
1490 std::string message2;
1491 bytes_read =
1492 process.ReadCStringFromMemory(annotations.message2, message2, error);
1493
1494 if (!message2.empty() && bytes_read == message2.size() && error.Success())
1495 if (message2.back() == '\n')
1496 message2.pop_back();
1497
1498 StructuredData::DictionarySP entry_sp =
1499 std::make_shared<StructuredData::Dictionary>();
1500
1501 entry_sp->AddStringItem("image", module->GetFileSpec().GetPath(false));
1502 entry_sp->AddStringItem("uuid", module->GetUUID().GetAsString());
1503 entry_sp->AddStringItem("message", message);
1504 entry_sp->AddStringItem("message2", message2);
1505 entry_sp->AddIntegerItem("abort-cause", annotations.abort_cause);
1506
1507 array_sp->AddItem(entry_sp);
1508 }
1509
1510 return array_sp;
1511 }
1512
AddClangModuleCompilationOptionsForSDKType(Target * target,std::vector<std::string> & options,XcodeSDK::Type sdk_type)1513 void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
1514 Target *target, std::vector<std::string> &options, XcodeSDK::Type sdk_type) {
1515 const std::vector<std::string> apple_arguments = {
1516 "-x", "objective-c++", "-fobjc-arc",
1517 "-fblocks", "-D_ISO646_H", "-D__ISO646_H",
1518 "-fgnuc-version=4.2.1"};
1519
1520 options.insert(options.end(), apple_arguments.begin(), apple_arguments.end());
1521
1522 StreamString minimum_version_option;
1523 bool use_current_os_version = false;
1524 // If the SDK type is for the host OS, use its version number.
1525 auto get_host_os = []() { return HostInfo::GetTargetTriple().getOS(); };
1526 switch (sdk_type) {
1527 case XcodeSDK::Type::MacOSX:
1528 use_current_os_version = get_host_os() == llvm::Triple::MacOSX;
1529 break;
1530 case XcodeSDK::Type::iPhoneOS:
1531 use_current_os_version = get_host_os() == llvm::Triple::IOS;
1532 break;
1533 case XcodeSDK::Type::AppleTVOS:
1534 use_current_os_version = get_host_os() == llvm::Triple::TvOS;
1535 break;
1536 case XcodeSDK::Type::watchOS:
1537 use_current_os_version = get_host_os() == llvm::Triple::WatchOS;
1538 break;
1539 default:
1540 break;
1541 }
1542
1543 llvm::VersionTuple version;
1544 if (use_current_os_version)
1545 version = GetOSVersion();
1546 else if (target) {
1547 // Our OS doesn't match our executable so we need to get the min OS version
1548 // from the object file
1549 ModuleSP exe_module_sp = target->GetExecutableModule();
1550 if (exe_module_sp) {
1551 ObjectFile *object_file = exe_module_sp->GetObjectFile();
1552 if (object_file)
1553 version = object_file->GetMinimumOSVersion();
1554 }
1555 }
1556 // Only add the version-min options if we got a version from somewhere
1557 if (!version.empty() && sdk_type != XcodeSDK::Type::Linux) {
1558 #define OPTION(PREFIX, NAME, VAR, ...) \
1559 const char *opt_##VAR = NAME; \
1560 (void)opt_##VAR;
1561 #include "clang/Driver/Options.inc"
1562 #undef OPTION
1563 minimum_version_option << '-';
1564 switch (sdk_type) {
1565 case XcodeSDK::Type::MacOSX:
1566 minimum_version_option << opt_mmacosx_version_min_EQ;
1567 break;
1568 case XcodeSDK::Type::iPhoneSimulator:
1569 minimum_version_option << opt_mios_simulator_version_min_EQ;
1570 break;
1571 case XcodeSDK::Type::iPhoneOS:
1572 minimum_version_option << opt_mios_version_min_EQ;
1573 break;
1574 case XcodeSDK::Type::AppleTVSimulator:
1575 minimum_version_option << opt_mtvos_simulator_version_min_EQ;
1576 break;
1577 case XcodeSDK::Type::AppleTVOS:
1578 minimum_version_option << opt_mtvos_version_min_EQ;
1579 break;
1580 case XcodeSDK::Type::WatchSimulator:
1581 minimum_version_option << opt_mwatchos_simulator_version_min_EQ;
1582 break;
1583 case XcodeSDK::Type::watchOS:
1584 minimum_version_option << opt_mwatchos_version_min_EQ;
1585 break;
1586 case XcodeSDK::Type::bridgeOS:
1587 case XcodeSDK::Type::Linux:
1588 case XcodeSDK::Type::unknown:
1589 if (lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)) {
1590 XcodeSDK::Info info;
1591 info.type = sdk_type;
1592 LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
1593 "Clang modules on %s are not supported",
1594 XcodeSDK::GetCanonicalName(info).c_str());
1595 }
1596 return;
1597 }
1598 minimum_version_option << version.getAsString();
1599 options.emplace_back(std::string(minimum_version_option.GetString()));
1600 }
1601
1602 FileSpec sysroot_spec;
1603 // Scope for mutex locker below
1604 {
1605 std::lock_guard<std::mutex> guard(m_mutex);
1606 sysroot_spec = GetSDKDirectoryForModules(sdk_type);
1607 }
1608
1609 if (FileSystem::Instance().IsDirectory(sysroot_spec.GetPath())) {
1610 options.push_back("-isysroot");
1611 options.push_back(sysroot_spec.GetPath());
1612 }
1613 }
1614
GetFullNameForDylib(ConstString basename)1615 ConstString PlatformDarwin::GetFullNameForDylib(ConstString basename) {
1616 if (basename.IsEmpty())
1617 return basename;
1618
1619 StreamString stream;
1620 stream.Printf("lib%s.dylib", basename.GetCString());
1621 return ConstString(stream.GetString());
1622 }
1623
GetOSVersion(Process * process)1624 llvm::VersionTuple PlatformDarwin::GetOSVersion(Process *process) {
1625 if (process && strstr(GetPluginName().GetCString(), "-simulator")) {
1626 lldb_private::ProcessInstanceInfo proc_info;
1627 if (Host::GetProcessInfo(process->GetID(), proc_info)) {
1628 const Environment &env = proc_info.GetEnvironment();
1629
1630 llvm::VersionTuple result;
1631 if (!result.tryParse(env.lookup("SIMULATOR_RUNTIME_VERSION")))
1632 return result;
1633
1634 std::string dyld_root_path = env.lookup("DYLD_ROOT_PATH");
1635 if (!dyld_root_path.empty()) {
1636 dyld_root_path += "/System/Library/CoreServices/SystemVersion.plist";
1637 ApplePropertyList system_version_plist(dyld_root_path.c_str());
1638 std::string product_version;
1639 if (system_version_plist.GetValueAsString("ProductVersion",
1640 product_version)) {
1641 if (!result.tryParse(product_version))
1642 return result;
1643 }
1644 }
1645 }
1646 // For simulator platforms, do NOT call back through
1647 // Platform::GetOSVersion() as it might call Process::GetHostOSVersion()
1648 // which we don't want as it will be incorrect
1649 return llvm::VersionTuple();
1650 }
1651
1652 return Platform::GetOSVersion(process);
1653 }
1654
LocateExecutable(const char * basename)1655 lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) {
1656 // A collection of SBFileSpec whose SBFileSpec.m_directory members are filled
1657 // in with any executable directories that should be searched.
1658 static std::vector<FileSpec> g_executable_dirs;
1659
1660 // Find the global list of directories that we will search for executables
1661 // once so we don't keep doing the work over and over.
1662 static llvm::once_flag g_once_flag;
1663 llvm::call_once(g_once_flag, []() {
1664
1665 // When locating executables, trust the DEVELOPER_DIR first if it is set
1666 FileSpec xcode_contents_dir = HostInfo::GetXcodeContentsDirectory();
1667 if (xcode_contents_dir) {
1668 FileSpec xcode_lldb_resources = xcode_contents_dir;
1669 xcode_lldb_resources.AppendPathComponent("SharedFrameworks");
1670 xcode_lldb_resources.AppendPathComponent("LLDB.framework");
1671 xcode_lldb_resources.AppendPathComponent("Resources");
1672 if (FileSystem::Instance().Exists(xcode_lldb_resources)) {
1673 FileSpec dir;
1674 dir.GetDirectory().SetCString(xcode_lldb_resources.GetPath().c_str());
1675 g_executable_dirs.push_back(dir);
1676 }
1677 }
1678 // Xcode might not be installed so we also check for the Command Line Tools.
1679 FileSpec command_line_tools_dir = GetCommandLineToolsLibraryPath();
1680 if (command_line_tools_dir) {
1681 FileSpec cmd_line_lldb_resources = command_line_tools_dir;
1682 cmd_line_lldb_resources.AppendPathComponent("PrivateFrameworks");
1683 cmd_line_lldb_resources.AppendPathComponent("LLDB.framework");
1684 cmd_line_lldb_resources.AppendPathComponent("Resources");
1685 if (FileSystem::Instance().Exists(cmd_line_lldb_resources)) {
1686 FileSpec dir;
1687 dir.GetDirectory().SetCString(
1688 cmd_line_lldb_resources.GetPath().c_str());
1689 g_executable_dirs.push_back(dir);
1690 }
1691 }
1692 });
1693
1694 // Now search the global list of executable directories for the executable we
1695 // are looking for
1696 for (const auto &executable_dir : g_executable_dirs) {
1697 FileSpec executable_file;
1698 executable_file.GetDirectory() = executable_dir.GetDirectory();
1699 executable_file.GetFilename().SetCString(basename);
1700 if (FileSystem::Instance().Exists(executable_file))
1701 return executable_file;
1702 }
1703
1704 return FileSpec();
1705 }
1706
1707 lldb_private::Status
LaunchProcess(lldb_private::ProcessLaunchInfo & launch_info)1708 PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) {
1709 // Starting in Fall 2016 OSes, NSLog messages only get mirrored to stderr if
1710 // the OS_ACTIVITY_DT_MODE environment variable is set. (It doesn't require
1711 // any specific value; rather, it just needs to exist). We will set it here
1712 // as long as the IDE_DISABLED_OS_ACTIVITY_DT_MODE flag is not set. Xcode
1713 // makes use of IDE_DISABLED_OS_ACTIVITY_DT_MODE to tell
1714 // LLDB *not* to muck with the OS_ACTIVITY_DT_MODE flag when they
1715 // specifically want it unset.
1716 const char *disable_env_var = "IDE_DISABLED_OS_ACTIVITY_DT_MODE";
1717 auto &env_vars = launch_info.GetEnvironment();
1718 if (!env_vars.count(disable_env_var)) {
1719 // We want to make sure that OS_ACTIVITY_DT_MODE is set so that we get
1720 // os_log and NSLog messages mirrored to the target process stderr.
1721 env_vars.try_emplace("OS_ACTIVITY_DT_MODE", "enable");
1722 }
1723
1724 // Let our parent class do the real launching.
1725 return PlatformPOSIX::LaunchProcess(launch_info);
1726 }
1727
FindBundleBinaryInExecSearchPaths(const ModuleSpec & module_spec,Process * process,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<ModuleSP> * old_modules,bool * did_create_ptr)1728 lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
1729 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
1730 const FileSpecList *module_search_paths_ptr,
1731 llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
1732 const FileSpec &platform_file = module_spec.GetFileSpec();
1733 // See if the file is present in any of the module_search_paths_ptr
1734 // directories.
1735 if (!module_sp && module_search_paths_ptr && platform_file) {
1736 // create a vector of all the file / directory names in platform_file e.g.
1737 // this might be
1738 // /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation
1739 //
1740 // We'll need to look in the module_search_paths_ptr directories for both
1741 // "UIFoundation" and "UIFoundation.framework" -- most likely the latter
1742 // will be the one we find there.
1743
1744 FileSpec platform_pull_upart(platform_file);
1745 std::vector<std::string> path_parts;
1746 path_parts.push_back(
1747 platform_pull_upart.GetLastPathComponent().AsCString());
1748 while (platform_pull_upart.RemoveLastPathComponent()) {
1749 ConstString part = platform_pull_upart.GetLastPathComponent();
1750 path_parts.push_back(part.AsCString());
1751 }
1752 const size_t path_parts_size = path_parts.size();
1753
1754 size_t num_module_search_paths = module_search_paths_ptr->GetSize();
1755 for (size_t i = 0; i < num_module_search_paths; ++i) {
1756 Log *log_verbose = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
1757 LLDB_LOGF(
1758 log_verbose,
1759 "PlatformRemoteDarwinDevice::GetSharedModule searching for binary in "
1760 "search-path %s",
1761 module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath().c_str());
1762 // Create a new FileSpec with this module_search_paths_ptr plus just the
1763 // filename ("UIFoundation"), then the parent dir plus filename
1764 // ("UIFoundation.framework/UIFoundation") etc - up to four names (to
1765 // handle "Foo.framework/Contents/MacOS/Foo")
1766
1767 for (size_t j = 0; j < 4 && j < path_parts_size - 1; ++j) {
1768 FileSpec path_to_try(module_search_paths_ptr->GetFileSpecAtIndex(i));
1769
1770 // Add the components backwards. For
1771 // .../PrivateFrameworks/UIFoundation.framework/UIFoundation path_parts
1772 // is
1773 // [0] UIFoundation
1774 // [1] UIFoundation.framework
1775 // [2] PrivateFrameworks
1776 //
1777 // and if 'j' is 2, we want to append path_parts[1] and then
1778 // path_parts[0], aka 'UIFoundation.framework/UIFoundation', to the
1779 // module_search_paths_ptr path.
1780
1781 for (int k = j; k >= 0; --k) {
1782 path_to_try.AppendPathComponent(path_parts[k]);
1783 }
1784
1785 if (FileSystem::Instance().Exists(path_to_try)) {
1786 ModuleSpec new_module_spec(module_spec);
1787 new_module_spec.GetFileSpec() = path_to_try;
1788 Status new_error(
1789 Platform::GetSharedModule(new_module_spec, process, module_sp,
1790 nullptr, old_modules, did_create_ptr));
1791
1792 if (module_sp) {
1793 module_sp->SetPlatformFileSpec(path_to_try);
1794 return new_error;
1795 }
1796 }
1797 }
1798 }
1799 }
1800 return Status();
1801 }
1802
FindComponentInPath(llvm::StringRef path,llvm::StringRef component)1803 std::string PlatformDarwin::FindComponentInPath(llvm::StringRef path,
1804 llvm::StringRef component) {
1805 auto begin = llvm::sys::path::begin(path);
1806 auto end = llvm::sys::path::end(path);
1807 for (auto it = begin; it != end; ++it) {
1808 if (it->contains(component)) {
1809 llvm::SmallString<128> buffer;
1810 llvm::sys::path::append(buffer, begin, ++it,
1811 llvm::sys::path::Style::posix);
1812 return buffer.str().str();
1813 }
1814 }
1815 return {};
1816 }
1817
GetCurrentToolchainDirectory()1818 FileSpec PlatformDarwin::GetCurrentToolchainDirectory() {
1819 if (FileSpec fspec = HostInfo::GetShlibDir())
1820 return FileSpec(FindComponentInPath(fspec.GetPath(), ".xctoolchain"));
1821 return {};
1822 }
1823
GetCurrentCommandLineToolsDirectory()1824 FileSpec PlatformDarwin::GetCurrentCommandLineToolsDirectory() {
1825 if (FileSpec fspec = HostInfo::GetShlibDir())
1826 return FileSpec(FindComponentInPath(fspec.GetPath(), "CommandLineTools"));
1827 return {};
1828 }
1829