| 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::(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::(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 | |