| 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_" + name; |
| 47 | // See if we have made this type before and can reuse it. |
| 48 | CompilerType fields_type = |
| 49 | type_system->GetTypeForIdentifier<clang::CXXRecordDecl>( |
| 50 | type_name: register_type_name); |
| 51 | |
| 52 | if (!fields_type) { |
| 53 | // In most ABI, a change of field type means a change in storage unit. |
| 54 | // We want it all in one unit, so we use a field type the same as the |
| 55 | // register's size. |
| 56 | CompilerType field_uint_type = |
| 57 | type_system->GetBuiltinTypeForEncodingAndBitSize(encoding: lldb::eEncodingUint, |
| 58 | bit_size: byte_size * 8); |
| 59 | |
| 60 | fields_type = type_system->CreateRecordType( |
| 61 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, |
| 62 | name: register_type_name, kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
| 63 | language: lldb::eLanguageTypeC); |
| 64 | type_system->StartTagDeclarationDefinition(type: fields_type); |
| 65 | |
| 66 | // We assume that RegisterFlags has padded and sorted the fields |
| 67 | // already. |
| 68 | for (const RegisterFlags::Field &field : flags.GetFields()) { |
| 69 | CompilerType field_type = field_uint_type; |
| 70 | |
| 71 | if (const FieldEnum *enum_type = field.GetEnum()) { |
| 72 | const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators(); |
| 73 | if (!enumerators.empty()) { |
| 74 | // Enums can be used by many registers and the size of each register |
| 75 | // may be different. The register size is used as the underlying size |
| 76 | // of the enumerators, so we must make one enum type per register size |
| 77 | // it is used with. |
| 78 | std::string enum_type_name = "__lldb_register_fields_enum_" + |
| 79 | enum_type->GetID() + "_" + |
| 80 | std::to_string(val: byte_size); |
| 81 | |
| 82 | // Enums can be used by mutiple fields and multiple registers, so we |
| 83 | // may have built this one already. |
| 84 | CompilerType field_enum_type = |
| 85 | type_system->GetTypeForIdentifier<clang::EnumDecl>( |
| 86 | type_name: enum_type_name); |
| 87 | |
| 88 | if (field_enum_type) |
| 89 | field_type = field_enum_type; |
| 90 | else { |
| 91 | field_type = type_system->CreateEnumerationType( |
| 92 | enum_type_name, type_system->GetTranslationUnitDecl(), |
| 93 | OptionalClangModuleID(), Declaration(), field_uint_type, false); |
| 94 | |
| 95 | type_system->StartTagDeclarationDefinition(type: field_type); |
| 96 | |
| 97 | Declaration decl; |
| 98 | for (auto enumerator : enumerators) { |
| 99 | type_system->AddEnumerationValueToEnumerationType( |
| 100 | enum_type: field_type, decl, name: enumerator.m_name.c_str(), |
| 101 | enum_value: enumerator.m_value, enum_value_bit_size: byte_size * 8); |
| 102 | } |
| 103 | |
| 104 | type_system->CompleteTagDeclarationDefinition(type: field_type); |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | type_system->AddFieldToRecordType(type: fields_type, name: field.GetName(), |
| 110 | field_type, access: lldb::eAccessPublic, |
| 111 | bitfield_bit_size: field.GetSizeInBits()); |
| 112 | } |
| 113 | |
| 114 | type_system->CompleteTagDeclarationDefinition(type: fields_type); |
| 115 | // So that the size of the type matches the size of the register. |
| 116 | type_system->SetIsPacked(fields_type); |
| 117 | |
| 118 | // This should be true if RegisterFlags padded correctly. |
| 119 | assert(llvm::expectedToOptional(fields_type.GetByteSize(nullptr)) |
| 120 | .value_or(0) == flags.GetSize()); |
| 121 | } |
| 122 | |
| 123 | return fields_type; |
| 124 | } |
| 125 | |