Index: include/llvm/DebugInfo/CodeView/CodeView.h =================================================================== --- include/llvm/DebugInfo/CodeView/CodeView.h +++ include/llvm/DebugInfo/CodeView/CodeView.h @@ -15,6 +15,75 @@ namespace llvm { namespace codeview { +/// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented +/// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx +enum class CPUType : uint16_t { + Intel8080 = 0x0, + Intel8086 = 0x1, + Intel80286 = 0x2, + Intel80386 = 0x3, + Intel80486 = 0x4, + Pentium = 0x5, + PentiumPro = 0x6, + Pentium3 = 0x7, + MIPS = 0x10, + MIPS16 = 0x11, + MIPS32 = 0x12, + MIPS64 = 0x13, + MIPSI = 0x14, + MIPSII = 0x15, + MIPSIII = 0x16, + MIPSIV = 0x17, + MIPSV = 0x18, + M68000 = 0x20, + M68010 = 0x21, + M68020 = 0x22, + M68030 = 0x23, + M68040 = 0x24, + Alpha = 0x30, + Alpha21164 = 0x31, + Alpha21164A = 0x32, + Alpha21264 = 0x33, + Alpha21364 = 0x34, + PPC601 = 0x40, + PPC603 = 0x41, + PPC604 = 0x42, + PPC620 = 0x43, + PPCFP = 0x44, + PPCBE = 0x45, + SH3 = 0x50, + SH3E = 0x51, + SH3DSP = 0x52, + SH4 = 0x53, + SHMedia = 0x54, + ARM3 = 0x60, + ARM4 = 0x61, + ARM4T = 0x62, + ARM5 = 0x63, + ARM5T = 0x64, + ARM6 = 0x65, + ARM_XMAC = 0x66, + ARM_WMMX = 0x67, + ARM7 = 0x68, + Omni = 0x70, + Ia64 = 0x80, + Ia64_2 = 0x81, + CEE = 0x90, + AM33 = 0xa0, + M32R = 0xb0, + TriCore = 0xc0, + X64 = 0xd0, + EBC = 0xe0, + Thumb = 0xf0, + ARMNT = 0xf4, + D3D11_Shader = 0x100, +}; + +/// These values correspond to the CV_call_e enumeration, and are documented +/// at the following locations: +/// https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx +/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680207(v=vs.85).aspx +/// enum class CallingConvention : uint8_t { NearC = 0x00, // near right to left push, caller pops stack FarC = 0x01, // far right to left push, caller pops stack @@ -140,6 +209,7 @@ Other = 0x03 }; +/// Source-level access specifier. (CV_access_e) enum class MemberAccess : uint8_t { None = 0, Private = 1, @@ -147,6 +217,7 @@ Public = 3 }; +/// Part of member attribute flags. (CV_methodprop_e) enum class MethodKind : uint8_t { Vanilla = 0x00, Virtual = 0x01, @@ -207,7 +278,15 @@ FrameData = 0xf5, InlineeLines = 0xf6, CrossScopeImports = 0xf7, - CrossScopeExports = 0xf8 + CrossScopeExports = 0xf8, + + // These appear to relate to .Net assembly info. + ILLines = 0xf9, + FuncMDTokenMap = 0xfa, + TypeMDTokenMap = 0xfb, + MergedAssemblyInput = 0xfc, + + CoffSymbolRVA = 0xfd, }; enum class PointerKind : uint8_t { Index: include/llvm/DebugInfo/CodeView/TypeIndex.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeIndex.h +++ include/llvm/DebugInfo/CodeView/TypeIndex.h @@ -74,6 +74,9 @@ NearPointer128 = 0x00000700 // 128 bit near pointer }; +/// A 32-bit type reference. Types are indexed by their order of appearance in +/// .debug$T plus 0x1000. Type indices less than 0x1000 are "simple" types, +/// composed of a SimpleTypeMode byte followed by a SimpleTypeKind byte. class TypeIndex { public: static const uint32_t FirstNonSimpleIndex = 0x1000; @@ -91,6 +94,8 @@ uint32_t getIndex() const { return Index; } bool isSimple() const { return Index < FirstNonSimpleIndex; } + bool isNoType() const { return Index == 0; } + SimpleTypeKind getSimpleKind() const { assert(isSimple()); return static_cast(Index & SimpleKindMask); @@ -144,7 +149,7 @@ static TypeIndex Float64() { return TypeIndex(SimpleTypeKind::Float64); } private: - uint32_t Index; + ulittle32_t Index; }; inline bool operator==(const TypeIndex &A, const TypeIndex &B) { Index: include/llvm/DebugInfo/PDB/PDBTypes.h =================================================================== --- include/llvm/DebugInfo/PDB/PDBTypes.h +++ include/llvm/DebugInfo/PDB/PDBTypes.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_PDB_PDBTYPES_H #include "llvm/Config/llvm-config.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/Support/Endian.h" #include #include @@ -108,67 +109,7 @@ /// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx -enum class PDB_Cpu { - Intel8080 = 0x0, - Intel8086 = 0x1, - Intel80286 = 0x2, - Intel80386 = 0x3, - Intel80486 = 0x4, - Pentium = 0x5, - PentiumPro = 0x6, - Pentium3 = 0x7, - MIPS = 0x10, - MIPS16 = 0x11, - MIPS32 = 0x12, - MIPS64 = 0x13, - MIPSI = 0x14, - MIPSII = 0x15, - MIPSIII = 0x16, - MIPSIV = 0x17, - MIPSV = 0x18, - M68000 = 0x20, - M68010 = 0x21, - M68020 = 0x22, - M68030 = 0x23, - M68040 = 0x24, - Alpha = 0x30, - Alpha21164 = 0x31, - Alpha21164A = 0x32, - Alpha21264 = 0x33, - Alpha21364 = 0x34, - PPC601 = 0x40, - PPC603 = 0x41, - PPC604 = 0x42, - PPC620 = 0x43, - PPCFP = 0x44, - PPCBE = 0x45, - SH3 = 0x50, - SH3E = 0x51, - SH3DSP = 0x52, - SH4 = 0x53, - SHMedia = 0x54, - ARM3 = 0x60, - ARM4 = 0x61, - ARM4T = 0x62, - ARM5 = 0x63, - ARM5T = 0x64, - ARM6 = 0x65, - ARM_XMAC = 0x66, - ARM_WMMX = 0x67, - ARM7 = 0x68, - Omni = 0x70, - Ia64 = 0x80, - Ia64_2 = 0x81, - CEE = 0x90, - AM33 = 0xa0, - M32R = 0xb0, - TriCore = 0xc0, - X64 = 0xd0, - EBC = 0xe0, - Thumb = 0xf0, - ARMNT = 0xf4, - D3D11_Shader = 0x100, -}; +typedef codeview::CPUType PDB_Cpu; enum class PDB_Machine { Invalid = 0xffff, @@ -200,34 +141,7 @@ /// https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680207(v=vs.85).aspx /// -enum class PDB_CallingConv { - NearCdecl = 0x00, - FarCdecl = 0x01, - NearPascal = 0x02, - FarPascal = 0x03, - NearFastcall = 0x04, - FarFastcall = 0x05, - Skipped = 0x06, - NearStdcall = 0x07, - FarStdcall = 0x08, - NearSyscall = 0x09, - FarSyscall = 0x0a, - Thiscall = 0x0b, - MipsCall = 0x0c, - Generic = 0x0d, - Alphacall = 0x0e, - Ppccall = 0x0f, - SuperHCall = 0x10, - Armcall = 0x11, - AM33call = 0x12, - Tricall = 0x13, - Sh5call = 0x14, - M32R = 0x15, - Clrcall = 0x16, - Inline = 0x17, - NearVectorcall = 0x18, - Reserved = 0x19, -}; +typedef codeview::CallingConvention PDB_CallingConv; /// These values correspond to the CV_CFL_LANG enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx Index: include/llvm/Support/COFF.h =================================================================== --- include/llvm/Support/COFF.h +++ include/llvm/Support/COFF.h @@ -665,6 +665,7 @@ DEBUG_INDEX_SUBSECTION = 0xF4, // Symbol subsections are split into records of different types. + DEBUG_SYMBOL_TYPE_LOCAL_PROC_START = 0x1146, DEBUG_SYMBOL_TYPE_PROC_START = 0x1147, DEBUG_SYMBOL_TYPE_PROC_END = 0x114F }; Index: include/llvm/Support/Endian.h =================================================================== --- include/llvm/Support/Endian.h +++ include/llvm/Support/Endian.h @@ -173,6 +173,10 @@ endianness endian, std::size_t alignment> struct packed_endian_specific_integral { + packed_endian_specific_integral() = default; + + explicit packed_endian_specific_integral(value_type val) { *this = val; } + operator value_type() const { return endian::read( (const void*)Value.buffer); Index: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp +++ lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp @@ -188,7 +188,6 @@ return; assert(FI.End && "Don't know where the function ends?"); - StringRef GVName = GV->getName(); StringRef FuncName; if (auto *SP = getDISubprogram(GV)) FuncName = SP->getDisplayName(); @@ -197,8 +196,8 @@ // "namespace_foo::bar" function, see PR21528. Luckily, dbghelp.dll is trying // to demangle display names anyways, so let's just put a mangled name into // the symbols subsection until Clang gives us what we need. - if (GVName.startswith("\01?")) - FuncName = GVName.substr(1); + if (FuncName.empty()) + FuncName = GlobalValue::getRealLinkageName(GV->getName()); // Emit a symbol subsection, required by VS2012+ to find function boundaries. MCSymbol *SymbolsBegin = Asm->MMI->getContext().createTempSymbol(), *SymbolsEnd = Asm->MMI->getContext().createTempSymbol(); Index: test/DebugInfo/COFF/asm.ll =================================================================== --- test/DebugInfo/COFF/asm.ll +++ test/DebugInfo/COFF/asm.ll @@ -96,14 +96,14 @@ ; OBJ32-NEXT: ] ; OBJ32: CodeViewDebugInfo [ ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF1 +; OBJ32-NEXT: SubSectionType: Symbols (0xF1) ; OBJ32-NOT: ] ; OBJ32: ProcStart { -; OBJ32-NEXT: DisplayName: f -; OBJ32-NEXT: Section: _f -; OBJ32-NEXT: CodeSize: 0x6 -; OBJ32-NEXT: } -; OBJ32-NEXT: ProcEnd +; OBJ32: CodeSize: 0x6 +; OBJ32: DisplayName: f +; OBJ32: LinkageName: _f +; OBJ32: } +; OBJ32: ProcEnd ; OBJ32-NEXT: ] ; OBJ32: FunctionLineTable [ ; OBJ32-NEXT: Name: _f @@ -217,13 +217,13 @@ ; OBJ64-NEXT: 0x48 IMAGE_REL_AMD64_SECTION f ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF1 +; OBJ64-NEXT: SubSectionType: Symbols (0xF1) ; OBJ64-NOT: ] ; OBJ64: ProcStart { -; OBJ64-NEXT: DisplayName: f -; OBJ64-NEXT: Section: f -; OBJ64-NEXT: CodeSize: 0xE -; OBJ64-NEXT: } +; OBJ64: CodeSize: 0xE +; OBJ64: DisplayName: f +; OBJ64: LinkageName: f +; OBJ64: } ; OBJ64-NEXT: ProcEnd ; OBJ64-NEXT: ] ; OBJ64: FunctionLineTable [ Index: test/DebugInfo/COFF/cpp-mangling.ll =================================================================== --- test/DebugInfo/COFF/cpp-mangling.ll +++ test/DebugInfo/COFF/cpp-mangling.ll @@ -10,8 +10,8 @@ ; CHECK: ProcStart { ; FIXME: The display name should in fact be "foo::bar", see PR21528 -; CHECK-NEXT: DisplayName: ?bar@foo@@YAHH@Z -; CHECK-NEXT: Section: ?bar@foo@@YAHH@Z +; CHECK: DisplayName: ?bar@foo@@YAHH@Z +; CHECK-NEXT: LinkageName: ?bar@foo@@YAHH@Z ; Function Attrs: nounwind define i32 @"\01?bar@foo@@YAHH@Z"(i32 %x) #0 { Index: test/DebugInfo/COFF/multifile.ll =================================================================== --- test/DebugInfo/COFF/multifile.ll +++ test/DebugInfo/COFF/multifile.ll @@ -122,13 +122,13 @@ ; OBJ32-NEXT: 0x48 IMAGE_REL_I386_SECTION _f ; OBJ32-NEXT: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF1 +; OBJ32-NEXT: SubSectionType: Symbols (0xF1) ; OBJ32-NOT: ] ; OBJ32: ProcStart { -; OBJ32-NEXT: DisplayName: f -; OBJ32-NEXT: Section: _f -; OBJ32-NEXT: CodeSize: 0x10 -; OBJ32-NEXT: } +; OBJ32: CodeSize: 0x10 +; OBJ32: DisplayName: f +; OBJ32: LinkageName: _f +; OBJ32: } ; OBJ32-NEXT: ProcEnd ; OBJ32-NEXT: ] ; OBJ32: FunctionLineTable [ @@ -282,14 +282,14 @@ ; OBJ64-NEXT: 0x48 IMAGE_REL_AMD64_SECTION f ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF1 +; OBJ64-NEXT: SubSectionType: Symbols (0xF1) ; OBJ64-NOT: ] ; OBJ64: ProcStart { -; OBJ64-NEXT: DisplayName: f -; OBJ64-NEXT: Section: f -; OBJ64-NEXT: CodeSize: 0x18 -; OBJ64-NEXT: } -; OBJ64-NEXT: ProcEnd +; OBJ64: CodeSize: 0x18 +; OBJ64: DisplayName: f +; OBJ64: LinkageName: f +; OBJ64: } +; OBJ64: ProcEnd ; OBJ64-NEXT: ] ; OBJ64: FunctionLineTable [ ; OBJ64-NEXT: Name: f Index: test/DebugInfo/COFF/multifunction.ll =================================================================== --- test/DebugInfo/COFF/multifunction.ll +++ test/DebugInfo/COFF/multifunction.ll @@ -221,43 +221,43 @@ ; OBJ32-NEXT: 0x128 IMAGE_REL_I386_SECTION _f ; OBJ32-NEXT: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF1 +; OBJ32-NEXT: SubSectionType: Symbols (0xF1) ; OBJ32-NOT: ] ; OBJ32: ProcStart { -; OBJ32-NEXT: DisplayName: x -; OBJ32-NEXT: Section: _x -; OBJ32-NEXT: CodeSize: 0x6 -; OBJ32-NEXT: } -; OBJ32-NEXT: ProcEnd +; OBJ32: CodeSize: 0x6 +; OBJ32: DisplayName: x +; OBJ32: LinkageName: _x +; OBJ32: } +; OBJ32: ProcEnd ; OBJ32-NEXT: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF2 +; OBJ32-NEXT: SubSectionType: Lines (0xF2) ; OBJ32: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF1 +; OBJ32-NEXT: SubSectionType: Symbols (0xF1) ; OBJ32-NOT: ] ; OBJ32: ProcStart { -; OBJ32-NEXT: DisplayName: y -; OBJ32-NEXT: Section: _y -; OBJ32-NEXT: CodeSize: 0x6 -; OBJ32-NEXT: } -; OBJ32-NEXT: ProcEnd +; OBJ32: CodeSize: 0x6 +; OBJ32: DisplayName: y +; OBJ32: LinkageName: _y +; OBJ32: } +; OBJ32: ProcEnd ; OBJ32-NEXT: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF2 +; OBJ32-NEXT: SubSectionType: Lines (0xF2) ; OBJ32: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF1 +; OBJ32-NEXT: SubSectionType: Symbols (0xF1) ; OBJ32-NOT: ] ; OBJ32: ProcStart { -; OBJ32-NEXT: DisplayName: f -; OBJ32-NEXT: Section: _f -; OBJ32-NEXT: CodeSize: 0x10 -; OBJ32-NEXT: } -; OBJ32-NEXT: ProcEnd +; OBJ32: CodeSize: 0x10 +; OBJ32: DisplayName: f +; OBJ32: LinkageName: _f +; OBJ32: } +; OBJ32: ProcEnd ; OBJ32-NEXT: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF2 +; OBJ32-NEXT: SubSectionType: Lines (0xF2) ; OBJ32: ] ; OBJ32: FunctionLineTable [ ; OBJ32-NEXT: Name: _x @@ -531,43 +531,43 @@ ; OBJ64-NEXT: 0x140 IMAGE_REL_AMD64_SECTION f ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF1 +; OBJ64-NEXT: SubSectionType: Symbols (0xF1) ; OBJ64-NOT: ] ; OBJ64: ProcStart { -; OBJ64-NEXT: DisplayName: x -; OBJ64-NEXT: Section: x -; OBJ64-NEXT: CodeSize: 0xE -; OBJ64-NEXT: } -; OBJ64-NEXT: ProcEnd +; OBJ64: CodeSize: 0xE +; OBJ64: DisplayName: x +; OBJ64: LinkageName: x +; OBJ64: } +; OBJ64: ProcEnd ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF2 +; OBJ64-NEXT: SubSectionType: Lines (0xF2) ; OBJ64: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF1 +; OBJ64-NEXT: SubSectionType: Symbols (0xF1) ; OBJ64-NOT: ] ; OBJ64: ProcStart { -; OBJ64-NEXT: DisplayName: y -; OBJ64-NEXT: Section: y -; OBJ64-NEXT: CodeSize: 0xE -; OBJ64-NEXT: } -; OBJ64-NEXT: ProcEnd +; OBJ64: CodeSize: 0xE +; OBJ64: DisplayName: y +; OBJ64: LinkageName: y +; OBJ64: } +; OBJ64: ProcEnd ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF2 +; OBJ64-NEXT: SubSectionType: Lines (0xF2) ; OBJ64: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF1 +; OBJ64-NEXT: SubSectionType: Symbols (0xF1) ; OBJ64-NOT: ] ; OBJ64: ProcStart { -; OBJ64-NEXT: DisplayName: f -; OBJ64-NEXT: Section: f -; OBJ64-NEXT: CodeSize: 0x18 -; OBJ64-NEXT: } -; OBJ64-NEXT: ProcEnd +; OBJ64: CodeSize: 0x18 +; OBJ64: DisplayName: f +; OBJ64: LinkageName: f +; OBJ64: } +; OBJ64: ProcEnd ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF2 +; OBJ64-NEXT: SubSectionType: Lines (0xF2) ; OBJ64: ] ; OBJ64: FunctionLineTable [ ; OBJ64-NEXT: Name: x Index: test/DebugInfo/COFF/simple.ll =================================================================== --- test/DebugInfo/COFF/simple.ll +++ test/DebugInfo/COFF/simple.ll @@ -89,13 +89,13 @@ ; OBJ32-NEXT: 0x48 IMAGE_REL_I386_SECTION _f ; OBJ32-NEXT: ] ; OBJ32: Subsection [ -; OBJ32-NEXT: Type: 0xF1 +; OBJ32-NEXT: SubSectionType: Symbols (0xF1) ; OBJ32-NOT: ] ; OBJ32: ProcStart { -; OBJ32-NEXT: DisplayName: f -; OBJ32-NEXT: Section: _f -; OBJ32-NEXT: CodeSize: 0x6 -; OBJ32-NEXT: } +; OBJ32: CodeSize: 0x6 +; OBJ32: DisplayName: f +; OBJ32: LinkageName: _f +; OBJ32: } ; OBJ32-NEXT: ProcEnd ; OBJ32-NEXT: ] ; OBJ32: FunctionLineTable [ @@ -199,13 +199,13 @@ ; OBJ64-NEXT: 0x48 IMAGE_REL_AMD64_SECTION f ; OBJ64-NEXT: ] ; OBJ64: Subsection [ -; OBJ64-NEXT: Type: 0xF1 +; OBJ64-NEXT: SubSectionType: Symbols (0xF1) ; OBJ64-NOT: ] ; OBJ64: ProcStart { -; OBJ64-NEXT: DisplayName: f -; OBJ64-NEXT: Section: f -; OBJ64-NEXT: CodeSize: 0xE -; OBJ64-NEXT: } +; OBJ64: CodeSize: 0xE +; OBJ64: DisplayName: f +; OBJ64: LinkageName: f +; OBJ64: } ; OBJ64-NEXT: ProcEnd ; OBJ64-NEXT: ] ; OBJ64: FunctionLineTable [ Index: test/tools/llvm-readobj/codeview-linetables.test =================================================================== --- test/tools/llvm-readobj/codeview-linetables.test +++ test/tools/llvm-readobj/codeview-linetables.test @@ -28,79 +28,80 @@ RUN: | FileCheck %s -check-prefix MFUN64 MFUN32: CodeViewDebugInfo [ +MFUN32-NEXT: Section: .debug$S (2) MFUN32-NEXT: Magic: 0x4 MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF1 -MFUN32-NEXT: PayloadSize: 0x52 +MFUN32-NEXT: SubSectionType: Symbols (0xF1) +MFUN32-NEXT: SubSectionSize: 0x52 MFUN32: ] -MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF5 -MFUN32-NEXT: PayloadSize: 0x24 +MFUN32: Subsection [ +MFUN32-NEXT: SubSectionType: FrameData (0xF5) +MFUN32-NEXT: SubSectionSize: 0x24 MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF1 -MFUN32-NEXT: PayloadSize: 0x4B +MFUN32-NEXT: SubSectionType: Symbols (0xF1) +MFUN32-NEXT: SubSectionSize: 0x4B MFUN32: ProcStart { -MFUN32-NEXT: DisplayName: x -MFUN32-NEXT: Section: _x -MFUN32-NEXT: CodeSize: 0xA -MFUN32-NEXT: } -MFUN32-NEXT: ProcEnd +MFUN32: CodeSize: 0xA +MFUN32: DisplayName: x +MFUN32: LinkageName: _x +MFUN32: } +MFUN32: ProcEnd MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF2 -MFUN32-NEXT: PayloadSize: 0x30 +MFUN32-NEXT: SubSectionType: Lines (0xF2) +MFUN32-NEXT: SubSectionSize: 0x30 MFUN32: LinkageName: _x MFUN32-NEXT: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF5 -MFUN32-NEXT: PayloadSize: 0x24 +MFUN32-NEXT: SubSectionType: FrameData (0xF5) +MFUN32-NEXT: SubSectionSize: 0x24 MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF1 -MFUN32-NEXT: PayloadSize: 0x4B +MFUN32-NEXT: SubSectionType: Symbols (0xF1) +MFUN32-NEXT: SubSectionSize: 0x4B MFUN32: ProcStart { -MFUN32-NEXT: DisplayName: y -MFUN32-NEXT: Section: _y -MFUN32-NEXT: CodeSize: 0xA -MFUN32-NEXT: } -MFUN32-NEXT: ProcEnd +MFUN32: CodeSize: 0xA +MFUN32: DisplayName: y +MFUN32: LinkageName: _y +MFUN32: } +MFUN32: ProcEnd MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF2 -MFUN32-NEXT: PayloadSize: 0x30 +MFUN32-NEXT: SubSectionType: Lines (0xF2) +MFUN32-NEXT: SubSectionSize: 0x30 MFUN32: LinkageName: _y MFUN32-NEXT: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF5 -MFUN32-NEXT: PayloadSize: 0x24 +MFUN32-NEXT: SubSectionType: FrameData (0xF5) +MFUN32-NEXT: SubSectionSize: 0x24 MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF1 -MFUN32-NEXT: PayloadSize: 0x4B +MFUN32-NEXT: SubSectionType: Symbols (0xF1) +MFUN32-NEXT: SubSectionSize: 0x4B MFUN32: ProcStart { -MFUN32-NEXT: DisplayName: f -MFUN32-NEXT: Section: _f -MFUN32-NEXT: CodeSize: 0x14 -MFUN32-NEXT: } -MFUN32-NEXT: ProcEnd +MFUN32: CodeSize: 0x14 +MFUN32: DisplayName: f +MFUN32: LinkageName: _f +MFUN32: } +MFUN32: ProcEnd MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF2 -MFUN32-NEXT: PayloadSize: 0x40 +MFUN32-NEXT: SubSectionType: Lines (0xF2) +MFUN32-NEXT: SubSectionSize: 0x40 MFUN32: LinkageName: _f MFUN32-NEXT: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF4 -MFUN32-NEXT: PayloadSize: 0x18 +MFUN32-NEXT: SubSectionType: FileChecksums (0xF4) +MFUN32-NEXT: SubSectionSize: 0x18 MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF3 -MFUN32-NEXT: PayloadSize: 0x46 +MFUN32-NEXT: SubSectionType: StringTable (0xF3) +MFUN32-NEXT: SubSectionSize: 0x46 MFUN32: ] MFUN32-NEXT: Subsection [ -MFUN32-NEXT: Type: 0xF1 -MFUN32-NEXT: PayloadSize: 0x8 +MFUN32-NEXT: SubSectionType: Symbols (0xF1) +MFUN32-NEXT: SubSectionSize: 0x8 MFUN32: ] MFUN32-NEXT: FunctionLineTable [ MFUN32-NEXT: LinkageName: _x @@ -137,70 +138,70 @@ MFUN32-NEXT: +0x12: 15 MFUN32-NEXT: ] MFUN32-NEXT: ] -MFUN32-NEXT: ] +MFUN32: ] MFUN64: CodeViewDebugInfo [ -MFUN64-NEXT: Magic: 0x4 +MFUN64: Magic: 0x4 MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF1 -MFUN64-NEXT: PayloadSize: 0x52 +MFUN64-NEXT: SubSectionType: Symbols (0xF1) +MFUN64-NEXT: SubSectionSize: 0x52 MFUN64: ] -MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF1 -MFUN64-NEXT: PayloadSize: 0x4B +MFUN64: Subsection [ +MFUN64-NEXT: SubSectionType: Symbols (0xF1) +MFUN64-NEXT: SubSectionSize: 0x4B MFUN64: ProcStart { -MFUN64-NEXT: DisplayName: x -MFUN64-NEXT: Section: x -MFUN64-NEXT: CodeSize: 0xE -MFUN64-NEXT: } -MFUN64-NEXT: ProcEnd +MFUN64: CodeSize: 0xE +MFUN64: DisplayName: x +MFUN64: LinkageName: x +MFUN64: } +MFUN64: ProcEnd MFUN64: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF2 -MFUN64-NEXT: PayloadSize: 0x30 +MFUN64-NEXT: SubSectionType: Lines (0xF2) +MFUN64-NEXT: SubSectionSize: 0x30 MFUN64: LinkageName: x MFUN64-NEXT: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF1 -MFUN64-NEXT: PayloadSize: 0x4B +MFUN64-NEXT: SubSectionType: Symbols (0xF1) +MFUN64-NEXT: SubSectionSize: 0x4B MFUN64: ProcStart { -MFUN64-NEXT: DisplayName: y -MFUN64-NEXT: Section: y -MFUN64-NEXT: CodeSize: 0xE -MFUN64-NEXT: } -MFUN64-NEXT: ProcEnd +MFUN64: CodeSize: 0xE +MFUN64: DisplayName: y +MFUN64: LinkageName: y +MFUN64: } +MFUN64: ProcEnd MFUN64: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF2 -MFUN64-NEXT: PayloadSize: 0x30 +MFUN64-NEXT: SubSectionType: Lines (0xF2) +MFUN64-NEXT: SubSectionSize: 0x30 MFUN64: LinkageName: y MFUN64-NEXT: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF1 -MFUN64-NEXT: PayloadSize: 0x4B +MFUN64-NEXT: SubSectionType: Symbols (0xF1) +MFUN64-NEXT: SubSectionSize: 0x4B MFUN64: ProcStart { -MFUN64-NEXT: DisplayName: f -MFUN64-NEXT: Section: f -MFUN64-NEXT: CodeSize: 0x18 -MFUN64-NEXT: } -MFUN64-NEXT: ProcEnd +MFUN64: CodeSize: 0x18 +MFUN64: DisplayName: f +MFUN64: LinkageName: f +MFUN64: } +MFUN64: ProcEnd MFUN64: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF2 -MFUN64-NEXT: PayloadSize: 0x40 +MFUN64-NEXT: SubSectionType: Lines (0xF2) +MFUN64-NEXT: SubSectionSize: 0x40 MFUN64: LinkageName: f MFUN64-NEXT: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF4 -MFUN64-NEXT: PayloadSize: 0x18 +MFUN64-NEXT: SubSectionType: FileChecksums (0xF4) +MFUN64-NEXT: SubSectionSize: 0x18 MFUN64: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF3 -MFUN64-NEXT: PayloadSize: 0xD +MFUN64-NEXT: SubSectionType: StringTable (0xF3) +MFUN64-NEXT: SubSectionSize: 0xD MFUN64: ] MFUN64-NEXT: Subsection [ -MFUN64-NEXT: Type: 0xF1 -MFUN64-NEXT: PayloadSize: 0x8 +MFUN64-NEXT: SubSectionType: Symbols (0xF1) +MFUN64-NEXT: SubSectionSize: 0x8 MFUN64: ] MFUN64-NEXT: FunctionLineTable [ MFUN64-NEXT: LinkageName: x @@ -237,7 +238,7 @@ MFUN64-NEXT: +0x13: 15 MFUN64-NEXT: ] MFUN64-NEXT: ] -MFUN64-NEXT: ] +MFUN64: ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; The following two object files were generated using the following command: @@ -264,41 +265,41 @@ RUN: | FileCheck %s -check-prefix MFILE64 MFILE32: CodeViewDebugInfo [ -MFILE32-NEXT: Magic: 0x4 +MFILE32: Magic: 0x4 MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF1 -MFILE32-NEXT: PayloadSize: 0x51 +MFILE32-NEXT: SubSectionType: Symbols (0xF1) +MFILE32-NEXT: SubSectionSize: 0x51 MFILE32: ] -MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF5 -MFILE32-NEXT: PayloadSize: 0x24 +MFILE32: Subsection [ +MFILE32-NEXT: SubSectionType: FrameData (0xF5) +MFILE32-NEXT: SubSectionSize: 0x24 MFILE32: ] MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF1 -MFILE32-NEXT: PayloadSize: 0x4B +MFILE32-NEXT: SubSectionType: Symbols (0xF1) +MFILE32-NEXT: SubSectionSize: 0x4B MFILE32: ProcStart { -MFILE32-NEXT: DisplayName: f -MFILE32-NEXT: Section: _f -MFILE32-NEXT: CodeSize: 0x14 -MFILE32-NEXT: } -MFILE32-NEXT: ProcEnd +MFILE32: CodeSize: 0x14 +MFILE32: DisplayName: f +MFILE32: LinkageName: _f +MFILE32: } +MFILE32: ProcEnd MFILE32: ] MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF2 -MFILE32-NEXT: PayloadSize: 0x64 +MFILE32-NEXT: SubSectionType: Lines (0xF2) +MFILE32-NEXT: SubSectionSize: 0x64 MFILE32: LinkageName: _f MFILE32-NEXT: ] MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF4 -MFILE32-NEXT: PayloadSize: 0x28 +MFILE32-NEXT: SubSectionType: FileChecksums (0xF4) +MFILE32-NEXT: SubSectionSize: 0x28 MFILE32: ] MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF3 -MFILE32-NEXT: PayloadSize: 0x57 +MFILE32-NEXT: SubSectionType: StringTable (0xF3) +MFILE32-NEXT: SubSectionSize: 0x57 MFILE32: ] MFILE32-NEXT: Subsection [ -MFILE32-NEXT: Type: 0xF1 -MFILE32-NEXT: PayloadSize: 0x8 +MFILE32-NEXT: SubSectionType: Symbols (0xF1) +MFILE32-NEXT: SubSectionSize: 0x8 MFILE32: ] MFILE32-NEXT: FunctionLineTable [ MFILE32-NEXT: LinkageName: _f @@ -322,40 +323,40 @@ MFILE32-NEXT: +0x12: 8 MFILE32-NEXT: ] MFILE32-NEXT: ] -MFILE32-NEXT: ] +MFILE32: ] MFILE64: CodeViewDebugInfo [ -MFILE64-NEXT: Magic: 0x4 +MFILE64: Magic: 0x4 MFILE64-NEXT: Subsection [ -MFILE64-NEXT: Type: 0xF1 -MFILE64-NEXT: PayloadSize: 0x51 +MFILE64-NEXT: SubSectionType: Symbols (0xF1) +MFILE64-NEXT: SubSectionSize: 0x51 MFILE64: ] -MFILE64-NEXT: Subsection [ -MFILE64-NEXT: Type: 0xF1 -MFILE64-NEXT: PayloadSize: 0x4B +MFILE64: Subsection [ +MFILE64-NEXT: SubSectionType: Symbols (0xF1) +MFILE64-NEXT: SubSectionSize: 0x4B MFILE64: ProcStart { -MFILE64-NEXT: DisplayName: f -MFILE64-NEXT: Section: f -MFILE64-NEXT: CodeSize: 0x18 -MFILE64-NEXT: } -MFILE64-NEXT: ProcEnd +MFILE64: CodeSize: 0x18 +MFILE64: DisplayName: f +MFILE64: LinkageName: f +MFILE64: } +MFILE64: ProcEnd MFILE64: ] MFILE64-NEXT: Subsection [ -MFILE64-NEXT: Type: 0xF2 -MFILE64-NEXT: PayloadSize: 0x64 +MFILE64-NEXT: SubSectionType: Lines (0xF2) +MFILE64-NEXT: SubSectionSize: 0x64 MFILE64: LinkageName: f MFILE64-NEXT: ] MFILE64-NEXT: Subsection [ -MFILE64-NEXT: Type: 0xF4 -MFILE64-NEXT: PayloadSize: 0x28 +MFILE64-NEXT: SubSectionType: FileChecksums (0xF4) +MFILE64-NEXT: SubSectionSize: 0x28 MFILE64: ] MFILE64-NEXT: Subsection [ -MFILE64-NEXT: Type: 0xF3 -MFILE64-NEXT: PayloadSize: 0x1E +MFILE64-NEXT: SubSectionType: StringTable (0xF3) +MFILE64-NEXT: SubSectionSize: 0x1E MFILE64: ] MFILE64-NEXT: Subsection [ -MFILE64-NEXT: Type: 0xF1 -MFILE64-NEXT: PayloadSize: 0x8 +MFILE64-NEXT: SubSectionType: Symbols (0xF1) +MFILE64-NEXT: SubSectionSize: 0x8 MFILE64: ] MFILE64-NEXT: FunctionLineTable [ MFILE64-NEXT: LinkageName: f @@ -379,7 +380,7 @@ MFILE64-NEXT: +0x13: 8 MFILE64-NEXT: ] MFILE64-NEXT: ] -MFILE64-NEXT: ] +MFILE64: ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; The following object files were generated using the following command: @@ -401,10 +402,10 @@ RUN: | FileCheck %s -check-prefix MCOMDAT MCOMDAT: ProcStart { -MCOMDAT-NEXT: DisplayName: f -MCOMDAT-NEXT: Section: ?f@@YAHXZ -MCOMDAT-NEXT: CodeSize: 0x7 -MCOMDAT-NEXT: } +MCOMDAT: CodeSize: 0x7 +MCOMDAT: DisplayName: f +MCOMDAT: LinkageName: ?f@@YAHXZ +MCOMDAT: } MCOMDAT: FunctionLineTable [ MCOMDAT-NEXT: LinkageName: ?f@@YAHXZ MCOMDAT-NEXT: Flags: 0x0 @@ -417,10 +418,10 @@ MCOMDAT-NEXT: ] MCOMDAT-NEXT: ] MCOMDAT: ProcStart { -MCOMDAT-NEXT: DisplayName: g -MCOMDAT-NEXT: Section: ?g@@YAHXZ -MCOMDAT-NEXT: CodeSize: 0x7 -MCOMDAT-NEXT: } +MCOMDAT: CodeSize: 0x7 +MCOMDAT: DisplayName: g +MCOMDAT: LinkageName: ?g@@YAHXZ +MCOMDAT: } MCOMDAT: FunctionLineTable [ MCOMDAT-NEXT: LinkageName: ?g@@YAHXZ MCOMDAT-NEXT: Flags: 0x0 Index: tools/llvm-readobj/COFFDumper.cpp =================================================================== --- tools/llvm-readobj/COFFDumper.cpp +++ tools/llvm-readobj/COFFDumper.cpp @@ -14,6 +14,7 @@ #include "llvm-readobj.h" #include "ARMWinEHPrinter.h" +#include "CodeView.h" #include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" @@ -22,6 +23,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/COFF.h" @@ -39,6 +41,7 @@ using namespace llvm; using namespace llvm::object; +using namespace llvm::codeview; using namespace llvm::Win64EH; namespace { @@ -72,12 +75,18 @@ void printBaseOfDataField(const pe32_header *Hdr); void printBaseOfDataField(const pe32plus_header *Hdr); - void printCodeViewSection(const SectionRef &Section); + void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section); + void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section); + void printCodeViewFieldList(StringRef FieldData); + StringRef getTypeName(TypeIndex Ty); + void printTypeIndex(StringRef FieldName, TypeIndex TI); void printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, uint32_t Offset); + void printMemberAttributes(MemberAttributes Attrs); + void cacheRelocations(); std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset, @@ -96,6 +105,13 @@ RelocMapTy RelocMap; StringRef CVFileIndexToStringOffsetTable; StringRef CVStringTable; + + /// All user defined type records in .debug$T live in here. Type indices + /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to + /// index into this vector. + SmallVector CVUDTNames; + + StringSet<> TypeNames; }; } // namespace @@ -331,6 +347,348 @@ { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } }; +static const EnumEntry CompileSym3Flags[] = { + LLVM_READOBJ_ENUM_ENT(CompileSym3, EC), + LLVM_READOBJ_ENUM_ENT(CompileSym3, NoDbgInfo), + LLVM_READOBJ_ENUM_ENT(CompileSym3, LTCG), + LLVM_READOBJ_ENUM_ENT(CompileSym3, NoDataAlign), + LLVM_READOBJ_ENUM_ENT(CompileSym3, ManagedPresent), + LLVM_READOBJ_ENUM_ENT(CompileSym3, SecurityChecks), + LLVM_READOBJ_ENUM_ENT(CompileSym3, HotPatch), + LLVM_READOBJ_ENUM_ENT(CompileSym3, CVTCIL), + LLVM_READOBJ_ENUM_ENT(CompileSym3, MSILModule), + LLVM_READOBJ_ENUM_ENT(CompileSym3, Sdl), + LLVM_READOBJ_ENUM_ENT(CompileSym3, PGO), + LLVM_READOBJ_ENUM_ENT(CompileSym3, Exp), +}; + +static const EnumEntry SourceLanguages[] = { + LLVM_READOBJ_ENUM_ENT(SourceLanguage, C), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cpp), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Fortran), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Masm), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Pascal), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Basic), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cobol), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Link), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cvtres), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cvtpgd), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, CSharp), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, VB), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, ILAsm), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, Java), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, JScript), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, MSIL), + LLVM_READOBJ_ENUM_ENT(SourceLanguage, HLSL), +}; + +static const EnumEntry SubSectionTypes[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA), +}; + +static const EnumEntry CPUTypeNames[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel8080), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel8086), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel80286), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel80386), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel80486), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Pentium), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PentiumPro), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Pentium3), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS16), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS32), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS64), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSI), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSII), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSIII), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSIV), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSV), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68000), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68010), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68020), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68030), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68040), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21164), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21164A), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21264), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21364), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC601), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC603), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC604), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC620), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPCFP), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPCBE), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH3), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH3E), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH3DSP), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH4), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SHMedia), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM3), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM4), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM4T), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM5), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM5T), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM6), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM_XMAC), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM_WMMX), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM7), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Omni), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Ia64), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Ia64_2), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, CEE), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, AM33), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M32R), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, TriCore), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, X64), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, EBC), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Thumb), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARMNT), + LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, D3D11_Shader), +}; + +static const EnumEntry ProcSymFlags[] = { + LLVM_READOBJ_ENUM_ENT(ProcFlags, HasFP), + LLVM_READOBJ_ENUM_ENT(ProcFlags, HasIRET), + LLVM_READOBJ_ENUM_ENT(ProcFlags, HasFRET), + LLVM_READOBJ_ENUM_ENT(ProcFlags, IsNoReturn), + LLVM_READOBJ_ENUM_ENT(ProcFlags, IsUnreachable), + LLVM_READOBJ_ENUM_ENT(ProcFlags, HasCustomCallingConv), + LLVM_READOBJ_ENUM_ENT(ProcFlags, IsNoInline), + LLVM_READOBJ_ENUM_ENT(ProcFlags, HasOptimizedDebugInfo), +}; + +static const EnumEntry FrameProcSymFlags[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, + HasStructuredExceptionHandling), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, Naked), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, + AsynchronousExceptionHandling), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, + NoStackOrderingForSecurityChecks), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, + ProfileGuidedOptimization), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg), + LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw), +}; + +static const EnumEntry FrameDataFlags[] = { + LLVM_READOBJ_ENUM_ENT(FrameData, HasSEH), + LLVM_READOBJ_ENUM_ENT(FrameData, HasEH), + LLVM_READOBJ_ENUM_ENT(FrameData, IsFunctionStart), +}; + +static const EnumEntry LocalFlags[] = { + LLVM_READOBJ_ENUM_ENT(LocalSym, IsParameter), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsAddressTaken), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsCompilerGenerated), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsAggregate), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsAggregated), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsAliased), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsAlias), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsReturnValue), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsOptimizedOut), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsEnregisteredGlobal), + LLVM_READOBJ_ENUM_ENT(LocalSym, IsEnregisteredStatic), +}; + +static const EnumEntry FrameCookieKinds[] = { + LLVM_READOBJ_ENUM_ENT(FrameCookieSym, Copy), + LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorStackPointer), + LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorFramePointer), + LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorR13), +}; + +static const EnumEntry ClassOptionNames[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Packed), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasConstructorOrDestructor), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasOverloadedOperator), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Nested), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, ContainsNestedClass), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasOverloadedAssignmentOperator), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasConversionOperator), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, ForwardReference), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Scoped), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasUniqueName), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Sealed), + LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Intrinsic), +}; + +static const EnumEntry MemberAccessNames[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, None), + LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Private), + LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Protected), + LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Public), +}; + +static const EnumEntry MemberAttributeNames[] = { + LLVM_READOBJ_ENUM_ENT(MemberAttributes, MA_Pseudo), + LLVM_READOBJ_ENUM_ENT(MemberAttributes, MA_NoInherit), + LLVM_READOBJ_ENUM_ENT(MemberAttributes, MA_NoConstruct), + LLVM_READOBJ_ENUM_ENT(MemberAttributes, MA_CompilerGenerated), + LLVM_READOBJ_ENUM_ENT(MemberAttributes, MA_Sealed), +}; + +static const EnumEntry MemberKindNames[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Vanilla), + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Virtual), + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Static), + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Friend), + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, IntroducingVirtual), + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, PureVirtual), + LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, PureIntroducingVirtual), +}; + +/// The names here all end in "*". If the simple type is a pointer type, we +/// return the whole name. Otherwise we lop off the last character in our +/// StringRef. +static const EnumEntry SimpleTypeNames[] = { + {"void*", SimpleTypeKind::Void}, + {"*", SimpleTypeKind::NotTranslated}, + {"HRESULT*", SimpleTypeKind::HResult}, + {"signed char*", SimpleTypeKind::SignedCharacter}, + {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, + {"char*", SimpleTypeKind::NarrowCharacter}, + {"wchar_t*", SimpleTypeKind::WideCharacter}, + {"__int8*", SimpleTypeKind::SByte}, + {"unsigned __int8*", SimpleTypeKind::Byte}, + {"short*", SimpleTypeKind::Int16Short}, + {"unsigned short*", SimpleTypeKind::UInt16Short}, + {"__int16*", SimpleTypeKind::Int16}, + {"unsigned __int16*", SimpleTypeKind::UInt16}, + {"long*", SimpleTypeKind::Int32Long}, + {"unsigned long*", SimpleTypeKind::UInt32Long}, + {"int*", SimpleTypeKind::Int32}, + {"unsigned*", SimpleTypeKind::UInt32}, + {"__int64*", SimpleTypeKind::Int64Quad}, + {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, + {"__int64*", SimpleTypeKind::Int64}, + {"unsigned __int64*", SimpleTypeKind::UInt64}, + {"__int128*", SimpleTypeKind::Int128}, + {"unsigned __int128*", SimpleTypeKind::UInt128}, + {"__half*", SimpleTypeKind::Float16}, + {"float*", SimpleTypeKind::Float32}, + {"float*", SimpleTypeKind::Float32PartialPrecision}, + {"__float48*", SimpleTypeKind::Float48}, + {"double*", SimpleTypeKind::Float64}, + {"long double*", SimpleTypeKind::Float80}, + {"__float128*", SimpleTypeKind::Float128}, + {"_Complex float*", SimpleTypeKind::Complex32}, + {"_Complex double*", SimpleTypeKind::Complex64}, + {"_Complex long double*", SimpleTypeKind::Complex80}, + {"_Complex __float128*", SimpleTypeKind::Complex128}, + {"bool*", SimpleTypeKind::Boolean8}, + {"__bool16*", SimpleTypeKind::Boolean16}, + {"__bool32*", SimpleTypeKind::Boolean32}, + {"__bool64*", SimpleTypeKind::Boolean64}, +}; + +static const EnumEntry LeafTypeNames[] = { +#define LEAF_TYPE(name, val) LLVM_READOBJ_ENUM_ENT(LeafType, name), +#include "CVLeafTypes.def" +}; + +static const EnumEntry PtrTypeNames[] = { + LLVM_READOBJ_ENUM_ENT(PointerType, Near16), + LLVM_READOBJ_ENUM_ENT(PointerType, Far16), + LLVM_READOBJ_ENUM_ENT(PointerType, Huge16), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnSegment), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnValue), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnSegmentValue), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnAddress), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnSegmentAddress), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnType), + LLVM_READOBJ_ENUM_ENT(PointerType, BasedOnSelf), + LLVM_READOBJ_ENUM_ENT(PointerType, Near32), + LLVM_READOBJ_ENUM_ENT(PointerType, Far32), + LLVM_READOBJ_ENUM_ENT(PointerType, Near64), +}; + +static const EnumEntry PtrModeNames[] = { + LLVM_READOBJ_ENUM_ENT(PointerType, Pointer), + LLVM_READOBJ_ENUM_ENT(PointerType, LValueReference), + LLVM_READOBJ_ENUM_ENT(PointerType, PointerToDataMember), + LLVM_READOBJ_ENUM_ENT(PointerType, PointerToMemberFunction), + LLVM_READOBJ_ENUM_ENT(PointerType, RValueReference), +}; + +static const EnumEntry + PtrMemberRepNames[] = { + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, Unknown), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, SingleInheritanceData), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, MultipleInheritanceData), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, VirtualInheritanceData), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, GeneralData), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, SingleInheritanceFunction), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, MultipleInheritanceFunction), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, VirtualInheritanceFunction), + LLVM_READOBJ_ENUM_ENT(PointerToMemberTail, GeneralFunction), +}; + +static const EnumEntry TypeModifierNames[] = { + LLVM_READOBJ_ENUM_ENT(TypeModifier, Const), + LLVM_READOBJ_ENUM_ENT(TypeModifier, Volatile), + LLVM_READOBJ_ENUM_ENT(TypeModifier, Unaligned), +}; + +static const EnumEntry CallingConventions[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearC), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarC), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearPascal), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarPascal), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearFast), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarFast), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearStdCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarStdCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearSysCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarSysCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ThisCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, MipsCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, Generic), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, AlphaCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, PpcCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, SHCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ArmCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, AM33Call), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, TriCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, SH5Call), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, M32RCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ClrCall), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, Inline), + LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearVector), +}; + +static const EnumEntry FunctionOptionEnum[] = { + LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, CxxReturnUdt), + LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, Constructor), + LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, ConstructorWithVirtualBases), +}; + template static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, COFFSymbolRef Symbol, @@ -476,110 +834,165 @@ void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} void COFFDumper::printCodeViewDebugInfo() { + // Print types first to build CVUDTNames, then print symbols. for (const SectionRef &S : Obj->sections()) { - StringRef SecName; - error(S.getName(SecName)); - if (SecName == ".debug$S") - printCodeViewSection(S); + StringRef SectionName; + error(S.getName(SectionName)); + if (SectionName == ".debug$T") + printCodeViewTypeSection(SectionName, S); + } + for (const SectionRef &S : Obj->sections()) { + StringRef SectionName; + error(S.getName(SectionName)); + if (SectionName == ".debug$S") + printCodeViewSymbolSection(SectionName, S); } } -void COFFDumper::printCodeViewSection(const SectionRef &Section) { - StringRef Data; - error(Section.getContents(Data)); +/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if +/// there are not enough bytes remaining. Reinterprets the consumed bytes as a +/// T object and points 'Res' at them. +template +static std::error_code consumeObject(StringRef &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) + return object_error::parse_failed; + Res = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return std::error_code(); +} + +static std::error_code consumeUInt32(StringRef &Data, uint32_t &Res) { + const ulittle32_t *IntPtr; + if (auto EC = consumeObject(Data, IntPtr)) + return EC; + Res = *IntPtr; + return std::error_code(); +} + +void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, + const SectionRef &Section) { + StringRef SectionContents; + error(Section.getContents(SectionContents)); + StringRef Data = SectionContents; SmallVector FunctionNames; StringMap FunctionLineTables; + std::map FunctionFrameData; ListScope D(W, "CodeViewDebugInfo"); - { - // FIXME: Add more offset correctness checks. - DataExtractor DE(Data, true, 4); - uint32_t Offset = 0, - Magic = DE.getU32(&Offset); - W.printHex("Magic", Magic); - if (Magic != COFF::DEBUG_SECTION_MAGIC) { - error(object_error::parse_failed); - return; - } + // Print the section to allow correlation with printSections. + W.printNumber("Section", SectionName, Obj->getSectionID(Section)); + + uint32_t Magic; + error(consumeUInt32(Data, Magic)); + W.printHex("Magic", Magic); + if (Magic != COFF::DEBUG_SECTION_MAGIC) + return error(object_error::parse_failed); + + while (!Data.empty()) { + // The section consists of a number of subsection in the following format: + // |SubSectionType|SubSectionSize|Contents...| + uint32_t SubType, SubSectionSize; + error(consumeUInt32(Data, SubType)); + error(consumeUInt32(Data, SubSectionSize)); + + ListScope S(W, "Subsection"); + W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes)); + W.printHex("SubSectionSize", SubSectionSize); + + // Get the contents of the subsection. + if (SubSectionSize > Data.size()) + return error(object_error::parse_failed); + StringRef Contents = Data.substr(0, SubSectionSize); + + // Add SubSectionSize to the current offset and align that offset to find + // the next subsection. + size_t SectionOffset = Data.data() - SectionContents.data(); + size_t NextOffset = SectionOffset + SubSectionSize; + NextOffset = RoundUpToAlignment(NextOffset, 4); + Data = SectionContents.drop_front(NextOffset); + + // Optionally print the subsection bytes in case our parsing gets confused + // later. + if (opts::CodeViewSubsectionBytes) + W.printBinaryBlock("SubSectionContents", Contents); + + switch (ModuleSubstreamKind(SubType)) { + case ModuleSubstreamKind::Symbols: + printCodeViewSymbolsSubsection(Contents, Section, SectionOffset); + break; + case ModuleSubstreamKind::Lines: { + // Holds a PC to file:line table. Some data to parse this subsection is + // stored in the other subsections, so just check sanity and store the + // pointers for deferred processing. + + if (SubSectionSize < 12) { + // There should be at least three words to store two function + // relocations and size of the code. + error(object_error::parse_failed); + return; + } - bool Finished = false; - while (DE.isValidOffset(Offset) && !Finished) { - // The section consists of a number of subsection in the following format: - // |Type|PayloadSize|Payload...| - uint32_t SubSectionType = DE.getU32(&Offset), - PayloadSize = DE.getU32(&Offset); - ListScope S(W, "Subsection"); - W.printHex("Type", SubSectionType); - W.printHex("PayloadSize", PayloadSize); - if (PayloadSize > Data.size() - Offset) { + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), SectionOffset, + LinkageName)); + W.printString("LinkageName", LinkageName); + if (FunctionLineTables.count(LinkageName) != 0) { + // Saw debug info for this function already? error(object_error::parse_failed); return; } - StringRef Contents = Data.substr(Offset, PayloadSize); - if (opts::CodeViewSubsectionBytes) { - // Print the raw contents to simplify debugging if anything goes wrong - // afterwards. - W.printBinaryBlock("Contents", Contents); + FunctionLineTables[LinkageName] = Contents; + FunctionNames.push_back(LinkageName); + break; + } + case ModuleSubstreamKind::StringTable: + if (SubSectionSize == 0 || CVStringTable.data() != nullptr || + Contents.back() != '\0') { + // Empty or duplicate or non-null-terminated subsection. + error(object_error::parse_failed); + return; } + CVStringTable = Contents; + break; + case ModuleSubstreamKind::FileChecksums: + // Holds the translation table from file indices + // to offsets in the string table. - switch (SubSectionType) { - case COFF::DEBUG_SYMBOL_SUBSECTION: - printCodeViewSymbolsSubsection(Contents, Section, Offset); - break; - case COFF::DEBUG_LINE_TABLE_SUBSECTION: { - // Holds a PC to file:line table. Some data to parse this subsection is - // stored in the other subsections, so just check sanity and store the - // pointers for deferred processing. - - if (PayloadSize < 12) { - // There should be at least three words to store two function - // relocations and size of the code. - error(object_error::parse_failed); - return; - } + if (SubSectionSize == 0 || + CVFileIndexToStringOffsetTable.data() != nullptr) { + // Empty or duplicate subsection. + error(object_error::parse_failed); + return; + } + CVFileIndexToStringOffsetTable = Contents; + break; + case ModuleSubstreamKind::FrameData: { + const size_t RelocationSize = 4; + if (SubSectionSize != sizeof(FrameData) + RelocationSize) { + // There should be exactly one relocation followed by the FrameData + // contents. + error(object_error::parse_failed); + return; + } - StringRef LinkageName; - error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, - LinkageName)); - W.printString("LinkageName", LinkageName); - if (FunctionLineTables.count(LinkageName) != 0) { - // Saw debug info for this function already? - error(object_error::parse_failed); - return; - } + const auto *FD = reinterpret_cast( + Contents.drop_front(RelocationSize).data()); - FunctionLineTables[LinkageName] = Contents; - FunctionNames.push_back(LinkageName); - break; - } - case COFF::DEBUG_STRING_TABLE_SUBSECTION: - if (PayloadSize == 0 || CVStringTable.data() != nullptr || - Contents.back() != '\0') { - // Empty or duplicate or non-null-terminated subsection. - error(object_error::parse_failed); - return; - } - CVStringTable = Contents; - break; - case COFF::DEBUG_INDEX_SUBSECTION: - // Holds the translation table from file indices - // to offsets in the string table. - - if (PayloadSize == 0 || - CVFileIndexToStringOffsetTable.data() != nullptr) { - // Empty or duplicate subsection. - error(object_error::parse_failed); - return; - } - CVFileIndexToStringOffsetTable = Contents; - break; + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), SectionOffset, + LinkageName)); + if (!FunctionFrameData.emplace(LinkageName, FD).second) { + error(object_error::parse_failed); + return; } - Offset += PayloadSize; + break; + } - // Align the reading pointer by 4. - Offset += (-Offset) % 4; + // Do nothing for unrecognized subsections. + default: + break; } } @@ -660,89 +1073,1099 @@ } } } + + for (auto FrameDataPair : FunctionFrameData) { + StringRef LinkageName = FrameDataPair.first; + const FrameData *FD = FrameDataPair.second; + ListScope S(W, "FunctionFrameData"); + W.printString("LinkageName", LinkageName); + W.printHex("RvaStart", FD->RvaStart); + W.printHex("CodeSize", FD->CodeSize); + W.printHex("LocalSize", FD->LocalSize); + W.printHex("ParamsSize", FD->ParamsSize); + W.printHex("MaxStackSize", FD->MaxStackSize); + W.printString("FrameFunc", StringRef(CVStringTable.data() + FD->FrameFunc)); + W.printHex("PrologSize", FD->PrologSize); + W.printHex("SavedRegsSize", FD->SavedRegsSize); + W.printFlags("Flags", FD->Flags, makeArrayRef(FrameDataFlags)); + } +} + +std::error_code decodeNumerictLeaf(StringRef &Data, APSInt &Num) { + // Used to avoid overload ambiguity on APInt construtor. + bool FalseVal = false; + if (Data.size() < 2) + return object_error::parse_failed; + uint16_t Short = *reinterpret_cast(Data.data()); + Data = Data.drop_front(2); + if (Short < LF_NUMERIC) { + Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), + /*isUnsigned=*/true); + return std::error_code(); + } + switch (Short) { + case LF_CHAR: + Num = APSInt(APInt(/*numBits=*/8, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(1); + return std::error_code(); + case LF_SHORT: + Num = APSInt(APInt(/*numBits=*/16, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(2); + return std::error_code(); + case LF_USHORT: + Num = APSInt(APInt(/*numBits=*/16, + *reinterpret_cast(Data.data()), + /*isSigned=*/false), + /*isUnsigned=*/true); + Data = Data.drop_front(2); + return std::error_code(); + case LF_LONG: + Num = APSInt(APInt(/*numBits=*/32, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(4); + return std::error_code(); + case LF_ULONG: + Num = APSInt(APInt(/*numBits=*/32, + *reinterpret_cast(Data.data()), + /*isSigned=*/FalseVal), + /*isUnsigned=*/true); + Data = Data.drop_front(4); + return std::error_code(); + case LF_QUADWORD: + Num = APSInt(APInt(/*numBits=*/64, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(8); + return std::error_code(); + case LF_UQUADWORD: + Num = APSInt(APInt(/*numBits=*/64, + *reinterpret_cast(Data.data()), + /*isSigned=*/false), + /*isUnsigned=*/true); + Data = Data.drop_front(8); + return std::error_code(); + } + return object_error::parse_failed; +} + +/// Decode an unsigned integer numeric leaf value. +std::error_code decodeUIntLeaf(StringRef &Data, uint64_t &Num) { + APSInt N; + if (std::error_code err = decodeNumerictLeaf(Data, N)) + return err; + if (N.isSigned() || !N.isIntN(64)) + return object_error::parse_failed; + Num = N.getLimitedValue(); + return std::error_code(); } void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, uint32_t OffsetInSection) { - if (Subsection.size() == 0) { - error(object_error::parse_failed); - return; - } - DataExtractor DE(Subsection, true, 4); - uint32_t Offset = 0; + if (Subsection.size() < sizeof(SymRecord)) + return error(object_error::parse_failed); + + // This holds the remaining data to parse. + StringRef Data = Subsection; - // Function-level subsections have "procedure start" and "procedure end" - // commands that should come in pairs and surround relevant info. bool InFunctionScope = false; - while (DE.isValidOffset(Offset)) { - // Read subsection segments one by one. - uint16_t Size = DE.getU16(&Offset); - // The section size includes the size of the type identifier. - if (Size < 2 || !DE.isValidOffsetForDataOfSize(Offset, Size)) { - error(object_error::parse_failed); - return; - } - Size -= 2; - uint16_t Type = DE.getU16(&Offset); + while (!Data.empty()) { + const SymRecord *Rec; + error(consumeObject(Data, Rec)); + + StringRef SymData = Data.substr(0, Rec->RecordLength - 2); + + Data = Data.drop_front(Rec->RecordLength - 2); + + SymType Type = static_cast(uint16_t(Rec->RecordType)); switch (Type) { - case COFF::DEBUG_SYMBOL_TYPE_PROC_START: { + case S_LPROC32: + case S_GPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + case S_LPROC32_DPC: + case S_LPROC32_DPC_ID: { DictScope S(W, "ProcStart"); - if (InFunctionScope || Size < 36) { - error(object_error::parse_failed); - return; - } + const ProcSym *Proc; + error(consumeObject(SymData, Proc)); + if (InFunctionScope) + return error(object_error::parse_failed); InFunctionScope = true; - // We're currently interested in a limited subset of fields in this - // segment, just ignore the rest of the fields for now. - uint8_t Unused[12]; - DE.getU8(&Offset, Unused, 12); - uint32_t CodeSize = DE.getU32(&Offset); - DE.getU8(&Offset, Unused, 12); - StringRef SectionName; + // In a COFF object file, the CodeOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfCodeOffset = + reinterpret_cast(&Proc->CodeOffset) - Subsection.data(); + StringRef LinkageName; error(resolveSymbolName(Obj->getCOFFSection(Section), - OffsetInSection + Offset, SectionName)); - Offset += 4; - DE.getU8(&Offset, Unused, 3); - StringRef DisplayName = DE.getCStr(&Offset); - if (!DE.isValidOffset(Offset)) { - error(object_error::parse_failed); - return; - } + OffsetInSection + SecOffsetOfCodeOffset, + LinkageName)); + + StringRef DisplayName = SymData.split('\0').first; + W.printHex("PtrParent", Proc->PtrParent); + W.printHex("PtrEnd", Proc->PtrEnd); + W.printHex("PtrNext", Proc->PtrNext); + W.printHex("CodeSize", Proc->CodeSize); + W.printHex("DbgStart", Proc->DbgStart); + W.printHex("DbgEnd", Proc->DbgEnd); + printTypeIndex("FunctionType", Proc->FunctionType); + W.printHex("CodeOffset", Proc->CodeOffset); + W.printHex("Segment", Proc->Segment); + W.printFlags("Flags", Proc->Flags, makeArrayRef(ProcSymFlags)); W.printString("DisplayName", DisplayName); - W.printString("Section", SectionName); - W.printHex("CodeSize", CodeSize); - + W.printString("LinkageName", LinkageName); break; } - case COFF::DEBUG_SYMBOL_TYPE_PROC_END: { + + case S_PROC_ID_END: { W.startLine() << "ProcEnd\n"; - if (!InFunctionScope || Size > 0) { - error(object_error::parse_failed); - return; - } InFunctionScope = false; break; } + + case S_BLOCK32: { + DictScope S(W, "BlockStart"); + const BlockSym *Block; + error(consumeObject(SymData, Block)); + + // In a COFF object file, the CodeOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfCodeOffset = + reinterpret_cast(&Block->CodeOffset) - Subsection.data(); + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + SecOffsetOfCodeOffset, + LinkageName)); + + StringRef BlockName = SymData.split('\0').first; + W.printHex("PtrParent", Block->PtrParent); + W.printHex("PtrEnd", Block->PtrEnd); + W.printHex("CodeSize", Block->CodeSize); + W.printHex("CodeOffset", Block->CodeOffset); + W.printHex("Segment", Block->Segment); + W.printString("BlockName", BlockName); + W.printString("LinkageName", LinkageName); + break; + } + + case S_END: { + W.startLine() << "BlockEnd\n"; + InFunctionScope = false; + break; + } + + case S_LABEL32: { + DictScope S(W, "Label"); + const LabelSym *Label; + error(consumeObject(SymData, Label)); + + // In a COFF object file, the CodeOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfCodeOffset = + reinterpret_cast(&Label->CodeOffset) - Subsection.data(); + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + SecOffsetOfCodeOffset, + LinkageName)); + + StringRef DisplayName = SymData.split('\0').first; + W.printHex("CodeOffset", Label->CodeOffset); + W.printHex("Segment", Label->Segment); + W.printHex("Flags", Label->Flags); + W.printFlags("Flags", Label->Flags, makeArrayRef(ProcSymFlags)); + W.printString("DisplayName", DisplayName); + W.printString("LinkageName", LinkageName); + break; + } + + case S_INLINESITE: { + DictScope S(W, "InlineSite"); + const InlineSiteSym *InlineSite; + error(consumeObject(SymData, InlineSite)); + W.printHex("PtrParent", InlineSite->PtrParent); + W.printHex("PtrEnd", InlineSite->PtrEnd); + printTypeIndex("Inlinee", InlineSite->Inlinee); + W.printBinaryBlock("BinaryAnnotations", SymData); + break; + } + + case S_INLINESITE_END: { + DictScope S(W, "InlineSiteEnd"); + break; + } + + case S_LOCAL: { + DictScope S(W, "Local"); + const LocalSym *Local; + error(consumeObject(SymData, Local)); + printTypeIndex("Type", Local->Type); + W.printFlags("Flags", uint16_t(Local->Flags), makeArrayRef(LocalFlags)); + StringRef VarName = SymData.split('\0').first; + W.printString("VarName", VarName); + break; + } + + case S_CALLSITEINFO: { + DictScope S(W, "CallSiteInfo"); + const CallSiteInfoSym *CallSiteInfo; + error(consumeObject(SymData, CallSiteInfo)); + + // In a COFF object file, the CodeOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfCodeOffset = + reinterpret_cast(&CallSiteInfo->CodeOffset) - Subsection.data(); + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + SecOffsetOfCodeOffset, + LinkageName)); + W.printHex("CodeOffset", CallSiteInfo->CodeOffset); + W.printHex("Segment", CallSiteInfo->Segment); + W.printHex("Reserved", CallSiteInfo->Reserved); + printTypeIndex("Type", CallSiteInfo->Type); + W.printString("LinkageName", LinkageName); + break; + } + + case S_HEAPALLOCSITE: { + DictScope S(W, "HeapAllocationSite"); + const HeapAllocationSiteSym *HeapAllocationSite; + error(consumeObject(SymData, HeapAllocationSite)); + + // In a COFF object file, the CodeOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfCodeOffset = + reinterpret_cast(&HeapAllocationSite->CodeOffset) - + Subsection.data(); + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + SecOffsetOfCodeOffset, + LinkageName)); + W.printHex("CodeOffset", HeapAllocationSite->CodeOffset); + W.printHex("Segment", HeapAllocationSite->Segment); + W.printHex("CallInstructionSize", + HeapAllocationSite->CallInstructionSize); + printTypeIndex("Type", HeapAllocationSite->Type); + W.printString("LinkageName", LinkageName); + break; + } + + case S_FRAMECOOKIE: { + DictScope S(W, "FrameCookie"); + const FrameCookieSym *FrameCookie; + error(consumeObject(SymData, FrameCookie)); + W.printHex("CodeOffset", FrameCookie->CodeOffset); + W.printHex("Register", FrameCookie->Register); + W.printEnum("CookieKind", uint16_t(FrameCookie->CookieKind), + makeArrayRef(FrameCookieKinds)); + break; + } + + case S_LDATA32: + case S_GDATA32: + case S_LMANDATA: + case S_GMANDATA: { + DictScope S(W, "DataSym"); + const DataSym *Data; + error(consumeObject(SymData, Data)); + + // In a COFF object file, the DataOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfDataOffset = + reinterpret_cast(&Data->DataOffset) - Subsection.data(); + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + SecOffsetOfDataOffset, + LinkageName)); + StringRef DisplayName = SymData.split('\0').first; + W.printHex("DataOffset", Data->DataOffset); + printTypeIndex("Type", Data->Type); + W.printString("DisplayName", DisplayName); + W.printString("LinkageName", LinkageName); + break; + } + case S_LTHREAD32: + case S_GTHREAD32: { + DictScope S(W, "ThreadLocalDataSym"); + const DataSym *Data; + error(consumeObject(SymData, Data)); + + // In a COFF object file, the DataOffset field is typically zero and has a + // relocation applied to it. Go and look up the symbol for that + // relocation. + ptrdiff_t SecOffsetOfDataOffset = + reinterpret_cast(&Data->DataOffset) - Subsection.data(); + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + SecOffsetOfDataOffset, + LinkageName)); + StringRef DisplayName = SymData.split('\0').first; + W.printHex("DataOffset", Data->DataOffset); + printTypeIndex("Type", Data->Type); + W.printString("DisplayName", DisplayName); + W.printString("LinkageName", LinkageName); + break; + } + + case S_OBJNAME: { + DictScope S(W, "ObjectName"); + const ObjNameSym *ObjName; + error(consumeObject(SymData, ObjName)); + W.printHex("Signature", ObjName->Signature); + StringRef ObjectName = SymData.split('\0').first; + W.printString("ObjectName", ObjectName); + break; + } + + case S_COMPILE3: { + DictScope S(W, "CompilerFlags"); + const CompileSym3 *CompFlags; + error(consumeObject(SymData, CompFlags)); + W.printEnum("Language", CompFlags->getLanguage(), + makeArrayRef(SourceLanguages)); + W.printFlags("Flags", CompFlags->flags & ~0xff, + makeArrayRef(CompileSym3Flags)); + W.printEnum("Machine", unsigned(CompFlags->Machine), + makeArrayRef(CPUTypeNames)); + std::string FrontendVersion; + { + raw_string_ostream Out(FrontendVersion); + Out << CompFlags->VersionFrontendMajor << '.' + << CompFlags->VersionFrontendMinor << '.' + << CompFlags->VersionFrontendBuild << '.' + << CompFlags->VersionFrontendQFE; + } + std::string BackendVersion; + { + raw_string_ostream Out(BackendVersion); + Out << CompFlags->VersionBackendMajor << '.' + << CompFlags->VersionBackendMinor << '.' + << CompFlags->VersionBackendBuild << '.' + << CompFlags->VersionBackendQFE; + } + W.printString("FrontendVersion", FrontendVersion); + W.printString("BackendVersion", BackendVersion); + StringRef VersionName = SymData.split('\0').first; + W.printString("VersionName", VersionName); + break; + } + + case S_FRAMEPROC: { + DictScope S(W, "FrameProc"); + const FrameProcSym *FrameProc; + error(consumeObject(SymData, FrameProc)); + W.printHex("TotalFrameBytes", FrameProc->TotalFrameBytes); + W.printHex("PaddingFrameBytes", FrameProc->PaddingFrameBytes); + W.printHex("OffsetToPadding", FrameProc->OffsetToPadding); + W.printHex("BytesOfCalleeSavedRegisters", FrameProc->BytesOfCalleeSavedRegisters); + W.printHex("OffsetOfExceptionHandler", FrameProc->OffsetOfExceptionHandler); + W.printHex("SectionIdOfExceptionHandler", FrameProc->SectionIdOfExceptionHandler); + W.printFlags("Flags", FrameProc->Flags, makeArrayRef(FrameProcSymFlags)); + break; + } + + case S_UDT: + case S_COBOLUDT: { + DictScope S(W, "UDT"); + const UDTSym *UDT; + error(consumeObject(SymData, UDT)); + printTypeIndex("Type", UDT->Type); + StringRef UDTName = SymData.split('\0').first; + W.printString("UDTName", UDTName); + break; + } + + case S_BPREL32: { + DictScope S(W, "BPRelativeSym"); + const BPRelativeSym *BPRel; + error(consumeObject(SymData, BPRel)); + W.printHex("Offset", BPRel->Offset); + printTypeIndex("Type", BPRel->Type); + StringRef VarName = SymData.split('\0').first; + W.printString("VarName", VarName); + break; + } + + case S_REGREL32: { + DictScope S(W, "RegRelativeSym"); + const RegRelativeSym *RegRel; + error(consumeObject(SymData, RegRel)); + W.printHex("Offset", RegRel->Offset); + printTypeIndex("Type", RegRel->Type); + W.printHex("Register", RegRel->Register); + StringRef VarName = SymData.split('\0').first; + W.printString("VarName", VarName); + break; + } + + case S_BUILDINFO: { + DictScope S(W, "BuildInfo"); + const BuildInfoSym *BuildInfo; + error(consumeObject(SymData, BuildInfo)); + W.printNumber("BuildId", BuildInfo->BuildId); + break; + } + + case S_CONSTANT: + case S_MANCONSTANT: { + DictScope S(W, "Constant"); + const ConstantSym *Constant; + error(consumeObject(SymData, Constant)); + printTypeIndex("Type", Constant->Type); + APSInt Value; + error(decodeNumerictLeaf(SymData, Value)); + W.printNumber("Value", Value); + StringRef Name = SymData.split('\0').first; + W.printString("Name", Name); + break; + } + + default: { + DictScope S(W, "UnknownSym"); + W.printHex("Type", unsigned(Type)); + W.printHex("Size", Rec->RecordLength); + W.printBinaryBlock("SymData", SymData); + break; + } + } + } +} + +StringRef getRemainingTypeBytes(const TypeRecord *Rec, const char *Start) { + ptrdiff_t StartOffset = Start - reinterpret_cast(Rec); + size_t RecSize = Rec->Len + 2; + assert(StartOffset >= 0 && "negative start-offset!"); + assert(static_cast(StartOffset) <= RecSize && + "Start beyond the end of Rec"); + return StringRef(Start, RecSize - StartOffset); +} + +StringRef getRemainingBytesAsString(const TypeRecord *Rec, const char *Start) { + StringRef Remaining = getRemainingTypeBytes(Rec, Start); + StringRef Leading, Trailing; + std::tie(Leading, Trailing) = Remaining.split('\0'); + return Leading; +} + +StringRef COFFDumper::getTypeName(TypeIndex TI) { + if (TI.isNoType()) + return ""; + + if (TI.isSimple()) { + // This is a simple type. + for (const auto &SimpleTypeName : SimpleTypeNames) { + if (SimpleTypeName.Value == TI.getSimpleKind()) { + if (TI.getSimpleMode() == SimpleTypeMode::Direct) + return SimpleTypeName.Name.drop_back(1); + // Otherwise, this is a pointer type. We gloss over the distinction + // between near, far, 64, 32, etc, and just give a pointer type. + return SimpleTypeName.Name; + } + } + return ""; + } + + // User-defined type. + StringRef UDTName; + unsigned UDTIndex = TI.getIndex() - 0x1000; + if (UDTIndex < CVUDTNames.size()) + return CVUDTNames[UDTIndex]; + + return ""; +} + +void COFFDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { + StringRef TypeName; + if (!TI.isNoType()) + TypeName = getTypeName(TI); + if (!TypeName.empty()) + W.printHex(FieldName, TypeName, TI.getIndex()); + else + W.printHex(FieldName, TI.getIndex()); +} + +static StringRef getLeafTypeName(LeafType LT) { + switch (LT) { + case LF_STRING_ID: return "StringId"; + case LF_FIELDLIST: return "FieldList"; + case LF_ARGLIST: + case LF_SUBSTR_LIST: return "ArgList"; + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: return "ClassType"; + case LF_UNION: return "UnionType"; + case LF_ENUM: return "EnumType"; + case LF_ARRAY: return "ArrayType"; + case LF_VFTABLE: return "VFTableType"; + case LF_MFUNC_ID: return "MemberFuncId"; + case LF_PROCEDURE: return "ProcedureType"; + case LF_MFUNCTION: return "MemberFunctionType"; + case LF_METHODLIST: return "MethodListEntry"; + case LF_FUNC_ID: return "FuncId"; + case LF_TYPESERVER2: return "TypeServer2"; + case LF_POINTER: return "PointerType"; + case LF_MODIFIER: return "TypeModifier"; + case LF_VTSHAPE: return "VTableShape"; + case LF_UDT_SRC_LINE: return "UDTSrcLine"; + case LF_BUILDINFO: return "BuildInfo"; + default: break; + } + return "UnknownLeaf"; +} + +void COFFDumper::printCodeViewTypeSection(StringRef SectionName, + const SectionRef &Section) { + ListScope D(W, "CodeViewTypes"); + W.printNumber("Section", SectionName, Obj->getSectionID(Section)); + StringRef Data; + error(Section.getContents(Data)); + W.printBinaryBlock("Data", Data); + + unsigned Magic = *reinterpret_cast(Data.data()); + W.printHex("Magic", Magic); + + Data = Data.drop_front(4); + + while (!Data.empty()) { + const TypeRecord *Rec; + error(consumeObject(Data, Rec)); + auto Leaf = static_cast(uint16_t(Rec->Leaf)); + + // This record is 'Len - 2' bytes, and the next one starts immediately + // afterwards. + StringRef LeafData = Data.substr(0, Rec->Len - 2); + StringRef RemainingData = Data.drop_front(LeafData.size()); + + // Find the name of this leaf type. + StringRef LeafName = getLeafTypeName(Leaf); + DictScope S(W, LeafName); + unsigned NextTypeIndex = 0x1000 + CVUDTNames.size(); + W.printEnum("LeafType", unsigned(Leaf), makeArrayRef(LeafTypeNames)); + W.printHex("TypeIndex", NextTypeIndex); + + // Fill this in inside the switch to get something in CVUDTNames. + StringRef Name; + + switch (Leaf) { default: { - if (opts::CodeViewSubsectionBytes) { - ListScope S(W, "Record"); - W.printHex("Size", Size); - W.printHex("Type", Type); + W.printHex("Size", Rec->Len); + if (opts::CodeViewSubsectionBytes) + W.printBinaryBlock("LeafData", LeafData); + break; + } + + case LF_STRING_ID: { + const StringId *String; + error(consumeObject(LeafData, String)); + W.printHex("Id", String->id.getIndex()); + StringRef StringData = getRemainingBytesAsString(Rec, LeafData.data()); + W.printString("StringData", StringData); + // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. + Name = StringData; + break; + } - StringRef Contents = DE.getData().substr(Offset, Size); - W.printBinaryBlock("Contents", Contents); + case LF_FIELDLIST: { + W.printHex("Size", Rec->Len); + // FieldList has no fixed prefix that can be described with a struct. All + // the bytes must be interpreted as more records. + printCodeViewFieldList(LeafData); + break; + } + + case LF_ARGLIST: + case LF_SUBSTR_LIST: { + const ArgList *Args; + error(consumeObject(LeafData, Args)); + W.printNumber("NumArgs", Args->NumArgs); + ListScope Arguments(W, "Arguments"); + SmallString<256> TypeName("("); + for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { + const TypeIndex *Type; + error(consumeObject(LeafData, Type)); + printTypeIndex("ArgType", *Type); + StringRef ArgTypeName = getTypeName(*Type); + TypeName.append(ArgTypeName); + if (ArgI + 1 != Args->NumArgs) + TypeName.append(", "); } + TypeName.push_back(')'); + Name = TypeNames.insert(TypeName).first->getKey(); + break; + } - Offset += Size; + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: { + const ClassType *Class; + error(consumeObject(LeafData, Class)); + W.printNumber("MemberCount", Class->MemberCount); + uint16_t Props = Class->Properties; + W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + printTypeIndex("FieldList", Class->FieldList); + printTypeIndex("DerivedFrom", Class->DerivedFrom); + printTypeIndex("VShape", Class->VShape); + uint64_t SizeOf; + error(decodeUIntLeaf(LeafData, SizeOf)); + W.printNumber("SizeOf", SizeOf); + StringRef LinkageName; + std::tie(Name, LinkageName) = LeafData.split('\0'); + W.printString("Name", Name); + if (Props & uint16_t(ClassOptions::HasUniqueName)) { + LinkageName = getRemainingBytesAsString(Rec, LinkageName.data()); + if (LinkageName.empty()) + return error(object_error::parse_failed); + W.printString("LinkageName", LinkageName); + } break; } + + case LF_UNION: { + const UnionType *Union; + error(consumeObject(LeafData, Union)); + W.printNumber("MemberCount", Union->MemberCount); + uint16_t Props = Union->Properties; + W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + printTypeIndex("FieldList", Union->FieldList); + uint64_t SizeOf; + error(decodeUIntLeaf(LeafData, SizeOf)); + W.printNumber("SizeOf", SizeOf); + StringRef LinkageName; + std::tie(Name, LinkageName) = LeafData.split('\0'); + W.printString("Name", Name); + if (Props & uint16_t(ClassOptions::HasUniqueName)) { + LinkageName = getRemainingBytesAsString(Rec, LinkageName.data()); + if (LinkageName.empty()) + return error(object_error::parse_failed); + W.printString("LinkageName", LinkageName); + } + break; + } + + case LF_ENUM: { + const EnumType *Enum; + error(consumeObject(LeafData, Enum)); + W.printNumber("NumEnumerators", Enum->NumEnumerators); + W.printFlags("Properties", uint16_t(Enum->Properties), + makeArrayRef(ClassOptionNames)); + printTypeIndex("UnderlyingType", Enum->UnderlyingType); + printTypeIndex("FieldListType", Enum->FieldListType); + Name = LeafData.split('\0').first; + W.printString("Name", Name); + break; + } + + case LF_ARRAY: { + const ArrayType *AT; + error(consumeObject(LeafData, AT)); + printTypeIndex("ElementType", AT->ElementType); + printTypeIndex("IndexType", AT->IndexType); + uint64_t SizeOf; + error(decodeUIntLeaf(LeafData, SizeOf)); + W.printNumber("SizeOf", SizeOf); + Name = LeafData.split('\0').first; + W.printString("Name", Name); + break; } + + case LF_VFTABLE: { + const VFTableType *VFT; + error(consumeObject(LeafData, VFT)); + printTypeIndex("CompleteClass", VFT->CompleteClass); + printTypeIndex("OverriddenVFTable", VFT->OverriddenVFTable); + W.printHex("VFPtrOffset", VFT->VFPtrOffset); + StringRef NamesData = LeafData.substr(0, VFT->NamesLen); + std::tie(Name, NamesData) = NamesData.split('\0'); + W.printString("VFTableName", Name); + while (!NamesData.empty()) { + StringRef MethodName; + std::tie(MethodName, NamesData) = NamesData.split('\0'); + W.printString("MethodName", MethodName); + } + break; + } + + case LF_MFUNC_ID: { + const MemberFuncId *Id; + error(consumeObject(LeafData, Id)); + printTypeIndex("ClassType", Id->ClassType); + printTypeIndex("FunctionType", Id->FunctionType); + Name = LeafData.split('\0').first; + W.printString("Name", Name); + break; + } + + case LF_PROCEDURE: { + const ProcedureType *Proc; + error(consumeObject(LeafData, Proc)); + printTypeIndex("ReturnType", Proc->ReturnType); + W.printEnum("CallingConvention", uint8_t(Proc->CallConv), + makeArrayRef(CallingConventions)); + W.printFlags("FunctionOptions", uint8_t(Proc->Options), + makeArrayRef(FunctionOptionEnum)); + W.printNumber("NumParameters", Proc->NumParameters); + printTypeIndex("ArgListType", Proc->ArgListType); + + StringRef ReturnTypeName = getTypeName(Proc->ReturnType); + StringRef ArgListTypeName = getTypeName(Proc->ArgListType); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ArgListTypeName); + Name = TypeNames.insert(TypeName).first->getKey(); + break; + } + + case LF_MFUNCTION: { + const MemberFunctionType *MemberFunc; + error(consumeObject(LeafData, MemberFunc)); + printTypeIndex("ReturnType", MemberFunc->ReturnType); + printTypeIndex("ClassType", MemberFunc->ClassType); + printTypeIndex("ThisType", MemberFunc->ThisType); + W.printEnum("CallingConvention", uint8_t(MemberFunc->CallConv), + makeArrayRef(CallingConventions)); + W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options), + makeArrayRef(FunctionOptionEnum)); + W.printNumber("NumParameters", MemberFunc->NumParameters); + printTypeIndex("ArgListType", MemberFunc->ArgListType); + W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment); + + StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType); + StringRef ClassTypeName = getTypeName(MemberFunc->ClassType); + StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ClassTypeName); + TypeName.append("::"); + TypeName.append(ArgListTypeName); + Name = TypeNames.insert(TypeName).first->getKey(); + break; + } + + case LF_METHODLIST: { + while (!LeafData.empty()) { + const MethodListEntry *Method; + error(consumeObject(LeafData, Method)); + ListScope S(W, "Method"); + printMemberAttributes(Method->Attrs); + printTypeIndex("Type", Method->Type); + if (Method->isIntroducedVirtual()) { + const little32_t *VFTOffsetPtr; + error(consumeObject(LeafData, VFTOffsetPtr)); + W.printHex("VFTableOffset", *VFTOffsetPtr); + } + } + break; + } + + case LF_FUNC_ID: { + const FuncId *Func; + error(consumeObject(LeafData, Func)); + printTypeIndex("ParentScope", Func->ParentScope); + printTypeIndex("FunctionType", Func->FunctionType); + StringRef Name, Null; + std::tie(Name, Null) = LeafData.split('\0'); + W.printString("Name", Name); + break; + } + + case LF_TYPESERVER2: { + const TypeServer2 *TypeServer; + error(consumeObject(LeafData, TypeServer)); + W.printBinary("Signature", StringRef(TypeServer->Signature, 16)); + W.printNumber("Age", TypeServer->Age); + Name = LeafData.split('\0').first; + W.printString("Name", Name); + break; + } + + case LF_POINTER: { + const PointerType *Ptr; + error(consumeObject(LeafData, Ptr)); + printTypeIndex("PointeeType", Ptr->PointeeType); + W.printHex("PointerAttributes", Ptr->Attrs); + W.printEnum("PtrType", unsigned(Ptr->getPtrKind()), + makeArrayRef(PtrTypeNames)); + W.printEnum("PtrMode", unsigned(Ptr->getPtrMode()), + makeArrayRef(PtrModeNames)); + W.printNumber("IsFlat", Ptr->isFlat()); + W.printNumber("IsConst", Ptr->isConst()); + W.printNumber("IsVolatile", Ptr->isVolatile()); + W.printNumber("IsUnaligned", Ptr->isUnaligned()); + + if (Ptr->isPointerToMember()) { + const PointerToMemberTail *PMT; + error(consumeObject(LeafData, PMT)); + printTypeIndex("ClassType", PMT->ClassType); + W.printEnum("Representation", PMT->Representation, + makeArrayRef(PtrMemberRepNames)); + + StringRef PointeeName = getTypeName(Ptr->PointeeType); + StringRef ClassName = getTypeName(PMT->ClassType); + SmallString<256> TypeName(PointeeName); + TypeName.push_back(' '); + TypeName.append(ClassName); + TypeName.append("::*"); + Name = TypeNames.insert(TypeName).first->getKey(); + } else { + W.printBinaryBlock("TailData", LeafData); + + SmallString<256> TypeName; + if (Ptr->isConst()) + TypeName.append("const "); + if (Ptr->isVolatile()) + TypeName.append("volatile "); + if (Ptr->isUnaligned()) + TypeName.append("__unaligned "); + + TypeName.append(getTypeName(Ptr->PointeeType)); + + if (Ptr->getPtrMode() == PointerType::LValueReference) + TypeName.append("&"); + else if (Ptr->getPtrMode() == PointerType::RValueReference) + TypeName.append("&&"); + else if (Ptr->getPtrMode() == PointerType::Pointer) + TypeName.append("*"); + + Name = TypeNames.insert(TypeName).first->getKey(); + } + break; + } + + case LF_MODIFIER: { + const TypeModifier *Mod; + error(consumeObject(LeafData, Mod)); + printTypeIndex("ModifiedType", Mod->ModifiedType); + W.printFlags("Modifiers", Mod->Modifiers, + makeArrayRef(TypeModifierNames)); + + StringRef ModifiedName = getTypeName(Mod->ModifiedType); + SmallString<256> TypeName; + if (Mod->Modifiers & TypeModifier::Const) + TypeName.append("const "); + if (Mod->Modifiers & TypeModifier::Volatile) + TypeName.append("volatile "); + if (Mod->Modifiers & TypeModifier::Unaligned) + TypeName.append("__unaligned "); + TypeName.append(ModifiedName); + Name = TypeNames.insert(TypeName).first->getKey(); + break; + } + + case LF_VTSHAPE: { + const VTableShape *Shape; + error(consumeObject(LeafData, Shape)); + unsigned VFEntryCount = Shape->VFEntryCount; + W.printNumber("VFEntryCount", VFEntryCount); + // We could print out whether the methods are near or far, but in practice + // today everything is CV_VTS_near32, so it's just noise. + break; + } + + case LF_UDT_SRC_LINE: { + const UDTSrcLine *Line; + error(consumeObject(LeafData, Line)); + printTypeIndex("UDT", Line->UDT); + printTypeIndex("SourceFile", Line->SourceFile); + W.printNumber("LineNumber", Line->LineNumber); + break; + } + + case LF_BUILDINFO: { + const BuildInfo *Args; + error(consumeObject(LeafData, Args)); + W.printNumber("NumArgs", Args->NumArgs); + + ListScope Arguments(W, "Arguments"); + for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { + const TypeIndex *Type; + error(consumeObject(LeafData, Type)); + printTypeIndex("ArgType", *Type); + } + break; + } + } + + CVUDTNames.push_back(Name); + + Data = RemainingData; + // FIXME: The stream contains LF_PAD bytes that we need to ignore, but those + // are typically included in LeafData. We may need to call skipPadding() if + // we ever find a record that doesn't count those bytes. } +} + +static StringRef skipPadding(StringRef Data) { + if (Data.empty()) + return Data; + uint8_t Leaf = Data.front(); + if (Leaf < LF_PAD0) + return Data; + // Leaf is greater than 0xf0. We should advance by the number of bytes in the + // low 4 bits. + return Data.drop_front(Leaf & 0x0F); +} + +void COFFDumper::printMemberAttributes(MemberAttributes Attrs) { + W.printEnum("AccessSpecifier", uint8_t(Attrs.getAccess()), + makeArrayRef(MemberAccessNames)); + auto MK = Attrs.getMethodKind(); + // Data members will be vanilla. Don't try to print a method kind for them. + if (MK != MethodKind::Vanilla) + W.printEnum("MethodKind", unsigned(MK), makeArrayRef(MemberKindNames)); + if (Attrs.getFlags()) { + W.printFlags("MemberAttributes", unsigned(Attrs.getFlags()), + makeArrayRef(MemberAttributeNames)); + } +} + +void COFFDumper::printCodeViewFieldList(StringRef FieldData) { + while (!FieldData.empty()) { + const ulittle16_t *LeafPtr; + error(consumeObject(FieldData, LeafPtr)); + uint16_t Leaf = *LeafPtr; + switch (Leaf) { + default: + W.printHex("UnknownMember", Leaf); + // We can't advance once we hit an unknown field. The size is not encoded. + return; + + case LF_NESTTYPE: { + const NestedType *Nested; + error(consumeObject(FieldData, Nested)); + DictScope S(W, "NestedType"); + printTypeIndex("Type", Nested->Type); + StringRef Name; + std::tie(Name, FieldData) = FieldData.split('\0'); + W.printString("Name", Name); + break; + } + + case LF_ONEMETHOD: { + const OneMethod *Method; + error(consumeObject(FieldData, Method)); + DictScope S(W, "OneMethod"); + printMemberAttributes(Method->Attrs); + printTypeIndex("Type", Method->Type); + // If virtual, then read the vftable offset. + if (Method->isIntroducedVirtual()) { + const little32_t *VFTOffsetPtr; + error(consumeObject(FieldData, VFTOffsetPtr)); + W.printHex("VFTableOffset", *VFTOffsetPtr); + } + StringRef Name; + std::tie(Name, FieldData) = FieldData.split('\0'); + W.printString("Name", Name); + break; + } + + case LF_METHOD: { + const OverloadedMethod *Method; + error(consumeObject(FieldData, Method)); + DictScope S(W, "OverloadedMethod"); + W.printHex("MethodCount", Method->MethodCount); + W.printHex("MethodListIndex", Method->MethList.getIndex()); + StringRef Name; + std::tie(Name, FieldData) = FieldData.split('\0'); + W.printString("Name", Name); + break; + } - if (InFunctionScope) - error(object_error::parse_failed); + case LF_MEMBER: { + const DataMember *Field; + error(consumeObject(FieldData, Field)); + DictScope S(W, "DataMember"); + printMemberAttributes(Field->Attrs); + printTypeIndex("Type", Field->Type); + uint64_t FieldOffset; + error(decodeUIntLeaf(FieldData, FieldOffset)); + W.printHex("FieldOffset", FieldOffset); + StringRef Name; + std::tie(Name, FieldData) = FieldData.split('\0'); + W.printString("Name", Name); + break; + } + + case LF_STMEMBER: { + const StaticDataMember *Field; + error(consumeObject(FieldData, Field)); + DictScope S(W, "StaticDataMember"); + printMemberAttributes(Field->Attrs); + printTypeIndex("Type", Field->Type); + StringRef Name; + std::tie(Name, FieldData) = FieldData.split('\0'); + W.printString("Name", Name); + break; + } + + case LF_VFUNCTAB: { + const VirtualFunctionPointer *VFTable; + error(consumeObject(FieldData, VFTable)); + DictScope S(W, "VirtualFunctionPointer"); + printTypeIndex("Type", VFTable->Type); + break; + } + + case LF_ENUMERATE: { + const Enumerator *Enum; + error(consumeObject(FieldData, Enum)); + DictScope S(W, "Enumerator"); + printMemberAttributes(Enum->Attrs); + APSInt EnumValue; + error(decodeNumerictLeaf(FieldData, EnumValue)); + W.printNumber("EnumValue", EnumValue); + StringRef Name; + std::tie(Name, FieldData) = FieldData.split('\0'); + W.printString("Name", Name); + break; + } + + case LF_BCLASS: + case LF_BINTERFACE: { + const BaseClass *Base; + error(consumeObject(FieldData, Base)); + DictScope S(W, "BaseClass"); + printMemberAttributes(Base->Attrs); + printTypeIndex("BaseType", Base->BaseType); + uint64_t BaseOffset; + error(decodeUIntLeaf(FieldData, BaseOffset)); + W.printHex("BaseOffset", BaseOffset); + break; + } + + case LF_VBCLASS: + case LF_IVBCLASS: { + const VirtualBaseClass *Base; + error(consumeObject(FieldData, Base)); + DictScope S(W, "VirtualBaseClass"); + printMemberAttributes(Base->Attrs); + printTypeIndex("BaseType", Base->BaseType); + printTypeIndex("VBPtrType", Base->VBPtrType); + uint64_t VBPtrOffset, VBTableIndex; + error(decodeUIntLeaf(FieldData, VBPtrOffset)); + error(decodeUIntLeaf(FieldData, VBTableIndex)); + W.printHex("VBPtrOffset", VBPtrOffset); + W.printHex("VBTableIndex", VBTableIndex); + break; + } + } + + // Handle padding. + FieldData = skipPadding(FieldData); + } } void COFFDumper::printSections() { Index: tools/llvm-readobj/CVLeafTypes.def =================================================================== --- /dev/null +++ tools/llvm-readobj/CVLeafTypes.def @@ -0,0 +1,211 @@ +//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See LEAF_ENUM_e in cvinfo.h. This should match the constants there. +// +//===----------------------------------------------------------------------===// + +#ifndef LEAF_TYPE +#define LEAF_TYPE(ename, value) +#endif + +// 16 bit type records. +LEAF_TYPE(LF_MODIFIER_16t, 0x0001) +LEAF_TYPE(LF_POINTER_16t, 0x0002) +LEAF_TYPE(LF_ARRAY_16t, 0x0003) +LEAF_TYPE(LF_CLASS_16t, 0x0004) +LEAF_TYPE(LF_STRUCTURE_16t, 0x0005) +LEAF_TYPE(LF_UNION_16t, 0x0006) +LEAF_TYPE(LF_ENUM_16t, 0x0007) +LEAF_TYPE(LF_PROCEDURE_16t, 0x0008) +LEAF_TYPE(LF_MFUNCTION_16t, 0x0009) +LEAF_TYPE(LF_VTSHAPE, 0x000a) +LEAF_TYPE(LF_COBOL0_16t, 0x000b) +LEAF_TYPE(LF_COBOL1, 0x000c) +LEAF_TYPE(LF_BARRAY_16t, 0x000d) +LEAF_TYPE(LF_LABEL, 0x000e) +LEAF_TYPE(LF_NULLLEAF, 0x000f) // LF_NULL +LEAF_TYPE(LF_NOTTRAN, 0x0010) +LEAF_TYPE(LF_DIMARRAY_16t, 0x0011) +LEAF_TYPE(LF_VFTPATH_16t, 0x0012) +LEAF_TYPE(LF_PRECOMP_16t, 0x0013) +LEAF_TYPE(LF_ENDPRECOMP, 0x0014) +LEAF_TYPE(LF_OEM_16t, 0x0015) +LEAF_TYPE(LF_TYPESERVER_ST, 0x0016) + +LEAF_TYPE(LF_SKIP_16t, 0x0200) +LEAF_TYPE(LF_ARGLIST_16t, 0x0201) +LEAF_TYPE(LF_DEFARG_16t, 0x0202) +LEAF_TYPE(LF_LIST, 0x0203) +LEAF_TYPE(LF_FIELDLIST_16t, 0x0204) +LEAF_TYPE(LF_DERIVED_16t, 0x0205) +LEAF_TYPE(LF_BITFIELD_16t, 0x0206) +LEAF_TYPE(LF_METHODLIST_16t, 0x0207) +LEAF_TYPE(LF_DIMCONU_16t, 0x0208) +LEAF_TYPE(LF_DIMCONLU_16t, 0x0209) +LEAF_TYPE(LF_DIMVARU_16t, 0x020a) +LEAF_TYPE(LF_DIMVARLU_16t, 0x020b) +LEAF_TYPE(LF_REFSYM, 0x020c) + +// 16 bit member types. Generally not length prefixed. +LEAF_TYPE(LF_BCLASS_16t, 0x0400) +LEAF_TYPE(LF_VBCLASS_16t, 0x0401) +LEAF_TYPE(LF_IVBCLASS_16t, 0x0402) +LEAF_TYPE(LF_ENUMERATE_ST, 0x0403) +LEAF_TYPE(LF_FRIENDFCN_16t, 0x0404) +LEAF_TYPE(LF_INDEX_16t, 0x0405) +LEAF_TYPE(LF_MEMBER_16t, 0x0406) +LEAF_TYPE(LF_STMEMBER_16t, 0x0407) +LEAF_TYPE(LF_METHOD_16t, 0x0408) +LEAF_TYPE(LF_NESTTYPE_16t, 0x0409) +LEAF_TYPE(LF_VFUNCTAB_16t, 0x040a) +LEAF_TYPE(LF_FRIENDCLS_16t, 0x040b) +LEAF_TYPE(LF_ONEMETHOD_16t, 0x040c) +LEAF_TYPE(LF_VFUNCOFF_16t, 0x040d) + +LEAF_TYPE(LF_TI16_MAX, 0x1000) + +LEAF_TYPE(LF_MODIFIER, 0x1001) +LEAF_TYPE(LF_POINTER, 0x1002) +LEAF_TYPE(LF_ARRAY_ST, 0x1003) +LEAF_TYPE(LF_CLASS_ST, 0x1004) +LEAF_TYPE(LF_STRUCTURE_ST, 0x1005) +LEAF_TYPE(LF_UNION_ST, 0x1006) +LEAF_TYPE(LF_ENUM_ST, 0x1007) +LEAF_TYPE(LF_PROCEDURE, 0x1008) +LEAF_TYPE(LF_MFUNCTION, 0x1009) +LEAF_TYPE(LF_COBOL0, 0x100a) +LEAF_TYPE(LF_BARRAY, 0x100b) +LEAF_TYPE(LF_DIMARRAY_ST, 0x100c) +LEAF_TYPE(LF_VFTPATH, 0x100d) +LEAF_TYPE(LF_PRECOMP_ST, 0x100e) +LEAF_TYPE(LF_OEM, 0x100f) +LEAF_TYPE(LF_ALIAS_ST, 0x1010) +LEAF_TYPE(LF_OEM2, 0x1011) + +LEAF_TYPE(LF_SKIP, 0x1200) +LEAF_TYPE(LF_ARGLIST, 0x1201) +LEAF_TYPE(LF_DEFARG_ST, 0x1202) +LEAF_TYPE(LF_FIELDLIST, 0x1203) +LEAF_TYPE(LF_DERIVED, 0x1204) +LEAF_TYPE(LF_BITFIELD, 0x1205) +LEAF_TYPE(LF_METHODLIST, 0x1206) +LEAF_TYPE(LF_DIMCONU, 0x1207) +LEAF_TYPE(LF_DIMCONLU, 0x1208) +LEAF_TYPE(LF_DIMVARU, 0x1209) +LEAF_TYPE(LF_DIMVARLU, 0x120a) + +// Member type records. These are generally not length prefixed, and appear +// inside of a field list record. +LEAF_TYPE(LF_BCLASS, 0x1400) +LEAF_TYPE(LF_VBCLASS, 0x1401) +LEAF_TYPE(LF_IVBCLASS, 0x1402) +LEAF_TYPE(LF_FRIENDFCN_ST, 0x1403) +LEAF_TYPE(LF_INDEX, 0x1404) +LEAF_TYPE(LF_MEMBER_ST, 0x1405) +LEAF_TYPE(LF_STMEMBER_ST, 0x1406) +LEAF_TYPE(LF_METHOD_ST, 0x1407) +LEAF_TYPE(LF_NESTTYPE_ST, 0x1408) +LEAF_TYPE(LF_VFUNCTAB, 0x1409) +LEAF_TYPE(LF_FRIENDCLS, 0x140a) +LEAF_TYPE(LF_ONEMETHOD_ST, 0x140b) +LEAF_TYPE(LF_VFUNCOFF, 0x140c) +LEAF_TYPE(LF_NESTTYPEEX_ST, 0x140d) +LEAF_TYPE(LF_MEMBERMODIFY_ST, 0x140e) +LEAF_TYPE(LF_MANAGED_ST, 0x140f) + +LEAF_TYPE(LF_ST_MAX, 0x1500) +LEAF_TYPE(LF_TYPESERVER, 0x1501) +LEAF_TYPE(LF_ENUMERATE, 0x1502) +LEAF_TYPE(LF_ARRAY, 0x1503) +LEAF_TYPE(LF_CLASS, 0x1504) +LEAF_TYPE(LF_STRUCTURE, 0x1505) +LEAF_TYPE(LF_UNION, 0x1506) +LEAF_TYPE(LF_ENUM, 0x1507) +LEAF_TYPE(LF_DIMARRAY, 0x1508) +LEAF_TYPE(LF_PRECOMP, 0x1509) +LEAF_TYPE(LF_ALIAS, 0x150a) +LEAF_TYPE(LF_DEFARG, 0x150b) +LEAF_TYPE(LF_FRIENDFCN, 0x150c) +LEAF_TYPE(LF_MEMBER, 0x150d) +LEAF_TYPE(LF_STMEMBER, 0x150e) +LEAF_TYPE(LF_METHOD, 0x150f) +LEAF_TYPE(LF_NESTTYPE, 0x1510) +LEAF_TYPE(LF_ONEMETHOD, 0x1511) +LEAF_TYPE(LF_NESTTYPEEX, 0x1512) +LEAF_TYPE(LF_MEMBERMODIFY, 0x1513) +LEAF_TYPE(LF_MANAGED, 0x1514) +LEAF_TYPE(LF_TYPESERVER2, 0x1515) +LEAF_TYPE(LF_STRIDED_ARRAY, 0x1516) +LEAF_TYPE(LF_HLSL, 0x1517) +LEAF_TYPE(LF_MODIFIER_EX, 0x1518) +LEAF_TYPE(LF_INTERFACE, 0x1519) +LEAF_TYPE(LF_BINTERFACE, 0x151a) +LEAF_TYPE(LF_VECTOR, 0x151b) +LEAF_TYPE(LF_MATRIX, 0x151c) +LEAF_TYPE(LF_VFTABLE, 0x151d) + +// ID leaf records. Subsequent leaf types may be referenced from .debug$S. + +LEAF_TYPE(LF_FUNC_ID, 0x1601) +LEAF_TYPE(LF_MFUNC_ID, 0x1602) +LEAF_TYPE(LF_BUILDINFO, 0x1603) +LEAF_TYPE(LF_SUBSTR_LIST, 0x1604) +LEAF_TYPE(LF_STRING_ID, 0x1605) +LEAF_TYPE(LF_UDT_SRC_LINE, 0x1606) +LEAF_TYPE(LF_UDT_MOD_SRC_LINE, 0x1607) + +// Numeric leaf types. These are generally contained in other records, and not +// encountered in the main type stream. + +LEAF_TYPE(LF_NUMERIC, 0x8000) +LEAF_TYPE(LF_CHAR, 0x8000) +LEAF_TYPE(LF_SHORT, 0x8001) +LEAF_TYPE(LF_USHORT, 0x8002) +LEAF_TYPE(LF_LONG, 0x8003) +LEAF_TYPE(LF_ULONG, 0x8004) +LEAF_TYPE(LF_REAL32, 0x8005) +LEAF_TYPE(LF_REAL64, 0x8006) +LEAF_TYPE(LF_REAL80, 0x8007) +LEAF_TYPE(LF_REAL128, 0x8008) +LEAF_TYPE(LF_QUADWORD, 0x8009) +LEAF_TYPE(LF_UQUADWORD, 0x800a) +LEAF_TYPE(LF_REAL48, 0x800b) +LEAF_TYPE(LF_COMPLEX32, 0x800c) +LEAF_TYPE(LF_COMPLEX64, 0x800d) +LEAF_TYPE(LF_COMPLEX80, 0x800e) +LEAF_TYPE(LF_COMPLEX128, 0x800f) +LEAF_TYPE(LF_VARSTRING, 0x8010) +LEAF_TYPE(LF_OCTWORD, 0x8017) +LEAF_TYPE(LF_UOCTWORD, 0x8018) +LEAF_TYPE(LF_DECIMAL, 0x8019) +LEAF_TYPE(LF_DATE, 0x801a) +LEAF_TYPE(LF_UTF8STRING, 0x801b) +LEAF_TYPE(LF_REAL16, 0x801c) + +// Padding bytes. These are emitted into alignment bytes in the type stream. + +LEAF_TYPE(LF_PAD0, 0xf0) +LEAF_TYPE(LF_PAD1, 0xf1) +LEAF_TYPE(LF_PAD2, 0xf2) +LEAF_TYPE(LF_PAD3, 0xf3) +LEAF_TYPE(LF_PAD4, 0xf4) +LEAF_TYPE(LF_PAD5, 0xf5) +LEAF_TYPE(LF_PAD6, 0xf6) +LEAF_TYPE(LF_PAD7, 0xf7) +LEAF_TYPE(LF_PAD8, 0xf8) +LEAF_TYPE(LF_PAD9, 0xf9) +LEAF_TYPE(LF_PAD10, 0xfa) +LEAF_TYPE(LF_PAD11, 0xfb) +LEAF_TYPE(LF_PAD12, 0xfc) +LEAF_TYPE(LF_PAD13, 0xfd) +LEAF_TYPE(LF_PAD14, 0xfe) +LEAF_TYPE(LF_PAD15, 0xff) + +#undef LEAF_TYPE Index: tools/llvm-readobj/CVSymbolTypes.def =================================================================== --- /dev/null +++ tools/llvm-readobj/CVSymbolTypes.def @@ -0,0 +1,237 @@ +//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See LEAF_ENUM_e in cvinfo.h. This should match the constants there. +// +//===----------------------------------------------------------------------===// + +#ifndef SYMBOL_TYPE +#define SYMBOL_TYPE(ename, value) +#endif + +// 16 bit symbol types. Not very useful, provided only for reference. +SYMBOL_TYPE(S_COMPILE , 0x0001) +SYMBOL_TYPE(S_REGISTER_16t , 0x0002) +SYMBOL_TYPE(S_CONSTANT_16t , 0x0003) +SYMBOL_TYPE(S_UDT_16t , 0x0004) +SYMBOL_TYPE(S_SSEARCH , 0x0005) +SYMBOL_TYPE(S_END , 0x0006) +SYMBOL_TYPE(S_SKIP , 0x0007) +SYMBOL_TYPE(S_CVRESERVE , 0x0008) +SYMBOL_TYPE(S_OBJNAME_ST , 0x0009) +SYMBOL_TYPE(S_ENDARG , 0x000a) +SYMBOL_TYPE(S_COBOLUDT_16t , 0x000b) +SYMBOL_TYPE(S_MANYREG_16t , 0x000c) +SYMBOL_TYPE(S_RETURN , 0x000d) +SYMBOL_TYPE(S_ENTRYTHIS , 0x000e) +SYMBOL_TYPE(S_BPREL16 , 0x0100) +SYMBOL_TYPE(S_LDATA16 , 0x0101) +SYMBOL_TYPE(S_GDATA16 , 0x0102) +SYMBOL_TYPE(S_PUB16 , 0x0103) +SYMBOL_TYPE(S_LPROC16 , 0x0104) +SYMBOL_TYPE(S_GPROC16 , 0x0105) +SYMBOL_TYPE(S_THUNK16 , 0x0106) +SYMBOL_TYPE(S_BLOCK16 , 0x0107) +SYMBOL_TYPE(S_WITH16 , 0x0108) +SYMBOL_TYPE(S_LABEL16 , 0x0109) +SYMBOL_TYPE(S_CEXMODEL16 , 0x010a) +SYMBOL_TYPE(S_VFTABLE16 , 0x010b) +SYMBOL_TYPE(S_REGREL16 , 0x010c) +SYMBOL_TYPE(S_BPREL32_16t , 0x0200) +SYMBOL_TYPE(S_LDATA32_16t , 0x0201) +SYMBOL_TYPE(S_GDATA32_16t , 0x0202) +SYMBOL_TYPE(S_PUB32_16t , 0x0203) +SYMBOL_TYPE(S_LPROC32_16t , 0x0204) +SYMBOL_TYPE(S_GPROC32_16t , 0x0205) +SYMBOL_TYPE(S_THUNK32_ST , 0x0206) +SYMBOL_TYPE(S_BLOCK32_ST , 0x0207) +SYMBOL_TYPE(S_WITH32_ST , 0x0208) +SYMBOL_TYPE(S_LABEL32_ST , 0x0209) +SYMBOL_TYPE(S_CEXMODEL32 , 0x020a) +SYMBOL_TYPE(S_VFTABLE32_16t , 0x020b) +SYMBOL_TYPE(S_REGREL32_16t , 0x020c) +SYMBOL_TYPE(S_LTHREAD32_16t , 0x020d) +SYMBOL_TYPE(S_GTHREAD32_16t , 0x020e) +SYMBOL_TYPE(S_SLINK32 , 0x020f) +SYMBOL_TYPE(S_LPROCMIPS_16t , 0x0300) +SYMBOL_TYPE(S_GPROCMIPS_16t , 0x0301) +SYMBOL_TYPE(S_PROCREF_ST , 0x0400) +SYMBOL_TYPE(S_DATAREF_ST , 0x0401) +SYMBOL_TYPE(S_ALIGN , 0x0402) +SYMBOL_TYPE(S_LPROCREF_ST , 0x0403) +SYMBOL_TYPE(S_OEM , 0x0404) + +// All post 16 bit symbol types have the 0x1000 bit set. +SYMBOL_TYPE(S_TI16_MAX , 0x1000) + +// Mostly unused "start" symbol types. +SYMBOL_TYPE(S_REGISTER_ST , 0x1001) +SYMBOL_TYPE(S_CONSTANT_ST , 0x1002) +SYMBOL_TYPE(S_UDT_ST , 0x1003) +SYMBOL_TYPE(S_COBOLUDT_ST , 0x1004) +SYMBOL_TYPE(S_MANYREG_ST , 0x1005) +SYMBOL_TYPE(S_BPREL32_ST , 0x1006) +SYMBOL_TYPE(S_LDATA32_ST , 0x1007) +SYMBOL_TYPE(S_GDATA32_ST , 0x1008) +SYMBOL_TYPE(S_PUB32_ST , 0x1009) +SYMBOL_TYPE(S_LPROC32_ST , 0x100a) +SYMBOL_TYPE(S_GPROC32_ST , 0x100b) +SYMBOL_TYPE(S_VFTABLE32 , 0x100c) +SYMBOL_TYPE(S_REGREL32_ST , 0x100d) +SYMBOL_TYPE(S_LTHREAD32_ST , 0x100e) +SYMBOL_TYPE(S_GTHREAD32_ST , 0x100f) +SYMBOL_TYPE(S_LPROCMIPS_ST , 0x1010) +SYMBOL_TYPE(S_GPROCMIPS_ST , 0x1011) + +// Information about the frame layout of a procedure. +SYMBOL_TYPE(S_FRAMEPROC , 0x1012) + +SYMBOL_TYPE(S_COMPILE2_ST , 0x1013) +SYMBOL_TYPE(S_MANYREG2_ST , 0x1014) +SYMBOL_TYPE(S_LPROCIA64_ST , 0x1015) +SYMBOL_TYPE(S_GPROCIA64_ST , 0x1016) +SYMBOL_TYPE(S_LOCALSLOT_ST , 0x1017) +SYMBOL_TYPE(S_PARAMSLOT_ST , 0x1018) +SYMBOL_TYPE(S_ANNOTATION , 0x1019) +SYMBOL_TYPE(S_GMANPROC_ST , 0x101a) +SYMBOL_TYPE(S_LMANPROC_ST , 0x101b) +SYMBOL_TYPE(S_RESERVED1 , 0x101c) +SYMBOL_TYPE(S_RESERVED2 , 0x101d) +SYMBOL_TYPE(S_RESERVED3 , 0x101e) +SYMBOL_TYPE(S_RESERVED4 , 0x101f) +SYMBOL_TYPE(S_LMANDATA_ST , 0x1020) +SYMBOL_TYPE(S_GMANDATA_ST , 0x1021) +SYMBOL_TYPE(S_MANFRAMEREL_ST, 0x1022) +SYMBOL_TYPE(S_MANREGISTER_ST, 0x1023) +SYMBOL_TYPE(S_MANSLOT_ST , 0x1024) +SYMBOL_TYPE(S_MANMANYREG_ST , 0x1025) +SYMBOL_TYPE(S_MANREGREL_ST , 0x1026) +SYMBOL_TYPE(S_MANMANYREG2_ST, 0x1027) +SYMBOL_TYPE(S_MANTYPREF , 0x1028) +SYMBOL_TYPE(S_UNAMESPACE_ST , 0x1029) + +// End of S_*_ST symbols, which do not appear to be generated by modern +// compilers. +SYMBOL_TYPE(S_ST_MAX , 0x1100) + +SYMBOL_TYPE(S_OBJNAME , 0x1101) +SYMBOL_TYPE(S_THUNK32 , 0x1102) +SYMBOL_TYPE(S_BLOCK32 , 0x1103) +SYMBOL_TYPE(S_WITH32 , 0x1104) +SYMBOL_TYPE(S_LABEL32 , 0x1105) +SYMBOL_TYPE(S_REGISTER , 0x1106) +SYMBOL_TYPE(S_CONSTANT , 0x1107) +SYMBOL_TYPE(S_UDT , 0x1108) +SYMBOL_TYPE(S_COBOLUDT , 0x1109) +SYMBOL_TYPE(S_MANYREG , 0x110a) +SYMBOL_TYPE(S_BPREL32 , 0x110b) +SYMBOL_TYPE(S_LDATA32 , 0x110c) +SYMBOL_TYPE(S_GDATA32 , 0x110d) +SYMBOL_TYPE(S_PUB32 , 0x110e) +SYMBOL_TYPE(S_LPROC32 , 0x110f) +SYMBOL_TYPE(S_GPROC32 , 0x1110) +SYMBOL_TYPE(S_REGREL32 , 0x1111) +SYMBOL_TYPE(S_LTHREAD32 , 0x1112) +SYMBOL_TYPE(S_GTHREAD32 , 0x1113) +SYMBOL_TYPE(S_LPROCMIPS , 0x1114) +SYMBOL_TYPE(S_GPROCMIPS , 0x1115) +SYMBOL_TYPE(S_COMPILE2 , 0x1116) +SYMBOL_TYPE(S_MANYREG2 , 0x1117) +SYMBOL_TYPE(S_LPROCIA64 , 0x1118) +SYMBOL_TYPE(S_GPROCIA64 , 0x1119) +SYMBOL_TYPE(S_LOCALSLOT , 0x111a) +SYMBOL_TYPE(S_PARAMSLOT , 0x111b) + +// Managed code symbols. +SYMBOL_TYPE(S_LMANDATA , 0x111c) +SYMBOL_TYPE(S_GMANDATA , 0x111d) +SYMBOL_TYPE(S_MANFRAMEREL , 0x111e) +SYMBOL_TYPE(S_MANREGISTER , 0x111f) +SYMBOL_TYPE(S_MANSLOT , 0x1120) +SYMBOL_TYPE(S_MANMANYREG , 0x1121) +SYMBOL_TYPE(S_MANREGREL , 0x1122) +SYMBOL_TYPE(S_MANMANYREG2 , 0x1123) +SYMBOL_TYPE(S_UNAMESPACE , 0x1124) +SYMBOL_TYPE(S_PROCREF , 0x1125) +SYMBOL_TYPE(S_DATAREF , 0x1126) +SYMBOL_TYPE(S_LPROCREF , 0x1127) +SYMBOL_TYPE(S_ANNOTATIONREF , 0x1128) +SYMBOL_TYPE(S_TOKENREF , 0x1129) +SYMBOL_TYPE(S_GMANPROC , 0x112a) +SYMBOL_TYPE(S_LMANPROC , 0x112b) +SYMBOL_TYPE(S_TRAMPOLINE , 0x112c) +SYMBOL_TYPE(S_MANCONSTANT , 0x112d) +SYMBOL_TYPE(S_ATTR_FRAMEREL , 0x112e) +SYMBOL_TYPE(S_ATTR_REGISTER , 0x112f) +SYMBOL_TYPE(S_ATTR_REGREL , 0x1130) +SYMBOL_TYPE(S_ATTR_MANYREG , 0x1131) + + +SYMBOL_TYPE(S_SEPCODE , 0x1132) +SYMBOL_TYPE(S_LOCAL_2005 , 0x1133) +SYMBOL_TYPE(S_DEFRANGE_2005 , 0x1134) +SYMBOL_TYPE(S_DEFRANGE2_2005, 0x1135) +SYMBOL_TYPE(S_SECTION , 0x1136) +SYMBOL_TYPE(S_COFFGROUP , 0x1137) +SYMBOL_TYPE(S_EXPORT , 0x1138) +SYMBOL_TYPE(S_CALLSITEINFO , 0x1139) +SYMBOL_TYPE(S_FRAMECOOKIE , 0x113a) +SYMBOL_TYPE(S_DISCARDED , 0x113b) +SYMBOL_TYPE(S_COMPILE3 , 0x113c) +SYMBOL_TYPE(S_ENVBLOCK , 0x113d) +SYMBOL_TYPE(S_LOCAL , 0x113e) +SYMBOL_TYPE(S_DEFRANGE , 0x113f) +SYMBOL_TYPE(S_DEFRANGE_SUBFIELD, 0x1140) +SYMBOL_TYPE(S_DEFRANGE_REGISTER, 0x1141) +SYMBOL_TYPE(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142) +SYMBOL_TYPE(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143) +SYMBOL_TYPE(S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144) +SYMBOL_TYPE(S_DEFRANGE_REGISTER_REL, 0x1145) + +// Current symbol types for most procedures as of this writing. +SYMBOL_TYPE(S_LPROC32_ID , 0x1146) +SYMBOL_TYPE(S_GPROC32_ID , 0x1147) +SYMBOL_TYPE(S_LPROCMIPS_ID , 0x1148) +SYMBOL_TYPE(S_GPROCMIPS_ID , 0x1149) +SYMBOL_TYPE(S_LPROCIA64_ID , 0x114a) +SYMBOL_TYPE(S_GPROCIA64_ID , 0x114b) + +SYMBOL_TYPE(S_BUILDINFO , 0x114c) + +// Inlined call site delimiters. +SYMBOL_TYPE(S_INLINESITE , 0x114d) +SYMBOL_TYPE(S_INLINESITE_END , 0x114e) + +// Procedure info end delimiter. +SYMBOL_TYPE(S_PROC_ID_END , 0x114f) + +SYMBOL_TYPE(S_DEFRANGE_HLSL , 0x1150) +SYMBOL_TYPE(S_GDATA_HLSL , 0x1151) +SYMBOL_TYPE(S_LDATA_HLSL , 0x1152) +SYMBOL_TYPE(S_FILESTATIC , 0x1153) +SYMBOL_TYPE(S_LOCAL_DPC_GROUPSHARED, 0x1154) +SYMBOL_TYPE(S_LPROC32_DPC , 0x1155) +SYMBOL_TYPE(S_LPROC32_DPC_ID , 0x1156) +SYMBOL_TYPE(S_DEFRANGE_DPC_PTR_TAG, 0x1157) +SYMBOL_TYPE(S_DPC_SYM_TAG_MAP, 0x1158) +SYMBOL_TYPE(S_ARMSWITCHTABLE , 0x1159) +SYMBOL_TYPE(S_CALLEES , 0x115a) +SYMBOL_TYPE(S_CALLERS , 0x115b) +SYMBOL_TYPE(S_POGODATA , 0x115c) +SYMBOL_TYPE(S_INLINESITE2 , 0x115d) +SYMBOL_TYPE(S_HEAPALLOCSITE , 0x115e) +SYMBOL_TYPE(S_MOD_TYPEREF , 0x115f) +SYMBOL_TYPE(S_REF_MINIPDB , 0x1160) +SYMBOL_TYPE(S_PDBMAP , 0x1161) +SYMBOL_TYPE(S_GDATA_HLSL32 , 0x1162) +SYMBOL_TYPE(S_LDATA_HLSL32 , 0x1163) +SYMBOL_TYPE(S_GDATA_HLSL32_EX, 0x1164) +SYMBOL_TYPE(S_LDATA_HLSL32_EX, 0x1165) + +#undef SYMBOL_TYPE Index: tools/llvm-readobj/CodeView.h =================================================================== --- /dev/null +++ tools/llvm-readobj/CodeView.h @@ -0,0 +1,643 @@ +//===-- 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. +}; + +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. +}; + +/// These values correspond to the CV_CFL_LANG enumeration, and are documented +/// here: https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx +enum SourceLanguage : uint8_t { + C = 0x00, + Cpp = 0x01, + Fortran = 0x02, + Masm = 0x03, + Pascal = 0x04, + Basic = 0x05, + Cobol = 0x06, + Link = 0x07, + Cvtres = 0x08, + Cvtpgd = 0x09, + CSharp = 0x0a, + VB = 0x0b, + ILAsm = 0x0c, + Java = 0x0d, + JScript = 0x0e, + MSIL = 0x0f, + HLSL = 0x10 +}; + +// 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 + + enum PointerKind : uint8_t { + Near16 = 0x00, // 16 bit pointer + Far16 = 0x01, // 16:16 far pointer + Huge16 = 0x02, // 16:16 huge pointer + BasedOnSegment = 0x03, // based on segment + BasedOnValue = 0x04, // based on value of base + BasedOnSegmentValue = 0x05, // based on segment value of base + BasedOnAddress = 0x06, // based on address of base + BasedOnSegmentAddress = 0x07, // based on segment address of base + BasedOnType = 0x08, // based on type + BasedOnSelf = 0x09, // based on self + Near32 = 0x0a, // 32 bit pointer + Far32 = 0x0b, // 16:32 pointer + Near64 = 0x0c // 64 bit pointer + }; + + enum PointerMode : uint8_t { + Pointer = 0x00, // "normal" pointer + LValueReference = 0x01, // "old" reference + PointerToDataMember = 0x02, // pointer to data member + PointerToMemberFunction = 0x03, // pointer to member function + RValueReference = 0x04 // r-value reference + }; + + 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() == PointerToDataMember; + } + bool isPointerToMemberFunction() const { + return getPtrMode() == PointerToMemberFunction; + } + bool isPointerToMember() const { + return isPointerToMemberFunction() || isPointerToDataMember(); + } +}; + +struct PointerToMemberTail { + TypeIndex ClassType; + ulittle16_t Representation; + + /// Equivalent to CV_pmtype_e. + enum PointerToMemberRepresentation : uint16_t { + Unknown = 0x00, // not specified (pre VC8) + SingleInheritanceData = 0x01, // member data, single inheritance + MultipleInheritanceData = 0x02, // member data, multiple inheritance + VirtualInheritanceData = 0x03, // member data, virtual inheritance + GeneralData = 0x04, // member data, most general + SingleInheritanceFunction = 0x05, // member function, single inheritance + MultipleInheritanceFunction = 0x06, // member function, multiple inheritance + VirtualInheritanceFunction = 0x07, // member function, virtual inheritance + GeneralFunction = 0x08 // member function, most general + }; +}; + +/// In Clang parlance, these are "qualifiers". LF_MODIFIER +struct TypeModifier { + TypeIndex ModifiedType; + ulittle16_t Modifiers; + + /// Equivalent to CV_modifier_t. + enum QualFlags : uint16_t { + Const = (1 << 0), + Volatile = (1 << 1), + Unaligned = (1 << 2), + }; +}; + +// 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; + + /// Keep in sync with MethodOptions. + enum Flags : uint16_t { + MA_Access = 0x3, + MA_MethodKind = (0x7 << 2), // bit field for method kind + MA_Pseudo = (0x1 << 5), // compiler generated fcn and does not exist + MA_NoInherit = (0x1 << 6), // true if class cannot be inherited + MA_NoConstruct = (0x1 << 7), // true if class cannot be constructed + MA_CompilerGenerated = (0x1 << 8), // compiler generated fcn and does exist + MA_Sealed = (0x1 << 9), // true if method cannot be overridden + }; + + /// Get the flags that are not included in access control or method + /// properties. + Flags getFlags() const { + return Flags(unsigned(Attrs) & ~(MA_Access | MA_MethodKind)); + } + + /// Indicates if a method is defined with friend, virtual, static, etc. + MethodKind getMethodKind() const { + return MethodKind((Attrs & MA_MethodKind) >> 2); + } + + /// 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; + } + + MemberAccess getAccess() const { + return MemberAccess(Attrs & MA_Access); + } +}; + +// 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 Index: tools/llvm-readobj/StreamWriter.h =================================================================== --- tools/llvm-readobj/StreamWriter.h +++ tools/llvm-readobj/StreamWriter.h @@ -10,6 +10,7 @@ #ifndef LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H #define LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -180,6 +181,10 @@ startLine() << Label << ": " << int(Value) << "\n"; } + void printNumber(StringRef Label, APSInt Value) { + startLine() << Label << ": " << Value << "\n"; + } + void printBoolean(StringRef Label, bool Value) { startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; } @@ -287,6 +292,12 @@ int IndentLevel; }; +template <> +inline void StreamWriter::printHex(StringRef Label, + ulittle16_t Value) { + startLine() << Label << ": " << hex(Value) << "\n"; +} + struct DictScope { DictScope(StreamWriter& W, StringRef N) : W(W) { W.startLine() << N << " {\n"; Index: tools/llvm-readobj/llvm-readobj.h =================================================================== --- tools/llvm-readobj/llvm-readobj.h +++ tools/llvm-readobj/llvm-readobj.h @@ -47,4 +47,7 @@ #define LLVM_READOBJ_ENUM_ENT(ns, enum) \ { #enum, ns::enum } +#define LLVM_READOBJ_ENUM_CLASS_ENT(enum_class, enum) \ + { #enum, std::underlying_type::type(enum_class::enum) } + #endif