1 | //===-- RegisterTypeBuilderClang.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 "clang/AST/DeclCXX.h" |
10 | |
11 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
12 | #include "RegisterTypeBuilderClang.h" |
13 | #include "lldb/Core/PluginManager.h" |
14 | #include "lldb/Target/RegisterFlags.h" |
15 | #include "lldb/lldb-enumerations.h" |
16 | |
17 | using namespace lldb_private; |
18 | |
19 | LLDB_PLUGIN_DEFINE(RegisterTypeBuilderClang) |
20 | |
21 | void RegisterTypeBuilderClang::Initialize() { |
22 | static llvm::once_flag g_once_flag; |
23 | llvm::call_once(flag&: g_once_flag, F: []() { |
24 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
25 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
26 | }); |
27 | } |
28 | |
29 | void RegisterTypeBuilderClang::Terminate() {} |
30 | |
31 | lldb::RegisterTypeBuilderSP |
32 | RegisterTypeBuilderClang::CreateInstance(Target &target) { |
33 | return std::make_shared<RegisterTypeBuilderClang>(args&: target); |
34 | } |
35 | |
36 | RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target) |
37 | : m_target(target) {} |
38 | |
39 | CompilerType RegisterTypeBuilderClang::GetRegisterType( |
40 | const std::string &name, const lldb_private::RegisterFlags &flags, |
41 | uint32_t byte_size) { |
42 | lldb::TypeSystemClangSP type_system = |
43 | ScratchTypeSystemClang::GetForTarget(target&: m_target); |
44 | assert(type_system); |
45 | |
46 | std::string register_type_name = "__lldb_register_fields_" ; |
47 | register_type_name += name; |
48 | // See if we have made this type before and can reuse it. |
49 | CompilerType fields_type = |
50 | type_system->GetTypeForIdentifier<clang::CXXRecordDecl>( |
51 | type_name: register_type_name); |
52 | |
53 | if (!fields_type) { |
54 | // In most ABI, a change of field type means a change in storage unit. |
55 | // We want it all in one unit, so we use a field type the same as the |
56 | // register's size. |
57 | CompilerType field_uint_type = |
58 | type_system->GetBuiltinTypeForEncodingAndBitSize(encoding: lldb::eEncodingUint, |
59 | bit_size: byte_size * 8); |
60 | |
61 | fields_type = type_system->CreateRecordType( |
62 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, |
63 | name: register_type_name, kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
64 | language: lldb::eLanguageTypeC); |
65 | type_system->StartTagDeclarationDefinition(type: fields_type); |
66 | |
67 | // We assume that RegisterFlags has padded and sorted the fields |
68 | // already. |
69 | for (const RegisterFlags::Field &field : flags.GetFields()) { |
70 | type_system->AddFieldToRecordType(type: fields_type, name: field.GetName(), |
71 | field_type: field_uint_type, access: lldb::eAccessPublic, |
72 | bitfield_bit_size: field.GetSizeInBits()); |
73 | } |
74 | |
75 | type_system->CompleteTagDeclarationDefinition(type: fields_type); |
76 | // So that the size of the type matches the size of the register. |
77 | type_system->SetIsPacked(fields_type); |
78 | |
79 | // This should be true if RegisterFlags padded correctly. |
80 | assert(*fields_type.GetByteSize(nullptr) == flags.GetSize()); |
81 | } |
82 | |
83 | return fields_type; |
84 | } |
85 | |