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 @@ -469,6 +469,28 @@ AddClangModuleCompilationOptions(Target *target, std::vector &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 + GetSDKPathFromDebugInfo(Module &module); + FileSpec GetWorkingDirectory(); bool SetWorkingDirectory(const FileSpec &working_dir); 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 @@ -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 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())) { 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" @@ -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::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}; +} 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,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(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 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(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(err)); + llvm::consumeError(std::move(err)); +} #endif