1 //===-- DWARFASTParserClangTests.cpp --------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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/ClangTestUtils.h"
13 #include "TestingSupport/Symbol/YAMLModuleTester.h"
14 #include "lldb/Core/Debugger.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
19 using namespace lldb_private
;
20 using namespace lldb_private::dwarf
;
21 using namespace lldb_private::plugin::dwarf
;
24 static std::once_flag debugger_initialize_flag
;
26 class DWARFASTParserClangTests
: public testing::Test
{
27 void SetUp() override
{
28 std::call_once(debugger_initialize_flag
,
29 []() { Debugger::Initialize(nullptr); });
33 class DWARFASTParserClangStub
: public DWARFASTParserClang
{
35 using DWARFASTParserClang::DWARFASTParserClang
;
36 using DWARFASTParserClang::LinkDeclContextToDIE
;
38 std::vector
<const clang::DeclContext
*> GetDeclContextToDIEMapKeys() {
39 std::vector
<const clang::DeclContext
*> keys
;
40 for (const auto &it
: m_decl_ctx_to_die
)
41 keys
.push_back(it
.first
);
47 // If your implementation needs to dereference the dummy pointers we are
48 // defining here, causing this test to fail, feel free to delete it.
49 TEST_F(DWARFASTParserClangTests
,
50 EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries
) {
52 /// Auxiliary debug info.
53 const char *yamldata
= R
"(
64 Tag: DW_TAG_compile_unit
65 Children: DW_CHILDREN_yes
67 - Attribute: DW_AT_language
71 Children: DW_CHILDREN_no
73 - Attribute: DW_AT_encoding
75 - Attribute: DW_AT_byte_size
81 - AbbrCode: 0x00000001
83 - Value: 0x000000000000000C
84 - AbbrCode: 0x00000002
86 - Value: 0x0000000000000007 # DW_ATE_unsigned
87 - Value: 0x0000000000000004
88 - AbbrCode: 0x00000002
90 - Value: 0x0000000000000007 # DW_ATE_unsigned
91 - Value: 0x0000000000000008
92 - AbbrCode: 0x00000002
94 - Value: 0x0000000000000005 # DW_ATE_signed
95 - Value: 0x0000000000000008
96 - AbbrCode: 0x00000002
98 - Value: 0x0000000000000008 # DW_ATE_unsigned_char
99 - Value: 0x0000000000000001
100 - AbbrCode: 0x00000000
103 YAMLModuleTester
t(yamldata
);
104 ASSERT_TRUE((bool)t
.GetDwarfUnit());
106 auto holder
= std::make_unique
<clang_utils::TypeSystemClangHolder
>("ast");
107 auto &ast_ctx
= *holder
->GetAST();
109 DWARFASTParserClangStub
ast_parser(ast_ctx
);
111 DWARFUnit
*unit
= t
.GetDwarfUnit();
112 const DWARFDebugInfoEntry
*die_first
= unit
->DIE().GetDIE();
113 const DWARFDebugInfoEntry
*die_child0
= die_first
->GetFirstChild();
114 const DWARFDebugInfoEntry
*die_child1
= die_child0
->GetSibling();
115 const DWARFDebugInfoEntry
*die_child2
= die_child1
->GetSibling();
116 const DWARFDebugInfoEntry
*die_child3
= die_child2
->GetSibling();
117 std::vector
<DWARFDIE
> dies
= {
118 DWARFDIE(unit
, die_child0
), DWARFDIE(unit
, die_child1
),
119 DWARFDIE(unit
, die_child2
), DWARFDIE(unit
, die_child3
)};
120 std::vector
<clang::DeclContext
*> decl_ctxs
= {
121 (clang::DeclContext
*)1LL, (clang::DeclContext
*)2LL,
122 (clang::DeclContext
*)2LL, (clang::DeclContext
*)3LL};
123 for (int i
= 0; i
< 4; ++i
)
124 ast_parser
.LinkDeclContextToDIE(decl_ctxs
[i
], dies
[i
]);
125 ast_parser
.EnsureAllDIEsInDeclContextHaveBeenParsed(
126 CompilerDeclContext(nullptr, decl_ctxs
[1]));
128 EXPECT_THAT(ast_parser
.GetDeclContextToDIEMapKeys(),
129 testing::UnorderedElementsAre(decl_ctxs
[0], decl_ctxs
[3]));
132 TEST_F(DWARFASTParserClangTests
, TestCallingConventionParsing
) {
133 // Tests parsing DW_AT_calling_convention values.
135 // The DWARF below just declares a list of function types with
136 // DW_AT_calling_convention on them.
137 const char *yamldata
= R
"(
159 Tag: DW_TAG_compile_unit
160 Children: DW_CHILDREN_yes
162 - Attribute: DW_AT_language
165 Tag: DW_TAG_subprogram
166 Children: DW_CHILDREN_no
168 - Attribute: DW_AT_low_pc
170 - Attribute: DW_AT_high_pc
172 - Attribute: DW_AT_name
174 - Attribute: DW_AT_calling_convention
176 - Attribute: DW_AT_external
177 Form: DW_FORM_flag_present
251 YAMLModuleTester
t(yamldata
);
253 DWARFUnit
*unit
= t
.GetDwarfUnit();
254 ASSERT_NE(unit
, nullptr);
255 const DWARFDebugInfoEntry
*cu_entry
= unit
->DIE().GetDIE();
256 ASSERT_EQ(cu_entry
->Tag(), DW_TAG_compile_unit
);
257 DWARFDIE
cu_die(unit
, cu_entry
);
259 auto holder
= std::make_unique
<clang_utils::TypeSystemClangHolder
>("ast");
260 auto &ast_ctx
= *holder
->GetAST();
261 DWARFASTParserClangStub
ast_parser(ast_ctx
);
263 std::vector
<std::string
> found_function_types
;
264 // The DWARF above is just a list of functions. Parse all of them to
265 // extract the function types and their calling convention values.
266 for (DWARFDIE func
: cu_die
.children()) {
267 ASSERT_EQ(func
.Tag(), DW_TAG_subprogram
);
269 bool new_type
= false;
270 lldb::TypeSP type
= ast_parser
.ParseTypeFromDWARF(sc
, func
, &new_type
);
271 found_function_types
.push_back(
272 type
->GetForwardCompilerType().GetTypeName().AsCString());
275 // Compare the parsed function types against the expected list of types.
276 const std::vector
<std::string
> expected_function_types
= {
277 "void () __attribute__((regcall))",
278 "void () __attribute__((fastcall))",
279 "void () __attribute__((stdcall))",
280 "void () __attribute__((vectorcall))",
281 "void () __attribute__((pascal))",
282 "void () __attribute__((ms_abi))",
283 "void () __attribute__((sysv_abi))",
284 "void ()", // invalid calling convention.
285 "void ()", // DW_CC_normal -> no attribute
287 ASSERT_EQ(found_function_types
, expected_function_types
);
290 struct ExtractIntFromFormValueTest
: public testing::Test
{
291 SubsystemRAII
<FileSystem
, HostInfo
> subsystems
;
292 clang_utils::TypeSystemClangHolder holder
;
295 DWARFASTParserClang parser
;
296 ExtractIntFromFormValueTest()
297 : holder("dummy ASTContext"), ts(*holder
.GetAST()), parser(ts
) {}
299 /// Takes the given integer value, stores it in a DWARFFormValue and then
300 /// tries to extract the value back via
301 /// DWARFASTParserClang::ExtractIntFromFormValue.
302 /// Returns the string representation of the extracted value or the error
303 /// that was returned from ExtractIntFromFormValue.
304 llvm::Expected
<std::string
> Extract(clang::QualType qt
, uint64_t value
) {
305 DWARFFormValue form_value
;
306 form_value
.SetUnsigned(value
);
307 llvm::Expected
<llvm::APInt
> result
=
308 parser
.ExtractIntFromFormValue(ts
.GetType(qt
), form_value
);
310 return result
.takeError();
311 llvm::SmallString
<16> result_str
;
312 result
->toStringUnsigned(result_str
);
313 return std::string(result_str
.str());
316 /// Same as ExtractIntFromFormValueTest::Extract but takes a signed integer
317 /// and treats the result as a signed integer.
318 llvm::Expected
<std::string
> ExtractS(clang::QualType qt
, int64_t value
) {
319 DWARFFormValue form_value
;
320 form_value
.SetSigned(value
);
321 llvm::Expected
<llvm::APInt
> result
=
322 parser
.ExtractIntFromFormValue(ts
.GetType(qt
), form_value
);
324 return result
.takeError();
325 llvm::SmallString
<16> result_str
;
326 result
->toStringSigned(result_str
);
327 return std::string(result_str
.str());
331 TEST_F(ExtractIntFromFormValueTest
, TestBool
) {
332 using namespace llvm
;
333 clang::ASTContext
&ast
= ts
.getASTContext();
335 EXPECT_THAT_EXPECTED(Extract(ast
.BoolTy
, 0), HasValue("0"));
336 EXPECT_THAT_EXPECTED(Extract(ast
.BoolTy
, 1), HasValue("1"));
337 EXPECT_THAT_EXPECTED(Extract(ast
.BoolTy
, 2), Failed());
338 EXPECT_THAT_EXPECTED(Extract(ast
.BoolTy
, 3), Failed());
341 TEST_F(ExtractIntFromFormValueTest
, TestInt
) {
342 using namespace llvm
;
344 clang::ASTContext
&ast
= ts
.getASTContext();
346 // Find the min/max values for 'int' on the current host target.
347 constexpr int64_t int_max
= std::numeric_limits
<int>::max();
348 constexpr int64_t int_min
= std::numeric_limits
<int>::min();
350 // Check that the bit width of int matches the int width in our type system.
351 ASSERT_EQ(sizeof(int) * 8, ast
.getIntWidth(ast
.IntTy
));
353 // Check values around int_min.
354 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_min
- 2), llvm::Failed());
355 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_min
- 1), llvm::Failed());
356 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_min
),
357 HasValue(std::to_string(int_min
)));
358 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_min
+ 1),
359 HasValue(std::to_string(int_min
+ 1)));
360 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_min
+ 2),
361 HasValue(std::to_string(int_min
+ 2)));
363 // Check values around 0.
364 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, -128), HasValue("-128"));
365 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, -10), HasValue("-10"));
366 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, -1), HasValue("-1"));
367 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, 0), HasValue("0"));
368 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, 1), HasValue("1"));
369 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, 10), HasValue("10"));
370 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, 128), HasValue("128"));
372 // Check values around int_max.
373 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_max
- 2),
374 HasValue(std::to_string(int_max
- 2)));
375 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_max
- 1),
376 HasValue(std::to_string(int_max
- 1)));
377 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_max
),
378 HasValue(std::to_string(int_max
)));
379 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_max
+ 1), llvm::Failed());
380 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_max
+ 5), llvm::Failed());
382 // Check some values not near an edge case.
383 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_max
/ 2),
384 HasValue(std::to_string(int_max
/ 2)));
385 EXPECT_THAT_EXPECTED(ExtractS(ast
.IntTy
, int_min
/ 2),
386 HasValue(std::to_string(int_min
/ 2)));
389 TEST_F(ExtractIntFromFormValueTest
, TestUnsignedInt
) {
390 using namespace llvm
;
392 clang::ASTContext
&ast
= ts
.getASTContext();
393 constexpr uint64_t uint_max
= std::numeric_limits
<uint32_t>::max();
395 // Check values around 0.
396 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, 0), HasValue("0"));
397 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, 1), HasValue("1"));
398 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, 1234), HasValue("1234"));
400 // Check some values not near an edge case.
401 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, uint_max
/ 2),
402 HasValue(std::to_string(uint_max
/ 2)));
404 // Check values around uint_max.
405 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, uint_max
- 2),
406 HasValue(std::to_string(uint_max
- 2)));
407 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, uint_max
- 1),
408 HasValue(std::to_string(uint_max
- 1)));
409 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, uint_max
),
410 HasValue(std::to_string(uint_max
)));
411 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, uint_max
+ 1),
413 EXPECT_THAT_EXPECTED(Extract(ast
.UnsignedIntTy
, uint_max
+ 2),
417 TEST_F(DWARFASTParserClangTests
, TestDefaultTemplateParamParsing
) {
418 // Tests parsing DW_AT_default_value for template parameters.
419 auto BufferOrError
= llvm::MemoryBuffer::getFile(
420 GetInputFilePath("DW_AT_default_value-test.yaml"), /*IsText=*/true);
421 ASSERT_TRUE(BufferOrError
);
422 YAMLModuleTester
t(BufferOrError
.get()->getBuffer());
424 DWARFUnit
*unit
= t
.GetDwarfUnit();
425 ASSERT_NE(unit
, nullptr);
426 const DWARFDebugInfoEntry
*cu_entry
= unit
->DIE().GetDIE();
427 ASSERT_EQ(cu_entry
->Tag(), DW_TAG_compile_unit
);
428 DWARFDIE
cu_die(unit
, cu_entry
);
430 auto holder
= std::make_unique
<clang_utils::TypeSystemClangHolder
>("ast");
431 auto &ast_ctx
= *holder
->GetAST();
432 DWARFASTParserClangStub
ast_parser(ast_ctx
);
434 llvm::SmallVector
<lldb::TypeSP
, 2> types
;
435 for (DWARFDIE die
: cu_die
.children()) {
436 if (die
.Tag() == DW_TAG_class_type
) {
438 bool new_type
= false;
439 types
.push_back(ast_parser
.ParseTypeFromDWARF(sc
, die
, &new_type
));
443 ASSERT_EQ(types
.size(), 3U);
445 auto check_decl
= [](auto const *decl
) {
446 clang::ClassTemplateSpecializationDecl
const *ctsd
=
447 llvm::dyn_cast_or_null
<clang::ClassTemplateSpecializationDecl
>(decl
);
448 ASSERT_NE(ctsd
, nullptr);
450 auto const &args
= ctsd
->getTemplateArgs();
451 ASSERT_GT(args
.size(), 0U);
453 for (auto const &arg
: args
.asArray()) {
454 EXPECT_TRUE(arg
.getIsDefaulted());
458 for (auto const &type_sp
: types
) {
459 ASSERT_NE(type_sp
, nullptr);
460 auto const *decl
= ClangUtil::GetAsTagDecl(type_sp
->GetFullCompilerType());
461 if (decl
->getName() == "bar" || decl
->getName() == "baz") {