Michael137 created this revision.
Michael137 added a reviewer: aprantl.
Herald added a project: All.
Michael137 requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
When we build the Clang module compilation command (e.g., when
a user requests import of a module via `expression @import Foundation`),
LLDB will try to determine which SDK directory to use as the `sysroot`.
However, it currently does so by simply enumerating the `SDKs` directory
and picking the last one that's appropriate for module compilation
(see `PlatformDarwin::GetSDKDirectoryForModules`). That means if we have
multiple platform SDKs installed (e.g., a public and internal one), we
may pick the wrong one by chance.
On Darwin platforms we emit the SDK path that a object
file was compiled against into DWARF (using `DW_AT_LLVM_sysroot`
and `DW_AT_APPLE_sdk`). For Swift debugging, we already parse the SDK
path from debug-info if we can.
This patch mimicks the Swift behaviour for non-Swift languages. I.e.,
if we can get the SDK path from debug-info, do so. Otherwise, fall back
to the old heuristic.
rdar://110407148
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D156020
Files:
lldb/include/lldb/Target/Platform.h
lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
lldb/source/Target/Platform.cpp
lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp
Index: lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp
===================================================================
--- lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp
+++ lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp
@@ -12,6 +12,7 @@
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/Symbol/YAMLModuleTester.h"
#include "lldb/Core/PluginManager.h"
+#include "llvm/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -72,4 +73,174 @@
ASSERT_EQ(sdk.GetType(), XcodeSDK::Type::MacOSX);
ASSERT_EQ(module->GetSourceMappingList().GetSize(), 1u);
}
+
+TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_InternalAndPublicSDK) {
+ // Tests that we can parse the SDK path from debug-info.
+ // In the presence of multiple compile units, one of which
+ // points to an internal SDK, we should pick the internal SDK.
+
+ const char *yamldata = R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_386
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_APPLE_sdk
+ Form: DW_FORM_string
+ - Attribute: DW_AT_LLVM_sysroot
+ Form: DW_FORM_string
+ - Code: 0x00000002
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_APPLE_sdk
+ Form: DW_FORM_string
+ - Attribute: DW_AT_LLVM_sysroot
+ Form: DW_FORM_string
+ debug_info:
+ - Version: 2
+ AddrSize: 8
+ AbbrevTableID: 0
+ AbbrOffset: 0x0
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x000000000000000C
+ - CStr: "MacOSX10.9.sdk"
+ - CStr: "/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk"
+ - AbbrCode: 0x00000000
+ - Version: 2
+ AddrSize: 8
+ AbbrevTableID: 0
+ AbbrOffset: 0x0
+ Entries:
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x0000000000000010
+ - CStr: "iPhoneOS14.0.Internal.sdk"
+ - CStr: "/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk"
+ - AbbrCode: 0x00000000
+...
+)";
+
+ YAMLModuleTester t(yamldata);
+ DWARFUnit *dwarf_unit = t.GetDwarfUnit();
+ auto *dwarf_cu = llvm::cast<DWARFCompileUnit>(dwarf_unit);
+ ASSERT_TRUE(static_cast<bool>(dwarf_cu));
+ SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF();
+ ASSERT_EQ(sym_file.GetNumCompileUnits(), 2U);
+ ModuleSP module = t.GetModule();
+ ASSERT_NE(module, nullptr);
+
+ auto path_or_err = Platform::GetSDKPathFromDebugInfo(*module);
+ ASSERT_TRUE(!!path_or_err);
+
+ auto [sdk_path, found_internal, found_public] = *path_or_err;
+
+ ASSERT_TRUE(found_internal);
+ ASSERT_TRUE(found_public);
+ ASSERT_NE(sdk_path.find("Internal.sdk"), std::string::npos);
+}
+
+TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_InvalidSDKPath) {
+ // Tests that parsing a CU with an invalid SDK directory name fails.
+
+ const char *yamldata = R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_386
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_APPLE_sdk
+ Form: DW_FORM_string
+ debug_info:
+ - Version: 2
+ AddrSize: 8
+ AbbrevTableID: 0
+ AbbrOffset: 0x0
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x000000000000000C
+ - CStr: "1abc@defgh2"
+ - AbbrCode: 0x00000000
+...
+)";
+
+ YAMLModuleTester t(yamldata);
+ ModuleSP module = t.GetModule();
+ ASSERT_NE(module, nullptr);
+
+ auto path_or_err = Platform::GetSDKPathFromDebugInfo(*module);
+ auto err = path_or_err.takeError();
+ ASSERT_TRUE(static_cast<bool>(err));
+ llvm::consumeError(std::move(err));
+}
+
+TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_No_DW_AT_APPLE_sdk) {
+ // Tests that parsing a CU without a DW_AT_APPLE_sdk fails.
+
+ const char *yamldata = R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_386
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_LLVM_sysroot
+ Form: DW_FORM_string
+ debug_info:
+ - Version: 2
+ AddrSize: 8
+ AbbrevTableID: 0
+ AbbrOffset: 0x0
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x000000000000000C
+ - CStr: "/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk"
+ - AbbrCode: 0x00000000
+...
+)";
+
+ YAMLModuleTester t(yamldata);
+ ModuleSP module = t.GetModule();
+ ASSERT_NE(module, nullptr);
+
+ auto path_or_err = Platform::GetSDKPathFromDebugInfo(*module);
+ auto err = path_or_err.takeError();
+ ASSERT_TRUE(static_cast<bool>(err));
+ llvm::consumeError(std::move(err));
+}
#endif
Index: lldb/source/Target/Platform.cpp
===================================================================
--- lldb/source/Target/Platform.cpp
+++ lldb/source/Target/Platform.cpp
@@ -28,7 +28,10 @@
#include "lldb/Interpreter/OptionValueFileSpec.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/Property.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/Language.h"
#include "lldb/Target/ModuleCache.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
@@ -41,6 +44,7 @@
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -2124,3 +2128,33 @@
}
return false;
}
+
+llvm::Expected<Platform::SDKPathSearchResult>
+Platform::GetSDKPathFromDebugInfo(Module &module) {
+ SymbolFile *sym_file = module.GetSymbolFile();
+ if (!sym_file)
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv("No symbol file available for module '{0}'",
+ module.GetFileSpec().GetFilename().AsCString("")));
+
+ bool found_public_sdk = false;
+ bool found_internal_sdk = false;
+ XcodeSDK sdk;
+ for (unsigned i = 0; i < sym_file->GetNumCompileUnits(); ++i) {
+ if (auto cu_sp = sym_file->GetCompileUnitAtIndex(i)) {
+ auto cu_sdk = sym_file->ParseXcodeSDK(*cu_sp);
+ sdk.Merge(cu_sdk);
+ bool is_internal_sdk = cu_sdk.IsAppleInternalSDK();
+ found_public_sdk |= !is_internal_sdk;
+ found_internal_sdk |= is_internal_sdk;
+ }
+ }
+
+ auto path_or_err = HostInfo::GetSDKRoot(HostInfo::SDKOptions{std::move(sdk)});
+ if (!path_or_err)
+ return path_or_err.takeError();
+
+ return SDKPathSearchResult{path_or_err->str(), found_internal_sdk,
+ found_public_sdk};
+}
Index: lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -29,10 +29,12 @@
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LocateSymbolFile.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/Language.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -42,6 +44,7 @@
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Timer.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/VersionTuple.h"
@@ -1098,7 +1101,18 @@
// Scope for mutex locker below
{
std::lock_guard<std::mutex> guard(m_mutex);
- sysroot_spec = GetSDKDirectoryForModules(sdk_type);
+ if (target) {
+ if (ModuleSP exe_module_sp = target->GetExecutableModule()) {
+ if (auto path_or_err = GetSDKPathFromDebugInfo(*exe_module_sp))
+ sysroot_spec = FileSpec(path_or_err->sdk_path);
+ else
+ llvm::consumeError(path_or_err.takeError());
+ }
+ }
+
+ if (!FileSystem::Instance().IsDirectory(sysroot_spec.GetPath())) {
+ sysroot_spec = GetSDKDirectoryForModules(sdk_type);
+ }
}
if (FileSystem::Instance().IsDirectory(sysroot_spec.GetPath())) {
Index: lldb/include/lldb/Target/Platform.h
===================================================================
--- lldb/include/lldb/Target/Platform.h
+++ lldb/include/lldb/Target/Platform.h
@@ -469,6 +469,28 @@
AddClangModuleCompilationOptions(Target *target,
std::vector<std::string> &options);
+ struct SDKPathSearchResult {
+ /// Full path to SDK directory that we parsed
+ /// from debug-info
+ std::string sdk_path;
+
+ /// True if one of the parsed CUs pointed
+ /// to an internal SDK
+ bool found_internal_sdk = false;
+
+ /// True if one of the parsed CUs pointed
+ /// to a public (i.e., non-interanl) SDK
+ bool found_public_sdk = false;
+ };
+
+ /// Will search each CU associated with the specified 'module'
+ /// for the SDK path the CU was compiled against.
+ ///
+ /// \returns If successful, returns a SDKPathSearchResult that
+ /// holds the SDK path.
+ static llvm::Expected<SDKPathSearchResult>
+ GetSDKPathFromDebugInfo(Module &module);
+
FileSpec GetWorkingDirectory();
bool SetWorkingDirectory(const FileSpec &working_dir);
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits