Make a symbol visitor and use it to dump CV symbols.

Differential Revision: http://reviews.llvm.org/D20534
Reviewed By: rnk

llvm-svn: 270511
This commit is contained in:
Zachary Turner 2016-05-23 23:41:13 +00:00
parent a5690b00af
commit aaad57440d
10 changed files with 1013 additions and 751 deletions

View File

@ -30,7 +30,6 @@ CV_SYMBOL(S_REGISTER_16t , 0x0002)
CV_SYMBOL(S_CONSTANT_16t , 0x0003)
CV_SYMBOL(S_UDT_16t , 0x0004)
CV_SYMBOL(S_SSEARCH , 0x0005)
CV_SYMBOL(S_END , 0x0006)
CV_SYMBOL(S_SKIP , 0x0007)
CV_SYMBOL(S_CVRESERVE , 0x0008)
CV_SYMBOL(S_OBJNAME_ST , 0x0009)
@ -179,12 +178,6 @@ CV_SYMBOL(S_GPROCMIPS_ID , 0x1149)
CV_SYMBOL(S_LPROCIA64_ID , 0x114a)
CV_SYMBOL(S_GPROCIA64_ID , 0x114b)
// Inlined call site delimiters.
CV_SYMBOL(S_INLINESITE_END , 0x114e)
// Procedure info end delimiter.
CV_SYMBOL(S_PROC_ID_END , 0x114f)
CV_SYMBOL(S_DEFRANGE_HLSL , 0x1150)
CV_SYMBOL(S_GDATA_HLSL , 0x1151)
CV_SYMBOL(S_LDATA_HLSL , 0x1152)
@ -193,8 +186,6 @@ CV_SYMBOL(S_LOCAL_DPC_GROUPSHARED, 0x1154)
CV_SYMBOL(S_DEFRANGE_DPC_PTR_TAG, 0x1157)
CV_SYMBOL(S_DPC_SYM_TAG_MAP, 0x1158)
CV_SYMBOL(S_ARMSWITCHTABLE , 0x1159)
CV_SYMBOL(S_CALLEES , 0x115a)
CV_SYMBOL(S_CALLERS , 0x115b)
CV_SYMBOL(S_POGODATA , 0x115c)
CV_SYMBOL(S_INLINESITE2 , 0x115d)
CV_SYMBOL(S_MOD_TYPEREF , 0x115f)
@ -206,19 +197,24 @@ CV_SYMBOL(S_GDATA_HLSL32_EX, 0x1164)
CV_SYMBOL(S_LDATA_HLSL32_EX, 0x1165)
// Known symbol types
SYMBOL_RECORD(S_END , 0x0006, ScopeEndSym)
SYMBOL_RECORD_ALIAS(S_INLINESITE_END , 0x114e, InlineSiteEnd, ScopeEndSym)
SYMBOL_RECORD_ALIAS(S_PROC_ID_END , 0x114f, ProcEnd, ScopeEndSym)
SYMBOL_RECORD(S_LPROC32 , 0x110f, ProcSym)
SYMBOL_RECORD_ALIAS(S_GPROC32 , 0x1110, GlobalProcSym, ProcSym)
SYMBOL_RECORD_ALIAS(S_LPROC32_ID , 0x1146, ProcIdSym, ProcSym)
SYMBOL_RECORD_ALIAS(S_GPROC32_ID , 0x1147, GlobalProcIdSym, ProcSym)
SYMBOL_RECORD_ALIAS(S_LPROC32_DPC , 0x1155, DPCProcSym, ProcSym)
SYMBOL_RECORD_ALIAS(S_LPROC32_DPC_ID , 0x1156, DPCProcIdSym, ProcSym)
SYMBOL_RECORD(S_INLINESITE , 0x114d, InlineSiteSym)
SYMBOL_RECORD(S_LOCAL , 0x113e, LocalSym)
SYMBOL_RECORD(S_DEFRANGE , 0x113f, DefRangeSym)
SYMBOL_RECORD(S_DEFRANGE_SUBFIELD, 0x1140, DefRangeSubfieldSym)
SYMBOL_RECORD(S_DEFRANGE_REGISTER, 0x1141, DefRangeRegisterSym)
SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142, DefRangeSubfieldRegisterSym)
SYMBOL_RECORD(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143, DefRangeFramePointerRelSym)
SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142, DefRangeFramePointerRelSym)
SYMBOL_RECORD(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143, DefRangeSubfieldRegisterSym)
SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144, DefRangeFramePointerRelFullScopeSym)
SYMBOL_RECORD(S_DEFRANGE_REGISTER_REL, 0x1145, DefRangeRegisterRelSym)
SYMBOL_RECORD(S_BLOCK32 , 0x1103, BlockSym)
@ -229,17 +225,25 @@ SYMBOL_RECORD(S_FRAMEPROC , 0x1012, FrameProcSym)
SYMBOL_RECORD(S_CALLSITEINFO , 0x1139, CallSiteInfoSym)
SYMBOL_RECORD(S_HEAPALLOCSITE , 0x115e, HeapAllocationSiteSym)
SYMBOL_RECORD(S_FRAMECOOKIE , 0x113a, FrameCookieSym)
SYMBOL_RECORD(S_CALLEES , 0x115a, CallerSym)
SYMBOL_RECORD_ALIAS(S_CALLERS , 0x115b, CalleeSym, CallerSym)
SYMBOL_RECORD(S_UDT , 0x1108, UDTSym)
SYMBOL_RECORD_ALIAS(S_COBOLUDT , 0x1109, CobolUDT, UDTSym)
SYMBOL_RECORD(S_BUILDINFO , 0x114c, BuildInfoSym)
SYMBOL_RECORD(S_BPREL32 , 0x110b, BPRelativeSym)
SYMBOL_RECORD(S_REGREL32 , 0x1111, RegRelativeSym)
SYMBOL_RECORD(S_CONSTANT , 0x1107, ConstantSym)
SYMBOL_RECORD_ALIAS(S_MANCONSTANT , 0x112d, ManagedConstant, ConstantSym)
SYMBOL_RECORD(S_LDATA32 , 0x110c, DataSym)
SYMBOL_RECORD_ALIAS(S_GDATA32 , 0x110d, GlobalData, DataSym)
SYMBOL_RECORD_ALIAS(S_LMANDATA , 0x111c, ManagedLocalData, DataSym)
SYMBOL_RECORD_ALIAS(S_GMANDATA , 0x111d, ManagedGlobalData, DataSym)
SYMBOL_RECORD(S_LTHREAD32 , 0x1112, ThreadLocalDataSym)
SYMBOL_RECORD_ALIAS(S_GTHREAD32 , 0x1113, GlobalTLS, ThreadLocalDataSym)

View File

@ -0,0 +1,103 @@
//===- CVSymbolVisitor.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H
#define LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/RecordIterator.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h"
#include "llvm/Support/ErrorOr.h"
namespace llvm {
namespace codeview {
template <typename Derived> class CVSymbolVisitor {
public:
CVSymbolVisitor(SymbolVisitorDelegate *Delegate) : Delegate(Delegate) {}
bool hadError() const { return HadError; }
template <typename T>
bool consumeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
if (Data.size() < sizeof(*Res)) {
HadError = true;
return false;
}
Res = reinterpret_cast<const T *>(Data.data());
Data = Data.drop_front(sizeof(*Res));
return true;
}
/// Actions to take on known symbols. By default, they do nothing. Visit methods
/// for member records take the FieldData by non-const reference and are
/// expected to consume the trailing bytes used by the field.
/// FIXME: Make the visitor interpret the trailing bytes so that clients don't
/// need to.
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
void visit##Name(SymbolRecordKind Kind, Name &Record) {}
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "CVSymbolTypes.def"
void visitSymbolRecord(const SymbolIterator::Record &Record) {
ArrayRef<uint8_t> Data = Record.Data;
auto *DerivedThis = static_cast<Derived *>(this);
DerivedThis->visitSymbolBegin(Record.Type, Data);
uint32_t RecordOffset = Delegate ? Delegate->getRecordOffset(Data) : 0;
switch (Record.Type) {
default:
DerivedThis->visitUnknownSymbol(Record.Type, Data);
break;
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
SymbolRecordKind RK = static_cast<SymbolRecordKind>(EnumName); \
auto Result = Name::deserialize(RK, RecordOffset, Data); \
if (Result.getError()) \
return parseError(); \
DerivedThis->visit##Name(Record.Type, *Result); \
break; \
}
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
#include "CVSymbolTypes.def"
}
DerivedThis->visitSymbolEnd(Record.Type, Record.Data);
}
/// Visits the symbol records in Data. Sets the error flag on parse failures.
void visitSymbolStream(ArrayRef<uint8_t> Data) {
for (const auto &I : makeSymbolRange(Data, &HadError)) {
visitSymbolRecord(I);
if (hadError())
break;
}
}
/// Action to take on unknown symbols. By default, they are ignored.
void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data) {}
/// Paired begin/end actions for all symbols. Receives all record data,
/// including the fixed-length record prefix.
void visitSymbolBegin(SymbolKind Leaf, ArrayRef<uint8_t> RecordData) {}
void visitSymbolEnd(SymbolKind Leaf, ArrayRef<uint8_t> OriginalSymData) {}
/// Helper for returning from a void function when the stream is corrupted.
void parseError() { HadError = true; }
private:
SymbolVisitorDelegate *Delegate;
/// Whether a symbol stream parsing error was encountered.
bool HadError = false;
};
} // end namespace codeview
} // end namespace llvm
#endif // LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H

View File

@ -0,0 +1,37 @@
//===-- SymbolDumpDelegate.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H
#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H
#include "SymbolVisitorDelegate.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <stdint.h>
namespace llvm {
namespace codeview {
class SymbolDumpDelegate : public SymbolVisitorDelegate {
public:
virtual ~SymbolDumpDelegate() {}
virtual void printRelocatedField(StringRef Label, uint32_t RelocOffset,
uint32_t Offset,
StringRef *RelocSym = nullptr) = 0;
virtual void printBinaryBlockWithRelocs(StringRef Label,
ArrayRef<uint8_t> Block) = 0;
};
} // end namespace codeview
} // end namespace llvm
#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H

View File

@ -0,0 +1,54 @@
//===-- SymbolDumper.h - CodeView symbol info dumper ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H
#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
namespace llvm {
class ScopedPrinter;
namespace codeview {
class CVTypeDumper;
/// Dumper for CodeView symbol streams found in COFF object files and PDB files.
class CVSymbolDumper {
public:
CVSymbolDumper(ScopedPrinter &W, CVTypeDumper &CVTD,
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
bool PrintRecordBytes)
: W(W), CVTD(CVTD), ObjDelegate(std::move(ObjDelegate)),
PrintRecordBytes(PrintRecordBytes) {}
/// Dumps one type record. Returns false if there was a type parsing error,
/// and true otherwise. This should be called in order, since the dumper
/// maintains state about previous records which are necessary for cross
/// type references.
bool dump(const SymbolIterator::Record &Record);
/// Dumps the type records in Data. Returns false if there was a type stream
/// parse error, and true otherwise.
bool dump(ArrayRef<uint8_t> Data);
private:
ScopedPrinter &W;
CVTypeDumper &CVTD;
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
bool PrintRecordBytes;
};
} // end namespace codeview
} // end namespace llvm
#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H

View File

@ -79,6 +79,46 @@ public:
StringRef Name;
};
class ScopeEndSym : public SymbolRecord {
public:
ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset)
: SymbolRecord(Kind), RecordOffset(RecordOffset) {}
static ErrorOr<ScopeEndSym> deserialize(SymbolRecordKind Kind,
uint32_t RecordOffset,
ArrayRef<uint8_t> &Data) {
return ScopeEndSym(Kind, RecordOffset);
}
uint32_t RecordOffset;
};
class CallerSym : public SymbolRecord {
public:
struct Hdr {
uint32_t Count;
};
CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *Header,
ArrayRef<TypeIndex> Indices)
: SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*Header),
Indices(Indices) {}
static ErrorOr<CallerSym> deserialize(SymbolRecordKind Kind,
uint32_t RecordOffset,
ArrayRef<uint8_t> &Data) {
const Hdr *Header;
ArrayRef<TypeIndex> Indices;
CV_DESERIALIZE(Data, Header, CV_ARRAY_FIELD_N(Indices, Header->Count));
return CallerSym(Kind, RecordOffset, Header, Indices);
}
Hdr Header;
uint32_t RecordOffset;
ArrayRef<TypeIndex> Indices;
};
struct BinaryAnnotationIterator {
struct AnnotationData {
BinaryAnnotationsOpCode OpCode;
@ -697,7 +737,7 @@ public:
};
// S_COMPILE3
class CompileSym3 : public SymbolRecord {
class Compile3Sym : public SymbolRecord {
public:
struct Hdr {
ulittle32_t flags; // CompileSym3Flags enum
@ -714,18 +754,18 @@ public:
// VersionString: The null-terminated version string follows.
};
CompileSym3(uint32_t RecordOffset, const Hdr *H, StringRef Version)
Compile3Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version)
: SymbolRecord(SymbolRecordKind::Compile3Sym), RecordOffset(RecordOffset),
Header(*H), Version(Version) {}
static ErrorOr<CompileSym3> deserialize(SymbolRecordKind Kind,
static ErrorOr<Compile3Sym> deserialize(SymbolRecordKind Kind,
uint32_t RecordOffset,
ArrayRef<uint8_t> &Data) {
const Hdr *H = nullptr;
StringRef Version;
CV_DESERIALIZE(Data, H, Version);
return CompileSym3(RecordOffset, H, Version);
return Compile3Sym(RecordOffset, H, Version);
}
uint32_t RecordOffset;
@ -1060,10 +1100,11 @@ public:
StringRef Name;
};
typedef RecordIterator<SymbolRecordKind> SymbolIterator;
typedef RecordIterator<SymbolKind> SymbolIterator;
inline iterator_range<SymbolIterator> makeSymbolRange(ArrayRef<uint8_t> Data) {
return make_range(SymbolIterator(Data, nullptr), SymbolIterator());
inline iterator_range<SymbolIterator> makeSymbolRange(ArrayRef<uint8_t> Data,
bool *HadError) {
return make_range(SymbolIterator(Data, HadError), SymbolIterator());
}
} // namespace codeview

View File

@ -0,0 +1,33 @@
//===-- SymbolVisitorDelegate.h ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H
#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <stdint.h>
namespace llvm {
namespace codeview {
class SymbolVisitorDelegate {
public:
virtual ~SymbolVisitorDelegate() {}
virtual uint32_t getRecordOffset(ArrayRef<uint8_t> Record) = 0;
virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0;
virtual StringRef getStringTable() = 0;
};
} // end namespace codeview
} // end namespace llvm
#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H

View File

@ -5,6 +5,7 @@ add_llvm_library(LLVMDebugInfoCodeView
MemoryTypeTableBuilder.cpp
MethodListRecordBuilder.cpp
RecordSerialization.cpp
SymbolDumper.cpp
TypeDumper.cpp
TypeRecord.cpp
TypeRecordBuilder.cpp

View File

@ -0,0 +1,670 @@
//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/Support/ScopedPrinter.h"
#include <system_error>
using namespace llvm;
using namespace llvm::codeview;
static const EnumEntry<SymbolKind> SymbolTypeNames[] = {
#define CV_SYMBOL(enum, val) {#enum, enum},
#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
};
namespace {
#define CV_ENUM_CLASS_ENT(enum_class, enum) \
{ #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
#define CV_ENUM_ENT(ns, enum) \
{ #enum, ns::enum }
static const EnumEntry<uint8_t> ProcSymFlagNames[] = {
CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP),
CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET),
CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET),
CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn),
CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable),
CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv),
CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline),
CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo),
};
static const EnumEntry<uint16_t> LocalFlags[] = {
CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal),
CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic),
};
static const EnumEntry<uint32_t> FrameCookieKinds[] = {
CV_ENUM_CLASS_ENT(FrameCookieKind, Copy),
CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer),
CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer),
CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13),
};
static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = {
CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp),
CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm),
CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic),
CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link),
CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd),
CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB),
CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java),
CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL),
CV_ENUM_ENT(SourceLanguage, HLSL),
};
static const EnumEntry<uint32_t> CompileSym3FlagNames[] = {
CV_ENUM_CLASS_ENT(CompileSym3Flags, EC),
CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo),
CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG),
CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign),
CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent),
CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks),
CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch),
CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL),
CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule),
CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl),
CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO),
CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp),
};
static const EnumEntry<unsigned> CPUTypeNames[] = {
CV_ENUM_CLASS_ENT(CPUType, Intel8080),
CV_ENUM_CLASS_ENT(CPUType, Intel8086),
CV_ENUM_CLASS_ENT(CPUType, Intel80286),
CV_ENUM_CLASS_ENT(CPUType, Intel80386),
CV_ENUM_CLASS_ENT(CPUType, Intel80486),
CV_ENUM_CLASS_ENT(CPUType, Pentium),
CV_ENUM_CLASS_ENT(CPUType, PentiumPro),
CV_ENUM_CLASS_ENT(CPUType, Pentium3),
CV_ENUM_CLASS_ENT(CPUType, MIPS),
CV_ENUM_CLASS_ENT(CPUType, MIPS16),
CV_ENUM_CLASS_ENT(CPUType, MIPS32),
CV_ENUM_CLASS_ENT(CPUType, MIPS64),
CV_ENUM_CLASS_ENT(CPUType, MIPSI),
CV_ENUM_CLASS_ENT(CPUType, MIPSII),
CV_ENUM_CLASS_ENT(CPUType, MIPSIII),
CV_ENUM_CLASS_ENT(CPUType, MIPSIV),
CV_ENUM_CLASS_ENT(CPUType, MIPSV),
CV_ENUM_CLASS_ENT(CPUType, M68000),
CV_ENUM_CLASS_ENT(CPUType, M68010),
CV_ENUM_CLASS_ENT(CPUType, M68020),
CV_ENUM_CLASS_ENT(CPUType, M68030),
CV_ENUM_CLASS_ENT(CPUType, M68040),
CV_ENUM_CLASS_ENT(CPUType, Alpha),
CV_ENUM_CLASS_ENT(CPUType, Alpha21164),
CV_ENUM_CLASS_ENT(CPUType, Alpha21164A),
CV_ENUM_CLASS_ENT(CPUType, Alpha21264),
CV_ENUM_CLASS_ENT(CPUType, Alpha21364),
CV_ENUM_CLASS_ENT(CPUType, PPC601),
CV_ENUM_CLASS_ENT(CPUType, PPC603),
CV_ENUM_CLASS_ENT(CPUType, PPC604),
CV_ENUM_CLASS_ENT(CPUType, PPC620),
CV_ENUM_CLASS_ENT(CPUType, PPCFP),
CV_ENUM_CLASS_ENT(CPUType, PPCBE),
CV_ENUM_CLASS_ENT(CPUType, SH3),
CV_ENUM_CLASS_ENT(CPUType, SH3E),
CV_ENUM_CLASS_ENT(CPUType, SH3DSP),
CV_ENUM_CLASS_ENT(CPUType, SH4),
CV_ENUM_CLASS_ENT(CPUType, SHMedia),
CV_ENUM_CLASS_ENT(CPUType, ARM3),
CV_ENUM_CLASS_ENT(CPUType, ARM4),
CV_ENUM_CLASS_ENT(CPUType, ARM4T),
CV_ENUM_CLASS_ENT(CPUType, ARM5),
CV_ENUM_CLASS_ENT(CPUType, ARM5T),
CV_ENUM_CLASS_ENT(CPUType, ARM6),
CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC),
CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX),
CV_ENUM_CLASS_ENT(CPUType, ARM7),
CV_ENUM_CLASS_ENT(CPUType, Omni),
CV_ENUM_CLASS_ENT(CPUType, Ia64),
CV_ENUM_CLASS_ENT(CPUType, Ia64_2),
CV_ENUM_CLASS_ENT(CPUType, CEE),
CV_ENUM_CLASS_ENT(CPUType, AM33),
CV_ENUM_CLASS_ENT(CPUType, M32R),
CV_ENUM_CLASS_ENT(CPUType, TriCore),
CV_ENUM_CLASS_ENT(CPUType, X64),
CV_ENUM_CLASS_ENT(CPUType, EBC),
CV_ENUM_CLASS_ENT(CPUType, Thumb),
CV_ENUM_CLASS_ENT(CPUType, ARMNT),
CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader),
};
static const EnumEntry<uint32_t> FrameProcSymFlags[] = {
CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg),
CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw),
};
/// Use this private dumper implementation to keep implementation details about
/// the visitor out of SymbolDumper.h.
class CVSymbolDumperImpl : public CVSymbolVisitor<CVSymbolDumperImpl> {
public:
CVSymbolDumperImpl(CVSymbolDumper &CVSD, CVTypeDumper &CVTD,
SymbolDumpDelegate *ObjDelegate, ScopedPrinter &W,
bool PrintRecordBytes)
: CVSymbolVisitor(ObjDelegate), CVSD(CVSD), CVTD(CVTD),
ObjDelegate(ObjDelegate), W(W), PrintRecordBytes(PrintRecordBytes),
InFunctionScope(false) {}
/// CVSymbolVisitor overrides.
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
void visit##Name(SymbolKind Kind, Name &Record);
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
void visitSymbolBegin(SymbolKind Kind, ArrayRef<uint8_t> Data);
void visitSymbolEnd(SymbolKind Kind, ArrayRef<uint8_t> OriginalSymData);
void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data);
private:
void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
uint32_t RelocationOffset);
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
CVSymbolDumper &CVSD;
CVTypeDumper &CVTD;
SymbolDumpDelegate *ObjDelegate;
ScopedPrinter &W;
bool PrintRecordBytes;
bool InFunctionScope;
};
}
void CVSymbolDumperImpl::printLocalVariableAddrRange(
const LocalVariableAddrRange &Range, uint32_t RelocationOffset) {
DictScope S(W, "LocalVariableAddrRange");
if (ObjDelegate)
ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset,
Range.OffsetStart);
W.printHex("ISectStart", Range.ISectStart);
W.printHex("Range", Range.Range);
}
void CVSymbolDumperImpl::printLocalVariableAddrGap(
ArrayRef<LocalVariableAddrGap> Gaps) {
for (auto &Gap : Gaps) {
ListScope S(W, "LocalVariableAddrGap");
W.printHex("GapStartOffset", Gap.GapStartOffset);
W.printHex("Range", Gap.Range);
}
}
void CVSymbolDumperImpl::visitSymbolBegin(SymbolKind Kind,
ArrayRef<uint8_t> Data) {}
void CVSymbolDumperImpl::visitSymbolEnd(SymbolKind Kind,
ArrayRef<uint8_t> OriginalSymData) {
if (PrintRecordBytes && ObjDelegate)
ObjDelegate->printBinaryBlockWithRelocs("SymData", OriginalSymData);
}
void CVSymbolDumperImpl::visitBlockSym(SymbolKind Kind, BlockSym &Block) {
DictScope S(W, "BlockStart");
StringRef LinkageName;
W.printHex("PtrParent", Block.Header.PtrParent);
W.printHex("PtrEnd", Block.Header.PtrEnd);
W.printHex("CodeSize", Block.Header.CodeSize);
if (ObjDelegate) {
ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(),
Block.Header.CodeOffset, &LinkageName);
}
W.printHex("Segment", Block.Header.Segment);
W.printString("BlockName", Block.Name);
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitBPRelativeSym(SymbolKind Kind,
BPRelativeSym &BPRel) {
DictScope S(W, "BPRelativeSym");
W.printNumber("Offset", BPRel.Header.Offset);
CVTD.printTypeIndex("Type", BPRel.Header.Type);
W.printString("VarName", BPRel.Name);
}
void CVSymbolDumperImpl::visitBuildInfoSym(SymbolKind Kind,
BuildInfoSym &BuildInfo) {
DictScope S(W, "BuildInfo");
W.printNumber("BuildId", BuildInfo.Header.BuildId);
}
void CVSymbolDumperImpl::visitCallSiteInfoSym(SymbolKind Kind,
CallSiteInfoSym &CallSiteInfo) {
DictScope S(W, "CallSiteInfo");
StringRef LinkageName;
if (ObjDelegate) {
ObjDelegate->printRelocatedField(
"CodeOffset", CallSiteInfo.getRelocationOffset(),
CallSiteInfo.Header.CodeOffset, &LinkageName);
}
W.printHex("Segment", CallSiteInfo.Header.Segment);
W.printHex("Reserved", CallSiteInfo.Header.Reserved);
CVTD.printTypeIndex("Type", CallSiteInfo.Header.Type);
if (!LinkageName.empty())
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitCompile3Sym(SymbolKind Kind,
Compile3Sym &Compile3) {
DictScope S(W, "CompilerFlags");
W.printEnum("Language", Compile3.Header.getLanguage(),
makeArrayRef(SourceLanguages));
W.printFlags("Flags", Compile3.Header.flags & ~0xff,
makeArrayRef(CompileSym3FlagNames));
W.printEnum("Machine", unsigned(Compile3.Header.Machine),
makeArrayRef(CPUTypeNames));
std::string FrontendVersion;
{
raw_string_ostream Out(FrontendVersion);
Out << Compile3.Header.VersionFrontendMajor << '.'
<< Compile3.Header.VersionFrontendMinor << '.'
<< Compile3.Header.VersionFrontendBuild << '.'
<< Compile3.Header.VersionFrontendQFE;
}
std::string BackendVersion;
{
raw_string_ostream Out(BackendVersion);
Out << Compile3.Header.VersionBackendMajor << '.'
<< Compile3.Header.VersionBackendMinor << '.'
<< Compile3.Header.VersionBackendBuild << '.'
<< Compile3.Header.VersionBackendQFE;
}
W.printString("FrontendVersion", FrontendVersion);
W.printString("BackendVersion", BackendVersion);
W.printString("VersionName", Compile3.Version);
}
void CVSymbolDumperImpl::visitConstantSym(SymbolKind Kind,
ConstantSym &Constant) {
DictScope S(W, "Constant");
CVTD.printTypeIndex("Type", Constant.Header.Type);
W.printNumber("Value", Constant.Value);
W.printString("Name", Constant.Name);
}
void CVSymbolDumperImpl::visitDataSym(SymbolKind Kind, DataSym &Data) {
DictScope S(W, "DataSym");
StringRef LinkageName;
if (ObjDelegate) {
ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
Data.Header.DataOffset, &LinkageName);
}
CVTD.printTypeIndex("Type", Data.Header.Type);
W.printString("DisplayName", Data.Name);
if (!LinkageName.empty())
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitDefRangeFramePointerRelFullScopeSym(
SymbolKind Kind,
DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
DictScope S(W, "DefRangeFramePointerRelFullScope");
W.printNumber("Offset", DefRangeFramePointerRelFullScope.Header.Offset);
}
void CVSymbolDumperImpl::visitDefRangeFramePointerRelSym(
SymbolKind Kind, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
DictScope S(W, "DefRangeFramePointerRel");
W.printNumber("Offset", DefRangeFramePointerRel.Header.Offset);
printLocalVariableAddrRange(DefRangeFramePointerRel.Header.Range,
DefRangeFramePointerRel.getRelocationOffset());
printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
}
void CVSymbolDumperImpl::visitDefRangeRegisterRelSym(
SymbolKind Kind, DefRangeRegisterRelSym &DefRangeRegisterRel) {
DictScope S(W, "DefRangeRegisterRel");
W.printNumber("BaseRegister", DefRangeRegisterRel.Header.BaseRegister);
W.printBoolean("HasSpilledUDTMember",
DefRangeRegisterRel.hasSpilledUDTMember());
W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
W.printNumber("BasePointerOffset",
DefRangeRegisterRel.Header.BasePointerOffset);
printLocalVariableAddrRange(DefRangeRegisterRel.Header.Range,
DefRangeRegisterRel.getRelocationOffset());
printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
}
void CVSymbolDumperImpl::visitDefRangeRegisterSym(
SymbolKind Kind, DefRangeRegisterSym &DefRangeRegister) {
DictScope S(W, "DefRangeRegister");
W.printNumber("Register", DefRangeRegister.Header.Register);
W.printNumber("MayHaveNoName", DefRangeRegister.Header.MayHaveNoName);
printLocalVariableAddrRange(DefRangeRegister.Header.Range,
DefRangeRegister.getRelocationOffset());
printLocalVariableAddrGap(DefRangeRegister.Gaps);
}
void CVSymbolDumperImpl::visitDefRangeSubfieldRegisterSym(
SymbolKind Kind, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
DictScope S(W, "DefRangeSubfieldRegister");
W.printNumber("Register", DefRangeSubfieldRegister.Header.Register);
W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Header.MayHaveNoName);
W.printNumber("OffsetInParent",
DefRangeSubfieldRegister.Header.OffsetInParent);
printLocalVariableAddrRange(DefRangeSubfieldRegister.Header.Range,
DefRangeSubfieldRegister.getRelocationOffset());
printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
}
void CVSymbolDumperImpl::visitDefRangeSubfieldSym(
SymbolKind Kind, DefRangeSubfieldSym &DefRangeSubfield) {
DictScope S(W, "DefRangeSubfield");
if (ObjDelegate) {
StringRef StringTable = ObjDelegate->getStringTable();
if (!StringTable.empty()) {
W.printString("Program",
StringTable.drop_front(DefRangeSubfield.Header.Program)
.split('\0')
.first);
}
}
W.printNumber("OffsetInParent", DefRangeSubfield.Header.OffsetInParent);
printLocalVariableAddrRange(DefRangeSubfield.Header.Range,
DefRangeSubfield.getRelocationOffset());
printLocalVariableAddrGap(DefRangeSubfield.Gaps);
}
void CVSymbolDumperImpl::visitDefRangeSym(SymbolKind Kind,
DefRangeSym &DefRange) {
DictScope S(W, "DefRange");
if (ObjDelegate) {
StringRef StringTable = ObjDelegate->getStringTable();
if (!StringTable.empty()) {
W.printString(
"Program",
StringTable.drop_front(DefRange.Header.Program).split('\0').first);
}
}
printLocalVariableAddrRange(DefRange.Header.Range,
DefRange.getRelocationOffset());
printLocalVariableAddrGap(DefRange.Gaps);
}
void CVSymbolDumperImpl::visitFrameCookieSym(SymbolKind Kind,
FrameCookieSym &FrameCookie) {
DictScope S(W, "FrameCookie");
StringRef LinkageName;
if (ObjDelegate) {
ObjDelegate->printRelocatedField(
"CodeOffset", FrameCookie.getRelocationOffset(),
FrameCookie.Header.CodeOffset, &LinkageName);
}
W.printHex("Register", FrameCookie.Header.Register);
W.printEnum("CookieKind", uint16_t(FrameCookie.Header.CookieKind),
makeArrayRef(FrameCookieKinds));
}
void CVSymbolDumperImpl::visitFrameProcSym(SymbolKind Kind,
FrameProcSym &FrameProc) {
DictScope S(W, "FrameProc");
W.printHex("TotalFrameBytes", FrameProc.Header.TotalFrameBytes);
W.printHex("PaddingFrameBytes", FrameProc.Header.PaddingFrameBytes);
W.printHex("OffsetToPadding", FrameProc.Header.OffsetToPadding);
W.printHex("BytesOfCalleeSavedRegisters",
FrameProc.Header.BytesOfCalleeSavedRegisters);
W.printHex("OffsetOfExceptionHandler",
FrameProc.Header.OffsetOfExceptionHandler);
W.printHex("SectionIdOfExceptionHandler",
FrameProc.Header.SectionIdOfExceptionHandler);
W.printFlags("Flags", FrameProc.Header.Flags,
makeArrayRef(FrameProcSymFlags));
}
void CVSymbolDumperImpl::visitHeapAllocationSiteSym(
SymbolKind Kind, HeapAllocationSiteSym &HeapAllocSite) {
DictScope S(W, "HeapAllocationSite");
StringRef LinkageName;
if (ObjDelegate) {
ObjDelegate->printRelocatedField(
"CodeOffset", HeapAllocSite.getRelocationOffset(),
HeapAllocSite.Header.CodeOffset, &LinkageName);
}
W.printHex("Segment", HeapAllocSite.Header.Segment);
W.printHex("CallInstructionSize", HeapAllocSite.Header.CallInstructionSize);
CVTD.printTypeIndex("Type", HeapAllocSite.Header.Type);
if (!LinkageName.empty())
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitInlineSiteSym(SymbolKind Kind,
InlineSiteSym &InlineSite) {
DictScope S(W, "InlineSite");
W.printHex("PtrParent", InlineSite.Header.PtrParent);
W.printHex("PtrEnd", InlineSite.Header.PtrEnd);
CVTD.printTypeIndex("Inlinee", InlineSite.Header.Inlinee);
ListScope BinaryAnnotations(W, "BinaryAnnotations");
for (auto &Annotation : InlineSite.annotations()) {
switch (Annotation.OpCode) {
case BinaryAnnotationsOpCode::Invalid:
return parseError();
case BinaryAnnotationsOpCode::CodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeLength:
W.printHex(Annotation.Name, Annotation.U1);
break;
case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
case BinaryAnnotationsOpCode::ChangeLineEndDelta:
case BinaryAnnotationsOpCode::ChangeRangeKind:
case BinaryAnnotationsOpCode::ChangeColumnStart:
case BinaryAnnotationsOpCode::ChangeColumnEnd:
W.printNumber(Annotation.Name, Annotation.U1);
break;
case BinaryAnnotationsOpCode::ChangeLineOffset:
case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
W.printNumber(Annotation.Name, Annotation.S1);
break;
case BinaryAnnotationsOpCode::ChangeFile:
if (ObjDelegate) {
W.printHex("ChangeFile",
ObjDelegate->getFileNameForFileOffset(Annotation.U1),
Annotation.U1);
} else {
W.printHex("ChangeFile", Annotation.U1);
}
break;
case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: "
<< W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1
<< "}\n";
break;
}
case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: "
<< W.hex(Annotation.U2)
<< ", Length: " << W.hex(Annotation.U1) << "}\n";
break;
}
}
}
}
void CVSymbolDumperImpl::visitLabelSym(SymbolKind Kind, LabelSym &Label) {
DictScope S(W, "Label");
StringRef LinkageName;
if (ObjDelegate) {
ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(),
Label.Header.CodeOffset, &LinkageName);
}
W.printHex("Segment", Label.Header.Segment);
W.printHex("Flags", Label.Header.Flags);
W.printFlags("Flags", Label.Header.Flags, makeArrayRef(ProcSymFlagNames));
W.printString("DisplayName", Label.Name);
if (!LinkageName.empty())
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitLocalSym(SymbolKind Kind, LocalSym &Local) {
DictScope S(W, "Local");
CVTD.printTypeIndex("Type", Local.Header.Type);
W.printFlags("Flags", uint16_t(Local.Header.Flags), makeArrayRef(LocalFlags));
W.printString("VarName", Local.Name);
}
void CVSymbolDumperImpl::visitObjNameSym(SymbolKind Kind, ObjNameSym &ObjName) {
DictScope S(W, "ObjectName");
W.printHex("Signature", ObjName.Header.Signature);
W.printString("ObjectName", ObjName.Name);
}
void CVSymbolDumperImpl::visitProcSym(SymbolKind Kind, ProcSym &Proc) {
DictScope S(W, "ProcStart");
if (InFunctionScope)
return parseError();
InFunctionScope = true;
StringRef LinkageName;
W.printHex("PtrParent", Proc.Header.PtrParent);
W.printHex("PtrEnd", Proc.Header.PtrEnd);
W.printHex("PtrNext", Proc.Header.PtrNext);
W.printHex("CodeSize", Proc.Header.CodeSize);
W.printHex("DbgStart", Proc.Header.DbgStart);
W.printHex("DbgEnd", Proc.Header.DbgEnd);
CVTD.printTypeIndex("FunctionType", Proc.Header.FunctionType);
if (ObjDelegate) {
ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(),
Proc.Header.CodeOffset, &LinkageName);
}
W.printHex("Segment", Proc.Header.Segment);
W.printFlags("Flags", static_cast<uint8_t>(Proc.Header.Flags),
makeArrayRef(ProcSymFlagNames));
W.printString("DisplayName", Proc.Name);
if (!LinkageName.empty())
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitScopeEndSym(SymbolKind Kind,
ScopeEndSym &ScopeEnd) {
if (Kind == SymbolKind::S_END)
W.startLine() << "BlockEnd\n";
else if (Kind == SymbolKind::S_PROC_ID_END)
W.startLine() << "ProcEnd\n";
else if (Kind == SymbolKind::S_INLINESITE_END)
DictScope S(W, "InlineSiteEnd");
InFunctionScope = false;
}
void CVSymbolDumperImpl::visitCallerSym(SymbolKind Kind, CallerSym &Caller) {
ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers");
for (auto FuncID : Caller.Indices)
CVTD.printTypeIndex("FuncID", FuncID);
}
void CVSymbolDumperImpl::visitRegRelativeSym(SymbolKind Kind,
RegRelativeSym &RegRel) {
DictScope S(W, "RegRelativeSym");
W.printHex("Offset", RegRel.Header.Offset);
CVTD.printTypeIndex("Type", RegRel.Header.Type);
W.printHex("Register", RegRel.Header.Register);
W.printString("VarName", RegRel.Name);
}
void CVSymbolDumperImpl::visitThreadLocalDataSym(SymbolKind Kind,
ThreadLocalDataSym &Data) {
DictScope S(W, "ThreadLocalDataSym");
StringRef LinkageName;
if (ObjDelegate) {
ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
Data.Header.DataOffset, &LinkageName);
}
CVTD.printTypeIndex("Type", Data.Header.Type);
W.printString("DisplayName", Data.Name);
if (!LinkageName.empty())
W.printString("LinkageName", LinkageName);
}
void CVSymbolDumperImpl::visitUDTSym(SymbolKind Kind, UDTSym &UDT) {
DictScope S(W, "UDT");
CVTD.printTypeIndex("Type", UDT.Header.Type);
W.printString("UDTName", UDT.Name);
}
void CVSymbolDumperImpl::visitUnknownSymbol(SymbolKind Kind,
ArrayRef<uint8_t> Data) {
DictScope S(W, "UnknownSym");
W.printHex("Kind", unsigned(Kind));
W.printHex("Size", Data.size());
}
bool CVSymbolDumper::dump(const SymbolIterator::Record &Record) {
CVSymbolDumperImpl Dumper(*this, CVTD, ObjDelegate.get(), W,
PrintRecordBytes);
Dumper.visitSymbolRecord(Record);
return !Dumper.hadError();
}
bool CVSymbolDumper::dump(ArrayRef<uint8_t> Data) {
CVSymbolDumperImpl Dumper(*this, CVTD, ObjDelegate.get(), W,
PrintRecordBytes);
Dumper.visitSymbolStream(Data);
return !Dumper.hadError();
}

View File

@ -51,5 +51,5 @@ Error ModStream::reload() {
}
iterator_range<codeview::SymbolIterator> ModStream::symbols() const {
return codeview::makeSymbolRange(SymbolsSubstream.data().slice(4));
return codeview::makeSymbolRange(SymbolsSubstream.data().slice(4), nullptr);
}

View File

@ -24,8 +24,10 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
@ -58,6 +60,7 @@ namespace {
class COFFDumper : public ObjDumper {
public:
friend class COFFObjectDumpDelegate;
COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
: ObjDumper(Writer), Obj(Obj),
CVTD(Writer, opts::CodeViewSubsectionBytes) {}
@ -96,10 +99,6 @@ private:
// Forward to CVTypeDumper for simplicity.
CVTD.printTypeIndex(FieldName, TI);
}
void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
const coff_section *Sec,
uint32_t RelocationOffset);
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
void printCodeViewSymbolsSubsection(StringRef Subsection,
const SectionRef &Section,
@ -148,6 +147,45 @@ private:
CVTypeDumper CVTD;
};
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
public:
COFFObjectDumpDelegate(COFFDumper &CD, const SectionRef &SR,
const COFFObjectFile *Obj, StringRef SectionContents)
: CD(CD), SR(SR), Obj(Obj), SectionContents(SectionContents) {
Sec = Obj->getCOFFSection(SR);
}
uint32_t getRecordOffset(ArrayRef<uint8_t> Record) override {
return Record.data() - SectionContents.bytes_begin();
}
void printRelocatedField(StringRef Label, uint32_t RelocOffset,
uint32_t Offset, StringRef *RelocSym) override {
CD.printRelocatedField(Label, Sec, RelocOffset, Offset, RelocSym);
}
void printBinaryBlockWithRelocs(StringRef Label,
ArrayRef<uint8_t> Block) override {
StringRef SBlock(reinterpret_cast<const char *>(Block.data()),
Block.size());
if (opts::CodeViewSubsectionBytes)
CD.printBinaryBlockWithRelocs(Label, SR, SectionContents, SBlock);
}
StringRef getFileNameForFileOffset(uint32_t FileOffset) override {
return CD.getFileNameForFileOffset(FileOffset);
}
StringRef getStringTable() override { return CD.CVStringTable; }
private:
COFFDumper &CD;
const SectionRef &SR;
const COFFObjectFile *Obj;
const coff_section *Sec;
StringRef SectionContents;
};
} // end namespace
namespace llvm {
@ -246,6 +284,7 @@ void COFFDumper::printBinaryBlockWithRelocs(StringRef Label,
uint64_t OffsetStart = Block.data() - SectionContents.data();
uint64_t OffsetEnd = OffsetStart + Block.size();
W.flush();
cacheRelocations();
ListScope D(W, "BlockRelocations");
const coff_section *Section = Obj->getCOFFSection(Sec);
@ -440,41 +479,6 @@ WeakExternalCharacteristics[] = {
{ "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
};
static const EnumEntry<uint32_t> CompileSym3FlagNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, EC),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, LTCG),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, Sdl),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, PGO),
LLVM_READOBJ_ENUM_CLASS_ENT(CompileSym3Flags, Exp),
};
static const EnumEntry<codeview::SourceLanguage> 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<uint32_t> SubSectionTypes[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols),
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines),
@ -491,68 +495,6 @@ static const EnumEntry<uint32_t> SubSectionTypes[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA),
};
static const EnumEntry<unsigned> 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<uint8_t> ProcSymFlagNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(ProcSymFlags, HasFP),
LLVM_READOBJ_ENUM_CLASS_ENT(ProcSymFlags, HasIRET),
@ -564,59 +506,12 @@ static const EnumEntry<uint8_t> ProcSymFlagNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo),
};
static const EnumEntry<uint32_t> 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<uint32_t> FrameDataFlags[] = {
LLVM_READOBJ_ENUM_ENT(FrameData, HasSEH),
LLVM_READOBJ_ENUM_ENT(FrameData, HasEH),
LLVM_READOBJ_ENUM_ENT(FrameData, IsFunctionStart),
};
static const EnumEntry<uint16_t> LocalFlags[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsParameter),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsAliased),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsAlias),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal),
LLVM_READOBJ_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic),
};
static const EnumEntry<uint32_t> FrameCookieKinds[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(FrameCookieKind, Copy),
LLVM_READOBJ_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer),
LLVM_READOBJ_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer),
LLVM_READOBJ_ENUM_CLASS_ENT(FrameCookieKind, XorR13),
};
static const EnumEntry<uint8_t> FileChecksumKindNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, None),
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, MD5),
@ -1009,574 +904,16 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
const SectionRef &Section,
StringRef SectionContents) {
if (Subsection.size() < sizeof(RecordPrefix))
return error(object_error::parse_failed);
ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(),
Subsection.bytes_end());
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
SectionContents);
const coff_section *Sec = Obj->getCOFFSection(Section);
CVSymbolDumper CVSD(W, CVTD, std::move(CODD), opts::CodeViewSubsectionBytes);
// This holds the remaining data to parse.
StringRef Data = Subsection;
bool InFunctionScope = false;
while (!Data.empty()) {
const RecordPrefix *Rec;
error(consumeObject(Data, Rec));
StringRef SymData = Data.substr(0, Rec->RecordLen - 2);
StringRef OrigSymData = SymData;
Data = Data.drop_front(Rec->RecordLen - 2);
uint32_t RecordOffset = SymData.data() - SectionContents.data();
SymbolKind Kind = static_cast<SymbolKind>(uint16_t(Rec->RecordKind));
switch (Kind) {
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");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto ProcOrError = ProcSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!ProcOrError)
error(ProcOrError.getError());
auto &Proc = ProcOrError.get();
if (InFunctionScope)
return error(object_error::parse_failed);
InFunctionScope = true;
StringRef LinkageName;
W.printHex("PtrParent", Proc.Header.PtrParent);
W.printHex("PtrEnd", Proc.Header.PtrEnd);
W.printHex("PtrNext", Proc.Header.PtrNext);
W.printHex("CodeSize", Proc.Header.CodeSize);
W.printHex("DbgStart", Proc.Header.DbgStart);
W.printHex("DbgEnd", Proc.Header.DbgEnd);
printTypeIndex("FunctionType", Proc.Header.FunctionType);
printRelocatedField("CodeOffset", Sec, Proc.getRelocationOffset(),
Proc.Header.CodeOffset, &LinkageName);
W.printHex("Segment", Proc.Header.Segment);
W.printFlags("Flags", static_cast<uint8_t>(Proc.Header.Flags),
makeArrayRef(ProcSymFlagNames));
W.printString("DisplayName", Proc.Name);
W.printString("LinkageName", LinkageName);
break;
}
case S_PROC_ID_END: {
W.startLine() << "ProcEnd\n";
InFunctionScope = false;
break;
}
case S_BLOCK32: {
DictScope S(W, "BlockStart");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto BlockOrError = BlockSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!BlockOrError)
error(BlockOrError.getError());
auto &Block = BlockOrError.get();
StringRef LinkageName;
W.printHex("PtrParent", Block.Header.PtrParent);
W.printHex("PtrEnd", Block.Header.PtrEnd);
W.printHex("CodeSize", Block.Header.CodeSize);
printRelocatedField("CodeOffset", Sec, Block.getRelocationOffset(),
Block.Header.CodeOffset, &LinkageName);
W.printHex("Segment", Block.Header.Segment);
W.printString("BlockName", Block.Name);
W.printString("LinkageName", LinkageName);
break;
}
case S_END: {
W.startLine() << "BlockEnd\n";
InFunctionScope = false;
break;
}
case S_LABEL32: {
DictScope S(W, "Label");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto LabelOrError = LabelSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!LabelOrError)
error(LabelOrError.getError());
auto &Label = LabelOrError.get();
StringRef LinkageName;
printRelocatedField("CodeOffset", Sec, Label.getRelocationOffset(),
Label.Header.CodeOffset, &LinkageName);
W.printHex("Segment", Label.Header.Segment);
W.printHex("Flags", Label.Header.Flags);
W.printFlags("Flags", Label.Header.Flags, makeArrayRef(ProcSymFlagNames));
W.printString("DisplayName", Label.Name);
W.printString("LinkageName", LinkageName);
break;
}
case S_INLINESITE: {
DictScope S(W, "InlineSite");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto InlineSiteOrError = InlineSiteSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!InlineSiteOrError)
error(InlineSiteOrError.getError());
auto &InlineSite = InlineSiteOrError.get();
W.printHex("PtrParent", InlineSite.Header.PtrParent);
W.printHex("PtrEnd", InlineSite.Header.PtrEnd);
printTypeIndex("Inlinee", InlineSite.Header.Inlinee);
ListScope BinaryAnnotations(W, "BinaryAnnotations");
for (auto &Annotation : InlineSite.annotations()) {
switch (Annotation.OpCode) {
case BinaryAnnotationsOpCode::Invalid:
return error(object_error::parse_failed);
case BinaryAnnotationsOpCode::CodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeLength:
W.printHex(Annotation.Name, Annotation.U1);
break;
case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
case BinaryAnnotationsOpCode::ChangeLineEndDelta:
case BinaryAnnotationsOpCode::ChangeRangeKind:
case BinaryAnnotationsOpCode::ChangeColumnStart:
case BinaryAnnotationsOpCode::ChangeColumnEnd:
W.printNumber(Annotation.Name, Annotation.U1);
break;
case BinaryAnnotationsOpCode::ChangeLineOffset:
case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
W.printNumber(Annotation.Name, Annotation.S1);
break;
case BinaryAnnotationsOpCode::ChangeFile:
printFileNameForOffset("ChangeFile", Annotation.U1);
break;
case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: "
<< W.hex(Annotation.U1)
<< ", LineOffset: " << Annotation.S1 << "}\n";
break;
}
case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: "
<< W.hex(Annotation.U2)
<< ", Length: " << W.hex(Annotation.U1) << "}\n";
break;
}
}
}
break;
}
case S_INLINESITE_END: {
DictScope S(W, "InlineSiteEnd");
break;
}
case S_CALLERS:
case S_CALLEES: {
ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers");
uint32_t Count;
error(consume(SymData, Count));
for (uint32_t I = 0; I < Count; ++I) {
const TypeIndex *FuncID;
error(consumeObject(SymData, FuncID));
printTypeIndex("FuncID", *FuncID);
}
break;
}
case S_LOCAL: {
DictScope S(W, "Local");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto LocalOrError = LocalSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!LocalOrError)
error(LocalOrError.getError());
auto &Local = LocalOrError.get();
printTypeIndex("Type", Local.Header.Type);
W.printFlags("Flags", uint16_t(Local.Header.Flags),
makeArrayRef(LocalFlags));
W.printString("VarName", Local.Name);
break;
}
case S_DEFRANGE: {
DictScope S(W, "DefRange");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRange = DefRangeOrError.get();
W.printString(
"Program",
CVStringTable.drop_front(DefRange.Header.Program).split('\0').first);
printLocalVariableAddrRange(DefRange.Header.Range, Sec,
DefRange.getRelocationOffset());
printLocalVariableAddrGap(DefRange.Gaps);
break;
}
case S_DEFRANGE_SUBFIELD: {
DictScope S(W, "DefRangeSubfield");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeSubfieldSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRangeSubfield = DefRangeOrError.get();
W.printString("Program",
CVStringTable.drop_front(DefRangeSubfield.Header.Program)
.split('\0')
.first);
W.printNumber("OffsetInParent", DefRangeSubfield.Header.OffsetInParent);
printLocalVariableAddrRange(DefRangeSubfield.Header.Range, Sec,
DefRangeSubfield.getRelocationOffset());
printLocalVariableAddrGap(DefRangeSubfield.Gaps);
break;
}
case S_DEFRANGE_REGISTER: {
DictScope S(W, "DefRangeRegister");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeRegisterSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRangeRegisterSym = DefRangeOrError.get();
W.printNumber("Register", DefRangeRegisterSym.Header.Register);
W.printNumber("MayHaveNoName", DefRangeRegisterSym.Header.MayHaveNoName);
printLocalVariableAddrRange(DefRangeRegisterSym.Header.Range, Sec,
DefRangeRegisterSym.getRelocationOffset());
printLocalVariableAddrGap(DefRangeRegisterSym.Gaps);
break;
}
case S_DEFRANGE_SUBFIELD_REGISTER: {
DictScope S(W, "DefRangeSubfieldRegister");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeSubfieldRegisterSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRangeSubfieldRegister = DefRangeOrError.get();
W.printNumber("Register", DefRangeSubfieldRegister.Header.Register);
W.printNumber("MayHaveNoName",
DefRangeSubfieldRegister.Header.MayHaveNoName);
W.printNumber("OffsetInParent",
DefRangeSubfieldRegister.Header.OffsetInParent);
printLocalVariableAddrRange(
DefRangeSubfieldRegister.Header.Range, Sec,
DefRangeSubfieldRegister.getRelocationOffset());
printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
break;
}
case S_DEFRANGE_FRAMEPOINTER_REL: {
DictScope S(W, "DefRangeFramePointerRel");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeFramePointerRelSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRangeFramePointerRel = DefRangeOrError.get();
W.printNumber("Offset", DefRangeFramePointerRel.Header.Offset);
printLocalVariableAddrRange(
DefRangeFramePointerRel.Header.Range, Sec,
DefRangeFramePointerRel.getRelocationOffset());
printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
break;
}
case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: {
DictScope S(W, "DefRangeFramePointerRelFullScope");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeFramePointerRelFullScopeSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRangeFramePointerRelFullScope = DefRangeOrError.get();
W.printNumber("Offset", DefRangeFramePointerRelFullScope.Header.Offset);
break;
}
case S_DEFRANGE_REGISTER_REL: {
DictScope S(W, "DefRangeRegisterRel");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto DefRangeOrError = DefRangeRegisterRelSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!DefRangeOrError)
error(DefRangeOrError.getError());
auto &DefRangeRegisterRel = DefRangeOrError.get();
W.printNumber("BaseRegister", DefRangeRegisterRel.Header.BaseRegister);
W.printBoolean("HasSpilledUDTMember",
DefRangeRegisterRel.hasSpilledUDTMember());
W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
W.printNumber("BasePointerOffset",
DefRangeRegisterRel.Header.BasePointerOffset);
printLocalVariableAddrRange(DefRangeRegisterRel.Header.Range, Sec,
DefRangeRegisterRel.getRelocationOffset());
printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
break;
}
case S_CALLSITEINFO: {
DictScope S(W, "CallSiteInfo");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto CallSiteOrError = CallSiteInfoSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!CallSiteOrError)
error(CallSiteOrError.getError());
auto &CallSiteInfo = CallSiteOrError.get();
StringRef LinkageName;
printRelocatedField("CodeOffset", Sec, CallSiteInfo.getRelocationOffset(),
CallSiteInfo.Header.CodeOffset, &LinkageName);
W.printHex("Segment", CallSiteInfo.Header.Segment);
W.printHex("Reserved", CallSiteInfo.Header.Reserved);
printTypeIndex("Type", CallSiteInfo.Header.Type);
W.printString("LinkageName", LinkageName);
break;
}
case S_HEAPALLOCSITE: {
DictScope S(W, "HeapAllocationSite");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto HeapAllocSiteOrError = HeapAllocationSiteSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!HeapAllocSiteOrError)
error(HeapAllocSiteOrError.getError());
auto &HeapAllocSite = HeapAllocSiteOrError.get();
StringRef LinkageName;
printRelocatedField("CodeOffset", Sec,
HeapAllocSite.getRelocationOffset(),
HeapAllocSite.Header.CodeOffset, &LinkageName);
W.printHex("Segment", HeapAllocSite.Header.Segment);
W.printHex("CallInstructionSize",
HeapAllocSite.Header.CallInstructionSize);
printTypeIndex("Type", HeapAllocSite.Header.Type);
W.printString("LinkageName", LinkageName);
break;
}
case S_FRAMECOOKIE: {
DictScope S(W, "FrameCookie");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto FrameCookieOrError = FrameCookieSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!FrameCookieOrError)
error(FrameCookieOrError.getError());
auto &FrameCookie = FrameCookieOrError.get();
StringRef LinkageName;
printRelocatedField("CodeOffset", Sec, FrameCookie.getRelocationOffset(),
FrameCookie.Header.CodeOffset, &LinkageName);
W.printHex("Register", FrameCookie.Header.Register);
W.printEnum("CookieKind", uint16_t(FrameCookie.Header.CookieKind),
makeArrayRef(FrameCookieKinds));
break;
}
case S_LDATA32:
case S_GDATA32:
case S_LMANDATA:
case S_GMANDATA: {
DictScope S(W, "DataSym");
ArrayRef<uint8_t> SymBytes(SymData.bytes_begin(), SymData.bytes_end());
auto DataOrError = DataSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, SymBytes);
if (!DataOrError)
error(DataOrError.getError());
auto &Data = DataOrError.get();
StringRef LinkageName;
printRelocatedField("DataOffset", Sec, Data.getRelocationOffset(),
Data.Header.DataOffset, &LinkageName);
printTypeIndex("Type", Data.Header.Type);
W.printString("DisplayName", Data.Name);
W.printString("LinkageName", LinkageName);
break;
}
case S_LTHREAD32:
case S_GTHREAD32: {
DictScope S(W, "ThreadLocalDataSym");
ArrayRef<uint8_t> SymBytes(SymData.bytes_begin(), SymData.bytes_end());
auto ThreadLocalDataOrError = ThreadLocalDataSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, SymBytes);
if (!ThreadLocalDataOrError)
error(ThreadLocalDataOrError.getError());
auto &Data = ThreadLocalDataOrError.get();
StringRef LinkageName;
printRelocatedField("DataOffset", Sec, Data.getRelocationOffset(),
Data.Header.DataOffset, &LinkageName);
printTypeIndex("Type", Data.Header.Type);
W.printString("DisplayName", Data.Name);
W.printString("LinkageName", LinkageName);
break;
}
case S_OBJNAME: {
DictScope S(W, "ObjectName");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto ObjNameOrError = ObjNameSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!ObjNameOrError)
error(ObjNameOrError.getError());
auto &ObjName = ObjNameOrError.get();
W.printHex("Signature", ObjName.Header.Signature);
W.printString("ObjectName", ObjName.Name);
break;
}
case S_COMPILE3: {
DictScope S(W, "CompilerFlags");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto Compile3OrError = CompileSym3::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!Compile3OrError)
error(Compile3OrError.getError());
auto &Compile3 = Compile3OrError.get();
W.printEnum("Language", Compile3.Header.getLanguage(),
makeArrayRef(SourceLanguages));
W.printFlags("Flags", Compile3.Header.flags & ~0xff,
makeArrayRef(CompileSym3FlagNames));
W.printEnum("Machine", unsigned(Compile3.Header.Machine),
makeArrayRef(CPUTypeNames));
std::string FrontendVersion;
{
raw_string_ostream Out(FrontendVersion);
Out << Compile3.Header.VersionFrontendMajor << '.'
<< Compile3.Header.VersionFrontendMinor << '.'
<< Compile3.Header.VersionFrontendBuild << '.'
<< Compile3.Header.VersionFrontendQFE;
}
std::string BackendVersion;
{
raw_string_ostream Out(BackendVersion);
Out << Compile3.Header.VersionBackendMajor << '.'
<< Compile3.Header.VersionBackendMinor << '.'
<< Compile3.Header.VersionBackendBuild << '.'
<< Compile3.Header.VersionBackendQFE;
}
W.printString("FrontendVersion", FrontendVersion);
W.printString("BackendVersion", BackendVersion);
W.printString("VersionName", Compile3.Version);
break;
}
case S_FRAMEPROC: {
DictScope S(W, "FrameProc");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto FrameProcOrError = FrameProcSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!FrameProcOrError)
error(FrameProcOrError.getError());
auto &FrameProc = FrameProcOrError.get();
W.printHex("TotalFrameBytes", FrameProc.Header.TotalFrameBytes);
W.printHex("PaddingFrameBytes", FrameProc.Header.PaddingFrameBytes);
W.printHex("OffsetToPadding", FrameProc.Header.OffsetToPadding);
W.printHex("BytesOfCalleeSavedRegisters",
FrameProc.Header.BytesOfCalleeSavedRegisters);
W.printHex("OffsetOfExceptionHandler",
FrameProc.Header.OffsetOfExceptionHandler);
W.printHex("SectionIdOfExceptionHandler",
FrameProc.Header.SectionIdOfExceptionHandler);
W.printFlags("Flags", FrameProc.Header.Flags,
makeArrayRef(FrameProcSymFlags));
break;
}
case S_UDT:
case S_COBOLUDT: {
DictScope S(W, "UDT");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto UdtOrError = UDTSym::deserialize(static_cast<SymbolRecordKind>(Kind),
RecordOffset, Data);
if (!UdtOrError)
error(UdtOrError.getError());
auto &UDT = UdtOrError.get();
printTypeIndex("Type", UDT.Header.Type);
W.printString("UDTName", UDT.Name);
break;
}
case S_BPREL32: {
DictScope S(W, "BPRelativeSym");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto BPRelOrError = BPRelativeSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!BPRelOrError)
error(BPRelOrError.getError());
auto &BPRel = BPRelOrError.get();
W.printNumber("Offset", BPRel.Header.Offset);
printTypeIndex("Type", BPRel.Header.Type);
W.printString("VarName", BPRel.Name);
break;
}
case S_REGREL32: {
DictScope S(W, "RegRelativeSym");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto RegRelOrError = RegRelativeSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!RegRelOrError)
error(RegRelOrError.getError());
auto &RegRel = RegRelOrError.get();
W.printHex("Offset", RegRel.Header.Offset);
printTypeIndex("Type", RegRel.Header.Type);
W.printHex("Register", RegRel.Header.Register);
W.printString("VarName", RegRel.Name);
break;
}
case S_BUILDINFO: {
DictScope S(W, "BuildInfo");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto BuildInfoOrError = BuildInfoSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!BuildInfoOrError)
error(BuildInfoOrError.getError());
auto &BuildInfo = BuildInfoOrError.get();
W.printNumber("BuildId", BuildInfo.Header.BuildId);
break;
}
case S_CONSTANT:
case S_MANCONSTANT: {
DictScope S(W, "Constant");
ArrayRef<uint8_t> Data(SymData.bytes_begin(), SymData.bytes_end());
auto ConstantOrError = ConstantSym::deserialize(
static_cast<SymbolRecordKind>(Kind), RecordOffset, Data);
if (!ConstantOrError)
error(ConstantOrError.getError());
auto &Constant = ConstantOrError.get();
printTypeIndex("Type", Constant.Header.Type);
W.printNumber("Value", Constant.Value);
W.printString("Name", Constant.Name);
break;
}
default: {
DictScope S(W, "UnknownSym");
W.printHex("Kind", unsigned(Kind));
W.printHex("Size", Rec->RecordLen);
break;
}
}
if (opts::CodeViewSubsectionBytes)
printBinaryBlockWithRelocs("SymData", Section, SectionContents,
OrigSymData);
if (!CVSD.dump(BinaryData)) {
W.flush();
error(object_error::parse_failed);
}
W.flush();
}
@ -1633,24 +970,6 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
}
}
void COFFDumper::printLocalVariableAddrRange(
const LocalVariableAddrRange &Range, const coff_section *Sec,
uint32_t RelocationOffset) {
DictScope S(W, "LocalVariableAddrRange");
printRelocatedField("OffsetStart", Sec, RelocationOffset, Range.OffsetStart);
W.printHex("ISectStart", Range.ISectStart);
W.printHex("Range", Range.Range);
}
void COFFDumper::printLocalVariableAddrGap(
ArrayRef<LocalVariableAddrGap> Gaps) {
for (auto &Gap : Gaps) {
ListScope S(W, "LocalVariableAddrGap");
W.printHex("GapStartOffset", Gap.GapStartOffset);
W.printHex("Range", Gap.Range);
}
}
StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {
// The file checksum subsection should precede all references to it.
if (!CVFileChecksumTable.data() || !CVStringTable.data())