diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h --- 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 @@ 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 @@ /// 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 --- 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 @@ 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 --- 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 @@ 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 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -434,6 +434,10 @@ 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 --- /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 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1596,6 +1596,24 @@ 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 --- 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 @@ } } } + +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 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h @@ -69,7 +69,7 @@ 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 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h @@ -69,7 +69,7 @@ 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.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h --- 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 @@ 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 @@ 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 @@ 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 @@ 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/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1220,56 +1220,12 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ #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 @@ // 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 @@ 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 @@ } } - 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/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -73,7 +73,7 @@ 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/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -208,7 +208,8 @@ } // 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/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -45,7 +45,7 @@ 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 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h @@ -71,7 +71,7 @@ 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 --- 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 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -664,6 +664,12 @@ 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 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -57,6 +57,7 @@ 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 --- /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 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -21,10 +21,6 @@ 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 @@ 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 @@ 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 --- a/lldb/unittests/Utility/CMakeLists.txt +++ b/lldb/unittests/Utility/CMakeLists.txt @@ -42,6 +42,7 @@ 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 --- /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)); +}