https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/83291
>From 7ffc5c966a7a0542cbde20ead3144344e68e648f Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Wed, 28 Feb 2024 13:32:01 +0000 Subject: [PATCH 1/4] [lldb][NFC] Move helpers to import record layout into ClangASTImporter --- .../Clang/ClangASTImporter.cpp | 204 +++++++++++++ .../ExpressionParser/Clang/ClangASTImporter.h | 61 ++++ .../ExpressionParser/Clang/ClangASTSource.cpp | 278 ++---------------- .../ExpressionParser/Clang/ClangASTSource.h | 5 + 4 files changed, 290 insertions(+), 258 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 62a30c14912bc9..b9f2c834dd1197 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -10,9 +10,11 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/RecordLayout.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" @@ -26,6 +28,7 @@ #include <memory> #include <optional> +#include <type_traits> using namespace lldb_private; using namespace clang; @@ -517,6 +520,207 @@ bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { return false; } +template <class D, class O> +static bool ImportOffsetMap(clang::ASTContext *dest_ctx, + llvm::DenseMap<const D *, O> &destination_map, + llvm::DenseMap<const D *, O> &source_map, + ClangASTImporter &importer) { + // When importing fields into a new record, clang has a hard requirement that + // fields be imported in field offset order. Since they are stored in a + // DenseMap with a pointer as the key type, this means we cannot simply + // iterate over the map, as the order will be non-deterministic. Instead we + // have to sort by the offset and then insert in sorted order. + typedef llvm::DenseMap<const D *, O> MapType; + typedef typename MapType::value_type PairType; + std::vector<PairType> sorted_items; + sorted_items.reserve(source_map.size()); + sorted_items.assign(source_map.begin(), source_map.end()); + llvm::sort(sorted_items, llvm::less_second()); + + for (const auto &item : sorted_items) { + DeclFromUser<D> user_decl(const_cast<D *>(item.first)); + DeclFromParser<D> parser_decl(user_decl.Import(dest_ctx, importer)); + if (parser_decl.IsInvalid()) + return false; + destination_map.insert( + std::pair<const D *, O>(parser_decl.decl, item.second)); + } + + return true; +} + +template <bool IsVirtual> +bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, + DeclFromUser<const CXXRecordDecl> &record, + llvm::DenseMap<const clang::CXXRecordDecl *, + clang::CharUnits> &base_offsets) { + for (CXXRecordDecl::base_class_const_iterator + bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), + be = (IsVirtual ? record->vbases_end() : record->bases_end()); + bi != be; ++bi) { + if (!IsVirtual && bi->isVirtual()) + continue; + + const clang::Type *origin_base_type = bi->getType().getTypePtr(); + const clang::RecordType *origin_base_record_type = + origin_base_type->getAs<RecordType>(); + + if (!origin_base_record_type) + return false; + + DeclFromUser<RecordDecl> origin_base_record( + origin_base_record_type->getDecl()); + + if (origin_base_record.IsInvalid()) + return false; + + DeclFromUser<CXXRecordDecl> origin_base_cxx_record( + DynCast<CXXRecordDecl>(origin_base_record)); + + if (origin_base_cxx_record.IsInvalid()) + return false; + + CharUnits base_offset; + + if (IsVirtual) + base_offset = + record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); + else + base_offset = + record_layout.getBaseClassOffset(origin_base_cxx_record.decl); + + base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>( + origin_base_cxx_record.decl, base_offset)); + } + + return true; +} + +bool ClangASTImporter::importRecordLayoutFromOrigin( + const RecordDecl *record, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets) { + + Log *log = GetLog(LLDBLog::Expressions); + + clang::ASTContext &dest_ctx = record->getASTContext(); + LLDB_LOG(log, + "LayoutRecordType on (ASTContext*){0} '{1}' for (RecordDecl*)" + "{2} [name = '{3}']", + &dest_ctx, + TypeSystemClang::GetASTContext(&dest_ctx)->getDisplayName(), record, + record->getName()); + + DeclFromParser<const RecordDecl> parser_record(record); + DeclFromUser<const RecordDecl> origin_record(parser_record.GetOrigin(*this)); + + if (origin_record.IsInvalid()) + return false; + + std::remove_reference_t<decltype(field_offsets)> origin_field_offsets; + std::remove_reference_t<decltype(base_offsets)> origin_base_offsets; + std::remove_reference_t<decltype(vbase_offsets)> origin_virtual_base_offsets; + + TypeSystemClang::GetCompleteDecl( + &origin_record->getASTContext(), + const_cast<RecordDecl *>(origin_record.decl)); + + clang::RecordDecl *definition = origin_record.decl->getDefinition(); + if (!definition || !definition->isCompleteDefinition()) + return false; + + const ASTRecordLayout &record_layout( + origin_record->getASTContext().getASTRecordLayout(origin_record.decl)); + + int field_idx = 0, field_count = record_layout.getFieldCount(); + + for (RecordDecl::field_iterator fi = origin_record->field_begin(), + fe = origin_record->field_end(); + fi != fe; ++fi) { + if (field_idx >= field_count) + return false; // Layout didn't go well. Bail out. + + uint64_t field_offset = record_layout.getFieldOffset(field_idx); + + origin_field_offsets.insert( + std::pair<const FieldDecl *, uint64_t>(*fi, field_offset)); + + field_idx++; + } + + DeclFromUser<const CXXRecordDecl> origin_cxx_record( + DynCast<const CXXRecordDecl>(origin_record)); + + if (origin_cxx_record.IsValid()) { + if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record, + origin_base_offsets) || + !ExtractBaseOffsets<true>(record_layout, origin_cxx_record, + origin_virtual_base_offsets)) + return false; + } + + if (!ImportOffsetMap(&dest_ctx, field_offsets, origin_field_offsets, *this) || + !ImportOffsetMap(&dest_ctx, base_offsets, origin_base_offsets, *this) || + !ImportOffsetMap(&dest_ctx, vbase_offsets, origin_virtual_base_offsets, + *this)) + return false; + + size = record_layout.getSize().getQuantity() * dest_ctx.getCharWidth(); + alignment = + record_layout.getAlignment().getQuantity() * dest_ctx.getCharWidth(); + + if (log) { + LLDB_LOG(log, "LRT returned:"); + LLDB_LOG(log, "LRT Original = (RecordDecl*){0}", + static_cast<const void *>(origin_record.decl)); + LLDB_LOG(log, "LRT Size = {0}", size); + LLDB_LOG(log, "LRT Alignment = {0}", alignment); + LLDB_LOG(log, "LRT Fields:"); + for (RecordDecl::field_iterator fi = record->field_begin(), + fe = record->field_end(); + fi != fe; ++fi) { + LLDB_LOG(log, + "LRT (FieldDecl*){0}, Name = '{1}', Type = '{2}', Offset = " + "{3} bits", + *fi, fi->getName(), fi->getType().getAsString(), + field_offsets[*fi]); + } + DeclFromParser<const CXXRecordDecl> parser_cxx_record = + DynCast<const CXXRecordDecl>(parser_record); + if (parser_cxx_record.IsValid()) { + LLDB_LOG(log, "LRT Bases:"); + for (CXXRecordDecl::base_class_const_iterator + bi = parser_cxx_record->bases_begin(), + be = parser_cxx_record->bases_end(); + bi != be; ++bi) { + bool is_virtual = bi->isVirtual(); + + QualType base_type = bi->getType(); + const RecordType *base_record_type = base_type->getAs<RecordType>(); + DeclFromParser<RecordDecl> base_record(base_record_type->getDecl()); + DeclFromParser<CXXRecordDecl> base_cxx_record = + DynCast<CXXRecordDecl>(base_record); + + LLDB_LOG(log, + "LRT {0}(CXXRecordDecl*){1}, Name = '{2}', Offset = " + "{3} chars", + (is_virtual ? "Virtual " : ""), base_cxx_record.decl, + base_cxx_record.decl->getName(), + (is_virtual + ? vbase_offsets[base_cxx_record.decl].getQuantity() + : base_offsets[base_cxx_record.decl].getQuantity())); + } + } else { + LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); + } + } + + return true; +} + bool ClangASTImporter::LayoutRecordType( const clang::RecordDecl *record_decl, uint64_t &bit_size, uint64_t &alignment, diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index e565a96b217ff4..f9c370bef94fc9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -14,6 +14,7 @@ #include <set> #include <vector> +#include "clang/AST/ASTContext.h" #include "clang/AST/ASTImporter.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" @@ -127,6 +128,14 @@ class ClangASTImporter { llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + bool importRecordLayoutFromOrigin( + const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets); + /// Returns true iff the given type was copied from another TypeSystemClang /// and the original type in this other TypeSystemClang might contain /// additional information (e.g., the definition of a 'class' type) that could @@ -456,6 +465,58 @@ class ClangASTImporter { RecordDeclToLayoutMap m_record_decl_to_layout_map; }; +template <class D> class TaggedASTDecl { +public: + TaggedASTDecl() : decl(nullptr) {} + TaggedASTDecl(D *_decl) : decl(_decl) {} + bool IsValid() const { return (decl != nullptr); } + bool IsInvalid() const { return !IsValid(); } + D *operator->() const { return decl; } + D *decl; +}; + +template <class D2, template <class D> class TD, class D1> +TD<D2> DynCast(TD<D1> source) { + return TD<D2>(llvm::dyn_cast<D2>(source.decl)); +} + +template <class D = clang::Decl> class DeclFromParser; +template <class D = clang::Decl> class DeclFromUser; + +template <class D> class DeclFromParser : public TaggedASTDecl<D> { +public: + DeclFromParser() : TaggedASTDecl<D>() {} + DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {} + + DeclFromUser<D> GetOrigin(ClangASTImporter &importer); +}; + +template <class D> class DeclFromUser : public TaggedASTDecl<D> { +public: + DeclFromUser() : TaggedASTDecl<D>() {} + DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {} + + DeclFromParser<D> Import(clang::ASTContext *dest_ctx, + ClangASTImporter &importer); +}; + +template <class D> +DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTImporter &importer) { + ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(this->decl); + if (!origin.Valid()) + return DeclFromUser<D>(); + return DeclFromUser<D>(llvm::dyn_cast<D>(origin.decl)); +} + +template <class D> +DeclFromParser<D> DeclFromUser<D>::Import(clang::ASTContext *dest_ctx, + ClangASTImporter &importer) { + DeclFromParser<> parser_generic_decl(importer.CopyDecl(dest_ctx, this->decl)); + if (parser_generic_decl.IsInvalid()) + return DeclFromParser<D>(); + return DeclFromParser<D>(llvm::dyn_cast<D>(parser_generic_decl.decl)); +} + } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 79dd306f7627fd..e88e2be5e5652a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -21,6 +21,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclVisitor.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" @@ -705,56 +706,6 @@ void ClangASTSource::FillNamespaceMap( } } -template <class D> class TaggedASTDecl { -public: - TaggedASTDecl() : decl(nullptr) {} - TaggedASTDecl(D *_decl) : decl(_decl) {} - bool IsValid() const { return (decl != nullptr); } - bool IsInvalid() const { return !IsValid(); } - D *operator->() const { return decl; } - D *decl; -}; - -template <class D2, template <class D> class TD, class D1> -TD<D2> DynCast(TD<D1> source) { - return TD<D2>(dyn_cast<D2>(source.decl)); -} - -template <class D = Decl> class DeclFromParser; -template <class D = Decl> class DeclFromUser; - -template <class D> class DeclFromParser : public TaggedASTDecl<D> { -public: - DeclFromParser() : TaggedASTDecl<D>() {} - DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {} - - DeclFromUser<D> GetOrigin(ClangASTSource &source); -}; - -template <class D> class DeclFromUser : public TaggedASTDecl<D> { -public: - DeclFromUser() : TaggedASTDecl<D>() {} - DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {} - - DeclFromParser<D> Import(ClangASTSource &source); -}; - -template <class D> -DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTSource &source) { - ClangASTImporter::DeclOrigin origin = source.GetDeclOrigin(this->decl); - if (!origin.Valid()) - return DeclFromUser<D>(); - return DeclFromUser<D>(dyn_cast<D>(origin.decl)); -} - -template <class D> -DeclFromParser<D> DeclFromUser<D>::Import(ClangASTSource &source) { - DeclFromParser<> parser_generic_decl(source.CopyDecl(this->decl)); - if (parser_generic_decl.IsInvalid()) - return DeclFromParser<D>(); - return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl)); -} - bool ClangASTSource::FindObjCMethodDeclsWithOrigin( NameSearchContext &context, ObjCInterfaceDecl *original_interface_decl, const char *log_info) { @@ -1188,8 +1139,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { } while (false); } -static bool FindObjCPropertyAndIvarDeclsWithOrigin( - NameSearchContext &context, ClangASTSource &source, +bool ClangASTSource::FindObjCPropertyAndIvarDeclsWithOrigin( + NameSearchContext &context, DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl) { Log *log = GetLog(LLDBLog::Expressions); @@ -1209,7 +1160,7 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( if (origin_property_decl.IsValid()) { DeclFromParser<ObjCPropertyDecl> parser_property_decl( - origin_property_decl.Import(source)); + origin_property_decl.Import(m_ast_context, *m_ast_importer_sp)); if (parser_property_decl.IsValid()) { LLDB_LOG(log, " CAS::FOPD found\n{0}", ClangUtil::DumpDecl(parser_property_decl.decl)); @@ -1224,7 +1175,7 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( if (origin_ivar_decl.IsValid()) { DeclFromParser<ObjCIvarDecl> parser_ivar_decl( - origin_ivar_decl.Import(source)); + origin_ivar_decl.Import(m_ast_context, *m_ast_importer_sp)); if (parser_ivar_decl.IsValid()) { LLDB_LOG(log, " CAS::FOPD found\n{0}", ClangUtil::DumpDecl(parser_ivar_decl.decl)); @@ -1243,7 +1194,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl( cast<ObjCInterfaceDecl>(context.m_decl_context)); DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl( - parser_iface_decl.GetOrigin(*this)); + parser_iface_decl.GetOrigin(*m_ast_importer_sp)); ConstString class_name(parser_iface_decl->getNameAsString().c_str()); @@ -1253,7 +1204,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { m_ast_context, m_clang_ast_context->getDisplayName(), parser_iface_decl->getName(), context.m_decl_name.getAsString()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, origin_iface_decl)) + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, origin_iface_decl)) return; LLDB_LOG(log, @@ -1286,7 +1237,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", complete_iface_decl.decl, &complete_iface_decl->getASTContext()); - FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, complete_iface_decl); + FindObjCPropertyAndIvarDeclsWithOrigin(context, complete_iface_decl); return; } while (false); @@ -1320,7 +1271,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { interface_decl_from_modules.decl, &interface_decl_from_modules->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, interface_decl_from_modules)) return; } while (false); @@ -1364,7 +1315,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { interface_decl_from_runtime.decl, &interface_decl_from_runtime->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, interface_decl_from_runtime)) return; } while (false); @@ -1395,205 +1346,16 @@ void ClangASTSource::LookupInNamespace(NameSearchContext &context) { } } -typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; -typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap; - -template <class D, class O> -static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, - llvm::DenseMap<const D *, O> &source_map, - ClangASTSource &source) { - // When importing fields into a new record, clang has a hard requirement that - // fields be imported in field offset order. Since they are stored in a - // DenseMap with a pointer as the key type, this means we cannot simply - // iterate over the map, as the order will be non-deterministic. Instead we - // have to sort by the offset and then insert in sorted order. - typedef llvm::DenseMap<const D *, O> MapType; - typedef typename MapType::value_type PairType; - std::vector<PairType> sorted_items; - sorted_items.reserve(source_map.size()); - sorted_items.assign(source_map.begin(), source_map.end()); - llvm::sort(sorted_items, llvm::less_second()); - - for (const auto &item : sorted_items) { - DeclFromUser<D> user_decl(const_cast<D *>(item.first)); - DeclFromParser<D> parser_decl(user_decl.Import(source)); - if (parser_decl.IsInvalid()) - return false; - destination_map.insert( - std::pair<const D *, O>(parser_decl.decl, item.second)); - } - - return true; -} - -template <bool IsVirtual> -bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, - DeclFromUser<const CXXRecordDecl> &record, - BaseOffsetMap &base_offsets) { - for (CXXRecordDecl::base_class_const_iterator - bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), - be = (IsVirtual ? record->vbases_end() : record->bases_end()); - bi != be; ++bi) { - if (!IsVirtual && bi->isVirtual()) - continue; - - const clang::Type *origin_base_type = bi->getType().getTypePtr(); - const clang::RecordType *origin_base_record_type = - origin_base_type->getAs<RecordType>(); - - if (!origin_base_record_type) - return false; - - DeclFromUser<RecordDecl> origin_base_record( - origin_base_record_type->getDecl()); - - if (origin_base_record.IsInvalid()) - return false; - - DeclFromUser<CXXRecordDecl> origin_base_cxx_record( - DynCast<CXXRecordDecl>(origin_base_record)); - - if (origin_base_cxx_record.IsInvalid()) - return false; - - CharUnits base_offset; - - if (IsVirtual) - base_offset = - record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); - else - base_offset = - record_layout.getBaseClassOffset(origin_base_cxx_record.decl); - - base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>( - origin_base_cxx_record.decl, base_offset)); - } - - return true; -} - -bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, - uint64_t &alignment, - FieldOffsetMap &field_offsets, - BaseOffsetMap &base_offsets, - BaseOffsetMap &virtual_base_offsets) { - - Log *log = GetLog(LLDBLog::Expressions); - - LLDB_LOG(log, - "LayoutRecordType on (ASTContext*){0} '{1}' for (RecordDecl*)" - "{2} [name = '{3}']", - m_ast_context, m_clang_ast_context->getDisplayName(), record, - record->getName()); - - DeclFromParser<const RecordDecl> parser_record(record); - DeclFromUser<const RecordDecl> origin_record( - parser_record.GetOrigin(*this)); - - if (origin_record.IsInvalid()) - return false; - - FieldOffsetMap origin_field_offsets; - BaseOffsetMap origin_base_offsets; - BaseOffsetMap origin_virtual_base_offsets; - - TypeSystemClang::GetCompleteDecl( - &origin_record->getASTContext(), - const_cast<RecordDecl *>(origin_record.decl)); - - clang::RecordDecl *definition = origin_record.decl->getDefinition(); - if (!definition || !definition->isCompleteDefinition()) - return false; - - const ASTRecordLayout &record_layout( - origin_record->getASTContext().getASTRecordLayout(origin_record.decl)); - - int field_idx = 0, field_count = record_layout.getFieldCount(); - - for (RecordDecl::field_iterator fi = origin_record->field_begin(), - fe = origin_record->field_end(); - fi != fe; ++fi) { - if (field_idx >= field_count) - return false; // Layout didn't go well. Bail out. - - uint64_t field_offset = record_layout.getFieldOffset(field_idx); - - origin_field_offsets.insert( - std::pair<const FieldDecl *, uint64_t>(*fi, field_offset)); - - field_idx++; - } - - lldbassert(&record->getASTContext() == m_ast_context); - - DeclFromUser<const CXXRecordDecl> origin_cxx_record( - DynCast<const CXXRecordDecl>(origin_record)); - - if (origin_cxx_record.IsValid()) { - if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record, - origin_base_offsets) || - !ExtractBaseOffsets<true>(record_layout, origin_cxx_record, - origin_virtual_base_offsets)) - return false; - } - - if (!ImportOffsetMap(field_offsets, origin_field_offsets, *this) || - !ImportOffsetMap(base_offsets, origin_base_offsets, *this) || - !ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, - *this)) - return false; - - size = record_layout.getSize().getQuantity() * m_ast_context->getCharWidth(); - alignment = record_layout.getAlignment().getQuantity() * - m_ast_context->getCharWidth(); - - if (log) { - LLDB_LOG(log, "LRT returned:"); - LLDB_LOG(log, "LRT Original = (RecordDecl*){0}", - static_cast<const void *>(origin_record.decl)); - LLDB_LOG(log, "LRT Size = {0}", size); - LLDB_LOG(log, "LRT Alignment = {0}", alignment); - LLDB_LOG(log, "LRT Fields:"); - for (RecordDecl::field_iterator fi = record->field_begin(), - fe = record->field_end(); - fi != fe; ++fi) { - LLDB_LOG(log, - "LRT (FieldDecl*){0}, Name = '{1}', Type = '{2}', Offset = " - "{3} bits", - *fi, fi->getName(), fi->getType().getAsString(), - field_offsets[*fi]); - } - DeclFromParser<const CXXRecordDecl> parser_cxx_record = - DynCast<const CXXRecordDecl>(parser_record); - if (parser_cxx_record.IsValid()) { - LLDB_LOG(log, "LRT Bases:"); - for (CXXRecordDecl::base_class_const_iterator - bi = parser_cxx_record->bases_begin(), - be = parser_cxx_record->bases_end(); - bi != be; ++bi) { - bool is_virtual = bi->isVirtual(); - - QualType base_type = bi->getType(); - const RecordType *base_record_type = base_type->getAs<RecordType>(); - DeclFromParser<RecordDecl> base_record(base_record_type->getDecl()); - DeclFromParser<CXXRecordDecl> base_cxx_record = - DynCast<CXXRecordDecl>(base_record); - - LLDB_LOG(log, - "LRT {0}(CXXRecordDecl*){1}, Name = '{2}', Offset = " - "{3} chars", - (is_virtual ? "Virtual " : ""), base_cxx_record.decl, - base_cxx_record.decl->getName(), - (is_virtual - ? virtual_base_offsets[base_cxx_record.decl].getQuantity() - : base_offsets[base_cxx_record.decl].getQuantity())); - } - } else { - LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); - } - } - - return true; +bool ClangASTSource::layoutRecordType( + const RecordDecl *record, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &virtual_base_offsets) { + return m_ast_importer_sp->importRecordLayoutFromOrigin( + record, size, alignment, field_offsets, base_offsets, + virtual_base_offsets); } void ClangASTSource::CompleteNamespaceMap( diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index f3fec3f944a146..f34e4661a81ca3 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -352,6 +352,11 @@ class ClangASTSource : public clang::ExternalASTSource, /// ExternalASTSource. TypeSystemClang *GetTypeSystem() const { return m_clang_ast_context; } +private: + bool FindObjCPropertyAndIvarDeclsWithOrigin( + NameSearchContext &context, + DeclFromUser<const clang::ObjCInterfaceDecl> &origin_iface_decl); + protected: bool FindObjCMethodDeclsWithOrigin( NameSearchContext &context, >From 391e87f97ee17281ef4a91b3cc1ca6cec8626058 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 29 Feb 2024 21:21:13 +0000 Subject: [PATCH 2/4] fixup! add doxygen comments --- .../Clang/ClangASTImporter.cpp | 28 +++++++++++++++++++ .../ExpressionParser/Clang/ClangASTImporter.h | 13 +++++++++ 2 files changed, 41 insertions(+) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index b9f2c834dd1197..be39e4c5ed20be 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -520,6 +520,24 @@ bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { return false; } +/// Copy layout information from \ref source_map to the \ref destination_map. +/// +/// In the process of copying over layout info, we may need to import +/// decls from the \ref source_map. This function will use the supplied +/// \ref importer to import the necessary decls into \ref dest_ctx. +/// +/// \param[in,out] dest_ctx Destination ASTContext into which we import +/// decls from the \ref source_map. +/// \param[out] destination_map A map from decls in \ref dest_ctx to an +/// integral offest, which will be copies +/// of the decl/offest pairs in \ref source_map +/// if successful. +/// \param[in] source_map A map from decls to integral offests. These will +/// be copied into \ref destination_map. +/// \param[in,out] importer Used to import decls into \ref dest_ctx. +/// +/// \returns On success, will return 'true' and the offsets in \ref destination_map +/// are usable copies of \ref source_map. template <class D, class O> static bool ImportOffsetMap(clang::ASTContext *dest_ctx, llvm::DenseMap<const D *, O> &destination_map, @@ -549,6 +567,16 @@ static bool ImportOffsetMap(clang::ASTContext *dest_ctx, return true; } +/// Given a CXXRecordDecl, will calculate and populate \ref base_offsets +/// with the integral offsets of any of its (possibly virtual) base classes. +/// +/// \param[in] record_layout ASTRecordLayout of \ref record. +/// \param[in] record The record that we're calculating the base layouts of. +/// \param[out] base_offsets Map of base-class decl to integral offset which +/// this function will fill in. +/// +/// \returns On success, will return 'true' and the offsets in \ref base_offsets +/// are usable. template <bool IsVirtual> bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, DeclFromUser<const CXXRecordDecl> &record, diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index f9c370bef94fc9..98cf4ba3602819 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -128,6 +128,19 @@ class ClangASTImporter { llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + /// If \ref record has a valid origin, this function copies that + /// origin's layout into this ClangASTImporter instance. + /// + /// \param[in] record The decl whose layout we're calculating. + /// \param[out] size Size of \ref record in bytes. + /// \param[out] alignment Alignment of \ref record in bytes. + /// \param[out] field_offsets Offsets of fields of \ref record. + /// \param[out] base_offsets Offsets of base classes of \ref record. + /// \param[out] vbase_offsets Offsets of virtual base classes of \ref record. + /// + /// \returns Returns 'false' if no valid origin was found for \ref record or + /// this function failed to import the layout from the origin. Otherwise, returns + /// 'true' and the offsets/size/alignment are valid for use. bool importRecordLayoutFromOrigin( const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment, llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, >From f7aa073eae020076bafc2e71afc0402c888abc71 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 29 Feb 2024 21:21:26 +0000 Subject: [PATCH 3/4] fixup! clang-format --- .../Plugins/ExpressionParser/Clang/ClangASTImporter.cpp | 7 ++++--- .../Plugins/ExpressionParser/Clang/ClangASTImporter.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index be39e4c5ed20be..99d210c347a21d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -535,8 +535,9 @@ bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { /// \param[in] source_map A map from decls to integral offests. These will /// be copied into \ref destination_map. /// \param[in,out] importer Used to import decls into \ref dest_ctx. -/// -/// \returns On success, will return 'true' and the offsets in \ref destination_map +/// +/// \returns On success, will return 'true' and the offsets in \ref +/// destination_map /// are usable copies of \ref source_map. template <class D, class O> static bool ImportOffsetMap(clang::ASTContext *dest_ctx, @@ -574,7 +575,7 @@ static bool ImportOffsetMap(clang::ASTContext *dest_ctx, /// \param[in] record The record that we're calculating the base layouts of. /// \param[out] base_offsets Map of base-class decl to integral offset which /// this function will fill in. -/// +/// /// \returns On success, will return 'true' and the offsets in \ref base_offsets /// are usable. template <bool IsVirtual> diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index 98cf4ba3602819..bc962e544d2f1a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -139,8 +139,8 @@ class ClangASTImporter { /// \param[out] vbase_offsets Offsets of virtual base classes of \ref record. /// /// \returns Returns 'false' if no valid origin was found for \ref record or - /// this function failed to import the layout from the origin. Otherwise, returns - /// 'true' and the offsets/size/alignment are valid for use. + /// this function failed to import the layout from the origin. Otherwise, + /// returns 'true' and the offsets/size/alignment are valid for use. bool importRecordLayoutFromOrigin( const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment, llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, >From 0910fa1fc378423e9a8b9481f0815002be8c99f7 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 29 Feb 2024 21:23:07 +0000 Subject: [PATCH 4/4] fixup! remove redundant headers --- lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index e88e2be5e5652a..a95a9e9f01e3fc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -21,8 +21,6 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits