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 | |