1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
//===-- RegisterTypeBuilderClang.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 "clang/AST/DeclCXX.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "RegisterTypeBuilderClang.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/RegisterFlags.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb_private;
LLDB_PLUGIN_DEFINE(RegisterTypeBuilderClang)
void RegisterTypeBuilderClang::Initialize() {
static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance);
});
}
void RegisterTypeBuilderClang::Terminate() {}
lldb::RegisterTypeBuilderSP
RegisterTypeBuilderClang::CreateInstance(Target &target) {
return std::make_shared<RegisterTypeBuilderClang>(target);
}
RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
: m_target(target) {}
CompilerType RegisterTypeBuilderClang::GetRegisterType(
const std::string &name, const lldb_private::RegisterFlags &flags,
uint32_t byte_size) {
lldb::TypeSystemClangSP type_system =
ScratchTypeSystemClang::GetForTarget(m_target);
assert(type_system);
std::string register_type_name = "__lldb_register_fields_" + name;
// See if we have made this type before and can reuse it.
CompilerType fields_type =
type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
type_system->getASTContext(), register_type_name);
if (!fields_type) {
// In most ABI, a change of field type means a change in storage unit.
// We want it all in one unit, so we use a field type the same as the
// register's size.
CompilerType field_uint_type =
type_system->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
byte_size * 8);
fields_type = type_system->CreateRecordType(
nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
register_type_name, llvm::to_underlying(clang::TagTypeKind::Struct),
lldb::eLanguageTypeC);
type_system->StartTagDeclarationDefinition(fields_type);
// We assume that RegisterFlags has padded and sorted the fields
// already.
for (const RegisterFlags::Field &field : flags.GetFields()) {
CompilerType field_type = field_uint_type;
if (const FieldEnum *enum_type = field.GetEnum()) {
const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators();
if (!enumerators.empty()) {
// Enums can be used by many registers and the size of each register
// may be different. The register size is used as the underlying size
// of the enumerators, so we must make one enum type per register size
// it is used with.
std::string enum_type_name = "__lldb_register_fields_enum_" +
enum_type->GetID() + "_" +
std::to_string(byte_size);
// Enums can be used by mutiple fields and multiple registers, so we
// may have built this one already.
CompilerType field_enum_type =
type_system->GetTypeForIdentifier<clang::EnumDecl>(
type_system->getASTContext(), enum_type_name);
if (field_enum_type)
field_type = field_enum_type;
else {
field_type = type_system->CreateEnumerationType(
enum_type_name, type_system->GetTranslationUnitDecl(),
OptionalClangModuleID(), Declaration(), field_uint_type, false);
type_system->StartTagDeclarationDefinition(field_type);
Declaration decl;
for (auto enumerator : enumerators) {
type_system->AddEnumerationValueToEnumerationType(
field_type, decl, enumerator.m_name.c_str(),
enumerator.m_value, byte_size * 8);
}
type_system->CompleteTagDeclarationDefinition(field_type);
}
}
}
type_system->AddFieldToRecordType(fields_type, field.GetName(),
field_type, lldb::eAccessPublic,
field.GetSizeInBits());
}
type_system->CompleteTagDeclarationDefinition(fields_type);
// So that the size of the type matches the size of the register.
type_system->SetIsPacked(fields_type);
// This should be true if RegisterFlags padded correctly.
assert(llvm::expectedToOptional(fields_type.GetByteSize(nullptr))
.value_or(0) == flags.GetSize());
}
return fields_type;
}
|