xref: /llvm-project/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp (revision 01d8e0fc75a897a6a9c2ce634645457a895ed505)
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