From 1e05d7b3d3c6d29ff6f9493cc478a36244cc32bd Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 19 Mar 2020 18:51:36 -0700 Subject: [PATCH] Remap the target (Xcode) SDK directory to the host SDK directory. This is mostly useful for Swift support; it allows LLDB to substitute a matching SDK it shipped with instead of the sysroot path that was used at compile time. The goal of this is to make the Xcode SDK something that behaves more like the compiler's resource directory, as in that it ships with LLDB rather than with the debugged program. This important primarily for importing Swift and Clang modules in the expression evaluator, and getting at the APINotes from the SDK in Swift. For a cross-debugging scenario, this means you have to have an SDK for your target installed alongside LLDB. In Xcode this will always be the case. rdar://problem/60640017 Differential Revision: https://reviews.llvm.org/D76471 --- lldb/include/lldb/Core/Module.h | 11 ++ lldb/include/lldb/Host/HostInfoBase.h | 4 + lldb/include/lldb/Host/macosx/HostInfoMacOSX.h | 4 + lldb/include/lldb/Target/Platform.h | 4 + lldb/include/lldb/Utility/XcodeSDK.h | 63 ++++++++ lldb/source/Core/Module.cpp | 18 +++ lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm | 37 +++++ .../Platform/MacOSX/PlatformAppleTVSimulator.h | 2 +- .../Platform/MacOSX/PlatformAppleWatchSimulator.h | 2 +- .../Plugins/Platform/MacOSX/PlatformDarwin.cpp | 146 +++--------------- .../Plugins/Platform/MacOSX/PlatformDarwin.h | 41 ++---- .../Plugins/Platform/MacOSX/PlatformMacOSX.cpp | 3 +- .../Plugins/Platform/MacOSX/PlatformMacOSX.h | 2 +- .../Platform/MacOSX/PlatformRemoteDarwinDevice.h | 2 +- .../Plugins/Platform/MacOSX/PlatformiOSSimulator.h | 2 +- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h | 1 + .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 6 + lldb/source/Utility/CMakeLists.txt | 1 + lldb/source/Utility/XcodeSDK.cpp | 163 +++++++++++++++++++++ lldb/unittests/Platform/PlatformDarwinTest.cpp | 45 ------ lldb/unittests/Utility/CMakeLists.txt | 1 + lldb/unittests/Utility/XcodeSDKTest.cpp | 86 +++++++++++ 22 files changed, 440 insertions(+), 204 deletions(-) create mode 100644 lldb/include/lldb/Utility/XcodeSDK.h create mode 100644 lldb/source/Utility/XcodeSDK.cpp create mode 100644 lldb/unittests/Utility/XcodeSDKTest.cpp diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 4715961..35d00d2 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -20,6 +20,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -509,6 +510,12 @@ public: m_mod_time = mod_time; } + /// This callback will be called by SymbolFile implementations when + /// parsing a compile unit that contains SDK information. + /// \param sdk will be merged with \p m_sdk. + /// \param sysroot will be added to the path remapping dictionary. + void RegisterXcodeSDK(llvm::StringRef sdk, llvm::StringRef sysroot); + /// Tells whether this module is capable of being the main executable for a /// process. /// @@ -971,6 +978,10 @@ protected: /// module that doesn't match where the sources currently are. PathMappingList m_source_mappings = ModuleList::GetGlobalModuleListProperties().GetSymlinkMappings(); + + /// The (Xcode) SDK this module was compiled with. + XcodeSDK m_xcode_sdk; + lldb::SectionListUP m_sections_up; ///< Unified section list for module that /// is used by the ObjectFile and and /// ObjectFile instances for the debug info diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index d7c2806..f195a9a 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -12,6 +12,7 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" @@ -91,6 +92,9 @@ public: static bool ComputePathRelativeToLibrary(FileSpec &file_spec, llvm::StringRef dir); + /// Return the directory containing a specific Xcode SDK. + static std::string GetXcodeSDK(XcodeSDK sdk) { return {}; } + protected: static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h index cd5161c..fdbe869 100644 --- a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h +++ b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h @@ -11,6 +11,7 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/VersionTuple.h" namespace lldb_private { @@ -31,7 +32,10 @@ public: static bool GetOSBuildString(std::string &s); static bool GetOSKernelDescription(std::string &s); static FileSpec GetProgramFileSpec(); + static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + /// Query xcrun to find an Xcode SDK directory. + static std::string GetXcodeSDK(XcodeSDK sdk); protected: static bool ComputeSupportExeDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 190ad06..029bb59 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -434,6 +434,10 @@ public: return lldb_private::ConstString(); } + virtual llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) { + return {}; + } + const std::string &GetRemoteURL() const { return m_remote_url; } bool IsHost() const { diff --git a/lldb/include/lldb/Utility/XcodeSDK.h b/lldb/include/lldb/Utility/XcodeSDK.h new file mode 100644 index 0000000..9b9f1d2 --- /dev/null +++ b/lldb/include/lldb/Utility/XcodeSDK.h @@ -0,0 +1,63 @@ +//===-- XcodeSDK.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_UTILITY_SDK_H +#define LLDB_UTILITY_SDK_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include + +namespace lldb_private { + +/// An abstraction for Xcode-style SDKs that works like \ref ArchSpec. +class XcodeSDK { + std::string m_name; + +public: + XcodeSDK() = default; + XcodeSDK(std::string &&name) : m_name(std::move(name)) {} + static XcodeSDK GetAnyMacOS() { return XcodeSDK("MacOSX.sdk"); } + + enum Type : int { + MacOSX = 0, + iPhoneSimulator, + iPhoneOS, + AppleTVSimulator, + AppleTVOS, + WatchSimulator, + watchOS, + bridgeOS, + Linux, + numSDKTypes, + unknown = -1 + }; + static llvm::StringRef GetNameForType(Type type); + + /// The merge function follows a strict order to maintain monotonicity: + /// 1. SDK with the higher SDKType wins. + /// 2. The newer SDK wins. + void Merge(XcodeSDK other); + + XcodeSDK &operator=(XcodeSDK other); + bool operator==(XcodeSDK other); + + /// Return parsed SDK number, and SDK version number. + std::tuple Parse() const; + llvm::VersionTuple GetVersion() const; + Type GetType() const; + llvm::StringRef GetString() const; + + static bool SDKSupportsModules(Type type, llvm::VersionTuple version); + static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path); + static llvm::StringRef GetSDKNameForType(Type type); +}; + +} // namespace lldb_private + +#endif diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index fefc23a..658bcff 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1596,6 +1596,24 @@ bool Module::RemapSourceFile(llvm::StringRef path, return m_source_mappings.RemapPath(path, new_path); } +void Module::RegisterXcodeSDK(llvm::StringRef sdk_name, llvm::StringRef sysroot) { + XcodeSDK sdk(sdk_name.str()); + if (m_xcode_sdk == sdk) + return; + m_xcode_sdk.Merge(sdk); + PlatformSP module_platform = + Platform::GetPlatformForArchitecture(GetArchitecture(), nullptr); + ConstString sdk_path(module_platform->GetSDKPath(sdk)); + if (!sdk_path) + return; + // If merged SDK changed for a previously registered source path, update it. + // This could happend with -fdebug-prefix-map, otherwise it's unlikely. + ConstString sysroot_cs(sysroot); + if (!m_source_mappings.Replace(sysroot_cs, sdk_path, true)) + // In the general case, however, append it to the list. + m_source_mappings.Append(sysroot_cs, sdk_path, false); +} + bool Module::MergeArchitecture(const ArchSpec &arch_spec) { if (!arch_spec.IsValid()) return false; diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index e73d2ff..c09339e 100644 --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -8,6 +8,7 @@ #include "lldb/Host/macosx/HostInfoMacOSX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Log.h" @@ -295,3 +296,39 @@ void HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32, } } } + +std::string HostInfoMacOSX::GetXcodeSDK(XcodeSDK sdk) { + std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + + XcodeSDK::GetSDKNameForType(sdk.GetType()).str(); + llvm::VersionTuple version = sdk.GetVersion(); + if (!version.empty()) + xcrun_cmd += version.getAsString(); + + int status = 0; + int signo = 0; + std::string output_str; + lldb_private::Status error = + Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + &output_str, std::chrono::seconds(15)); + + // Check that xcrun return something useful. + if (status != 0 || output_str.empty()) + return {}; + + // Convert to a StringRef so we can manipulate the string without modifying + // the underlying data. + llvm::StringRef output(output_str); + + // Remove any trailing newline characters. + output = output.rtrim(); + + // Strip any leading newline characters and everything before them. + const size_t last_newline = output.rfind('\n'); + if (last_newline != llvm::StringRef::npos) + output = output.substr(last_newline + 1); + + // Whatever is left in output should be a valid path. + if (!FileSystem::Instance().Exists(output)) + return {}; + return output.str(); +} diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h index 34cbff9..2170e03 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h @@ -69,7 +69,7 @@ public: AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h index 04c3eb1..eceb3f0 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h @@ -69,7 +69,7 @@ public: AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index e163300..0777c78 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1220,56 +1220,12 @@ static FileSpec GetCommandLineToolsLibraryPath() { return g_command_line_tools_filespec; } -bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, - llvm::VersionTuple version) { - switch (sdk_type) { - case SDKType::MacOSX: - return version >= llvm::VersionTuple(10, 10); - case SDKType::iPhoneOS: - case SDKType::iPhoneSimulator: - case SDKType::AppleTVOS: - case SDKType::AppleTVSimulator: - return version >= llvm::VersionTuple(8); - case SDKType::watchOS: - case SDKType::WatchSimulator: - return version >= llvm::VersionTuple(6); - default: - return false; - } - - return false; -} - -bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, - const FileSpec &sdk_path) { - ConstString last_path_component = sdk_path.GetLastPathComponent(); - - if (last_path_component) { - const llvm::StringRef sdk_name = last_path_component.GetStringRef(); - - const std::string sdk_name_lower = sdk_name.lower(); - const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); - if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) - return false; - - auto version_part = sdk_name.drop_front(sdk_string.size()); - version_part.consume_back(".sdk"); - - llvm::VersionTuple version; - if (version.tryParse(version_part)) - return false; - return SDKSupportsModules(desired_type, version); - } - - return false; -} - FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) { SDKEnumeratorInfo *enumerator_info = static_cast(baton); FileSpec spec(path); - if (SDKSupportsModules(enumerator_info->sdk_type, spec)) { + if (XcodeSDK::SDKSupportsModules(enumerator_info->sdk_type, spec)) { enumerator_info->found_path = spec; return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } @@ -1277,7 +1233,7 @@ FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } -FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, +FileSpec PlatformDarwin::FindSDKInXcodeForModules(XcodeSDK::Type sdk_type, const FileSpec &sdks_spec) { // Look inside Xcode for the required installed iOS SDK version @@ -1303,19 +1259,19 @@ FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, return FileSpec(); } -FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { +FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) { FileSpec sdks_spec = GetXcodeContentsDirectory(); sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("Platforms"); switch (sdk_type) { - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: sdks_spec.AppendPathComponent("MacOSX.platform"); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: sdks_spec.AppendPathComponent("iPhoneSimulator.platform"); break; - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: sdks_spec.AppendPathComponent("iPhoneOS.platform"); break; default: @@ -1325,11 +1281,11 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("SDKs"); - if (sdk_type == SDKType::MacOSX) { + if (sdk_type == XcodeSDK::Type::MacOSX) { llvm::VersionTuple version = HostInfo::GetOSVersion(); if (!version.empty()) { - if (SDKSupportsModules(SDKType::MacOSX, version)) { + if (XcodeSDK::SDKSupportsModules(XcodeSDK::Type::MacOSX, version)) { // If the Xcode SDKs are not available then try to use the // Command Line Tools one which is only for MacOSX. if (!FileSystem::Instance().Exists(sdks_spec)) { @@ -1498,7 +1454,7 @@ PlatformDarwin::ExtractCrashInfoAnnotations(Process &process) { } void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - Target *target, std::vector &options, SDKType sdk_type) { + Target *target, std::vector &options, XcodeSDK::Type sdk_type) { const std::vector apple_arguments = { "-x", "objective-c++", "-fobjc-arc", "-fblocks", "-D_ISO646_H", "-D__ISO646_H", @@ -1509,7 +1465,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( StreamString minimum_version_option; bool use_current_os_version = false; switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) use_current_os_version = true; #else @@ -1517,11 +1473,11 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( #endif break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: use_current_os_version = false; break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: #if defined(__i386__) || defined(__x86_64__) use_current_os_version = true; #else @@ -1548,15 +1504,15 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( // Only add the version-min options if we got a version from somewhere if (!version.empty()) { switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: minimum_version_option.PutCString("-mios-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: minimum_version_option.PutCString("-mios-simulator-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: minimum_version_option.PutCString("-mmacosx-version-min="); minimum_version_option.PutCString(version.getAsString()); break; @@ -1805,70 +1761,11 @@ PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { return {}; } -llvm::StringRef PlatformDarwin::GetSDKNameForType(SDKType type) { - switch (type) { - case MacOSX: - return "macosx"; - case iPhoneSimulator: - return "iphonesimulator"; - case iPhoneOS: - return "iphoneos"; - case AppleTVSimulator: - return "appletvsimulator"; - case AppleTVOS: - return "appletvos"; - case WatchSimulator: - return "watchsimulator"; - case watchOS: - return "watchos"; - case bridgeOS: - return "bridgeos"; - case Linux: - return "linux"; - case numSDKTypes: - case unknown: - return ""; - } - llvm_unreachable("unhandled switch case"); -} - -FileSpec PlatformDarwin::GetXcodeSDK(SDKType type) { - std::string xcrun_cmd = - "xcrun --show-sdk-path --sdk " + GetSDKNameForType(type).str(); - - int status = 0; - int signo = 0; - std::string output_str; - lldb_private::Status error = - Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, - &output_str, std::chrono::seconds(15)); - - // Check that xcrun return something useful. - if (status != 0 || output_str.empty()) - return {}; - - // Convert to a StringRef so we can manipulate the string without modifying - // the underlying data. - llvm::StringRef output(output_str); - - // Remove any trailing newline characters. - output = output.rtrim(); - - // Strip any leading newline characters and everything before them. - const size_t last_newline = output.rfind('\n'); - if (last_newline != llvm::StringRef::npos) - output = output.substr(last_newline + 1); - - // Whatever is left in output should be a valid path. - if (!FileSystem::Instance().Exists(output)) - return {}; - - // Find the contents dir in the xcrun provided path. - std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(output); - if (xcode_contents_dir.empty()) - return {}; - - return FileSpec(xcode_contents_dir); +llvm::StringRef PlatformDarwin::GetSDKPath(XcodeSDK sdk) { + std::string &path = m_sdk_path[sdk.GetString()]; + if (path.empty()) + path = HostInfo::GetXcodeSDK(sdk); + return path; } FileSpec PlatformDarwin::GetXcodeContentsDirectory() { @@ -1899,7 +1796,8 @@ FileSpec PlatformDarwin::GetXcodeContentsDirectory() { } } - if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + FileSpec fspec(HostInfo::GetXcodeSDK(XcodeSDK::GetAnyMacOS())); + if (fspec) { if (FileSystem::Instance().Exists(fspec)) { std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(fspec.GetPath()); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 619a859..7d205be 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -11,8 +11,10 @@ #include "Plugins/Platform/POSIX/PlatformPOSIX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" @@ -84,25 +86,11 @@ public: static std::tuple ParseVersionBuildDir(llvm::StringRef str); - enum SDKType : int { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - AppleTVSimulator, - AppleTVOS, - WatchSimulator, - watchOS, - bridgeOS, - Linux, - numSDKTypes, - unknown = -1 - }; - llvm::Expected FetchExtendedCrashInformation(lldb_private::Process &process) override; - static llvm::StringRef GetSDKNameForType(SDKType type); - static lldb_private::FileSpec GetXcodeSDK(SDKType type); + llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) override; + static lldb_private::FileSpec GetXcodeContentsDirectory(); static lldb_private::FileSpec GetXcodeDeveloperDirectory(); @@ -151,14 +139,9 @@ protected: const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - static bool SDKSupportsModules(SDKType sdk_type, llvm::VersionTuple version); - - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path); - struct SDKEnumeratorInfo { lldb_private::FileSpec found_path; - SDKType sdk_type; + lldb_private::XcodeSDK::Type sdk_type; }; static lldb_private::FileSystem::EnumerateDirectoryResult @@ -166,17 +149,15 @@ protected: llvm::StringRef path); static lldb_private::FileSpec - FindSDKInXcodeForModules(SDKType sdk_type, + FindSDKInXcodeForModules(lldb_private::XcodeSDK::Type sdk_type, const lldb_private::FileSpec &sdks_spec); static lldb_private::FileSpec - GetSDKDirectoryForModules(PlatformDarwin::SDKType sdk_type); - - void - AddClangModuleCompilationOptionsForSDKType(lldb_private::Target *target, - std::vector &options, - SDKType sdk_type); + GetSDKDirectoryForModules(lldb_private::XcodeSDK::Type sdk_type); + void AddClangModuleCompilationOptionsForSDKType( + lldb_private::Target *target, std::vector &options, + lldb_private::XcodeSDK::Type sdk_type); lldb_private::Status FindBundleBinaryInExecSearchPaths( const lldb_private::ModuleSpec &module_spec, @@ -188,6 +169,8 @@ protected: llvm::StringRef component); static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + std::string m_developer_directory; + llvm::StringMap m_sdk_path; private: DISALLOW_COPY_AND_ASSIGN(PlatformDarwin); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index 5efb041..4fcecf7 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -208,7 +208,8 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { } // Use the default SDK as a fallback. - if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + FileSpec fspec(HostInfo::GetXcodeSDK(lldb_private::XcodeSDK::GetAnyMacOS())); + if (fspec) { if (FileSystem::Instance().Exists(fspec)) return ConstString(fspec.GetPath()); } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h index 82568ef..3e3187c 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -73,7 +73,7 @@ public: AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::MacOSX); + target, options, lldb_private::XcodeSDK::Type::MacOSX); } private: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index baf004b..5e8422b 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -45,7 +45,7 @@ public: AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneOS); + target, options, lldb_private::XcodeSDK::Type::iPhoneOS); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h index a3110ee..095d81b 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h @@ -71,7 +71,7 @@ public: AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 938a494..bc080db 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -12,6 +12,7 @@ #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/RWMutex.h" #include diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index ab271d2..6d43f95 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -664,6 +664,12 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { const DWARFBaseDIE cu_die = dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); if (cu_die) { + if (const char *sdk = + cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr)) { + const char *sysroot = + cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, ""); + module_sp->RegisterXcodeSDK(sdk, sysroot); + } FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index 1bbacc3..48456ef 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -57,6 +57,7 @@ add_lldb_library(lldbUtility UserIDResolver.cpp VASprintf.cpp VMRange.cpp + XcodeSDK.cpp LINK_LIBS ${LLDB_SYSTEM_LIBS} diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp new file mode 100644 index 0000000..f2403f1 --- /dev/null +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -0,0 +1,163 @@ +//===-- XcodeSDK.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "lldb/lldb-types.h" + +using namespace lldb; +using namespace lldb_private; + +XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { + m_name = other.m_name; + return *this; +} + +bool XcodeSDK::operator==(XcodeSDK other) { + return m_name == other.m_name; +} + +static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { + if (name.consume_front("MacOSX")) + return XcodeSDK::MacOSX; + if (name.consume_front("iPhoneSimulator")) + return XcodeSDK::iPhoneSimulator; + if (name.consume_front("iPhoneOS")) + return XcodeSDK::iPhoneOS; + if (name.consume_front("AppleTVSimulator")) + return XcodeSDK::AppleTVSimulator; + if (name.consume_front("AppleTVOS")) + return XcodeSDK::AppleTVOS; + if (name.consume_front("WatchSimulator")) + return XcodeSDK::WatchSimulator; + if (name.consume_front("WatchOS")) + return XcodeSDK::watchOS; + if (name.consume_front("bridgeOS")) + return XcodeSDK::bridgeOS; + if (name.consume_front("Linux")) + return XcodeSDK::Linux; + static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, + "New SDK type was added, update this list!"); + return XcodeSDK::unknown; +} + +static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { + unsigned i = 0; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + + llvm::VersionTuple version; + version.tryParse(name.slice(0, i - 1)); + name = name.drop_front(i); + return version; +} + + +std::tuple XcodeSDK::Parse() const { + llvm::StringRef input(m_name); + XcodeSDK::Type sdk = ParseSDKName(input); + llvm::VersionTuple version = ParseSDKVersion(input); + return {sdk, version}; +} + +llvm::VersionTuple XcodeSDK::GetVersion() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + return ParseSDKVersion(input); +} + +XcodeSDK::Type XcodeSDK::GetType() const { + llvm::StringRef input(m_name); + return ParseSDKName(input); +} + +llvm::StringRef XcodeSDK::GetString() const { return m_name; } + +void XcodeSDK::Merge(XcodeSDK other) { + // The "bigger" SDK always wins. + if (Parse() < other.Parse()) + *this = other; +} + +llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) { + switch (type) { + case MacOSX: + return "macosx"; + case iPhoneSimulator: + return "iphonesimulator"; + case iPhoneOS: + return "iphoneos"; + case AppleTVSimulator: + return "appletvsimulator"; + case AppleTVOS: + return "appletvos"; + case WatchSimulator: + return "watchsimulator"; + case watchOS: + return "watchos"; + case bridgeOS: + return "bridgeos"; + case Linux: + return "linux"; + case numSDKTypes: + case unknown: + return ""; + } + llvm_unreachable("unhandled switch case"); +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, + llvm::VersionTuple version) { + switch (sdk_type) { + case Type::MacOSX: + return version >= llvm::VersionTuple(10, 10); + case Type::iPhoneOS: + case Type::iPhoneSimulator: + case Type::AppleTVOS: + case Type::AppleTVSimulator: + return version >= llvm::VersionTuple(8); + case Type::watchOS: + case Type::WatchSimulator: + return version >= llvm::VersionTuple(6); + default: + return false; + } + + return false; +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, + const FileSpec &sdk_path) { + ConstString last_path_component = sdk_path.GetLastPathComponent(); + + if (last_path_component) { + const llvm::StringRef sdk_name = last_path_component.GetStringRef(); + + const std::string sdk_name_lower = sdk_name.lower(); + const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); + if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) + return false; + + auto version_part = sdk_name.drop_front(sdk_string.size()); + version_part.consume_back(".sdk"); + + llvm::VersionTuple version; + if (version.tryParse(version_part)) + return false; + return SDKSupportsModules(desired_type, version); + } + + return false; +} diff --git a/lldb/unittests/Platform/PlatformDarwinTest.cpp b/lldb/unittests/Platform/PlatformDarwinTest.cpp index 20916f3..0a4c802 100644 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -21,10 +21,6 @@ struct PlatformDarwinTester : public PlatformDarwin { public: using PlatformDarwin::FindComponentInPath; using PlatformDarwin::FindXcodeContentsDirectoryInPath; - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path) { - return PlatformDarwin::SDKSupportsModules(desired_type, sdk_path); - } }; TEST(PlatformDarwinTest, TestParseVersionBuildDir) { @@ -53,24 +49,6 @@ TEST(PlatformDarwinTest, TestParseVersionBuildDir) { std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("3.4.5"); EXPECT_EQ(llvm::VersionTuple(3, 4, 5), V); - - std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); } TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { @@ -111,29 +89,6 @@ TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { no_capitalization)); } -TEST(PlatformDarwinTest, GetSDKNameForType) { - EXPECT_EQ("macosx", - PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::MacOSX)); - EXPECT_EQ("iphonesimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::iPhoneSimulator)); - EXPECT_EQ("iphoneos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::iPhoneOS)); - EXPECT_EQ("appletvsimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::AppleTVSimulator)); - EXPECT_EQ("appletvos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::AppleTVOS)); - EXPECT_EQ("watchsimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::WatchSimulator)); - EXPECT_EQ("watchos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::watchOS)); - EXPECT_EQ("linux", - PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::Linux)); - EXPECT_EQ("", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::numSDKTypes)); - EXPECT_EQ( - "", PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::unknown)); -} - TEST(PlatformDarwinTest, FindComponentInPath) { EXPECT_EQ("/path/to/foo", PlatformDarwinTester::FindComponentInPath("/path/to/foo/", "foo")); diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt index 5e27c67..c624c36 100644 --- a/lldb/unittests/Utility/CMakeLists.txt +++ b/lldb/unittests/Utility/CMakeLists.txt @@ -42,6 +42,7 @@ add_lldb_unittest(UtilityTests UUIDTest.cpp VASprintfTest.cpp VMRangeTest.cpp + XcodeSDKTest.cpp LINK_LIBS lldbUtility diff --git a/lldb/unittests/Utility/XcodeSDKTest.cpp b/lldb/unittests/Utility/XcodeSDKTest.cpp new file mode 100644 index 0000000..a316516 --- /dev/null +++ b/lldb/unittests/Utility/XcodeSDKTest.cpp @@ -0,0 +1,86 @@ +//===-- XcodeSDKTest.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "llvm/ADT/StringRef.h" + +#include + +using namespace lldb_private; + +TEST(XcodeSDKTest, ParseTest) { + EXPECT_EQ(XcodeSDK::GetAnyMacOS().GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("iPhoneSimulator.sdk").GetType(), XcodeSDK::iPhoneSimulator); + EXPECT_EQ(XcodeSDK("iPhoneOS.sdk").GetType(), XcodeSDK::iPhoneOS); + EXPECT_EQ(XcodeSDK("AppleTVSimulator.sdk").GetType(), XcodeSDK::AppleTVSimulator); + EXPECT_EQ(XcodeSDK("AppleTVOS.sdk").GetType(), XcodeSDK::AppleTVOS); + EXPECT_EQ(XcodeSDK("WatchSimulator.sdk").GetType(), XcodeSDK::WatchSimulator); + EXPECT_EQ(XcodeSDK("WatchOS.sdk").GetType(), XcodeSDK::watchOS); + EXPECT_EQ(XcodeSDK("Linux.sdk").GetType(), XcodeSDK::Linux); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetVersion(), llvm::VersionTuple()); + EXPECT_EQ(XcodeSDK("MacOSX10.9.sdk").GetVersion(), llvm::VersionTuple(10, 9)); + EXPECT_EQ(XcodeSDK("MacOSX10.15.4.sdk").GetVersion(), llvm::VersionTuple(10, 15)); + EXPECT_EQ(XcodeSDK().GetType(), XcodeSDK::unknown); + EXPECT_EQ(XcodeSDK().GetVersion(), llvm::VersionTuple()); +} + +TEST(XcodeSDKTest, MergeTest) { + XcodeSDK sdk("MacOSX.sdk"); + sdk.Merge(XcodeSDK("WatchOS.sdk")); + // This doesn't make any particular sense and shouldn't happen in practice, we + // just want to guarantee a well-defined behavior when choosing one + // SDK to fit all CUs in an lldb::Module. + // -> The higher number wins. + EXPECT_EQ(sdk.GetType(), XcodeSDK::watchOS); + sdk.Merge(XcodeSDK("WatchOS1.1.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(1, 1)); + sdk.Merge(XcodeSDK("WatchOS2.0.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0)); +} + +TEST(XcodeSDKTest, SDKSupportsModules) { + std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); +} + +TEST(XcodeSDKTest, GetSDKNameForType) { + EXPECT_EQ("macosx", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::MacOSX)); + EXPECT_EQ("iphonesimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneSimulator)); + EXPECT_EQ("iphoneos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneOS)); + EXPECT_EQ("appletvsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVSimulator)); + EXPECT_EQ("appletvos", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVOS)); + EXPECT_EQ("watchsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::WatchSimulator)); + EXPECT_EQ("watchos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::watchOS)); + EXPECT_EQ("linux", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::Linux)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::numSDKTypes)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::unknown)); +} -- 2.7.4