Skip to content

Commit

Permalink
Remap the target (Xcode) SDK directory to the host SDK directory.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
adrian-prantl committed Apr 6, 2020
1 parent 276d2b7 commit 1e05d7b
Show file tree
Hide file tree
Showing 22 changed files with 440 additions and 204 deletions.
11 changes: 11 additions & 0 deletions lldb/include/lldb/Core/Module.h
Expand Up @@ -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"
Expand Down Expand Up @@ -509,6 +510,12 @@ class Module : public std::enable_shared_from_this<Module>,
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.
///
Expand Down Expand Up @@ -971,6 +978,10 @@ class Module : public std::enable_shared_from_this<Module>,
/// 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
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Host/HostInfoBase.h
Expand Up @@ -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"

Expand Down Expand Up @@ -91,6 +92,9 @@ class HostInfoBase {
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);
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
Expand Up @@ -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 {
Expand All @@ -31,7 +32,10 @@ class HostInfoMacOSX : public HostInfoPosix {
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,
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/Platform.h
Expand Up @@ -434,6 +434,10 @@ class Platform : public PluginInterface {
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 {
Expand Down
63 changes: 63 additions & 0 deletions 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 <tuple>

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<Type, llvm::VersionTuple> 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
18 changes: 18 additions & 0 deletions lldb/source/Core/Module.cpp
Expand Up @@ -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;
Expand Down
37 changes: 37 additions & 0 deletions lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
Expand Up @@ -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"
Expand Down Expand Up @@ -295,3 +296,39 @@ static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) {
}
}
}

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();
}
Expand Up @@ -69,7 +69,7 @@ class PlatformAppleTVSimulator : public PlatformDarwin {
AddClangModuleCompilationOptions(lldb_private::Target *target,
std::vector<std::string> &options) override {
return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
target, options, PlatformDarwin::SDKType::iPhoneSimulator);
target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator);
}

protected:
Expand Down
Expand Up @@ -69,7 +69,7 @@ class PlatformAppleWatchSimulator : public PlatformDarwin {
AddClangModuleCompilationOptions(lldb_private::Target *target,
std::vector<std::string> &options) override {
return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
target, options, PlatformDarwin::SDKType::iPhoneSimulator);
target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator);
}

protected:
Expand Down

0 comments on commit 1e05d7b

Please sign in to comment.