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 <cstring> |
12 | |
13 | #include <algorithm> |
14 | #include <memory> |
15 | #include <mutex> |
16 | #include <optional> |
17 | |
18 | #include "lldb/Breakpoint/BreakpointLocation.h" |
19 | #include "lldb/Breakpoint/BreakpointSite.h" |
20 | #include "lldb/Core/Debugger.h" |
21 | #include "lldb/Core/Module.h" |
22 | #include "lldb/Core/ModuleSpec.h" |
23 | #include "lldb/Core/PluginManager.h" |
24 | #include "lldb/Core/Section.h" |
25 | #include "lldb/Host/Host.h" |
26 | #include "lldb/Host/HostInfo.h" |
27 | #include "lldb/Host/XML.h" |
28 | #include "lldb/Interpreter/CommandInterpreter.h" |
29 | #include "lldb/Interpreter/OptionValueProperties.h" |
30 | #include "lldb/Interpreter/OptionValueString.h" |
31 | #include "lldb/Interpreter/Options.h" |
32 | #include "lldb/Symbol/CompileUnit.h" |
33 | #include "lldb/Symbol/ObjectFile.h" |
34 | #include "lldb/Symbol/SymbolFile.h" |
35 | #include "lldb/Symbol/SymbolVendor.h" |
36 | #include "lldb/Target/Platform.h" |
37 | #include "lldb/Target/Process.h" |
38 | #include "lldb/Target/Target.h" |
39 | #include "lldb/Utility/LLDBLog.h" |
40 | #include "lldb/Utility/Log.h" |
41 | #include "lldb/Utility/ProcessInfo.h" |
42 | #include "lldb/Utility/Status.h" |
43 | #include "lldb/Utility/Timer.h" |
44 | #include "llvm/ADT/STLExtras.h" |
45 | #include "llvm/ADT/StringTable.h" |
46 | #include "llvm/Support/Error.h" |
47 | #include "llvm/Support/FileSystem.h" |
48 | #include "llvm/Support/Threading.h" |
49 | #include "llvm/Support/VersionTuple.h" |
50 | |
51 | #if defined(__APPLE__) |
52 | #include <TargetConditionals.h> |
53 | #endif |
54 | |
55 | using namespace lldb; |
56 | using namespace lldb_private; |
57 | |
58 | #define OPTTABLE_STR_TABLE_CODE |
59 | #include "clang/Driver/Options.inc" |
60 | #undef OPTTABLE_STR_TABLE_CODE |
61 | |
62 | static Status ExceptionMaskValidator(const char *string, void *unused) { |
63 | Status error; |
64 | llvm::StringRef str_ref(string); |
65 | llvm::SmallVector<llvm::StringRef> candidates; |
66 | str_ref.split(candidates, '|'); |
67 | for (auto candidate : candidates) { |
68 | if (!(candidate == "EXC_BAD_ACCESS" |
69 | || candidate == "EXC_BAD_INSTRUCTION" |
70 | || candidate == "EXC_ARITHMETIC" |
71 | || candidate == "EXC_RESOURCE" |
72 | || candidate == "EXC_GUARD" |
73 | || candidate == "EXC_SYSCALL")) { |
74 | error = Status::FromErrorStringWithFormat("invalid exception type: '%s'", |
75 | candidate.str().c_str()); |
76 | return error; |
77 | } |
78 | } |
79 | return {}; |
80 | } |
81 | |
82 | /// Destructor. |
83 | /// |
84 | /// The destructor is virtual since this class is designed to be |
85 | /// inherited from by the plug-in instance. |
86 | PlatformDarwin::~PlatformDarwin() = default; |
87 | |
88 | // Static Variables |
89 | static uint32_t g_initialize_count = 0; |
90 | |
91 | void PlatformDarwin::Initialize() { |
92 | Platform::Initialize(); |
93 | |
94 | if (g_initialize_count++ == 0) { |
95 | PluginManager::RegisterPlugin(name: PlatformDarwin::GetPluginNameStatic(), |
96 | description: PlatformDarwin::GetDescriptionStatic(), |
97 | create_callback: PlatformDarwin::CreateInstance, |
98 | debugger_init_callback: PlatformDarwin::DebuggerInitialize); |
99 | } |
100 | } |
101 | |
102 | void PlatformDarwin::Terminate() { |
103 | if (g_initialize_count > 0) { |
104 | if (--g_initialize_count == 0) { |
105 | PluginManager::UnregisterPlugin(create_callback: PlatformDarwin::CreateInstance); |
106 | } |
107 | } |
108 | |
109 | Platform::Terminate(); |
110 | } |
111 | |
112 | llvm::StringRef PlatformDarwin::GetDescriptionStatic() { |
113 | return "Darwin platform plug-in."; |
114 | } |
115 | |
116 | PlatformSP PlatformDarwin::CreateInstance(bool force, const ArchSpec *arch) { |
117 | // We only create subclasses of the PlatformDarwin plugin. |
118 | return PlatformSP(); |
119 | } |
120 | |
121 | #define LLDB_PROPERTIES_platformdarwin |
122 | #include "PlatformMacOSXProperties.inc" |
123 | |
124 | #define LLDB_PROPERTIES_platformdarwin |
125 | enum { |
126 | #include "PlatformMacOSXPropertiesEnum.inc" |
127 | }; |
128 | |
129 | class PlatformDarwinProperties : public Properties { |
130 | public: |
131 | static llvm::StringRef GetSettingName() { |
132 | static constexpr llvm::StringLiteral g_setting_name("darwin"); |
133 | return g_setting_name; |
134 | } |
135 | |
136 | PlatformDarwinProperties() : Properties() { |
137 | m_collection_sp = std::make_shared<OptionValueProperties>(args: GetSettingName()); |
138 | m_collection_sp->Initialize(setting_definitions: g_platformdarwin_properties); |
139 | } |
140 | |
141 | ~PlatformDarwinProperties() override = default; |
142 | |
143 | const char *GetIgnoredExceptions() const { |
144 | const uint32_t idx = ePropertyIgnoredExceptions; |
145 | const OptionValueString *option_value = |
146 | m_collection_sp->GetPropertyAtIndexAsOptionValueString(idx); |
147 | assert(option_value); |
148 | return option_value->GetCurrentValue(); |
149 | } |
150 | |
151 | OptionValueString *GetIgnoredExceptionValue() { |
152 | const uint32_t idx = ePropertyIgnoredExceptions; |
153 | OptionValueString *option_value = |
154 | m_collection_sp->GetPropertyAtIndexAsOptionValueString(idx); |
155 | assert(option_value); |
156 | return option_value; |
157 | } |
158 | }; |
159 | |
160 | static PlatformDarwinProperties &GetGlobalProperties() { |
161 | static PlatformDarwinProperties g_settings; |
162 | return g_settings; |
163 | } |
164 | |
165 | void PlatformDarwin::DebuggerInitialize( |
166 | lldb_private::Debugger &debugger) { |
167 | if (!PluginManager::GetSettingForPlatformPlugin( |
168 | debugger, setting_name: PlatformDarwinProperties::GetSettingName())) { |
169 | const bool is_global_setting = false; |
170 | PluginManager::CreateSettingForPlatformPlugin( |
171 | debugger, properties_sp: GetGlobalProperties().GetValueProperties(), |
172 | description: "Properties for the Darwin platform plug-in.", is_global_property: is_global_setting); |
173 | OptionValueString *value = GetGlobalProperties().GetIgnoredExceptionValue(); |
174 | value->SetValidator(validator: ExceptionMaskValidator); |
175 | } |
176 | } |
177 | |
178 | Args |
179 | PlatformDarwin::GetExtraStartupCommands() { |
180 | std::string ignored_exceptions |
181 | = GetGlobalProperties().GetIgnoredExceptions(); |
182 | if (ignored_exceptions.empty()) |
183 | return {}; |
184 | Args ret_args; |
185 | std::string packet = "QSetIgnoredExceptions:"; |
186 | packet.append(str: ignored_exceptions); |
187 | ret_args.AppendArgument(arg_str: packet); |
188 | return ret_args; |
189 | } |
190 | |
191 | lldb_private::Status |
192 | PlatformDarwin::PutFile(const lldb_private::FileSpec &source, |
193 | const lldb_private::FileSpec &destination, uint32_t uid, |
194 | uint32_t gid) { |
195 | // Unconditionally unlink the destination. If it is an executable, |
196 | // simply opening it and truncating its contents would invalidate |
197 | // its cached code signature. |
198 | Unlink(file_spec: destination); |
199 | return PlatformPOSIX::PutFile(source, destination, uid, gid); |
200 | } |
201 | |
202 | FileSpecList PlatformDarwin::LocateExecutableScriptingResources( |
203 | Target *target, Module &module, Stream &feedback_stream) { |
204 | FileSpecList file_list; |
205 | if (target && |
206 | target->GetDebugger().GetScriptLanguage() == eScriptLanguagePython) { |
207 | // NB some extensions might be meaningful and should not be stripped - |
208 | // "this.binary.file" |
209 | // should not lose ".file" but GetFileNameStrippingExtension() will do |
210 | // precisely that. Ideally, we should have a per-platform list of |
211 | // extensions (".exe", ".app", ".dSYM", ".framework") which should be |
212 | // stripped while leaving "this.binary.file" as-is. |
213 | |
214 | FileSpec module_spec = module.GetFileSpec(); |
215 | |
216 | if (module_spec) { |
217 | if (SymbolFile *symfile = module.GetSymbolFile()) { |
218 | ObjectFile *objfile = symfile->GetObjectFile(); |
219 | if (objfile) { |
220 | FileSpec symfile_spec(objfile->GetFileSpec()); |
221 | if (symfile_spec && |
222 | llvm::StringRef(symfile_spec.GetPath()) |
223 | .contains_insensitive(Other: ".dSYM/Contents/Resources/DWARF") && |
224 | FileSystem::Instance().Exists(file_spec: symfile_spec)) { |
225 | while (module_spec.GetFilename()) { |
226 | std::string module_basename( |
227 | module_spec.GetFilename().GetCString()); |
228 | std::string original_module_basename(module_basename); |
229 | |
230 | bool was_keyword = false; |
231 | |
232 | // FIXME: for Python, we cannot allow certain characters in |
233 | // module |
234 | // filenames we import. Theoretically, different scripting |
235 | // languages may have different sets of forbidden tokens in |
236 | // filenames, and that should be dealt with by each |
237 | // ScriptInterpreter. For now, we just replace dots with |
238 | // underscores, but if we ever support anything other than |
239 | // Python we will need to rework this |
240 | llvm::replace(Range&: module_basename, OldValue: '.', NewValue: '_'); |
241 | llvm::replace(Range&: module_basename, OldValue: ' ', NewValue: '_'); |
242 | llvm::replace(Range&: module_basename, OldValue: '-', NewValue: '_'); |
243 | ScriptInterpreter *script_interpreter = |
244 | target->GetDebugger().GetScriptInterpreter(); |
245 | if (script_interpreter && |
246 | script_interpreter->IsReservedWord(word: module_basename.c_str())) { |
247 | module_basename.insert(p: module_basename.begin(), c: '_'); |
248 | was_keyword = true; |
249 | } |
250 | |
251 | StreamString path_string; |
252 | StreamString original_path_string; |
253 | // for OSX we are going to be in |
254 | // .dSYM/Contents/Resources/DWARF/<basename> let us go to |
255 | // .dSYM/Contents/Resources/Python/<basename>.py and see if the |
256 | // file exists |
257 | path_string.Printf(format: "%s/../Python/%s.py", |
258 | symfile_spec.GetDirectory().GetCString(), |
259 | module_basename.c_str()); |
260 | original_path_string.Printf( |
261 | format: "%s/../Python/%s.py", |
262 | symfile_spec.GetDirectory().GetCString(), |
263 | original_module_basename.c_str()); |
264 | FileSpec script_fspec(path_string.GetString()); |
265 | FileSystem::Instance().Resolve(file_spec&: script_fspec); |
266 | FileSpec orig_script_fspec(original_path_string.GetString()); |
267 | FileSystem::Instance().Resolve(file_spec&: orig_script_fspec); |
268 | |
269 | // if we did some replacements of reserved characters, and a |
270 | // file with the untampered name exists, then warn the user |
271 | // that the file as-is shall not be loaded |
272 | if (module_basename != original_module_basename && |
273 | FileSystem::Instance().Exists(file_spec: orig_script_fspec)) { |
274 | const char *reason_for_complaint = |
275 | was_keyword ? "conflicts with a keyword" |
276 | : "contains reserved characters"; |
277 | if (FileSystem::Instance().Exists(file_spec: script_fspec)) |
278 | feedback_stream.Printf( |
279 | format: "warning: the symbol file '%s' contains a debug " |
280 | "script. However, its name" |
281 | " '%s' %s and as such cannot be loaded. LLDB will" |
282 | " load '%s' instead. Consider removing the file with " |
283 | "the malformed name to" |
284 | " eliminate this warning.\n", |
285 | symfile_spec.GetPath().c_str(), |
286 | original_path_string.GetData(), reason_for_complaint, |
287 | path_string.GetData()); |
288 | else |
289 | feedback_stream.Printf( |
290 | format: "warning: the symbol file '%s' contains a debug " |
291 | "script. However, its name" |
292 | " %s and as such cannot be loaded. If you intend" |
293 | " to have this script loaded, please rename '%s' to " |
294 | "'%s' and retry.\n", |
295 | symfile_spec.GetPath().c_str(), reason_for_complaint, |
296 | original_path_string.GetData(), path_string.GetData()); |
297 | } |
298 | |
299 | if (FileSystem::Instance().Exists(file_spec: script_fspec)) { |
300 | file_list.Append(file: script_fspec); |
301 | break; |
302 | } |
303 | |
304 | // If we didn't find the python file, then keep stripping the |
305 | // extensions and try again |
306 | ConstString filename_no_extension( |
307 | module_spec.GetFileNameStrippingExtension()); |
308 | if (module_spec.GetFilename() == filename_no_extension) |
309 | break; |
310 | |
311 | module_spec.SetFilename(filename_no_extension); |
312 | } |
313 | } |
314 | } |
315 | } |
316 | } |
317 | } |
318 | return file_list; |
319 | } |
320 | |
321 | Status PlatformDarwin::ResolveSymbolFile(Target &target, |
322 | const ModuleSpec &sym_spec, |
323 | FileSpec &sym_file) { |
324 | sym_file = sym_spec.GetSymbolFileSpec(); |
325 | if (FileSystem::Instance().IsDirectory(file_spec: sym_file)) { |
326 | sym_file = PluginManager::FindSymbolFileInBundle( |
327 | dsym_bundle_fspec: sym_file, uuid: sym_spec.GetUUIDPtr(), arch: sym_spec.GetArchitecturePtr()); |
328 | } |
329 | return {}; |
330 | } |
331 | |
332 | Status PlatformDarwin::GetSharedModule( |
333 | const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, |
334 | const FileSpecList *module_search_paths_ptr, |
335 | llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) { |
336 | Status error; |
337 | module_sp.reset(); |
338 | |
339 | if (IsRemote()) { |
340 | // If we have a remote platform always, let it try and locate the shared |
341 | // module first. |
342 | if (m_remote_platform_sp) { |
343 | error = m_remote_platform_sp->GetSharedModule( |
344 | module_spec, process, module_sp, module_search_paths_ptr, old_modules, |
345 | did_create_ptr); |
346 | } |
347 | } |
348 | |
349 | if (!module_sp) { |
350 | // Fall back to the local platform and find the file locally |
351 | error = Platform::GetSharedModule(module_spec, process, module_sp, |
352 | module_search_paths_ptr, old_modules, |
353 | did_create_ptr); |
354 | |
355 | const FileSpec &platform_file = module_spec.GetFileSpec(); |
356 | if (!module_sp && module_search_paths_ptr && platform_file) { |
357 | // We can try to pull off part of the file path up to the bundle |
358 | // directory level and try any module search paths... |
359 | FileSpec bundle_directory; |
360 | if (Host::GetBundleDirectory(file: platform_file, bundle_directory)) { |
361 | if (platform_file == bundle_directory) { |
362 | ModuleSpec new_module_spec(module_spec); |
363 | new_module_spec.GetFileSpec() = bundle_directory; |
364 | if (Host::ResolveExecutableInBundle(file&: new_module_spec.GetFileSpec())) { |
365 | Status new_error(Platform::GetSharedModule( |
366 | module_spec: new_module_spec, process, module_sp, module_search_paths_ptr: nullptr, old_modules, |
367 | did_create_ptr)); |
368 | |
369 | if (module_sp) |
370 | return new_error; |
371 | } |
372 | } else { |
373 | char platform_path[PATH_MAX]; |
374 | char bundle_dir[PATH_MAX]; |
375 | platform_file.GetPath(path: platform_path, max_path_length: sizeof(platform_path)); |
376 | const size_t bundle_directory_len = |
377 | bundle_directory.GetPath(path: bundle_dir, max_path_length: sizeof(bundle_dir)); |
378 | char new_path[PATH_MAX]; |
379 | size_t num_module_search_paths = module_search_paths_ptr->GetSize(); |
380 | for (size_t i = 0; i < num_module_search_paths; ++i) { |
381 | const size_t search_path_len = |
382 | module_search_paths_ptr->GetFileSpecAtIndex(idx: i).GetPath( |
383 | path: new_path, max_path_length: sizeof(new_path)); |
384 | if (search_path_len < sizeof(new_path)) { |
385 | snprintf(s: new_path + search_path_len, |
386 | maxlen: sizeof(new_path) - search_path_len, format: "/%s", |
387 | platform_path + bundle_directory_len); |
388 | FileSpec new_file_spec(new_path); |
389 | if (FileSystem::Instance().Exists(file_spec: new_file_spec)) { |
390 | ModuleSpec new_module_spec(module_spec); |
391 | new_module_spec.GetFileSpec() = new_file_spec; |
392 | Status new_error(Platform::GetSharedModule( |
393 | module_spec: new_module_spec, process, module_sp, module_search_paths_ptr: nullptr, old_modules, |
394 | did_create_ptr)); |
395 | |
396 | if (module_sp) { |
397 | module_sp->SetPlatformFileSpec(new_file_spec); |
398 | return new_error; |
399 | } |
400 | } |
401 | } |
402 | } |
403 | } |
404 | } |
405 | } |
406 | } |
407 | if (module_sp) |
408 | module_sp->SetPlatformFileSpec(module_spec.GetFileSpec()); |
409 | return error; |
410 | } |
411 | |
412 | size_t |
413 | PlatformDarwin::GetSoftwareBreakpointTrapOpcode(Target &target, |
414 | BreakpointSite *bp_site) { |
415 | const uint8_t *trap_opcode = nullptr; |
416 | uint32_t trap_opcode_size = 0; |
417 | bool bp_is_thumb = false; |
418 | |
419 | llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine(); |
420 | switch (machine) { |
421 | case llvm::Triple::aarch64_32: |
422 | case llvm::Triple::aarch64: { |
423 | // 'brk #0' or 0xd4200000 in BE byte order |
424 | static const uint8_t g_arm64_breakpoint_opcode[] = {0x00, 0x00, 0x20, 0xD4}; |
425 | trap_opcode = g_arm64_breakpoint_opcode; |
426 | trap_opcode_size = sizeof(g_arm64_breakpoint_opcode); |
427 | } break; |
428 | |
429 | case llvm::Triple::thumb: |
430 | bp_is_thumb = true; |
431 | [[fallthrough]]; |
432 | case llvm::Triple::arm: { |
433 | static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7}; |
434 | static const uint8_t g_thumb_breakpooint_opcode[] = {0xFE, 0xDE}; |
435 | |
436 | // Auto detect arm/thumb if it wasn't explicitly specified |
437 | if (!bp_is_thumb) { |
438 | lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(idx: 0)); |
439 | if (bp_loc_sp) |
440 | bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass() == |
441 | AddressClass::eCodeAlternateISA; |
442 | } |
443 | if (bp_is_thumb) { |
444 | trap_opcode = g_thumb_breakpooint_opcode; |
445 | trap_opcode_size = sizeof(g_thumb_breakpooint_opcode); |
446 | break; |
447 | } |
448 | trap_opcode = g_arm_breakpoint_opcode; |
449 | trap_opcode_size = sizeof(g_arm_breakpoint_opcode); |
450 | } break; |
451 | |
452 | case llvm::Triple::ppc: |
453 | case llvm::Triple::ppc64: { |
454 | static const uint8_t g_ppc_breakpoint_opcode[] = {0x7F, 0xC0, 0x00, 0x08}; |
455 | trap_opcode = g_ppc_breakpoint_opcode; |
456 | trap_opcode_size = sizeof(g_ppc_breakpoint_opcode); |
457 | } break; |
458 | |
459 | default: |
460 | return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site); |
461 | } |
462 | |
463 | if (trap_opcode && trap_opcode_size) { |
464 | if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) |
465 | return trap_opcode_size; |
466 | } |
467 | return 0; |
468 | } |
469 | |
470 | bool PlatformDarwin::ModuleIsExcludedForUnconstrainedSearches( |
471 | lldb_private::Target &target, const lldb::ModuleSP &module_sp) { |
472 | if (!module_sp) |
473 | return false; |
474 | |
475 | ObjectFile *obj_file = module_sp->GetObjectFile(); |
476 | if (!obj_file) |
477 | return false; |
478 | |
479 | ObjectFile::Type obj_type = obj_file->GetType(); |
480 | return obj_type == ObjectFile::eTypeDynamicLinker; |
481 | } |
482 | |
483 | void PlatformDarwin::x86GetSupportedArchitectures( |
484 | std::vector<ArchSpec> &archs) { |
485 | ArchSpec host_arch = HostInfo::GetArchitecture(arch_kind: HostInfo::eArchKindDefault); |
486 | archs.push_back(x: host_arch); |
487 | |
488 | if (host_arch.GetCore() == ArchSpec::eCore_x86_64_x86_64h) { |
489 | archs.push_back(x: ArchSpec("x86_64-apple-macosx")); |
490 | archs.push_back(x: HostInfo::GetArchitecture(arch_kind: HostInfo::eArchKind32)); |
491 | } else { |
492 | ArchSpec host_arch64 = HostInfo::GetArchitecture(arch_kind: HostInfo::eArchKind64); |
493 | if (host_arch.IsExactMatch(rhs: host_arch64)) |
494 | archs.push_back(x: HostInfo::GetArchitecture(arch_kind: HostInfo::eArchKind32)); |
495 | } |
496 | } |
497 | |
498 | static llvm::ArrayRef<const char *> GetCompatibleArchs(ArchSpec::Core core) { |
499 | switch (core) { |
500 | default: |
501 | [[fallthrough]]; |
502 | case ArchSpec::eCore_arm_arm64e: { |
503 | static const char *g_arm64e_compatible_archs[] = { |
504 | "arm64e", "arm64", "armv7", "armv7f", "armv7k", "armv7s", |
505 | "armv7m", "armv7em", "armv6m", "armv6", "armv5", "armv4", |
506 | "arm", "thumbv7", "thumbv7f", "thumbv7k", "thumbv7s", "thumbv7m", |
507 | "thumbv7em", "thumbv6m", "thumbv6", "thumbv5", "thumbv4t", "thumb", |
508 | }; |
509 | return {g_arm64e_compatible_archs}; |
510 | } |
511 | case ArchSpec::eCore_arm_arm64: { |
512 | static const char *g_arm64_compatible_archs[] = { |
513 | "arm64", "armv7", "armv7f", "armv7k", "armv7s", "armv7m", |
514 | "armv7em", "armv6m", "armv6", "armv5", "armv4", "arm", |
515 | "thumbv7", "thumbv7f", "thumbv7k", "thumbv7s", "thumbv7m", "thumbv7em", |
516 | "thumbv6m", "thumbv6", "thumbv5", "thumbv4t", "thumb", |
517 | }; |
518 | return {g_arm64_compatible_archs}; |
519 | } |
520 | case ArchSpec::eCore_arm_armv7: { |
521 | static const char *g_armv7_compatible_archs[] = { |
522 | "armv7", "armv6m", "armv6", "armv5", "armv4", "arm", |
523 | "thumbv7", "thumbv6m", "thumbv6", "thumbv5", "thumbv4t", "thumb", |
524 | }; |
525 | return {g_armv7_compatible_archs}; |
526 | } |
527 | case ArchSpec::eCore_arm_armv7f: { |
528 | static const char *g_armv7f_compatible_archs[] = { |
529 | "armv7f", "armv7", "armv6m", "armv6", "armv5", |
530 | "armv4", "arm", "thumbv7f", "thumbv7", "thumbv6m", |
531 | "thumbv6", "thumbv5", "thumbv4t", "thumb", |
532 | }; |
533 | return {g_armv7f_compatible_archs}; |
534 | } |
535 | case ArchSpec::eCore_arm_armv7k: { |
536 | static const char *g_armv7k_compatible_archs[] = { |
537 | "armv7k", "armv7", "armv6m", "armv6", "armv5", |
538 | "armv4", "arm", "thumbv7k", "thumbv7", "thumbv6m", |
539 | "thumbv6", "thumbv5", "thumbv4t", "thumb", |
540 | }; |
541 | return {g_armv7k_compatible_archs}; |
542 | } |
543 | case ArchSpec::eCore_arm_armv7s: { |
544 | static const char *g_armv7s_compatible_archs[] = { |
545 | "armv7s", "armv7", "armv6m", "armv6", "armv5", |
546 | "armv4", "arm", "thumbv7s", "thumbv7", "thumbv6m", |
547 | "thumbv6", "thumbv5", "thumbv4t", "thumb", |
548 | }; |
549 | return {g_armv7s_compatible_archs}; |
550 | } |
551 | case ArchSpec::eCore_arm_armv7m: { |
552 | static const char *g_armv7m_compatible_archs[] = { |
553 | "armv7m", "armv7", "armv6m", "armv6", "armv5", |
554 | "armv4", "arm", "thumbv7m", "thumbv7", "thumbv6m", |
555 | "thumbv6", "thumbv5", "thumbv4t", "thumb", |
556 | }; |
557 | return {g_armv7m_compatible_archs}; |
558 | } |
559 | case ArchSpec::eCore_arm_armv7em: { |
560 | static const char *g_armv7em_compatible_archs[] = { |
561 | "armv7em", "armv7", "armv6m", "armv6", "armv5", |
562 | "armv4", "arm", "thumbv7em", "thumbv7", "thumbv6m", |
563 | "thumbv6", "thumbv5", "thumbv4t", "thumb", |
564 | }; |
565 | return {g_armv7em_compatible_archs}; |
566 | } |
567 | case ArchSpec::eCore_arm_armv6m: { |
568 | static const char *g_armv6m_compatible_archs[] = { |
569 | "armv6m", "armv6", "armv5", "armv4", "arm", |
570 | "thumbv6m", "thumbv6", "thumbv5", "thumbv4t", "thumb", |
571 | }; |
572 | return {g_armv6m_compatible_archs}; |
573 | } |
574 | case ArchSpec::eCore_arm_armv6: { |
575 | static const char *g_armv6_compatible_archs[] = { |
576 | "armv6", "armv5", "armv4", "arm", |
577 | "thumbv6", "thumbv5", "thumbv4t", "thumb", |
578 | }; |
579 | return {g_armv6_compatible_archs}; |
580 | } |
581 | case ArchSpec::eCore_arm_armv5: { |
582 | static const char *g_armv5_compatible_archs[] = { |
583 | "armv5", "armv4", "arm", "thumbv5", "thumbv4t", "thumb", |
584 | }; |
585 | return {g_armv5_compatible_archs}; |
586 | } |
587 | case ArchSpec::eCore_arm_armv4: { |
588 | static const char *g_armv4_compatible_archs[] = { |
589 | "armv4", |
590 | "arm", |
591 | "thumbv4t", |
592 | "thumb", |
593 | }; |
594 | return {g_armv4_compatible_archs}; |
595 | } |
596 | } |
597 | return {}; |
598 | } |
599 | |
600 | /// The architecture selection rules for arm processors These cpu subtypes have |
601 | /// distinct names (e.g. armv7f) but armv7 binaries run fine on an armv7f |
602 | /// processor. |
603 | void PlatformDarwin::ARMGetSupportedArchitectures( |
604 | std::vector<ArchSpec> &archs, std::optional<llvm::Triple::OSType> os) { |
605 | const ArchSpec system_arch = GetSystemArchitecture(); |
606 | const ArchSpec::Core system_core = system_arch.GetCore(); |
607 | for (const char *arch : GetCompatibleArchs(core: system_core)) { |
608 | llvm::Triple triple; |
609 | triple.setArchName(arch); |
610 | triple.setVendor(llvm::Triple::VendorType::Apple); |
611 | if (os) |
612 | triple.setOS(*os); |
613 | archs.push_back(x: ArchSpec(triple)); |
614 | } |
615 | } |
616 | |
617 | static FileSpec GetXcodeSelectPath() { |
618 | static FileSpec g_xcode_select_filespec; |
619 | |
620 | if (!g_xcode_select_filespec) { |
621 | FileSpec xcode_select_cmd("/usr/bin/xcode-select"); |
622 | if (FileSystem::Instance().Exists(file_spec: xcode_select_cmd)) { |
623 | int exit_status = -1; |
624 | int signo = -1; |
625 | std::string command_output; |
626 | Status status = |
627 | Host::RunShellCommand(command: "/usr/bin/xcode-select --print-path", |
628 | working_dir: FileSpec(), // current working directory |
629 | status_ptr: &exit_status, signo_ptr: &signo, command_output: &command_output, |
630 | timeout: std::chrono::seconds(2), // short timeout |
631 | run_in_shell: false); // don't run in a shell |
632 | if (status.Success() && exit_status == 0 && !command_output.empty()) { |
633 | size_t first_non_newline = command_output.find_last_not_of(s: "\r\n"); |
634 | if (first_non_newline != std::string::npos) { |
635 | command_output.erase(pos: first_non_newline + 1); |
636 | } |
637 | g_xcode_select_filespec = FileSpec(command_output); |
638 | } |
639 | } |
640 | } |
641 | |
642 | return g_xcode_select_filespec; |
643 | } |
644 | |
645 | BreakpointSP PlatformDarwin::SetThreadCreationBreakpoint(Target &target) { |
646 | BreakpointSP bp_sp; |
647 | static const char *g_bp_names[] = { |
648 | "start_wqthread", "_pthread_wqthread", "_pthread_start", |
649 | }; |
650 | |
651 | static const char *g_bp_modules[] = {"libsystem_c.dylib", "libSystem.B.dylib", |
652 | "libsystem_pthread.dylib"}; |
653 | |
654 | FileSpecList bp_modules; |
655 | for (size_t i = 0; i < std::size(g_bp_modules); i++) { |
656 | const char *bp_module = g_bp_modules[i]; |
657 | bp_modules.EmplaceBack(args&: bp_module); |
658 | } |
659 | |
660 | bool internal = true; |
661 | bool hardware = false; |
662 | LazyBool skip_prologue = eLazyBoolNo; |
663 | bp_sp = target.CreateBreakpoint(containingModules: &bp_modules, containingSourceFiles: nullptr, func_names: g_bp_names, |
664 | num_names: std::size(g_bp_names), func_name_type_mask: eFunctionNameTypeFull, |
665 | language: eLanguageTypeUnknown, offset: 0, skip_prologue, |
666 | internal, request_hardware: hardware); |
667 | bp_sp->SetBreakpointKind("thread-creation"); |
668 | |
669 | return bp_sp; |
670 | } |
671 | |
672 | uint32_t |
673 | PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { |
674 | const FileSpec &shell = launch_info.GetShell(); |
675 | if (!shell) |
676 | return 1; |
677 | |
678 | std::string shell_string = shell.GetPath(); |
679 | const char *shell_name = strrchr(s: shell_string.c_str(), c: '/'); |
680 | if (shell_name == nullptr) |
681 | shell_name = shell_string.c_str(); |
682 | else |
683 | shell_name++; |
684 | |
685 | if (strcmp(s1: shell_name, s2: "sh") == 0) { |
686 | // /bin/sh re-exec's itself as /bin/bash requiring another resume. But it |
687 | // only does this if the COMMAND_MODE environment variable is set to |
688 | // "legacy". |
689 | if (launch_info.GetEnvironment().lookup(Key: "COMMAND_MODE") == "legacy") |
690 | return 2; |
691 | return 1; |
692 | } else if (strcmp(s1: shell_name, s2: "csh") == 0 || |
693 | strcmp(s1: shell_name, s2: "tcsh") == 0 || |
694 | strcmp(s1: shell_name, s2: "zsh") == 0) { |
695 | // csh and tcsh always seem to re-exec themselves. |
696 | return 2; |
697 | } else |
698 | return 1; |
699 | } |
700 | |
701 | lldb::ProcessSP PlatformDarwin::DebugProcess(ProcessLaunchInfo &launch_info, |
702 | Debugger &debugger, Target &target, |
703 | Status &error) { |
704 | ProcessSP process_sp; |
705 | |
706 | if (IsHost()) { |
707 | // We are going to hand this process off to debugserver which will be in |
708 | // charge of setting the exit status. However, we still need to reap it |
709 | // from lldb. So, make sure we use a exit callback which does not set exit |
710 | // status. |
711 | launch_info.SetMonitorProcessCallback( |
712 | &ProcessLaunchInfo::NoOpMonitorCallback); |
713 | process_sp = Platform::DebugProcess(launch_info, debugger, target, error); |
714 | } else { |
715 | if (m_remote_platform_sp) |
716 | process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, |
717 | target, error); |
718 | else |
719 | error = |
720 | Status::FromErrorString(str: "the platform is not currently connected"); |
721 | } |
722 | return process_sp; |
723 | } |
724 | |
725 | void PlatformDarwin::CalculateTrapHandlerSymbolNames() { |
726 | m_trap_handlers.push_back(x: ConstString("_sigtramp")); |
727 | } |
728 | |
729 | static FileSpec GetCommandLineToolsLibraryPath() { |
730 | static FileSpec g_command_line_tools_filespec; |
731 | |
732 | if (!g_command_line_tools_filespec) { |
733 | FileSpec command_line_tools_path(GetXcodeSelectPath()); |
734 | command_line_tools_path.AppendPathComponent(component: "Library"); |
735 | if (FileSystem::Instance().Exists(file_spec: command_line_tools_path)) { |
736 | g_command_line_tools_filespec = command_line_tools_path; |
737 | } |
738 | } |
739 | |
740 | return g_command_line_tools_filespec; |
741 | } |
742 | |
743 | FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( |
744 | void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) { |
745 | SDKEnumeratorInfo *enumerator_info = static_cast<SDKEnumeratorInfo *>(baton); |
746 | |
747 | FileSpec spec(path); |
748 | if (XcodeSDK::SDKSupportsModules(desired_type: enumerator_info->sdk_type, sdk_path: spec)) { |
749 | enumerator_info->found_path = spec; |
750 | return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; |
751 | } |
752 | |
753 | return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; |
754 | } |
755 | |
756 | FileSpec PlatformDarwin::FindSDKInXcodeForModules(XcodeSDK::Type sdk_type, |
757 | const FileSpec &sdks_spec) { |
758 | // Look inside Xcode for the required installed iOS SDK version |
759 | |
760 | if (!FileSystem::Instance().IsDirectory(file_spec: sdks_spec)) { |
761 | return FileSpec(); |
762 | } |
763 | |
764 | const bool find_directories = true; |
765 | const bool find_files = false; |
766 | const bool find_other = true; // include symlinks |
767 | |
768 | SDKEnumeratorInfo enumerator_info; |
769 | |
770 | enumerator_info.sdk_type = sdk_type; |
771 | |
772 | FileSystem::Instance().EnumerateDirectory( |
773 | path: sdks_spec.GetPath(), find_directories, find_files, find_other, |
774 | callback: DirectoryEnumerator, callback_baton: &enumerator_info); |
775 | |
776 | if (FileSystem::Instance().IsDirectory(file_spec: enumerator_info.found_path)) |
777 | return enumerator_info.found_path; |
778 | else |
779 | return FileSpec(); |
780 | } |
781 | |
782 | FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) { |
783 | FileSpec sdks_spec = HostInfo::GetXcodeContentsDirectory(); |
784 | sdks_spec.AppendPathComponent(component: "Developer"); |
785 | sdks_spec.AppendPathComponent(component: "Platforms"); |
786 | |
787 | switch (sdk_type) { |
788 | case XcodeSDK::Type::MacOSX: |
789 | sdks_spec.AppendPathComponent(component: "MacOSX.platform"); |
790 | break; |
791 | case XcodeSDK::Type::iPhoneSimulator: |
792 | sdks_spec.AppendPathComponent(component: "iPhoneSimulator.platform"); |
793 | break; |
794 | case XcodeSDK::Type::iPhoneOS: |
795 | sdks_spec.AppendPathComponent(component: "iPhoneOS.platform"); |
796 | break; |
797 | case XcodeSDK::Type::WatchSimulator: |
798 | sdks_spec.AppendPathComponent(component: "WatchSimulator.platform"); |
799 | break; |
800 | case XcodeSDK::Type::AppleTVSimulator: |
801 | sdks_spec.AppendPathComponent(component: "AppleTVSimulator.platform"); |
802 | break; |
803 | case XcodeSDK::Type::XRSimulator: |
804 | sdks_spec.AppendPathComponent(component: "XRSimulator.platform"); |
805 | break; |
806 | default: |
807 | llvm_unreachable("unsupported sdk"); |
808 | } |
809 | |
810 | sdks_spec.AppendPathComponent(component: "Developer"); |
811 | sdks_spec.AppendPathComponent(component: "SDKs"); |
812 | |
813 | if (sdk_type == XcodeSDK::Type::MacOSX) { |
814 | llvm::VersionTuple version = HostInfo::GetOSVersion(); |
815 | |
816 | if (!version.empty()) { |
817 | if (XcodeSDK::SDKSupportsModules(type: XcodeSDK::Type::MacOSX, version)) { |
818 | // If the Xcode SDKs are not available then try to use the |
819 | // Command Line Tools one which is only for MacOSX. |
820 | if (!FileSystem::Instance().Exists(file_spec: sdks_spec)) { |
821 | sdks_spec = GetCommandLineToolsLibraryPath(); |
822 | sdks_spec.AppendPathComponent(component: "SDKs"); |
823 | } |
824 | |
825 | // We slightly prefer the exact SDK for this machine. See if it is |
826 | // there. |
827 | |
828 | FileSpec native_sdk_spec = sdks_spec; |
829 | StreamString native_sdk_name; |
830 | native_sdk_name.Printf(format: "MacOSX%u.%u.sdk", version.getMajor(), |
831 | version.getMinor().value_or(u: 0)); |
832 | native_sdk_spec.AppendPathComponent(component: native_sdk_name.GetString()); |
833 | |
834 | if (FileSystem::Instance().Exists(file_spec: native_sdk_spec)) { |
835 | return native_sdk_spec; |
836 | } |
837 | } |
838 | } |
839 | } |
840 | |
841 | return FindSDKInXcodeForModules(sdk_type, sdks_spec); |
842 | } |
843 | |
844 | std::tuple<llvm::VersionTuple, llvm::StringRef> |
845 | PlatformDarwin::ParseVersionBuildDir(llvm::StringRef dir) { |
846 | llvm::StringRef build; |
847 | llvm::StringRef version_str; |
848 | llvm::StringRef build_str; |
849 | std::tie(args&: version_str, args&: build_str) = dir.split(Separator: ' '); |
850 | llvm::VersionTuple version; |
851 | if (!version.tryParse(string: version_str) || |
852 | build_str.empty()) { |
853 | if (build_str.consume_front(Prefix: "(")) { |
854 | size_t pos = build_str.find(C: ')'); |
855 | build = build_str.slice(Start: 0, End: pos); |
856 | } |
857 | } |
858 | |
859 | return std::make_tuple(args&: version, args&: build); |
860 | } |
861 | |
862 | llvm::Expected<StructuredData::DictionarySP> |
863 | PlatformDarwin::FetchExtendedCrashInformation(Process &process) { |
864 | static constexpr llvm::StringLiteral crash_info_key("Crash-Info Annotations"); |
865 | static constexpr llvm::StringLiteral asi_info_key( |
866 | "Application Specific Information"); |
867 | |
868 | // We cache the information we find in the process extended info dict: |
869 | StructuredData::DictionarySP process_dict_sp = |
870 | process.GetExtendedCrashInfoDict(); |
871 | StructuredData::Array *annotations = nullptr; |
872 | StructuredData::ArraySP new_annotations_sp; |
873 | if (!process_dict_sp->GetValueForKeyAsArray(key: crash_info_key, result&: annotations)) { |
874 | new_annotations_sp = ExtractCrashInfoAnnotations(process); |
875 | if (new_annotations_sp && new_annotations_sp->GetSize()) { |
876 | process_dict_sp->AddItem(key: crash_info_key, value_sp: new_annotations_sp); |
877 | annotations = new_annotations_sp.get(); |
878 | } |
879 | } |
880 | |
881 | StructuredData::Dictionary *app_specific_info; |
882 | StructuredData::DictionarySP new_app_specific_info_sp; |
883 | if (!process_dict_sp->GetValueForKeyAsDictionary(key: asi_info_key, |
884 | result&: app_specific_info)) { |
885 | new_app_specific_info_sp = ExtractAppSpecificInfo(process); |
886 | if (new_app_specific_info_sp && new_app_specific_info_sp->GetSize()) { |
887 | process_dict_sp->AddItem(key: asi_info_key, value_sp: new_app_specific_info_sp); |
888 | app_specific_info = new_app_specific_info_sp.get(); |
889 | } |
890 | } |
891 | |
892 | // Now get anything else that was in the process info dict, and add it to the |
893 | // return here: |
894 | return process_dict_sp->GetSize() ? process_dict_sp : nullptr; |
895 | } |
896 | |
897 | StructuredData::ArraySP |
898 | PlatformDarwin::ExtractCrashInfoAnnotations(Process &process) { |
899 | Log *log = GetLog(mask: LLDBLog::Process); |
900 | |
901 | ConstString section_name("__crash_info"); |
902 | Target &target = process.GetTarget(); |
903 | StructuredData::ArraySP array_sp = std::make_shared<StructuredData::Array>(); |
904 | |
905 | for (ModuleSP module : target.GetImages().Modules()) { |
906 | SectionList *sections = module->GetSectionList(); |
907 | |
908 | std::string module_name = module->GetSpecificationDescription(); |
909 | |
910 | // The DYDL module is skipped since it's always loaded when running the |
911 | // binary. |
912 | if (module_name == "/usr/lib/dyld") |
913 | continue; |
914 | |
915 | if (!sections) { |
916 | LLDB_LOG(log, "Module {0} doesn't have any section!", module_name); |
917 | continue; |
918 | } |
919 | |
920 | SectionSP crash_info = sections->FindSectionByName(section_dstr: section_name); |
921 | if (!crash_info) { |
922 | LLDB_LOG(log, "Module {0} doesn't have section {1}!", module_name, |
923 | section_name); |
924 | continue; |
925 | } |
926 | |
927 | addr_t load_addr = crash_info->GetLoadBaseAddress(target: &target); |
928 | |
929 | if (load_addr == LLDB_INVALID_ADDRESS) { |
930 | LLDB_LOG(log, "Module {0} has an invalid '{1}' section load address: {2}", |
931 | module_name, section_name, load_addr); |
932 | continue; |
933 | } |
934 | |
935 | Status error; |
936 | CrashInfoAnnotations annotations; |
937 | size_t expected_size = sizeof(CrashInfoAnnotations); |
938 | size_t bytes_read = process.ReadMemoryFromInferior(vm_addr: load_addr, buf: &annotations, |
939 | size: expected_size, error); |
940 | |
941 | if (expected_size != bytes_read || error.Fail()) { |
942 | LLDB_LOG(log, "Failed to read {0} section from memory in module {1}: {2}", |
943 | section_name, module_name, error); |
944 | continue; |
945 | } |
946 | |
947 | // initial support added for version 5 |
948 | if (annotations.version < 5) { |
949 | LLDB_LOG(log, |
950 | "Annotation version lower than 5 unsupported! Module {0} has " |
951 | "version {1} instead.", |
952 | module_name, annotations.version); |
953 | continue; |
954 | } |
955 | |
956 | if (!annotations.message) { |
957 | LLDB_LOG(log, "No message available for module {0}.", module_name); |
958 | continue; |
959 | } |
960 | |
961 | std::string message; |
962 | bytes_read = |
963 | process.ReadCStringFromMemory(vm_addr: annotations.message, out_str&: message, error); |
964 | |
965 | if (message.empty() || bytes_read != message.size() || error.Fail()) { |
966 | LLDB_LOG(log, "Failed to read the message from memory in module {0}: {1}", |
967 | module_name, error); |
968 | continue; |
969 | } |
970 | |
971 | // Remove trailing newline from message |
972 | if (message.back() == '\n') |
973 | message.pop_back(); |
974 | |
975 | if (!annotations.message2) |
976 | LLDB_LOG(log, "No message2 available for module {0}.", module_name); |
977 | |
978 | std::string message2; |
979 | bytes_read = |
980 | process.ReadCStringFromMemory(vm_addr: annotations.message2, out_str&: message2, error); |
981 | |
982 | if (!message2.empty() && bytes_read == message2.size() && error.Success()) |
983 | if (message2.back() == '\n') |
984 | message2.pop_back(); |
985 | |
986 | StructuredData::DictionarySP entry_sp = |
987 | std::make_shared<StructuredData::Dictionary>(); |
988 | |
989 | entry_sp->AddStringItem(key: "image", value: module->GetFileSpec().GetPath(denormalize: false)); |
990 | entry_sp->AddStringItem(key: "uuid", value: module->GetUUID().GetAsString()); |
991 | entry_sp->AddStringItem(key: "message", value: message); |
992 | entry_sp->AddStringItem(key: "message2", value: message2); |
993 | entry_sp->AddIntegerItem(key: "abort-cause", value: annotations.abort_cause); |
994 | |
995 | array_sp->AddItem(item: entry_sp); |
996 | } |
997 | |
998 | return array_sp; |
999 | } |
1000 | |
1001 | StructuredData::DictionarySP |
1002 | PlatformDarwin::ExtractAppSpecificInfo(Process &process) { |
1003 | StructuredData::DictionarySP metadata_sp = process.GetMetadata(); |
1004 | |
1005 | if (!metadata_sp || !metadata_sp->GetSize() || !metadata_sp->HasKey(key: "asi")) |
1006 | return {}; |
1007 | |
1008 | StructuredData::Dictionary *asi; |
1009 | if (!metadata_sp->GetValueForKeyAsDictionary(key: "asi", result&: asi)) |
1010 | return {}; |
1011 | |
1012 | StructuredData::DictionarySP dict_sp = |
1013 | std::make_shared<StructuredData::Dictionary>(); |
1014 | |
1015 | auto flatten_asi_dict = [&dict_sp](llvm::StringRef key, |
1016 | StructuredData::Object *val) -> bool { |
1017 | if (!val) |
1018 | return false; |
1019 | |
1020 | StructuredData::Array *arr = val->GetAsArray(); |
1021 | if (!arr || !arr->GetSize()) |
1022 | return false; |
1023 | |
1024 | dict_sp->AddItem(key, value_sp: arr->GetItemAtIndex(idx: 0)); |
1025 | return true; |
1026 | }; |
1027 | |
1028 | asi->ForEach(callback: flatten_asi_dict); |
1029 | |
1030 | return dict_sp; |
1031 | } |
1032 | |
1033 | void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( |
1034 | Target *target, std::vector<std::string> &options, XcodeSDK::Type sdk_type) { |
1035 | const std::vector<std::string> apple_arguments = { |
1036 | "-x", "objective-c++", "-fobjc-arc", |
1037 | "-fblocks", "-D_ISO646_H", "-D__ISO646_H", |
1038 | "-fgnuc-version=4.2.1"}; |
1039 | |
1040 | options.insert(position: options.end(), first: apple_arguments.begin(), last: apple_arguments.end()); |
1041 | |
1042 | StreamString minimum_version_option; |
1043 | bool use_current_os_version = false; |
1044 | // If the SDK type is for the host OS, use its version number. |
1045 | auto get_host_os = []() { return HostInfo::GetTargetTriple().getOS(); }; |
1046 | switch (sdk_type) { |
1047 | case XcodeSDK::Type::MacOSX: |
1048 | use_current_os_version = get_host_os() == llvm::Triple::MacOSX; |
1049 | break; |
1050 | case XcodeSDK::Type::iPhoneOS: |
1051 | use_current_os_version = get_host_os() == llvm::Triple::IOS; |
1052 | break; |
1053 | case XcodeSDK::Type::AppleTVOS: |
1054 | use_current_os_version = get_host_os() == llvm::Triple::TvOS; |
1055 | break; |
1056 | case XcodeSDK::Type::watchOS: |
1057 | use_current_os_version = get_host_os() == llvm::Triple::WatchOS; |
1058 | break; |
1059 | case XcodeSDK::Type::XROS: |
1060 | use_current_os_version = get_host_os() == llvm::Triple::XROS; |
1061 | break; |
1062 | default: |
1063 | break; |
1064 | } |
1065 | |
1066 | llvm::VersionTuple version; |
1067 | if (use_current_os_version) |
1068 | version = GetOSVersion(); |
1069 | else if (target) { |
1070 | // Our OS doesn't match our executable so we need to get the min OS version |
1071 | // from the object file |
1072 | ModuleSP exe_module_sp = target->GetExecutableModule(); |
1073 | if (exe_module_sp) { |
1074 | ObjectFile *object_file = exe_module_sp->GetObjectFile(); |
1075 | if (object_file) |
1076 | version = object_file->GetMinimumOSVersion(); |
1077 | } |
1078 | } |
1079 | // Only add the version-min options if we got a version from somewhere. |
1080 | // clang has no version-min clang flag for XROS. |
1081 | if (!version.empty() && sdk_type != XcodeSDK::Type::Linux && |
1082 | sdk_type != XcodeSDK::Type::XROS) { |
1083 | #define OPTION(PREFIX_OFFSET, NAME_OFFSET, VAR, ...) \ |
1084 | llvm::StringRef opt_##VAR = OptionStrTable[NAME_OFFSET]; \ |
1085 | (void)opt_##VAR; |
1086 | #include "clang/Driver/Options.inc" |
1087 | #undef OPTION |
1088 | minimum_version_option << '-'; |
1089 | switch (sdk_type) { |
1090 | case XcodeSDK::Type::MacOSX: |
1091 | minimum_version_option << opt_mmacos_version_min_EQ; |
1092 | break; |
1093 | case XcodeSDK::Type::iPhoneSimulator: |
1094 | minimum_version_option << opt_mios_simulator_version_min_EQ; |
1095 | break; |
1096 | case XcodeSDK::Type::iPhoneOS: |
1097 | minimum_version_option << opt_mios_version_min_EQ; |
1098 | break; |
1099 | case XcodeSDK::Type::AppleTVSimulator: |
1100 | minimum_version_option << opt_mtvos_simulator_version_min_EQ; |
1101 | break; |
1102 | case XcodeSDK::Type::AppleTVOS: |
1103 | minimum_version_option << opt_mtvos_version_min_EQ; |
1104 | break; |
1105 | case XcodeSDK::Type::WatchSimulator: |
1106 | minimum_version_option << opt_mwatchos_simulator_version_min_EQ; |
1107 | break; |
1108 | case XcodeSDK::Type::watchOS: |
1109 | minimum_version_option << opt_mwatchos_version_min_EQ; |
1110 | break; |
1111 | case XcodeSDK::Type::XRSimulator: |
1112 | case XcodeSDK::Type::XROS: |
1113 | // FIXME: Pass the right argument once it exists. |
1114 | case XcodeSDK::Type::bridgeOS: |
1115 | case XcodeSDK::Type::Linux: |
1116 | case XcodeSDK::Type::unknown: |
1117 | if (Log *log = GetLog(LLDBLog::Host)) { |
1118 | XcodeSDK::Info info; |
1119 | info.type = sdk_type; |
1120 | LLDB_LOGF(log, "Clang modules on %s are not supported", |
1121 | XcodeSDK::GetCanonicalName(info).c_str()); |
1122 | } |
1123 | return; |
1124 | } |
1125 | minimum_version_option << version.getAsString(); |
1126 | options.emplace_back(std::string(minimum_version_option.GetString())); |
1127 | } |
1128 | |
1129 | FileSpec sysroot_spec; |
1130 | |
1131 | if (target) { |
1132 | if (ModuleSP exe_module_sp = target->GetExecutableModule()) { |
1133 | auto path_or_err = ResolveSDKPathFromDebugInfo(*exe_module_sp); |
1134 | if (path_or_err) { |
1135 | sysroot_spec = FileSpec(*path_or_err); |
1136 | } else { |
1137 | LLDB_LOG_ERROR(GetLog(LLDBLog::Types | LLDBLog::Host), |
1138 | path_or_err.takeError(), |
1139 | "Failed to resolve SDK path: {0}"); |
1140 | } |
1141 | } |
1142 | } |
1143 | |
1144 | if (!FileSystem::Instance().IsDirectory(path: sysroot_spec.GetPath())) { |
1145 | std::lock_guard<std::mutex> guard(m_mutex); |
1146 | sysroot_spec = GetSDKDirectoryForModules(sdk_type); |
1147 | } |
1148 | |
1149 | if (FileSystem::Instance().IsDirectory(path: sysroot_spec.GetPath())) { |
1150 | options.push_back("-isysroot"); |
1151 | options.push_back(x: sysroot_spec.GetPath()); |
1152 | } |
1153 | } |
1154 | |
1155 | ConstString PlatformDarwin::GetFullNameForDylib(ConstString basename) { |
1156 | if (basename.IsEmpty()) |
1157 | return basename; |
1158 | |
1159 | StreamString stream; |
1160 | stream.Printf(format: "lib%s.dylib", basename.GetCString()); |
1161 | return ConstString(stream.GetString()); |
1162 | } |
1163 | |
1164 | llvm::VersionTuple PlatformDarwin::GetOSVersion(Process *process) { |
1165 | if (process && GetPluginName().contains(Other: "-simulator")) { |
1166 | lldb_private::ProcessInstanceInfo proc_info; |
1167 | if (Host::GetProcessInfo(pid: process->GetID(), proc_info)) { |
1168 | const Environment &env = proc_info.GetEnvironment(); |
1169 | |
1170 | llvm::VersionTuple result; |
1171 | if (!result.tryParse(string: env.lookup(Key: "SIMULATOR_RUNTIME_VERSION"))) |
1172 | return result; |
1173 | |
1174 | std::string dyld_root_path = env.lookup(Key: "DYLD_ROOT_PATH"); |
1175 | if (!dyld_root_path.empty()) { |
1176 | dyld_root_path += "/System/Library/CoreServices/SystemVersion.plist"; |
1177 | ApplePropertyList system_version_plist(dyld_root_path.c_str()); |
1178 | std::string product_version; |
1179 | if (system_version_plist.GetValueAsString(key: "ProductVersion", |
1180 | value&: product_version)) { |
1181 | if (!result.tryParse(string: product_version)) |
1182 | return result; |
1183 | } |
1184 | } |
1185 | } |
1186 | // For simulator platforms, do NOT call back through |
1187 | // Platform::GetOSVersion() as it might call Process::GetHostOSVersion() |
1188 | // which we don't want as it will be incorrect |
1189 | return llvm::VersionTuple(); |
1190 | } |
1191 | |
1192 | return Platform::GetOSVersion(process); |
1193 | } |
1194 | |
1195 | lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { |
1196 | // A collection of SBFileSpec whose SBFileSpec.m_directory members are filled |
1197 | // in with any executable directories that should be searched. |
1198 | static std::vector<FileSpec> g_executable_dirs; |
1199 | |
1200 | // Find the global list of directories that we will search for executables |
1201 | // once so we don't keep doing the work over and over. |
1202 | static llvm::once_flag g_once_flag; |
1203 | llvm::call_once(flag&: g_once_flag, F: []() { |
1204 | |
1205 | // When locating executables, trust the DEVELOPER_DIR first if it is set |
1206 | FileSpec xcode_contents_dir = HostInfo::GetXcodeContentsDirectory(); |
1207 | if (xcode_contents_dir) { |
1208 | FileSpec xcode_lldb_resources = xcode_contents_dir; |
1209 | xcode_lldb_resources.AppendPathComponent(component: "SharedFrameworks"); |
1210 | xcode_lldb_resources.AppendPathComponent(component: "LLDB.framework"); |
1211 | xcode_lldb_resources.AppendPathComponent(component: "Resources"); |
1212 | if (FileSystem::Instance().Exists(file_spec: xcode_lldb_resources)) { |
1213 | FileSpec dir; |
1214 | dir.SetDirectory(xcode_lldb_resources.GetPathAsConstString()); |
1215 | g_executable_dirs.push_back(x: dir); |
1216 | } |
1217 | } |
1218 | // Xcode might not be installed so we also check for the Command Line Tools. |
1219 | FileSpec command_line_tools_dir = GetCommandLineToolsLibraryPath(); |
1220 | if (command_line_tools_dir) { |
1221 | FileSpec cmd_line_lldb_resources = command_line_tools_dir; |
1222 | cmd_line_lldb_resources.AppendPathComponent(component: "PrivateFrameworks"); |
1223 | cmd_line_lldb_resources.AppendPathComponent(component: "LLDB.framework"); |
1224 | cmd_line_lldb_resources.AppendPathComponent(component: "Resources"); |
1225 | if (FileSystem::Instance().Exists(file_spec: cmd_line_lldb_resources)) { |
1226 | FileSpec dir; |
1227 | dir.SetDirectory(cmd_line_lldb_resources.GetPathAsConstString()); |
1228 | g_executable_dirs.push_back(x: dir); |
1229 | } |
1230 | } |
1231 | }); |
1232 | |
1233 | // Now search the global list of executable directories for the executable we |
1234 | // are looking for |
1235 | for (const auto &executable_dir : g_executable_dirs) { |
1236 | FileSpec executable_file; |
1237 | executable_file.SetDirectory(executable_dir.GetDirectory()); |
1238 | executable_file.SetFilename(basename); |
1239 | if (FileSystem::Instance().Exists(file_spec: executable_file)) |
1240 | return executable_file; |
1241 | } |
1242 | |
1243 | return FileSpec(); |
1244 | } |
1245 | |
1246 | lldb_private::Status |
1247 | PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) { |
1248 | // Starting in Fall 2016 OSes, NSLog messages only get mirrored to stderr if |
1249 | // the OS_ACTIVITY_DT_MODE environment variable is set. (It doesn't require |
1250 | // any specific value; rather, it just needs to exist). We will set it here |
1251 | // as long as the IDE_DISABLED_OS_ACTIVITY_DT_MODE flag is not set. Xcode |
1252 | // makes use of IDE_DISABLED_OS_ACTIVITY_DT_MODE to tell |
1253 | // LLDB *not* to muck with the OS_ACTIVITY_DT_MODE flag when they |
1254 | // specifically want it unset. |
1255 | const char *disable_env_var = "IDE_DISABLED_OS_ACTIVITY_DT_MODE"; |
1256 | auto &env_vars = launch_info.GetEnvironment(); |
1257 | if (!env_vars.count(Key: disable_env_var)) { |
1258 | // We want to make sure that OS_ACTIVITY_DT_MODE is set so that we get |
1259 | // os_log and NSLog messages mirrored to the target process stderr. |
1260 | env_vars.try_emplace(Key: "OS_ACTIVITY_DT_MODE", Args: "enable"); |
1261 | } |
1262 | |
1263 | // Let our parent class do the real launching. |
1264 | return PlatformPOSIX::LaunchProcess(launch_info); |
1265 | } |
1266 | |
1267 | lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths( |
1268 | const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, |
1269 | const FileSpecList *module_search_paths_ptr, |
1270 | llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) { |
1271 | const FileSpec &platform_file = module_spec.GetFileSpec(); |
1272 | // See if the file is present in any of the module_search_paths_ptr |
1273 | // directories. |
1274 | if (!module_sp && module_search_paths_ptr && platform_file) { |
1275 | // create a vector of all the file / directory names in platform_file e.g. |
1276 | // this might be |
1277 | // /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation |
1278 | // |
1279 | // We'll need to look in the module_search_paths_ptr directories for both |
1280 | // "UIFoundation" and "UIFoundation.framework" -- most likely the latter |
1281 | // will be the one we find there. |
1282 | |
1283 | std::vector<llvm::StringRef> path_parts = platform_file.GetComponents(); |
1284 | // We want the components in reverse order. |
1285 | std::reverse(first: path_parts.begin(), last: path_parts.end()); |
1286 | const size_t path_parts_size = path_parts.size(); |
1287 | |
1288 | size_t num_module_search_paths = module_search_paths_ptr->GetSize(); |
1289 | for (size_t i = 0; i < num_module_search_paths; ++i) { |
1290 | Log *log_verbose = GetLog(mask: LLDBLog::Host); |
1291 | LLDB_LOGF( |
1292 | log_verbose, |
1293 | "PlatformRemoteDarwinDevice::GetSharedModule searching for binary in " |
1294 | "search-path %s", |
1295 | module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath().c_str()); |
1296 | // Create a new FileSpec with this module_search_paths_ptr plus just the |
1297 | // filename ("UIFoundation"), then the parent dir plus filename |
1298 | // ("UIFoundation.framework/UIFoundation") etc - up to four names (to |
1299 | // handle "Foo.framework/Contents/MacOS/Foo") |
1300 | |
1301 | for (size_t j = 0; j < 4 && j < path_parts_size - 1; ++j) { |
1302 | FileSpec path_to_try(module_search_paths_ptr->GetFileSpecAtIndex(idx: i)); |
1303 | |
1304 | // Add the components backwards. For |
1305 | // .../PrivateFrameworks/UIFoundation.framework/UIFoundation path_parts |
1306 | // is |
1307 | // [0] UIFoundation |
1308 | // [1] UIFoundation.framework |
1309 | // [2] PrivateFrameworks |
1310 | // |
1311 | // and if 'j' is 2, we want to append path_parts[1] and then |
1312 | // path_parts[0], aka 'UIFoundation.framework/UIFoundation', to the |
1313 | // module_search_paths_ptr path. |
1314 | |
1315 | for (int k = j; k >= 0; --k) { |
1316 | path_to_try.AppendPathComponent(component: path_parts[k]); |
1317 | } |
1318 | |
1319 | if (FileSystem::Instance().Exists(file_spec: path_to_try)) { |
1320 | ModuleSpec new_module_spec(module_spec); |
1321 | new_module_spec.GetFileSpec() = path_to_try; |
1322 | Status new_error( |
1323 | Platform::GetSharedModule(module_spec: new_module_spec, process, module_sp, |
1324 | module_search_paths_ptr: nullptr, old_modules, did_create_ptr)); |
1325 | |
1326 | if (module_sp) { |
1327 | module_sp->SetPlatformFileSpec(path_to_try); |
1328 | return new_error; |
1329 | } |
1330 | } |
1331 | } |
1332 | } |
1333 | } |
1334 | return Status(); |
1335 | } |
1336 | |
1337 | llvm::Triple::OSType PlatformDarwin::GetHostOSType() { |
1338 | #if !defined(__APPLE__) |
1339 | return llvm::Triple::MacOSX; |
1340 | #else |
1341 | #if TARGET_OS_OSX |
1342 | return llvm::Triple::MacOSX; |
1343 | #elif TARGET_OS_IOS |
1344 | return llvm::Triple::IOS; |
1345 | #elif TARGET_OS_WATCH |
1346 | return llvm::Triple::WatchOS; |
1347 | #elif TARGET_OS_TV |
1348 | return llvm::Triple::TvOS; |
1349 | #elif TARGET_OS_BRIDGE |
1350 | return llvm::Triple::BridgeOS; |
1351 | #elif TARGET_OS_XR |
1352 | return llvm::Triple::XROS; |
1353 | #else |
1354 | #error "LLDB being compiled for an unrecognized Darwin OS" |
1355 | #endif |
1356 | #endif // __APPLE__ |
1357 | } |
1358 | |
1359 | llvm::Expected<std::pair<XcodeSDK, bool>> |
1360 | PlatformDarwin::GetSDKPathFromDebugInfo(Module &module) { |
1361 | SymbolFile *sym_file = module.GetSymbolFile(); |
1362 | if (!sym_file) |
1363 | return llvm::createStringError( |
1364 | EC: llvm::inconvertibleErrorCode(), |
1365 | S: llvm::formatv(Fmt: "No symbol file available for module '{0}'", |
1366 | Vals: module.GetFileSpec().GetFilename().AsCString(value_if_empty: ""))); |
1367 | |
1368 | bool found_public_sdk = false; |
1369 | bool found_internal_sdk = false; |
1370 | XcodeSDK merged_sdk; |
1371 | for (unsigned i = 0; i < sym_file->GetNumCompileUnits(); ++i) { |
1372 | if (auto cu_sp = sym_file->GetCompileUnitAtIndex(idx: i)) { |
1373 | auto cu_sdk = sym_file->ParseXcodeSDK(comp_unit&: *cu_sp); |
1374 | bool is_internal_sdk = cu_sdk.IsAppleInternalSDK(); |
1375 | found_public_sdk |= !is_internal_sdk; |
1376 | found_internal_sdk |= is_internal_sdk; |
1377 | |
1378 | merged_sdk.Merge(other: cu_sdk); |
1379 | } |
1380 | } |
1381 | |
1382 | const bool found_mismatch = found_internal_sdk && found_public_sdk; |
1383 | |
1384 | return std::pair{std::move(merged_sdk), found_mismatch}; |
1385 | } |
1386 | |
1387 | llvm::Expected<std::string> |
1388 | PlatformDarwin::ResolveSDKPathFromDebugInfo(Module &module) { |
1389 | auto sdk_or_err = GetSDKPathFromDebugInfo(module); |
1390 | if (!sdk_or_err) |
1391 | return llvm::createStringError( |
1392 | EC: llvm::inconvertibleErrorCode(), |
1393 | S: llvm::formatv(Fmt: "Failed to parse SDK path from debug-info: {0}", |
1394 | Vals: llvm::toString(E: sdk_or_err.takeError()))); |
1395 | |
1396 | auto [sdk, _] = std::move(*sdk_or_err); |
1397 | |
1398 | if (FileSystem::Instance().Exists(file_spec: sdk.GetSysroot())) |
1399 | return sdk.GetSysroot().GetPath(); |
1400 | |
1401 | auto path_or_err = HostInfo::GetSDKRoot(options: HostInfo::SDKOptions{.XcodeSDKSelection: sdk}); |
1402 | if (!path_or_err) |
1403 | return llvm::createStringError( |
1404 | EC: llvm::inconvertibleErrorCode(), |
1405 | S: llvm::formatv(Fmt: "Error while searching for SDK (XcodeSDK '{0}'): {1}", |
1406 | Vals: sdk.GetString(), |
1407 | Vals: llvm::toString(E: path_or_err.takeError()))); |
1408 | |
1409 | return path_or_err->str(); |
1410 | } |
1411 | |
1412 | llvm::Expected<XcodeSDK> |
1413 | PlatformDarwin::GetSDKPathFromDebugInfo(CompileUnit &unit) { |
1414 | ModuleSP module_sp = unit.CalculateSymbolContextModule(); |
1415 | if (!module_sp) |
1416 | return llvm::createStringError(Fmt: "compile unit has no module"); |
1417 | SymbolFile *sym_file = module_sp->GetSymbolFile(); |
1418 | if (!sym_file) |
1419 | return llvm::createStringError( |
1420 | S: llvm::formatv(Fmt: "No symbol file available for module '{0}'", |
1421 | Vals: module_sp->GetFileSpec().GetFilename())); |
1422 | |
1423 | return sym_file->ParseXcodeSDK(comp_unit&: unit); |
1424 | } |
1425 | |
1426 | llvm::Expected<std::string> |
1427 | PlatformDarwin::ResolveSDKPathFromDebugInfo(CompileUnit &unit) { |
1428 | auto sdk_or_err = GetSDKPathFromDebugInfo(unit); |
1429 | if (!sdk_or_err) |
1430 | return llvm::createStringError( |
1431 | EC: llvm::inconvertibleErrorCode(), |
1432 | S: llvm::formatv(Fmt: "Failed to parse SDK path from debug-info: {0}", |
1433 | Vals: llvm::toString(E: sdk_or_err.takeError()))); |
1434 | |
1435 | auto sdk = std::move(*sdk_or_err); |
1436 | |
1437 | auto path_or_err = HostInfo::GetSDKRoot(options: HostInfo::SDKOptions{.XcodeSDKSelection: sdk}); |
1438 | if (!path_or_err) |
1439 | return llvm::createStringError( |
1440 | EC: llvm::inconvertibleErrorCode(), |
1441 | S: llvm::formatv(Fmt: "Error while searching for SDK (XcodeSDK '{0}'): {1}", |
1442 | Vals: sdk.GetString(), |
1443 | Vals: llvm::toString(E: path_or_err.takeError()))); |
1444 | |
1445 | return path_or_err->str(); |
1446 | } |
1447 |
Definitions
- ExceptionMaskValidator
- ~PlatformDarwin
- g_initialize_count
- Initialize
- Terminate
- GetDescriptionStatic
- CreateInstance
- PlatformDarwinProperties
- GetSettingName
- PlatformDarwinProperties
- ~PlatformDarwinProperties
- GetIgnoredExceptions
- GetIgnoredExceptionValue
- GetGlobalProperties
- DebuggerInitialize
- GetExtraStartupCommands
- PutFile
- LocateExecutableScriptingResources
- ResolveSymbolFile
- GetSharedModule
- GetSoftwareBreakpointTrapOpcode
- ModuleIsExcludedForUnconstrainedSearches
- x86GetSupportedArchitectures
- GetCompatibleArchs
- ARMGetSupportedArchitectures
- GetXcodeSelectPath
- SetThreadCreationBreakpoint
- GetResumeCountForLaunchInfo
- DebugProcess
- CalculateTrapHandlerSymbolNames
- GetCommandLineToolsLibraryPath
- DirectoryEnumerator
- FindSDKInXcodeForModules
- GetSDKDirectoryForModules
- ParseVersionBuildDir
- FetchExtendedCrashInformation
- ExtractCrashInfoAnnotations
- ExtractAppSpecificInfo
- AddClangModuleCompilationOptionsForSDKType
- GetFullNameForDylib
- GetOSVersion
- LocateExecutable
- LaunchProcess
- FindBundleBinaryInExecSearchPaths
- GetHostOSType
- GetSDKPathFromDebugInfo
- ResolveSDKPathFromDebugInfo
- GetSDKPathFromDebugInfo
Improve your Profiling and Debugging skills
Find out more