From 8fdccd95fcc98956cddd9f10b4d72b0c01bf3eac Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Thu, 24 Sep 2009 23:50:42 +0000 Subject: [PATCH] Improve the record layout dumper. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82733 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Frontend/ASTConsumers.cpp | 89 ++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index aec68f3e11..5ef5c0e6f0 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -24,6 +24,7 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/CodeGen/ModuleBuilder.h" #include "llvm/Module.h" +#include "llvm/Support/Format.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -425,11 +426,95 @@ namespace { class RecordLayoutDumper : public ASTConsumer { llvm::raw_ostream& Out; - // FIXME: Maybe this be useful in ASTContext.cpp. + void PrintOffset(uint64_t Offset, unsigned IndentLevel) { + Out << llvm::format("%4d | ", Offset); + for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' '; + } + + void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C, + uint64_t Offset, + unsigned IndentLevel, const char* Description, + bool IncludeVirtualBases) { + const ASTRecordLayout &Info = C.getASTRecordLayout(RD); + + PrintOffset(Offset, IndentLevel); + Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString(); + if (Description) + Out << ' ' << Description; + if (RD->isEmpty()) + Out << " (empty)"; + Out << '\n'; + + IndentLevel++; + + const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); + + // Vtable pointer. + if (RD->isDynamicClass() && !PrimaryBase) { + PrintOffset(Offset, IndentLevel); + Out << '(' << RD->getNameAsString() << " vtable pointer)\n"; + } + // Dump (non-virtual) bases + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8; + + DumpRecordLayoutOffsets(Base, C, BaseOffset, IndentLevel, + Base == PrimaryBase ? "(primary base)" : "(base)", + /*IncludeVirtualBases=*/false); + } + + // Dump fields. + uint64_t FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *Field = *I; + uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8; + + if (const RecordType *RT = Field->getType()->getAs()) { + if (const CXXRecordDecl *D = dyn_cast(RT->getDecl())) { + DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel, + Field->getNameAsCString(), + /*IncludeVirtualBases=*/true); + continue; + } + } + + PrintOffset(FieldOffset, IndentLevel); + Out << Field->getType().getAsString() << ' '; + Out << Field->getNameAsString() << '\n'; + } + + if (!IncludeVirtualBases) + return; + + // Dump virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + assert(I->isVirtual() && "Found non-virtual class!"); + const CXXRecordDecl *VBase = + cast(I->getType()->getAs()->getDecl()); + + uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8; + DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel, + VBase == PrimaryBase ? + "(primary virtual base)" : "(virtual base)", + /*IncludeVirtualBases=*/false); + } + } + + // FIXME: Maybe this could be useful in ASTContext.cpp. void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) { const ASTRecordLayout &Info = C.getASTRecordLayout(RD); - Out << RD->getKindName() << ' ' << RD->getQualifiedNameAsString() << '\n'; + DumpRecordLayoutOffsets(RD, C, 0, 0, 0, + /*IncludeVirtualBases=*/true); Out << " sizeof=" << Info.getSize() / 8; Out << ", dsize=" << Info.getDataSize() / 8; Out << ", align=" << Info.getAlignment() / 8 << '\n'; -- 2.40.0