[readobj] Expand CodeView dumping functionality
This rewrites and expands the existing codeview dumping functionality in
llvm-readobj using techniques similar to those in lib/Object. This defines a
number of new records and enums useful for reading memory mapped codeview
sections in COFF objects.
The dumper is intended as a testing tool for LLVM as it grows more codeview
output capabilities.
Reviewers: majnemer
Differential Revision: http://reviews.llvm.org/D16104
llvm-svn: 257658
diff --git a/llvm/tools/llvm-readobj/CodeView.h b/llvm/tools/llvm-readobj/CodeView.h
new file mode 100644
index 0000000..444b264
--- /dev/null
+++ b/llvm/tools/llvm-readobj/CodeView.h
@@ -0,0 +1,571 @@
+//===-- CodeView.h - On-disk record types for CodeView ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides data structures useful for consuming on-disk
+/// CodeView. It is based on information published by Microsoft at
+/// https://github.com/Microsoft/microsoft-pdb/.
+///
+//===----------------------------------------------------------------------===//
+
+// FIXME: Find a home for this in include/llvm/DebugInfo/CodeView/.
+
+#ifndef LLVM_READOBJ_CODEVIEW_H
+#define LLVM_READOBJ_CODEVIEW_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+namespace codeview {
+
+/// A Symbols subsection is a sequence of SymRecords. Advancing by 'len'
+/// bytes will find the next SymRecord. These are the possible types of a
+/// record. Equivalent to SYM_ENUM_e in cvinfo.h.
+enum SymType : uint16_t {
+#define SYMBOL_TYPE(ename, value) ename = value,
+#include "CVSymbolTypes.def"
+};
+
+/// Generic record compatible with all symbol records.
+struct SymRecord {
+ ulittle16_t RecordLength; // Record length, starting from the next field
+ ulittle16_t RecordType; // Record type (SymType)
+ // Symbol data follows.
+};
+
+/// Corresponds to the CV_PROCFLAGS bitfield.
+enum ProcFlags : uint8_t {
+ HasFP = 1 << 0,
+ HasIRET = 1 << 1,
+ HasFRET = 1 << 2,
+ IsNoReturn = 1 << 3,
+ IsUnreachable = 1 << 4,
+ HasCustomCallingConv = 1 << 5,
+ IsNoInline = 1 << 6,
+ HasOptimizedDebugInfo = 1 << 7,
+};
+
+// S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or
+// S_LPROC32_DPC_ID
+struct ProcSym {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+ ulittle32_t PtrNext;
+ ulittle32_t CodeSize;
+ ulittle32_t DbgStart;
+ ulittle32_t DbgEnd;
+ TypeIndex FunctionType;
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ uint8_t Flags; // CV_PROCFLAGS
+ // Name: The null-terminated name follows.
+};
+
+// S_INLINESITE
+struct InlineSiteSym {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+ TypeIndex Inlinee;
+ // BinaryAnnotations
+};
+
+// S_LOCAL
+struct LocalSym {
+ TypeIndex Type;
+ ulittle16_t Flags;
+ enum : uint16_t {
+ IsParameter = 1 << 0,
+ IsAddressTaken = 1 << 1,
+ IsCompilerGenerated = 1 << 2,
+ IsAggregate = 1 << 3,
+ IsAggregated = 1 << 4,
+ IsAliased = 1 << 5,
+ IsAlias = 1 << 6,
+ IsReturnValue = 1 << 7,
+ IsOptimizedOut = 1 << 8,
+ IsEnregisteredGlobal = 1 << 9,
+ IsEnregisteredStatic = 1 << 10,
+ };
+ // Name: The null-terminated name follows.
+};
+
+// S_BLOCK32
+struct BlockSym {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+ ulittle32_t CodeSize;
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+};
+
+// S_LABEL32
+struct LabelSym {
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ uint8_t Flags; // CV_PROCFLAGS
+ // Name: The null-terminated name follows.
+};
+
+// S_OBJNAME
+struct ObjNameSym {
+ ulittle32_t Signature;
+ // Name: The null-terminated name follows.
+};
+
+// S_COMPILE3
+struct CompileSym3 {
+ ulittle32_t flags;
+ uint8_t getLanguage() const { return flags & 0xff; }
+ enum Flags : uint32_t {
+ EC = 1 << 8,
+ NoDbgInfo = 1 << 9,
+ LTCG = 1 << 10,
+ NoDataAlign = 1 << 11,
+ ManagedPresent = 1 << 12,
+ SecurityChecks = 1 << 13,
+ HotPatch = 1 << 14,
+ CVTCIL = 1 << 15,
+ MSILModule = 1 << 16,
+ Sdl = 1 << 17,
+ PGO = 1 << 18,
+ Exp = 1 << 19,
+ };
+ ulittle16_t Machine; // CPUType
+ ulittle16_t VersionFrontendMajor;
+ ulittle16_t VersionFrontendMinor;
+ ulittle16_t VersionFrontendBuild;
+ ulittle16_t VersionFrontendQFE;
+ ulittle16_t VersionBackendMajor;
+ ulittle16_t VersionBackendMinor;
+ ulittle16_t VersionBackendBuild;
+ ulittle16_t VersionBackendQFE;
+ // VersionString: The null-terminated version string follows.
+};
+
+// S_FRAMEPROC
+struct FrameProcSym {
+ ulittle32_t TotalFrameBytes;
+ ulittle32_t PaddingFrameBytes;
+ ulittle32_t OffsetToPadding;
+ ulittle32_t BytesOfCalleeSavedRegisters;
+ ulittle32_t OffsetOfExceptionHandler;
+ ulittle16_t SectionIdOfExceptionHandler;
+ ulittle32_t Flags;
+};
+
+// S_CALLSITEINFO
+struct CallSiteInfoSym {
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ ulittle16_t Reserved;
+ TypeIndex Type;
+};
+
+// S_HEAPALLOCSITE
+struct HeapAllocationSiteSym {
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ ulittle16_t CallInstructionSize;
+ TypeIndex Type;
+};
+
+// S_FRAMECOOKIE
+struct FrameCookieSym {
+ ulittle32_t CodeOffset;
+ ulittle16_t Register;
+ ulittle16_t CookieKind;
+
+ enum : uint16_t {
+ Copy,
+ XorStackPointer,
+ XorFramePointer,
+ XorR13,
+ };
+};
+
+// S_UDT, S_COBOLUDT
+struct UDTSym {
+ TypeIndex Type; // Type of the UDT
+ // Name: The null-terminated name follows.
+};
+
+// S_BUILDINFO
+struct BuildInfoSym {
+ ulittle32_t BuildId;
+};
+
+// S_BPREL32
+struct BPRelativeSym {
+ ulittle32_t Offset; // Offset from the base pointer register
+ TypeIndex Type; // Type of the variable
+ // Name: The null-terminated name follows.
+};
+
+// S_REGREL32
+struct RegRelativeSym {
+ ulittle32_t Offset; // Offset from the register
+ TypeIndex Type; // Type of the variable
+ ulittle16_t Register; // Register to which the variable is relative
+ // Name: The null-terminated name follows.
+};
+
+// S_CONSTANT, S_MANCONSTANT
+struct ConstantSym {
+ TypeIndex Type;
+ // Value: The value of the constant.
+ // Name: The null-terminated name follows.
+};
+
+// S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA
+struct DataSym {
+ TypeIndex Type;
+ ulittle32_t DataOffset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+};
+
+// S_LTHREAD32, S_GTHREAD32
+struct ThreadLocalDataSym {
+ TypeIndex Type;
+ ulittle32_t DataOffset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+};
+
+/// Data in the the SUBSEC_FRAMEDATA subection.
+struct FrameData {
+ ulittle32_t RvaStart;
+ ulittle32_t CodeSize;
+ ulittle32_t LocalSize;
+ ulittle32_t ParamsSize;
+ ulittle32_t MaxStackSize;
+ ulittle32_t FrameFunc;
+ ulittle16_t PrologSize;
+ ulittle16_t SavedRegsSize;
+ ulittle32_t Flags;
+ enum : uint32_t {
+ HasSEH = 1 << 0,
+ HasEH = 1 << 1,
+ IsFunctionStart = 1 << 2,
+ };
+};
+
+//===----------------------------------------------------------------------===//
+// On-disk representation of type information
+
+/// Indicates the kind of TypeRecord we're dealing with here. The documentation
+/// and headers talk about this as the "leaf" type.
+enum LeafType : uint16_t {
+#define LEAF_TYPE(name, val) name = val,
+#include "CVLeafTypes.def"
+};
+
+// A CodeView type stream is a sequence of TypeRecords. Records larger than
+// 65536 must chain on to a second record. Each TypeRecord is followed by one of
+// the leaf types described below.
+struct TypeRecord {
+ ulittle16_t Len; // Type record length, starting from &Leaf.
+ ulittle16_t Leaf; // Type record kind (LeafType)
+};
+
+// LF_TYPESERVER2
+struct TypeServer2 {
+ char Signature[16]; // GUID
+ ulittle32_t Age;
+ // Name: Name of the PDB as a null-terminated string
+};
+
+// LF_STRING_ID
+struct StringId {
+ TypeIndex id;
+};
+
+// LF_FUNC_ID
+struct FuncId {
+ TypeIndex ParentScope;
+ TypeIndex FunctionType;
+ // Name: The null-terminated name follows.
+};
+
+// LF_CLASS, LF_STRUCT, LF_INTERFACE
+struct ClassType {
+ ulittle16_t MemberCount; // Number of members in FieldList.
+ ulittle16_t Properties; // ClassOptions bitset
+ TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members
+ TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes
+ TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable
+ // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer.
+ // Name: The null-terminated name follows.
+};
+
+// LF_UNION
+struct UnionType {
+ ulittle16_t MemberCount; // Number of members in FieldList.
+ ulittle16_t Properties; // ClassOptions bitset
+ TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members
+ // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer.
+ // Name: The null-terminated name follows.
+};
+
+// LF_POINTER
+struct PointerType {
+ TypeIndex PointeeType;
+ ulittle32_t Attrs; // pointer attributes
+ // if pointer to member:
+ // PointerToMemberTail
+
+ PointerKind getPtrKind() const { return PointerKind(Attrs & 0x1f); }
+ PointerMode getPtrMode() const { return PointerMode((Attrs >> 5) & 0x07); }
+ bool isFlat() const { return Attrs & (1 << 8); }
+ bool isVolatile() const { return Attrs & (1 << 9); }
+ bool isConst() const { return Attrs & (1 << 10); }
+ bool isUnaligned() const { return Attrs & (1 << 11); }
+
+ bool isPointerToDataMember() const {
+ return getPtrMode() == PointerMode::PointerToDataMember;
+ }
+ bool isPointerToMemberFunction() const {
+ return getPtrMode() == PointerMode::PointerToMemberFunction;
+ }
+ bool isPointerToMember() const {
+ return isPointerToMemberFunction() || isPointerToDataMember();
+ }
+};
+
+struct PointerToMemberTail {
+ TypeIndex ClassType;
+ ulittle16_t Representation; // PointerToMemberRepresentation
+};
+
+/// In Clang parlance, these are "qualifiers". LF_MODIFIER
+struct TypeModifier {
+ TypeIndex ModifiedType;
+ ulittle16_t Modifiers; // ModifierOptions
+};
+
+// LF_VTSHAPE
+struct VTableShape {
+ // Number of vftable entries. Each method may have more than one entry due to
+ // things like covariant return types.
+ ulittle16_t VFEntryCount;
+ // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e.
+};
+
+// LF_UDT_SRC_LINE
+struct UDTSrcLine {
+ TypeIndex UDT; // The user-defined type
+ TypeIndex SourceFile; // StringID containing the source filename
+ ulittle32_t LineNumber;
+};
+
+// LF_ARGLIST, LF_SUBSTR_LIST
+struct ArgList {
+ ulittle32_t NumArgs; // Number of arguments
+ // ArgTypes[]: Type indicies of arguments
+};
+
+// LF_BUILDINFO
+struct BuildInfo {
+ ulittle16_t NumArgs; // Number of arguments
+ // ArgTypes[]: Type indicies of arguments
+};
+
+// LF_ENUM
+struct EnumType {
+ ulittle16_t NumEnumerators; // Number of enumerators
+ ulittle16_t Properties;
+ TypeIndex UnderlyingType;
+ TypeIndex FieldListType;
+ // Name: The null-terminated name follows.
+};
+
+// LF_ARRAY
+struct ArrayType {
+ TypeIndex ElementType;
+ TypeIndex IndexType;
+ // SizeOf: LF_NUMERIC encoded size in bytes. Not element count!
+ // Name: The null-terminated name follows.
+};
+
+// LF_VFTABLE
+struct VFTableType {
+ TypeIndex CompleteClass; // Class that owns this vftable.
+ TypeIndex OverriddenVFTable; // VFTable that this overrides.
+ ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass
+ ulittle32_t NamesLen; // Length of subsequent names array in bytes.
+ // Names: A sequence of null-terminated strings. First string is vftable
+ // names.
+};
+
+// LF_MFUNC_ID
+struct MemberFuncId {
+ TypeIndex ClassType;
+ TypeIndex FunctionType;
+ // Name: The null-terminated name follows.
+};
+
+// LF_PROCEDURE
+struct ProcedureType {
+ TypeIndex ReturnType;
+ CallingConvention CallConv;
+ FunctionOptions Options;
+ ulittle16_t NumParameters;
+ TypeIndex ArgListType;
+};
+
+// LF_MFUNCTION
+struct MemberFunctionType {
+ TypeIndex ReturnType;
+ TypeIndex ClassType;
+ TypeIndex ThisType;
+ CallingConvention CallConv;
+ FunctionOptions Options;
+ ulittle16_t NumParameters;
+ TypeIndex ArgListType;
+ little32_t ThisAdjustment;
+};
+
+//===----------------------------------------------------------------------===//
+// Field list records, which do not include leafs or sizes
+
+/// Equvalent to CV_fldattr_t in cvinfo.h.
+struct MemberAttributes {
+ ulittle16_t Attrs;
+
+ /// Get the access specifier. Valid for any kind of member.
+ MemberAccess getAccess() const {
+ return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask));
+ }
+
+ /// Indicates if a method is defined with friend, virtual, static, etc.
+ MethodKind getMethodKind() const {
+ return MethodKind(
+ (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2);
+ }
+
+ /// Get the flags that are not included in access control or method
+ /// properties.
+ MethodOptions getFlags() const {
+ return MethodOptions(
+ unsigned(Attrs) &
+ ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask));
+ }
+
+ /// Is this method virtual.
+ bool isVirtual() const {
+ auto MP = getMethodKind();
+ return MP != MethodKind::Vanilla && MP != MethodKind::Friend &&
+ MP != MethodKind::Static;
+ }
+
+ /// Does this member introduce a new virtual method.
+ bool isIntroducedVirtual() const {
+ auto MP = getMethodKind();
+ return MP == MethodKind::IntroducingVirtual ||
+ MP == MethodKind::PureIntroducingVirtual;
+ }
+};
+
+// LF_NESTTYPE
+struct NestedType {
+ ulittle16_t Pad0; // Should be zero
+ TypeIndex Type; // Type index of nested type
+ // Name: Null-terminated string
+};
+
+// LF_ONEMETHOD
+struct OneMethod {
+ MemberAttributes Attrs;
+ TypeIndex Type;
+ // If is introduced virtual method:
+ // VFTableOffset: int32_t offset in vftable
+ // Name: Null-terminated string
+
+ MethodKind getMethodKind() const {
+ return Attrs.getMethodKind();
+ }
+
+ bool isVirtual() const { return Attrs.isVirtual(); }
+ bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); }
+};
+
+struct MethodListEntry {
+ MemberAttributes Attrs;
+ ulittle16_t Padding;
+
+ TypeIndex Type;
+ // If is introduced virtual method:
+ // VFTableOffset: int32_t offset in vftable
+
+ MethodKind getMethodKind() const {
+ return Attrs.getMethodKind();
+ }
+
+ bool isVirtual() const { return Attrs.isVirtual(); }
+ bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); }
+};
+
+/// For method overload sets. LF_METHOD
+struct OverloadedMethod {
+ ulittle16_t MethodCount; // Size of overload set
+ TypeIndex MethList; // Type index of methods in overload set
+ // Name: Null-terminated string
+};
+
+// LF_VFUNCTAB
+struct VirtualFunctionPointer {
+ ulittle16_t Pad0;
+ TypeIndex Type; // Type of vfptr
+};
+
+// LF_MEMBER
+struct DataMember {
+ MemberAttributes Attrs; // Access control attributes, etc
+ TypeIndex Type;
+ // FieldOffset: LF_NUMERIC encoded byte offset
+ // Name: Null-terminated string
+};
+
+// LF_STMEMBER
+struct StaticDataMember {
+ MemberAttributes Attrs; // Access control attributes, etc
+ TypeIndex Type;
+ // Name: Null-terminated string
+};
+
+// LF_ENUMERATE
+struct Enumerator {
+ MemberAttributes Attrs; // Access control attributes, etc
+ // EnumValue: LF_NUMERIC encoded enumerator value
+ // Name: Null-terminated string
+};
+
+// LF_BCLASS, LF_BINTERFACE
+struct BaseClass {
+ MemberAttributes Attrs; // Access control attributes, etc
+ TypeIndex BaseType; // Base class type
+ // BaseOffset: LF_NUMERIC encoded byte offset of base from derived.
+};
+
+// LF_VBCLASS | LV_IVBCLASS
+struct VirtualBaseClass {
+ MemberAttributes Attrs; // Access control attributes, etc.
+ TypeIndex BaseType; // Base class type
+ TypeIndex VBPtrType; // Virtual base pointer type
+ // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC.
+ // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC.
+};
+
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_READOBJ_CODEVIEW_H