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