Files
clang-p2996/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
Raphael Isemann 3256aa8fe6 [lldb] Add support for DW_AT_calling_convention to the DWARF parser
This adds support for parsing DW_AT_calling_convention in the DWARF parser.

The generic DWARF parsing code already support extracting this attribute from A
DIE and TypeSystemClang already offers a parameter to add a calling convention
to a function type (as the PDB parser supports calling convention parsing), so
this patch just converts the DWARF enum value to the Clang enum value and adds a
few tests.

There are two tests in this patch.:

* A unit test for the added DWARF parsing code that should run on all platforms.

* An API tests that covers the whole expression evaluation machinery by trying
to call functions with non-standard calling conventions. The specific subtests
are target specific as some calling conventions only work on e.g. win32 (or, if
they work on other platforms they only really have observable differences on a
specific target).  The tests are also highly compiler-specific, so if GCC or
Clang tell us that they don't support a specific calling convention then we just
skip the test.

Note that some calling conventions are supported by Clang but aren't implemented
in LLVM (e.g. `pascal`), so there we just test that if this ever gets
implemented in LLVM that LLDB works too. There are also some more tricky/obscure
conventions that are left out such as the different swift* conventions, some
planned Obj-C conventions (`Preserve*`), AAPCS* conventions (as the DWARF->Clang
conversion is ambiguous for AAPCS and APPCS-VFP) and conventions only used for
OpenCL etc.

Reviewed By: aprantl

Differential Revision: https://reviews.llvm.org/D108629
2021-10-11 13:44:10 +02:00

275 lines
9.2 KiB
C++

//===-- DWARFASTParserClangTests.cpp --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
#include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h"
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "TestingSupport/Symbol/YAMLModuleTester.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
namespace {
class DWARFASTParserClangTests : public testing::Test {};
class DWARFASTParserClangStub : public DWARFASTParserClang {
public:
using DWARFASTParserClang::DWARFASTParserClang;
using DWARFASTParserClang::LinkDeclContextToDIE;
std::vector<const clang::DeclContext *> GetDeclContextToDIEMapKeys() {
std::vector<const clang::DeclContext *> keys;
for (const auto &it : m_decl_ctx_to_die)
keys.push_back(it.first);
return keys;
}
};
} // namespace
// If your implementation needs to dereference the dummy pointers we are
// defining here, causing this test to fail, feel free to delete it.
TEST_F(DWARFASTParserClangTests,
EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries) {
/// Auxiliary debug info.
const char *yamldata = R"(
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_386
DWARF:
debug_abbrev:
- Table:
- Code: 0x00000001
Tag: DW_TAG_compile_unit
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_language
Form: DW_FORM_data2
- Code: 0x00000002
Tag: DW_TAG_base_type
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_encoding
Form: DW_FORM_data1
- Attribute: DW_AT_byte_size
Form: DW_FORM_data1
debug_info:
- Version: 4
AddrSize: 8
Entries:
- AbbrCode: 0x00000001
Values:
- Value: 0x000000000000000C
- AbbrCode: 0x00000002
Values:
- Value: 0x0000000000000007 # DW_ATE_unsigned
- Value: 0x0000000000000004
- AbbrCode: 0x00000002
Values:
- Value: 0x0000000000000007 # DW_ATE_unsigned
- Value: 0x0000000000000008
- AbbrCode: 0x00000002
Values:
- Value: 0x0000000000000005 # DW_ATE_signed
- Value: 0x0000000000000008
- AbbrCode: 0x00000002
Values:
- Value: 0x0000000000000008 # DW_ATE_unsigned_char
- Value: 0x0000000000000001
- AbbrCode: 0x00000000
)";
YAMLModuleTester t(yamldata);
ASSERT_TRUE((bool)t.GetDwarfUnit());
TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple());
DWARFASTParserClangStub ast_parser(ast_ctx);
DWARFUnit *unit = t.GetDwarfUnit();
const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild();
const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling();
const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling();
const DWARFDebugInfoEntry *die_child3 = die_child2->GetSibling();
std::vector<DWARFDIE> dies = {
DWARFDIE(unit, die_child0), DWARFDIE(unit, die_child1),
DWARFDIE(unit, die_child2), DWARFDIE(unit, die_child3)};
std::vector<clang::DeclContext *> decl_ctxs = {
(clang::DeclContext *)1LL, (clang::DeclContext *)2LL,
(clang::DeclContext *)2LL, (clang::DeclContext *)3LL};
for (int i = 0; i < 4; ++i)
ast_parser.LinkDeclContextToDIE(decl_ctxs[i], dies[i]);
ast_parser.EnsureAllDIEsInDeclContextHaveBeenParsed(
CompilerDeclContext(nullptr, decl_ctxs[1]));
EXPECT_THAT(ast_parser.GetDeclContextToDIEMapKeys(),
testing::UnorderedElementsAre(decl_ctxs[0], decl_ctxs[3]));
}
TEST_F(DWARFASTParserClangTests, TestCallingConventionParsing) {
// Tests parsing DW_AT_calling_convention values.
// The DWARF below just declares a list of function types with
// DW_AT_calling_convention on them.
const char *yamldata = R"(
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_386
DWARF:
debug_str:
- func1
- func2
- func3
- func4
- func5
- func6
- func7
- func8
- func9
debug_abbrev:
- ID: 0
Table:
- Code: 0x1
Tag: DW_TAG_compile_unit
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_language
Form: DW_FORM_data2
- Code: 0x2
Tag: DW_TAG_subprogram
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_low_pc
Form: DW_FORM_addr
- Attribute: DW_AT_high_pc
Form: DW_FORM_data4
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_calling_convention
Form: DW_FORM_data1
- Attribute: DW_AT_external
Form: DW_FORM_flag_present
debug_info:
- Version: 4
AddrSize: 4
Entries:
- AbbrCode: 0x1
Values:
- Value: 0xC
- AbbrCode: 0x2
Values:
- Value: 0x0
- Value: 0x5
- Value: 0x00
- Value: 0xCB
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x10
- Value: 0x5
- Value: 0x06
- Value: 0xB3
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x20
- Value: 0x5
- Value: 0x0C
- Value: 0xB1
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x30
- Value: 0x5
- Value: 0x12
- Value: 0xC0
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x40
- Value: 0x5
- Value: 0x18
- Value: 0xB2
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x50
- Value: 0x5
- Value: 0x1E
- Value: 0xC1
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x60
- Value: 0x5
- Value: 0x24
- Value: 0xC2
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x70
- Value: 0x5
- Value: 0x2a
- Value: 0xEE
- Value: 0x1
- AbbrCode: 0x2
Values:
- Value: 0x80
- Value: 0x5
- Value: 0x30
- Value: 0x01
- Value: 0x1
- AbbrCode: 0x0
...
)";
YAMLModuleTester t(yamldata);
DWARFUnit *unit = t.GetDwarfUnit();
ASSERT_NE(unit, nullptr);
const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
DWARFDIE cu_die(unit, cu_entry);
TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple());
DWARFASTParserClangStub ast_parser(ast_ctx);
std::vector<std::string> found_function_types;
// The DWARF above is just a list of functions. Parse all of them to
// extract the function types and their calling convention values.
for (DWARFDIE func : cu_die.children()) {
ASSERT_EQ(func.Tag(), DW_TAG_subprogram);
SymbolContext sc;
bool new_type = false;
lldb::TypeSP type = ast_parser.ParseTypeFromDWARF(sc, func, &new_type);
found_function_types.push_back(
type->GetForwardCompilerType().GetTypeName().AsCString());
}
// Compare the parsed function types against the expected list of types.
const std::vector<std::string> expected_function_types = {
"void () __attribute__((regcall))",
"void () __attribute__((fastcall))",
"void () __attribute__((stdcall))",
"void () __attribute__((vectorcall))",
"void () __attribute__((pascal))",
"void () __attribute__((ms_abi))",
"void () __attribute__((sysv_abi))",
"void ()", // invalid calling convention.
"void ()", // DW_CC_normal -> no attribute
};
ASSERT_EQ(found_function_types, expected_function_types);
}