1 //===-- DWARFASTParserClangTests.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/SymbolFile/DWARF/DWARFASTParserClang.h"
10 #include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h"
11 #include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
12 #include "TestingSupport/Symbol/YAMLModuleTester.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15
16 using namespace lldb;
17 using namespace lldb_private;
18 using namespace lldb_private::dwarf;
19
20 namespace {
21 class DWARFASTParserClangTests : public testing::Test {};
22
23 class DWARFASTParserClangStub : public DWARFASTParserClang {
24 public:
25 using DWARFASTParserClang::DWARFASTParserClang;
26 using DWARFASTParserClang::LinkDeclContextToDIE;
27
GetDeclContextToDIEMapKeys()28 std::vector<const clang::DeclContext *> GetDeclContextToDIEMapKeys() {
29 std::vector<const clang::DeclContext *> keys;
30 for (const auto &it : m_decl_ctx_to_die)
31 keys.push_back(it.first);
32 return keys;
33 }
34 };
35 } // namespace
36
37 // If your implementation needs to dereference the dummy pointers we are
38 // defining here, causing this test to fail, feel free to delete it.
TEST_F(DWARFASTParserClangTests,EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries)39 TEST_F(DWARFASTParserClangTests,
40 EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries) {
41
42 /// Auxiliary debug info.
43 const char *yamldata = R"(
44 --- !ELF
45 FileHeader:
46 Class: ELFCLASS64
47 Data: ELFDATA2LSB
48 Type: ET_EXEC
49 Machine: EM_386
50 DWARF:
51 debug_abbrev:
52 - Table:
53 - Code: 0x00000001
54 Tag: DW_TAG_compile_unit
55 Children: DW_CHILDREN_yes
56 Attributes:
57 - Attribute: DW_AT_language
58 Form: DW_FORM_data2
59 - Code: 0x00000002
60 Tag: DW_TAG_base_type
61 Children: DW_CHILDREN_no
62 Attributes:
63 - Attribute: DW_AT_encoding
64 Form: DW_FORM_data1
65 - Attribute: DW_AT_byte_size
66 Form: DW_FORM_data1
67 debug_info:
68 - Version: 4
69 AddrSize: 8
70 Entries:
71 - AbbrCode: 0x00000001
72 Values:
73 - Value: 0x000000000000000C
74 - AbbrCode: 0x00000002
75 Values:
76 - Value: 0x0000000000000007 # DW_ATE_unsigned
77 - Value: 0x0000000000000004
78 - AbbrCode: 0x00000002
79 Values:
80 - Value: 0x0000000000000007 # DW_ATE_unsigned
81 - Value: 0x0000000000000008
82 - AbbrCode: 0x00000002
83 Values:
84 - Value: 0x0000000000000005 # DW_ATE_signed
85 - Value: 0x0000000000000008
86 - AbbrCode: 0x00000002
87 Values:
88 - Value: 0x0000000000000008 # DW_ATE_unsigned_char
89 - Value: 0x0000000000000001
90 - AbbrCode: 0x00000000
91 )";
92
93 YAMLModuleTester t(yamldata);
94 ASSERT_TRUE((bool)t.GetDwarfUnit());
95
96 TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple());
97 DWARFASTParserClangStub ast_parser(ast_ctx);
98
99 DWARFUnit *unit = t.GetDwarfUnit();
100 const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
101 const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild();
102 const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling();
103 const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling();
104 const DWARFDebugInfoEntry *die_child3 = die_child2->GetSibling();
105 std::vector<DWARFDIE> dies = {
106 DWARFDIE(unit, die_child0), DWARFDIE(unit, die_child1),
107 DWARFDIE(unit, die_child2), DWARFDIE(unit, die_child3)};
108 std::vector<clang::DeclContext *> decl_ctxs = {
109 (clang::DeclContext *)1LL, (clang::DeclContext *)2LL,
110 (clang::DeclContext *)2LL, (clang::DeclContext *)3LL};
111 for (int i = 0; i < 4; ++i)
112 ast_parser.LinkDeclContextToDIE(decl_ctxs[i], dies[i]);
113 ast_parser.EnsureAllDIEsInDeclContextHaveBeenParsed(
114 CompilerDeclContext(nullptr, decl_ctxs[1]));
115
116 EXPECT_THAT(ast_parser.GetDeclContextToDIEMapKeys(),
117 testing::UnorderedElementsAre(decl_ctxs[0], decl_ctxs[3]));
118 }
119
TEST_F(DWARFASTParserClangTests,TestCallingConventionParsing)120 TEST_F(DWARFASTParserClangTests, TestCallingConventionParsing) {
121 // Tests parsing DW_AT_calling_convention values.
122
123 // The DWARF below just declares a list of function types with
124 // DW_AT_calling_convention on them.
125 const char *yamldata = R"(
126 --- !ELF
127 FileHeader:
128 Class: ELFCLASS32
129 Data: ELFDATA2LSB
130 Type: ET_EXEC
131 Machine: EM_386
132 DWARF:
133 debug_str:
134 - func1
135 - func2
136 - func3
137 - func4
138 - func5
139 - func6
140 - func7
141 - func8
142 - func9
143 debug_abbrev:
144 - ID: 0
145 Table:
146 - Code: 0x1
147 Tag: DW_TAG_compile_unit
148 Children: DW_CHILDREN_yes
149 Attributes:
150 - Attribute: DW_AT_language
151 Form: DW_FORM_data2
152 - Code: 0x2
153 Tag: DW_TAG_subprogram
154 Children: DW_CHILDREN_no
155 Attributes:
156 - Attribute: DW_AT_low_pc
157 Form: DW_FORM_addr
158 - Attribute: DW_AT_high_pc
159 Form: DW_FORM_data4
160 - Attribute: DW_AT_name
161 Form: DW_FORM_strp
162 - Attribute: DW_AT_calling_convention
163 Form: DW_FORM_data1
164 - Attribute: DW_AT_external
165 Form: DW_FORM_flag_present
166 debug_info:
167 - Version: 4
168 AddrSize: 4
169 Entries:
170 - AbbrCode: 0x1
171 Values:
172 - Value: 0xC
173 - AbbrCode: 0x2
174 Values:
175 - Value: 0x0
176 - Value: 0x5
177 - Value: 0x00
178 - Value: 0xCB
179 - Value: 0x1
180 - AbbrCode: 0x2
181 Values:
182 - Value: 0x10
183 - Value: 0x5
184 - Value: 0x06
185 - Value: 0xB3
186 - Value: 0x1
187 - AbbrCode: 0x2
188 Values:
189 - Value: 0x20
190 - Value: 0x5
191 - Value: 0x0C
192 - Value: 0xB1
193 - Value: 0x1
194 - AbbrCode: 0x2
195 Values:
196 - Value: 0x30
197 - Value: 0x5
198 - Value: 0x12
199 - Value: 0xC0
200 - Value: 0x1
201 - AbbrCode: 0x2
202 Values:
203 - Value: 0x40
204 - Value: 0x5
205 - Value: 0x18
206 - Value: 0xB2
207 - Value: 0x1
208 - AbbrCode: 0x2
209 Values:
210 - Value: 0x50
211 - Value: 0x5
212 - Value: 0x1E
213 - Value: 0xC1
214 - Value: 0x1
215 - AbbrCode: 0x2
216 Values:
217 - Value: 0x60
218 - Value: 0x5
219 - Value: 0x24
220 - Value: 0xC2
221 - Value: 0x1
222 - AbbrCode: 0x2
223 Values:
224 - Value: 0x70
225 - Value: 0x5
226 - Value: 0x2a
227 - Value: 0xEE
228 - Value: 0x1
229 - AbbrCode: 0x2
230 Values:
231 - Value: 0x80
232 - Value: 0x5
233 - Value: 0x30
234 - Value: 0x01
235 - Value: 0x1
236 - AbbrCode: 0x0
237 ...
238 )";
239 YAMLModuleTester t(yamldata);
240
241 DWARFUnit *unit = t.GetDwarfUnit();
242 ASSERT_NE(unit, nullptr);
243 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
244 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
245 DWARFDIE cu_die(unit, cu_entry);
246
247 TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple());
248 DWARFASTParserClangStub ast_parser(ast_ctx);
249
250 std::vector<std::string> found_function_types;
251 // The DWARF above is just a list of functions. Parse all of them to
252 // extract the function types and their calling convention values.
253 for (DWARFDIE func : cu_die.children()) {
254 ASSERT_EQ(func.Tag(), DW_TAG_subprogram);
255 SymbolContext sc;
256 bool new_type = false;
257 lldb::TypeSP type = ast_parser.ParseTypeFromDWARF(sc, func, &new_type);
258 found_function_types.push_back(
259 type->GetForwardCompilerType().GetTypeName().AsCString());
260 }
261
262 // Compare the parsed function types against the expected list of types.
263 const std::vector<std::string> expected_function_types = {
264 "void () __attribute__((regcall))",
265 "void () __attribute__((fastcall))",
266 "void () __attribute__((stdcall))",
267 "void () __attribute__((vectorcall))",
268 "void () __attribute__((pascal))",
269 "void () __attribute__((ms_abi))",
270 "void () __attribute__((sysv_abi))",
271 "void ()", // invalid calling convention.
272 "void ()", // DW_CC_normal -> no attribute
273 };
274 ASSERT_EQ(found_function_types, expected_function_types);
275 }
276
277 struct ExtractIntFromFormValueTest : public testing::Test {
278 SubsystemRAII<FileSystem, HostInfo> subsystems;
279 TypeSystemClang ts;
280 DWARFASTParserClang parser;
ExtractIntFromFormValueTestExtractIntFromFormValueTest281 ExtractIntFromFormValueTest()
282 : ts("dummy ASTContext", HostInfoBase::GetTargetTriple()), parser(ts) {}
283
284 /// Takes the given integer value, stores it in a DWARFFormValue and then
285 /// tries to extract the value back via
286 /// DWARFASTParserClang::ExtractIntFromFormValue.
287 /// Returns the string representation of the extracted value or the error
288 /// that was returned from ExtractIntFromFormValue.
ExtractExtractIntFromFormValueTest289 llvm::Expected<std::string> Extract(clang::QualType qt, uint64_t value) {
290 DWARFFormValue form_value;
291 form_value.SetUnsigned(value);
292 llvm::Expected<llvm::APInt> result =
293 parser.ExtractIntFromFormValue(ts.GetType(qt), form_value);
294 if (!result)
295 return result.takeError();
296 llvm::SmallString<16> result_str;
297 result->toStringUnsigned(result_str);
298 return std::string(result_str.str());
299 }
300
301 /// Same as ExtractIntFromFormValueTest::Extract but takes a signed integer
302 /// and treats the result as a signed integer.
ExtractSExtractIntFromFormValueTest303 llvm::Expected<std::string> ExtractS(clang::QualType qt, int64_t value) {
304 DWARFFormValue form_value;
305 form_value.SetSigned(value);
306 llvm::Expected<llvm::APInt> result =
307 parser.ExtractIntFromFormValue(ts.GetType(qt), form_value);
308 if (!result)
309 return result.takeError();
310 llvm::SmallString<16> result_str;
311 result->toStringSigned(result_str);
312 return std::string(result_str.str());
313 }
314 };
315
TEST_F(ExtractIntFromFormValueTest,TestBool)316 TEST_F(ExtractIntFromFormValueTest, TestBool) {
317 using namespace llvm;
318 clang::ASTContext &ast = ts.getASTContext();
319
320 EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 0), HasValue("0"));
321 EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 1), HasValue("1"));
322 EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 2), Failed());
323 EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 3), Failed());
324 }
325
TEST_F(ExtractIntFromFormValueTest,TestInt)326 TEST_F(ExtractIntFromFormValueTest, TestInt) {
327 using namespace llvm;
328
329 clang::ASTContext &ast = ts.getASTContext();
330
331 // Find the min/max values for 'int' on the current host target.
332 constexpr int64_t int_max = std::numeric_limits<int>::max();
333 constexpr int64_t int_min = std::numeric_limits<int>::min();
334
335 // Check that the bit width of int matches the int width in our type system.
336 ASSERT_EQ(sizeof(int) * 8, ast.getIntWidth(ast.IntTy));
337
338 // Check values around int_min.
339 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min - 2), llvm::Failed());
340 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min - 1), llvm::Failed());
341 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min),
342 HasValue(std::to_string(int_min)));
343 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min + 1),
344 HasValue(std::to_string(int_min + 1)));
345 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min + 2),
346 HasValue(std::to_string(int_min + 2)));
347
348 // Check values around 0.
349 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -128), HasValue("-128"));
350 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -10), HasValue("-10"));
351 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -1), HasValue("-1"));
352 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 0), HasValue("0"));
353 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 1), HasValue("1"));
354 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 10), HasValue("10"));
355 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 128), HasValue("128"));
356
357 // Check values around int_max.
358 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max - 2),
359 HasValue(std::to_string(int_max - 2)));
360 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max - 1),
361 HasValue(std::to_string(int_max - 1)));
362 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max),
363 HasValue(std::to_string(int_max)));
364 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max + 1), llvm::Failed());
365 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max + 5), llvm::Failed());
366
367 // Check some values not near an edge case.
368 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max / 2),
369 HasValue(std::to_string(int_max / 2)));
370 EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min / 2),
371 HasValue(std::to_string(int_min / 2)));
372 }
373
TEST_F(ExtractIntFromFormValueTest,TestUnsignedInt)374 TEST_F(ExtractIntFromFormValueTest, TestUnsignedInt) {
375 using namespace llvm;
376
377 clang::ASTContext &ast = ts.getASTContext();
378 constexpr uint64_t uint_max = std::numeric_limits<uint32_t>::max();
379
380 // Check values around 0.
381 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 0), HasValue("0"));
382 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 1), HasValue("1"));
383 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 1234), HasValue("1234"));
384
385 // Check some values not near an edge case.
386 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max / 2),
387 HasValue(std::to_string(uint_max / 2)));
388
389 // Check values around uint_max.
390 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max - 2),
391 HasValue(std::to_string(uint_max - 2)));
392 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max - 1),
393 HasValue(std::to_string(uint_max - 1)));
394 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max),
395 HasValue(std::to_string(uint_max)));
396 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max + 1),
397 llvm::Failed());
398 EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max + 2),
399 llvm::Failed());
400 }
401