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 @@ -27,6 +27,7 @@ #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/Timeout.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" #include "llvm/Support/VersionTuple.h" 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 @@ -124,6 +124,17 @@ /// located in. static FileSpec GetCurrentCommandLineToolsDirectory(); + /// Will search each CU associated with the specified 'module' + /// for the SDK paths the CUs were compiled against. In the presence + /// of different SDKs, we try to pick the most appropriate one using + /// \ref XcodeSDK::Merge. + /// + /// \returns If successful, returns a parsed XcodeSDK object + static llvm::Expected GetSDKPathFromDebugInfo(Module &module); + + static llvm::Expected + ResolveSDKPathFromDebugInfo(Module &module); + protected: static const char *GetCompatibleArch(ArchSpec::Core core, size_t idx); 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 @@ -42,6 +42,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" @@ -1095,8 +1096,21 @@ } FileSpec sysroot_spec; - // Scope for mutex locker below - { + + if (target) { + if (ModuleSP exe_module_sp = target->GetExecutableModule()) { + auto path_or_err = ResolveSDKPathFromDebugInfo(*exe_module_sp); + if (path_or_err) { + sysroot_spec = FileSpec(*path_or_err); + } else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types | LLDBLog::Host), + path_or_err.takeError(), + "Failed to resolve SDK path: {0}"); + } + } + } + + if (!FileSystem::Instance().IsDirectory(sysroot_spec.GetPath())) { std::lock_guard guard(m_mutex); sysroot_spec = GetSDKDirectoryForModules(sdk_type); } @@ -1335,3 +1349,41 @@ #endif #endif // __APPLE__ } + +llvm::Expected +PlatformDarwin::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(""))); + + XcodeSDK sdk; + for (unsigned i = 0; i < sym_file->GetNumCompileUnits(); ++i) + if (auto cu_sp = sym_file->GetCompileUnitAtIndex(i)) + sdk.Merge(sym_file->ParseXcodeSDK(*cu_sp)); + + return sdk; +} + +llvm::Expected +PlatformDarwin::ResolveSDKPathFromDebugInfo(Module &module) { + auto sdk_or_err = GetSDKPathFromDebugInfo(module); + if (!sdk_or_err) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + llvm::formatv("Failed to parse SDK path from debug-info: {0}", + llvm::toString(sdk_or_err.takeError()))); + + auto path_or_err = + HostInfo::GetSDKRoot(HostInfo::SDKOptions{std::move(*sdk_or_err)}); + if (!path_or_err) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + llvm::formatv("Error while searching for SDK (XcodeSDK '{0}'): {1}", + sdk_or_err->GetString(), + llvm::toString(path_or_err.takeError()))); + + return path_or_err->str(); +} diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp --- a/lldb/source/Target/Platform.cpp +++ b/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" @@ -40,7 +43,9 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" diff --git a/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp b/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp --- a/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp +++ b/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,169 @@ 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(dwarf_unit); + ASSERT_TRUE(static_cast(dwarf_cu)); + SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF(); + ASSERT_EQ(sym_file.GetNumCompileUnits(), 2U); + ModuleSP module = t.GetModule(); + ASSERT_NE(module, nullptr); + + auto sdk_or_err = PlatformDarwin::GetSDKPathFromDebugInfo(*module); + ASSERT_TRUE(static_cast(sdk_or_err)); + + ASSERT_TRUE(sdk_or_err->IsAppleInternalSDK()); + ASSERT_NE(sdk_or_err->GetString().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 = PlatformDarwin::ResolveSDKPathFromDebugInfo(*module); + ASSERT_FALSE(static_cast(path_or_err)); + llvm::consumeError(path_or_err.takeError()); +} + +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 = PlatformDarwin::ResolveSDKPathFromDebugInfo(*module); + ASSERT_FALSE(static_cast(path_or_err)); + llvm::consumeError(path_or_err.takeError()); +} #endif