| 1 | //===-- XcodeSDKModuleTests.cpp -------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "Plugins/Platform/MacOSX/PlatformMacOSX.h" |
| 10 | #include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h" |
| 11 | #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" |
| 12 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
| 13 | #include "TestingSupport/Symbol/YAMLModuleTester.h" |
| 14 | #include "lldb/Core/PluginManager.h" |
| 15 | #include "llvm/Support/Error.h" |
| 16 | #include "llvm/Support/Path.h" |
| 17 | #include "gmock/gmock.h" |
| 18 | #include "gtest/gtest.h" |
| 19 | |
| 20 | using namespace lldb; |
| 21 | using namespace lldb_private; |
| 22 | using namespace lldb_private::plugin::dwarf; |
| 23 | |
| 24 | #ifdef __APPLE__ |
| 25 | namespace { |
| 26 | class XcodeSDKModuleTests : public testing::Test { |
| 27 | SubsystemRAII<HostInfoBase, PlatformMacOSX> subsystems; |
| 28 | }; |
| 29 | |
| 30 | struct SDKPathParsingTestData { |
| 31 | /// Each path will be put into a new CU's |
| 32 | /// DW_AT_LLVM_sysroot. |
| 33 | std::vector<llvm::StringRef> input_sdk_paths; |
| 34 | |
| 35 | /// 'true' if we expect \ref GetSDKPathFromDebugInfo |
| 36 | /// to notify us about an SDK mismatch. |
| 37 | bool expect_mismatch; |
| 38 | |
| 39 | /// 'true if the test expects the parsed SDK to |
| 40 | /// be an internal one. |
| 41 | bool expect_internal_sdk; |
| 42 | |
| 43 | /// A substring that the final parsed sdk |
| 44 | /// is expected to contain. |
| 45 | llvm::StringRef expect_sdk_path_pattern; |
| 46 | }; |
| 47 | |
| 48 | struct SDKPathParsingMultiparamTests |
| 49 | : public XcodeSDKModuleTests, |
| 50 | public testing::WithParamInterface<SDKPathParsingTestData> { |
| 51 | std::vector<std::string> |
| 52 | createCompileUnits(std::vector<llvm::StringRef> const &sdk_paths) { |
| 53 | std::vector<std::string> compile_units; |
| 54 | |
| 55 | for (auto sdk_path : sdk_paths) { |
| 56 | compile_units.emplace_back(llvm::formatv( |
| 57 | R"( |
| 58 | - Version: 2 |
| 59 | AddrSize: 8 |
| 60 | AbbrevTableID: 0 |
| 61 | AbbrOffset: 0x0 |
| 62 | Entries: |
| 63 | - AbbrCode: 0x00000001 |
| 64 | Values: |
| 65 | - Value: 0x000000000000000C |
| 66 | - CStr: {0} |
| 67 | - CStr: {1} |
| 68 | - AbbrCode: 0x00000000 |
| 69 | )" , |
| 70 | llvm::sys::path::filename(sdk_path, llvm::sys::path::Style::posix), |
| 71 | sdk_path)); |
| 72 | } |
| 73 | |
| 74 | return compile_units; |
| 75 | } |
| 76 | }; |
| 77 | } // namespace |
| 78 | |
| 79 | TEST_F(XcodeSDKModuleTests, TestModuleGetXcodeSDK) { |
| 80 | const char *yamldata = R"( |
| 81 | --- !ELF |
| 82 | FileHeader: |
| 83 | Class: ELFCLASS64 |
| 84 | Data: ELFDATA2LSB |
| 85 | Type: ET_EXEC |
| 86 | Machine: EM_386 |
| 87 | DWARF: |
| 88 | debug_str: |
| 89 | - MacOSX10.9.sdk |
| 90 | debug_abbrev: |
| 91 | - Table: |
| 92 | - Code: 0x00000001 |
| 93 | Tag: DW_TAG_compile_unit |
| 94 | Children: DW_CHILDREN_no |
| 95 | Attributes: |
| 96 | - Attribute: DW_AT_language |
| 97 | Form: DW_FORM_data2 |
| 98 | - Attribute: DW_AT_APPLE_sdk |
| 99 | Form: DW_FORM_strp |
| 100 | debug_info: |
| 101 | - Version: 2 |
| 102 | AddrSize: 8 |
| 103 | Entries: |
| 104 | - AbbrCode: 0x00000001 |
| 105 | Values: |
| 106 | - Value: 0x000000000000000C |
| 107 | - Value: 0x0000000000000000 |
| 108 | - AbbrCode: 0x00000000 |
| 109 | ... |
| 110 | )" ; |
| 111 | |
| 112 | YAMLModuleTester t(yamldata); |
| 113 | DWARFUnit *dwarf_unit = t.GetDwarfUnit(); |
| 114 | auto *dwarf_cu = llvm::cast<DWARFCompileUnit>(dwarf_unit); |
| 115 | ASSERT_TRUE(static_cast<bool>(dwarf_cu)); |
| 116 | SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF(); |
| 117 | CompUnitSP comp_unit = sym_file.GetCompileUnitAtIndex(0); |
| 118 | ASSERT_TRUE(static_cast<bool>(comp_unit.get())); |
| 119 | XcodeSDK sdk = sym_file.ParseXcodeSDK(*comp_unit); |
| 120 | ASSERT_EQ(sdk.GetType(), XcodeSDK::Type::MacOSX); |
| 121 | } |
| 122 | |
| 123 | TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_InvalidSDKPath) { |
| 124 | // Tests that parsing a CU with an invalid SDK directory name fails. |
| 125 | |
| 126 | const char *yamldata = R"( |
| 127 | --- !ELF |
| 128 | FileHeader: |
| 129 | Class: ELFCLASS64 |
| 130 | Data: ELFDATA2LSB |
| 131 | Type: ET_EXEC |
| 132 | Machine: EM_386 |
| 133 | DWARF: |
| 134 | debug_abbrev: |
| 135 | - Table: |
| 136 | - Code: 0x00000001 |
| 137 | Tag: DW_TAG_compile_unit |
| 138 | Children: DW_CHILDREN_no |
| 139 | Attributes: |
| 140 | - Attribute: DW_AT_language |
| 141 | Form: DW_FORM_data2 |
| 142 | - Attribute: DW_AT_APPLE_sdk |
| 143 | Form: DW_FORM_string |
| 144 | debug_info: |
| 145 | - Version: 2 |
| 146 | AddrSize: 8 |
| 147 | AbbrevTableID: 0 |
| 148 | AbbrOffset: 0x0 |
| 149 | Entries: |
| 150 | - AbbrCode: 0x00000001 |
| 151 | Values: |
| 152 | - Value: 0x000000000000000C |
| 153 | - CStr: "1abc@defgh2" |
| 154 | - AbbrCode: 0x00000000 |
| 155 | ... |
| 156 | )" ; |
| 157 | |
| 158 | YAMLModuleTester t(yamldata); |
| 159 | ModuleSP module = t.GetModule(); |
| 160 | ASSERT_NE(module, nullptr); |
| 161 | |
| 162 | auto platform_sp = Platform::GetHostPlatform(); |
| 163 | ASSERT_TRUE(platform_sp); |
| 164 | auto path_or_err = platform_sp->ResolveSDKPathFromDebugInfo(*module); |
| 165 | EXPECT_FALSE(static_cast<bool>(path_or_err)); |
| 166 | llvm::consumeError(path_or_err.takeError()); |
| 167 | } |
| 168 | |
| 169 | TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_No_DW_AT_APPLE_sdk) { |
| 170 | // Tests that parsing a CU without a DW_AT_APPLE_sdk fails. |
| 171 | |
| 172 | const char *yamldata = R"( |
| 173 | --- !ELF |
| 174 | FileHeader: |
| 175 | Class: ELFCLASS64 |
| 176 | Data: ELFDATA2LSB |
| 177 | Type: ET_EXEC |
| 178 | Machine: EM_386 |
| 179 | DWARF: |
| 180 | debug_abbrev: |
| 181 | - Table: |
| 182 | - Code: 0x00000001 |
| 183 | Tag: DW_TAG_compile_unit |
| 184 | Children: DW_CHILDREN_no |
| 185 | Attributes: |
| 186 | - Attribute: DW_AT_language |
| 187 | Form: DW_FORM_data2 |
| 188 | - Attribute: DW_AT_LLVM_sysroot |
| 189 | Form: DW_FORM_string |
| 190 | debug_info: |
| 191 | - Version: 2 |
| 192 | AddrSize: 8 |
| 193 | AbbrevTableID: 0 |
| 194 | AbbrOffset: 0x0 |
| 195 | Entries: |
| 196 | - AbbrCode: 0x00000001 |
| 197 | Values: |
| 198 | - Value: 0x000000000000000C |
| 199 | - CStr: "/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk" |
| 200 | - AbbrCode: 0x00000000 |
| 201 | ... |
| 202 | )" ; |
| 203 | |
| 204 | YAMLModuleTester t(yamldata); |
| 205 | ModuleSP module = t.GetModule(); |
| 206 | ASSERT_NE(module, nullptr); |
| 207 | |
| 208 | auto platform_sp = Platform::GetHostPlatform(); |
| 209 | ASSERT_TRUE(platform_sp); |
| 210 | auto path_or_err = platform_sp->ResolveSDKPathFromDebugInfo(*module); |
| 211 | EXPECT_FALSE(static_cast<bool>(path_or_err)); |
| 212 | llvm::consumeError(path_or_err.takeError()); |
| 213 | } |
| 214 | |
| 215 | TEST_P(SDKPathParsingMultiparamTests, TestSDKPathFromDebugInfo) { |
| 216 | // Tests that we can parse the SDK path from debug-info. |
| 217 | // In the presence of multiple compile units, one of which |
| 218 | // points to an internal SDK, we should pick the internal SDK. |
| 219 | |
| 220 | std::string yamldata = R"( |
| 221 | --- !ELF |
| 222 | FileHeader: |
| 223 | Class: ELFCLASS64 |
| 224 | Data: ELFDATA2LSB |
| 225 | Type: ET_EXEC |
| 226 | Machine: EM_386 |
| 227 | DWARF: |
| 228 | debug_abbrev: |
| 229 | - Table: |
| 230 | - Code: 0x00000001 |
| 231 | Tag: DW_TAG_compile_unit |
| 232 | Children: DW_CHILDREN_no |
| 233 | Attributes: |
| 234 | - Attribute: DW_AT_language |
| 235 | Form: DW_FORM_data2 |
| 236 | - Attribute: DW_AT_APPLE_sdk |
| 237 | Form: DW_FORM_string |
| 238 | - Attribute: DW_AT_LLVM_sysroot |
| 239 | Form: DW_FORM_string |
| 240 | debug_info: |
| 241 | )" ; |
| 242 | |
| 243 | auto [input_sdk_paths, expect_mismatch, expect_internal_sdk, |
| 244 | expect_sdk_path_pattern] = GetParam(); |
| 245 | |
| 246 | for (auto &&sdk : createCompileUnits(input_sdk_paths)) |
| 247 | yamldata += std::move(sdk); |
| 248 | |
| 249 | YAMLModuleTester t(yamldata); |
| 250 | DWARFUnit *dwarf_unit = t.GetDwarfUnit(); |
| 251 | auto *dwarf_cu = llvm::cast<DWARFCompileUnit>(dwarf_unit); |
| 252 | ASSERT_TRUE(static_cast<bool>(dwarf_cu)); |
| 253 | SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF(); |
| 254 | ASSERT_EQ(sym_file.GetNumCompileUnits(), input_sdk_paths.size()); |
| 255 | ModuleSP module = t.GetModule(); |
| 256 | ASSERT_NE(module, nullptr); |
| 257 | |
| 258 | auto platform_sp = Platform::GetHostPlatform(); |
| 259 | ASSERT_TRUE(platform_sp); |
| 260 | auto sdk_or_err = platform_sp->GetSDKPathFromDebugInfo(*module); |
| 261 | ASSERT_TRUE(static_cast<bool>(sdk_or_err)); |
| 262 | |
| 263 | auto [sdk, found_mismatch] = *sdk_or_err; |
| 264 | |
| 265 | EXPECT_EQ(found_mismatch, expect_mismatch); |
| 266 | EXPECT_EQ(sdk.IsAppleInternalSDK(), expect_internal_sdk); |
| 267 | EXPECT_NE(sdk.GetString().find(expect_sdk_path_pattern), std::string::npos); |
| 268 | |
| 269 | { |
| 270 | auto sdk_or_err = |
| 271 | platform_sp->GetSDKPathFromDebugInfo(*dwarf_cu->GetLLDBCompUnit()); |
| 272 | ASSERT_TRUE(static_cast<bool>(sdk_or_err)); |
| 273 | EXPECT_EQ(sdk.IsAppleInternalSDK(), expect_internal_sdk); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | SDKPathParsingTestData sdkPathParsingTestCases[] = { |
| 278 | /// Multiple CUs with a mix of internal and public SDKs |
| 279 | {.input_sdk_paths = |
| 280 | {"/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk" , |
| 281 | "/invalid/path/to/something.invalid.sdk" , |
| 282 | "/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk" , |
| 283 | "/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk" }, |
| 284 | .expect_mismatch = true, |
| 285 | .expect_internal_sdk = true, |
| 286 | .expect_sdk_path_pattern = "Internal.sdk" }, |
| 287 | |
| 288 | /// Single CU with a public SDK |
| 289 | {.input_sdk_paths = |
| 290 | {"/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk" }, |
| 291 | .expect_mismatch = false, |
| 292 | .expect_internal_sdk = false, |
| 293 | .expect_sdk_path_pattern = "MacOSX10.9.sdk" }, |
| 294 | |
| 295 | /// Single CU with an internal SDK |
| 296 | {.input_sdk_paths = |
| 297 | {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk" }, |
| 298 | .expect_mismatch = false, |
| 299 | .expect_internal_sdk = true, |
| 300 | .expect_sdk_path_pattern = "Internal.sdk" }, |
| 301 | |
| 302 | /// Two CUs with an internal SDK each |
| 303 | {.input_sdk_paths = |
| 304 | {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk" , |
| 305 | "/Library/Developer/CommandLineTools/SDKs/iPhoneOS12.9.Internal.sdk" }, |
| 306 | .expect_mismatch = false, |
| 307 | .expect_internal_sdk = true, |
| 308 | .expect_sdk_path_pattern = "Internal.sdk" }, |
| 309 | |
| 310 | /// Two CUs with a public (non-CommandLineTools) SDK each |
| 311 | {.input_sdk_paths = {"/Path/To/SDKs/iPhoneOS14.1.sdk" , |
| 312 | "/Path/To/SDKs/MacOSX11.3.sdk" }, |
| 313 | .expect_mismatch = false, |
| 314 | .expect_internal_sdk = false, |
| 315 | .expect_sdk_path_pattern = "iPhoneOS14.1.sdk" }, |
| 316 | |
| 317 | /// One CU with CommandLineTools and the other a public SDK |
| 318 | {.input_sdk_paths = |
| 319 | {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.1.sdk" , |
| 320 | "/Path/To/SDKs/MacOSX11.3.sdk" }, |
| 321 | .expect_mismatch = false, |
| 322 | .expect_internal_sdk = false, |
| 323 | .expect_sdk_path_pattern = "iPhoneOS14.1.sdk" }, |
| 324 | |
| 325 | /// One CU with CommandLineTools and the other an internal SDK |
| 326 | {.input_sdk_paths = |
| 327 | {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.1.sdk" , |
| 328 | "/Path/To/SDKs/MacOSX11.3.Internal.sdk" }, |
| 329 | .expect_mismatch = true, |
| 330 | .expect_internal_sdk = true, |
| 331 | .expect_sdk_path_pattern = "iPhoneOS14.1.Internal.sdk" }, |
| 332 | }; |
| 333 | |
| 334 | INSTANTIATE_TEST_SUITE_P(SDKPathParsingTests, SDKPathParsingMultiparamTests, |
| 335 | ::testing::ValuesIn(sdkPathParsingTestCases)); |
| 336 | #endif |
| 337 | |