llvm-vtabledump: Dump RTTI structures for the MS ABI
authorDavid Majnemer <david.majnemer@gmail.com>
Fri, 26 Sep 2014 04:21:51 +0000 (04:21 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Fri, 26 Sep 2014 04:21:51 +0000 (04:21 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218498 91177308-0d34-0410-b5e6-96231b3b80d8

test/tools/llvm-vtabledump/trivial.test
tools/llvm-vtabledump/llvm-vtabledump.cpp

index e24d6ad842e19f46833cdd110076722257b3253f..a0b9683296e2f525d7b56cc2f50b055b9c9b530c 100644 (file)
@@ -5,3 +5,46 @@ CHECK:      ??_7S@@6B@[0]: ??_R4S@@6B@
 CHECK-NEXT: ??_7S@@6B@[4]: ??_GS@@UAEPAXI@Z
 CHECK-NEXT: ??_8S@@7B@[0]: -4
 CHECK-NEXT: ??_8S@@7B@[4]: 4
+CHECK-NEXT: ??_R4S@@6B@[IsImageRelative]: 0
+CHECK-NEXT: ??_R4S@@6B@[OffsetToTop]: 0
+CHECK-NEXT: ??_R4S@@6B@[VFPtrOffset]: 0
+CHECK-NEXT: ??_R4S@@6B@[TypeDescriptor]: ??_R0?AUS@@@8
+CHECK-NEXT: ??_R4S@@6B@[ClassHierarchyDescriptor]: ??_R3S@@8
+CHECK-NEXT: ??_R3A@@8[AlwaysZero]: 0
+CHECK-NEXT: ??_R3A@@8[Flags]: 0
+CHECK-NEXT: ??_R3A@@8[NumClasses]: 1
+CHECK-NEXT: ??_R3A@@8[BaseClassArray]: ??_R2A@@8
+CHECK-NEXT: ??_R3S@@8[AlwaysZero]: 0
+CHECK-NEXT: ??_R3S@@8[Flags]: 0
+CHECK-NEXT: ??_R3S@@8[NumClasses]: 2
+CHECK-NEXT: ??_R3S@@8[BaseClassArray]: ??_R2S@@8
+CHECK-NEXT: ??_R2A@@8[0]: ??_R1A@?0A@EA@A@@8
+CHECK-NEXT: ??_R2S@@8[0]: ??_R1A@?0A@EA@S@@8
+CHECK-NEXT: ??_R2S@@8[4]: ??_R1A@33FA@A@@8
+CHECK-NEXT: ??_R1A@33FA@A@@8[TypeDescriptor]: ??_R0?AUA@@@8
+CHECK-NEXT: ??_R1A@33FA@A@@8[NumBases]: 0
+CHECK-NEXT: ??_R1A@33FA@A@@8[OffsetInVBase]: 0
+CHECK-NEXT: ??_R1A@33FA@A@@8[VBPtrOffset]: 4
+CHECK-NEXT: ??_R1A@33FA@A@@8[OffsetInVBTable]: 4
+CHECK-NEXT: ??_R1A@33FA@A@@8[Flags]: 80
+CHECK-NEXT: ??_R1A@33FA@A@@8[ClassHierarchyDescriptor]: ??_R3A@@8
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[TypeDescriptor]: ??_R0?AUA@@@8
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[NumBases]: 0
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[OffsetInVBase]: 0
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[VBPtrOffset]: -1
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[OffsetInVBTable]: 0
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[Flags]: 64
+CHECK-NEXT: ??_R1A@?0A@EA@A@@8[ClassHierarchyDescriptor]: ??_R3A@@8
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[TypeDescriptor]: ??_R0?AUS@@@8
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[NumBases]: 1
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[OffsetInVBase]: 0
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[VBPtrOffset]: -1
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[OffsetInVBTable]: 0
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[Flags]: 64
+CHECK-NEXT: ??_R1A@?0A@EA@S@@8[ClassHierarchyDescriptor]: ??_R3S@@8
+CHECK-NEXT: ??_R0?AUA@@@8[VFPtr]: ??_7type_info@@6B@
+CHECK-NEXT: ??_R0?AUA@@@8[AlwaysZero]: 0
+CHECK-NEXT: ??_R0?AUA@@@8[MangledName]: .?AUA@@\x00
+CHECK-NEXT: ??_R0?AUS@@@8[VFPtr]: ??_7type_info@@6B@
+CHECK-NEXT: ??_R0?AUS@@@8[AlwaysZero]: 0
+CHECK-NEXT: ??_R0?AUS@@@8[MangledName]: .?AUS@@\x00
index 3119fc0d6f30e9044b3d9126d1796e2c0bb5fbad..e3e13693923a95dfdca8786275864a705f456c38 100644 (file)
@@ -68,9 +68,67 @@ static void reportError(StringRef Input, std::error_code EC) {
   reportError(Input, EC.message());
 }
 
+static bool collectRelocatedSymbols(const ObjectFile *Obj,
+                                    object::section_iterator SecI, StringRef *I,
+                                    StringRef *E) {
+  for (const object::RelocationRef &Reloc : SecI->relocations()) {
+    if (I == E)
+      break;
+    const object::symbol_iterator RelocSymI = Reloc.getSymbol();
+    if (RelocSymI == Obj->symbol_end())
+      continue;
+    StringRef RelocSymName;
+    if (error(RelocSymI->getName(RelocSymName)))
+      return true;
+    *I = RelocSymName;
+    ++I;
+  }
+  return false;
+}
+
+static bool collectRelocationOffsets(
+    const ObjectFile *Obj, object::section_iterator SecI, StringRef SymName,
+    std::map<std::pair<StringRef, uint64_t>, StringRef> &Collection) {
+  for (const object::RelocationRef &Reloc : SecI->relocations()) {
+    const object::symbol_iterator RelocSymI = Reloc.getSymbol();
+    if (RelocSymI == Obj->symbol_end())
+      continue;
+    StringRef RelocSymName;
+    if (error(RelocSymI->getName(RelocSymName)))
+      return true;
+    uint64_t Offset;
+    if (error(Reloc.getOffset(Offset)))
+      return true;
+    Collection[std::make_pair(SymName, Offset)] = RelocSymName;
+  }
+  return false;
+}
+
 static void dumpVTables(const ObjectFile *Obj) {
+  struct CompleteObjectLocator {
+    StringRef Symbols[2];
+    ArrayRef<aligned_little32_t> Data;
+  };
+  struct ClassHierarchyDescriptor {
+    StringRef Symbols[1];
+    ArrayRef<aligned_little32_t> Data;
+  };
+  struct BaseClassDescriptor {
+    StringRef Symbols[2];
+    ArrayRef<aligned_little32_t> Data;
+  };
+  struct TypeDescriptor {
+    StringRef Symbols[1];
+    ArrayRef<aligned_little32_t> Data;
+    StringRef MangledName;
+  };
   std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries;
   std::map<StringRef, ArrayRef<aligned_little32_t>> VBTables;
+  std::map<StringRef, CompleteObjectLocator> COLs;
+  std::map<StringRef, ClassHierarchyDescriptor> CHDs;
+  std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries;
+  std::map<StringRef, BaseClassDescriptor> BCDs;
+  std::map<StringRef, TypeDescriptor> TDs;
   for (const object::SymbolRef &Sym : Obj->symbols()) {
     StringRef SymName;
     if (error(Sym.getName(SymName)))
@@ -86,18 +144,7 @@ static void dumpVTables(const ObjectFile *Obj) {
         continue;
       // Each relocation either names a virtual method or a thunk.  We note the
       // offset into the section and the symbol used for the relocation.
-      for (const object::RelocationRef &Reloc : SecI->relocations()) {
-        const object::symbol_iterator RelocSymI = Reloc.getSymbol();
-        if (RelocSymI == Obj->symbol_end())
-          continue;
-        StringRef RelocSymName;
-        if (error(RelocSymI->getName(RelocSymName)))
-          return;
-        uint64_t Offset;
-        if (error(Reloc.getOffset(Offset)))
-          return;
-        VFTableEntries[std::make_pair(SymName, Offset)] = RelocSymName;
-      }
+      collectRelocationOffsets(Obj, SecI, SymName, VFTableEntries);
     }
     // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
     // offsets of virtual bases.
@@ -116,10 +163,88 @@ static void dumpVTables(const ObjectFile *Obj) {
           SecContents.size() / sizeof(aligned_little32_t));
       VBTables[SymName] = VBTableData;
     }
+    // Complete object locators in the MS-ABI start with '??_R4'
+    else if (SymName.startswith("??_R4")) {
+      object::section_iterator SecI(Obj->section_begin());
+      if (error(Sym.getSection(SecI)))
+        return;
+      StringRef SecContents;
+      if (error(SecI->getContents(SecContents)))
+        return;
+      CompleteObjectLocator COL;
+      COL.Data = ArrayRef<aligned_little32_t>(
+          reinterpret_cast<const aligned_little32_t *>(SecContents.data()), 3);
+      StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols);
+      if (collectRelocatedSymbols(Obj, SecI, I, E))
+        return;
+      COLs[SymName] = COL;
+    }
+    // Class hierarchy descriptors in the MS-ABI start with '??_R3'
+    else if (SymName.startswith("??_R3")) {
+      object::section_iterator SecI(Obj->section_begin());
+      if (error(Sym.getSection(SecI)))
+        return;
+      StringRef SecContents;
+      if (error(SecI->getContents(SecContents)))
+        return;
+      ClassHierarchyDescriptor CHD;
+      CHD.Data = ArrayRef<aligned_little32_t>(
+          reinterpret_cast<const aligned_little32_t *>(SecContents.data()), 3);
+      StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols);
+      if (collectRelocatedSymbols(Obj, SecI, I, E))
+        return;
+      CHDs[SymName] = CHD;
+    }
+    // Class hierarchy descriptors in the MS-ABI start with '??_R2'
+    else if (SymName.startswith("??_R2")) {
+      object::section_iterator SecI(Obj->section_begin());
+      if (error(Sym.getSection(SecI)))
+        return;
+      if (SecI == Obj->section_end())
+        continue;
+      // Each relocation names a base class descriptor.  We note the offset into
+      // the section and the symbol used for the relocation.
+      collectRelocationOffsets(Obj, SecI, SymName, BCAEntries);
+    }
+    // Base class descriptors in the MS-ABI start with '??_R1'
+    else if (SymName.startswith("??_R1")) {
+      object::section_iterator SecI(Obj->section_begin());
+      if (error(Sym.getSection(SecI)))
+        return;
+      StringRef SecContents;
+      if (error(SecI->getContents(SecContents)))
+        return;
+      BaseClassDescriptor BCD;
+      BCD.Data = ArrayRef<aligned_little32_t>(
+          reinterpret_cast<const aligned_little32_t *>(SecContents.data()) + 1,
+          5);
+      StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols);
+      if (collectRelocatedSymbols(Obj, SecI, I, E))
+        return;
+      BCDs[SymName] = BCD;
+    }
+    // Type descriptors in the MS-ABI start with '??_R0'
+    else if (SymName.startswith("??_R0")) {
+      object::section_iterator SecI(Obj->section_begin());
+      if (error(Sym.getSection(SecI)))
+        return;
+      StringRef SecContents;
+      if (error(SecI->getContents(SecContents)))
+        return;
+      TypeDescriptor TD;
+      TD.Data = makeArrayRef(
+          reinterpret_cast<const aligned_little32_t *>(
+              SecContents.drop_front(Obj->getBytesInAddress()).data()),
+          Obj->getBytesInAddress() / sizeof(aligned_little32_t));
+      TD.MangledName = SecContents.drop_front(Obj->getBytesInAddress() * 2);
+      StringRef *I = std::begin(TD.Symbols), *E = std::end(TD.Symbols);
+      if (collectRelocatedSymbols(Obj, SecI, I, E))
+        return;
+      TDs[SymName] = TD;
+    }
   }
-  for (
-      const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VFTableEntry :
-      VFTableEntries) {
+  for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VFTableEntry :
+       VFTableEntries) {
     StringRef VFTableName = VFTableEntry.first.first;
     uint64_t Offset = VFTableEntry.first.second;
     StringRef SymName = VFTableEntry.second;
@@ -134,6 +259,52 @@ static void dumpVTables(const ObjectFile *Obj) {
       Idx += sizeof(Offset);
     }
   }
+  for (const std::pair<StringRef, CompleteObjectLocator> &COLPair : COLs) {
+    StringRef COLName = COLPair.first;
+    const CompleteObjectLocator &COL = COLPair.second;
+    outs() << COLName << "[IsImageRelative]: " << COL.Data[0] << '\n';
+    outs() << COLName << "[OffsetToTop]: " << COL.Data[1] << '\n';
+    outs() << COLName << "[VFPtrOffset]: " << COL.Data[2] << '\n';
+    outs() << COLName << "[TypeDescriptor]: " << COL.Symbols[0] << '\n';
+    outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1] << '\n';
+  }
+  for (const std::pair<StringRef, ClassHierarchyDescriptor> &CHDPair : CHDs) {
+    StringRef CHDName = CHDPair.first;
+    const ClassHierarchyDescriptor &CHD = CHDPair.second;
+    outs() << CHDName << "[AlwaysZero]: " << CHD.Data[0] << '\n';
+    outs() << CHDName << "[Flags]: " << CHD.Data[1] << '\n';
+    outs() << CHDName << "[NumClasses]: " << CHD.Data[2] << '\n';
+    outs() << CHDName << "[BaseClassArray]: " << CHD.Symbols[0] << '\n';
+  }
+  for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &BCAEntry :
+       BCAEntries) {
+    StringRef BCAName = BCAEntry.first.first;
+    uint64_t Offset = BCAEntry.first.second;
+    StringRef SymName = BCAEntry.second;
+    outs() << BCAName << '[' << Offset << "]: " << SymName << '\n';
+  }
+  for (const std::pair<StringRef, BaseClassDescriptor> &BCDPair : BCDs) {
+    StringRef BCDName = BCDPair.first;
+    const BaseClassDescriptor &BCD = BCDPair.second;
+    outs() << BCDName << "[TypeDescriptor]: " << BCD.Symbols[0] << '\n';
+    outs() << BCDName << "[NumBases]: " << BCD.Data[0] << '\n';
+    outs() << BCDName << "[OffsetInVBase]: " << BCD.Data[1] << '\n';
+    outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n';
+    outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n';
+    outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n';
+    outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] << '\n';
+  }
+  for (const std::pair<StringRef, TypeDescriptor> &TDPair : TDs) {
+    StringRef TDName = TDPair.first;
+    const TypeDescriptor &TD = TDPair.second;
+    outs() << TDName << "[VFPtr]: " << TD.Symbols[0] << '\n';
+    uint32_t AlwaysZero = 0;
+    for (aligned_little32_t Data : TD.Data)
+      AlwaysZero |= Data;
+    outs() << TDName << "[AlwaysZero]: " << AlwaysZero << '\n';
+    outs() << TDName << "[MangledName]: ";
+    outs().write_escaped(TD.MangledName, /*UseHexEscapes=*/true) << '\n';
+  }
 }
 
 static void dumpArchive(const Archive *Arc) {