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 ModuleSP module = t.GetModule(); 120 ASSERT_EQ(module->GetSourceMappingList().GetSize(), 0u); 121 XcodeSDK sdk = sym_file.ParseXcodeSDK(*comp_unit); 122 ASSERT_EQ(sdk.GetType(), XcodeSDK::Type::MacOSX); 123 ASSERT_EQ(module->GetSourceMappingList().GetSize(), 1u); 124 } 125 126 TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_InvalidSDKPath) { 127 // Tests that parsing a CU with an invalid SDK directory name fails. 128 129 const char *yamldata = R"( 130 --- !ELF 131 FileHeader: 132 Class: ELFCLASS64 133 Data: ELFDATA2LSB 134 Type: ET_EXEC 135 Machine: EM_386 136 DWARF: 137 debug_abbrev: 138 - Table: 139 - Code: 0x00000001 140 Tag: DW_TAG_compile_unit 141 Children: DW_CHILDREN_no 142 Attributes: 143 - Attribute: DW_AT_language 144 Form: DW_FORM_data2 145 - Attribute: DW_AT_APPLE_sdk 146 Form: DW_FORM_string 147 debug_info: 148 - Version: 2 149 AddrSize: 8 150 AbbrevTableID: 0 151 AbbrOffset: 0x0 152 Entries: 153 - AbbrCode: 0x00000001 154 Values: 155 - Value: 0x000000000000000C 156 - CStr: "1abc@defgh2" 157 - AbbrCode: 0x00000000 158 ... 159 )"; 160 161 YAMLModuleTester t(yamldata); 162 ModuleSP module = t.GetModule(); 163 ASSERT_NE(module, nullptr); 164 165 auto platform_sp = Platform::GetHostPlatform(); 166 ASSERT_TRUE(platform_sp); 167 auto path_or_err = platform_sp->ResolveSDKPathFromDebugInfo(*module); 168 EXPECT_FALSE(static_cast<bool>(path_or_err)); 169 llvm::consumeError(path_or_err.takeError()); 170 } 171 172 TEST_F(XcodeSDKModuleTests, TestSDKPathFromDebugInfo_No_DW_AT_APPLE_sdk) { 173 // Tests that parsing a CU without a DW_AT_APPLE_sdk fails. 174 175 const char *yamldata = R"( 176 --- !ELF 177 FileHeader: 178 Class: ELFCLASS64 179 Data: ELFDATA2LSB 180 Type: ET_EXEC 181 Machine: EM_386 182 DWARF: 183 debug_abbrev: 184 - Table: 185 - Code: 0x00000001 186 Tag: DW_TAG_compile_unit 187 Children: DW_CHILDREN_no 188 Attributes: 189 - Attribute: DW_AT_language 190 Form: DW_FORM_data2 191 - Attribute: DW_AT_LLVM_sysroot 192 Form: DW_FORM_string 193 debug_info: 194 - Version: 2 195 AddrSize: 8 196 AbbrevTableID: 0 197 AbbrOffset: 0x0 198 Entries: 199 - AbbrCode: 0x00000001 200 Values: 201 - Value: 0x000000000000000C 202 - CStr: "/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk" 203 - AbbrCode: 0x00000000 204 ... 205 )"; 206 207 YAMLModuleTester t(yamldata); 208 ModuleSP module = t.GetModule(); 209 ASSERT_NE(module, nullptr); 210 211 auto platform_sp = Platform::GetHostPlatform(); 212 ASSERT_TRUE(platform_sp); 213 auto path_or_err = platform_sp->ResolveSDKPathFromDebugInfo(*module); 214 EXPECT_FALSE(static_cast<bool>(path_or_err)); 215 llvm::consumeError(path_or_err.takeError()); 216 } 217 218 TEST_P(SDKPathParsingMultiparamTests, TestSDKPathFromDebugInfo) { 219 // Tests that we can parse the SDK path from debug-info. 220 // In the presence of multiple compile units, one of which 221 // points to an internal SDK, we should pick the internal SDK. 222 223 std::string yamldata = R"( 224 --- !ELF 225 FileHeader: 226 Class: ELFCLASS64 227 Data: ELFDATA2LSB 228 Type: ET_EXEC 229 Machine: EM_386 230 DWARF: 231 debug_abbrev: 232 - Table: 233 - Code: 0x00000001 234 Tag: DW_TAG_compile_unit 235 Children: DW_CHILDREN_no 236 Attributes: 237 - Attribute: DW_AT_language 238 Form: DW_FORM_data2 239 - Attribute: DW_AT_APPLE_sdk 240 Form: DW_FORM_string 241 - Attribute: DW_AT_LLVM_sysroot 242 Form: DW_FORM_string 243 debug_info: 244 )"; 245 246 auto [input_sdk_paths, expect_mismatch, expect_internal_sdk, 247 expect_sdk_path_pattern] = GetParam(); 248 249 for (auto &&sdk : createCompileUnits(input_sdk_paths)) 250 yamldata += std::move(sdk); 251 252 YAMLModuleTester t(yamldata); 253 DWARFUnit *dwarf_unit = t.GetDwarfUnit(); 254 auto *dwarf_cu = llvm::cast<DWARFCompileUnit>(dwarf_unit); 255 ASSERT_TRUE(static_cast<bool>(dwarf_cu)); 256 SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF(); 257 ASSERT_EQ(sym_file.GetNumCompileUnits(), input_sdk_paths.size()); 258 ModuleSP module = t.GetModule(); 259 ASSERT_NE(module, nullptr); 260 261 auto platform_sp = Platform::GetHostPlatform(); 262 ASSERT_TRUE(platform_sp); 263 auto sdk_or_err = platform_sp->GetSDKPathFromDebugInfo(*module); 264 ASSERT_TRUE(static_cast<bool>(sdk_or_err)); 265 266 auto [sdk, found_mismatch] = *sdk_or_err; 267 268 EXPECT_EQ(found_mismatch, expect_mismatch); 269 EXPECT_EQ(sdk.IsAppleInternalSDK(), expect_internal_sdk); 270 EXPECT_NE(sdk.GetString().find(expect_sdk_path_pattern), std::string::npos); 271 272 { 273 auto sdk_or_err = 274 platform_sp->GetSDKPathFromDebugInfo(*dwarf_cu->GetLLDBCompUnit()); 275 ASSERT_TRUE(static_cast<bool>(sdk_or_err)); 276 EXPECT_EQ(sdk.IsAppleInternalSDK(), expect_internal_sdk); 277 } 278 } 279 280 SDKPathParsingTestData sdkPathParsingTestCases[] = { 281 /// Multiple CUs with a mix of internal and public SDKs 282 {.input_sdk_paths = 283 {"/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk", 284 "/invalid/path/to/something.invalid.sdk", 285 "/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk", 286 "/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk"}, 287 .expect_mismatch = true, 288 .expect_internal_sdk = true, 289 .expect_sdk_path_pattern = "Internal.sdk"}, 290 291 /// Single CU with a public SDK 292 {.input_sdk_paths = 293 {"/Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk"}, 294 .expect_mismatch = false, 295 .expect_internal_sdk = false, 296 .expect_sdk_path_pattern = "MacOSX10.9.sdk"}, 297 298 /// Single CU with an internal SDK 299 {.input_sdk_paths = 300 {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk"}, 301 .expect_mismatch = false, 302 .expect_internal_sdk = true, 303 .expect_sdk_path_pattern = "Internal.sdk"}, 304 305 /// Two CUs with an internal SDK each 306 {.input_sdk_paths = 307 {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.0.Internal.sdk", 308 "/Library/Developer/CommandLineTools/SDKs/iPhoneOS12.9.Internal.sdk"}, 309 .expect_mismatch = false, 310 .expect_internal_sdk = true, 311 .expect_sdk_path_pattern = "Internal.sdk"}, 312 313 /// Two CUs with an internal SDK each 314 {.input_sdk_paths = 315 {"/Library/Developer/CommandLineTools/SDKs/iPhoneOS14.1.sdk", 316 "/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk"}, 317 .expect_mismatch = false, 318 .expect_internal_sdk = false, 319 .expect_sdk_path_pattern = "iPhoneOS14.1.sdk"}, 320 }; 321 322 INSTANTIATE_TEST_SUITE_P(SDKPathParsingTests, SDKPathParsingMultiparamTests, 323 ::testing::ValuesIn(sdkPathParsingTestCases)); 324 #endif 325