1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00

[Debuginfo][COFF] Minimal serialization support for precompiled types records

This change adds support for the LF_PRECOMP and LF_ENDPRECOMP records required
to read/write Microsoft precompiled types .objs.
See https://en.wikipedia.org/wiki/Precompiled_header#Microsoft_Visual_C_and_C++

This also adds handling for the .debug$P section, which is actually a .debug$T
section in disguise, found only in precompiled .objs.

Differential Revision: https://reviews.llvm.org/D45283

llvm-svn: 329613
This commit is contained in:
Alexandre Ganea 2018-04-09 20:17:56 +00:00
parent 8fce7e82b9
commit 325264aa91
21 changed files with 4384 additions and 4203 deletions

View File

@ -22,8 +22,8 @@
namespace llvm { namespace llvm {
namespace codeview { namespace codeview {
/// Distinguishes individual records in .debug$T section or PDB type stream. The /// Distinguishes individual records in .debug$T or .debug$P section or PDB type
/// documentation and headers talk about this as the "leaf" type. /// stream. The documentation and headers talk about this as the "leaf" type.
enum class TypeRecordKind : uint16_t { enum class TypeRecordKind : uint16_t {
#define TYPE_RECORD(lf_ename, value, name) name = value, #define TYPE_RECORD(lf_ename, value, name) name = value,
#include "CodeViewTypes.def" #include "CodeViewTypes.def"

View File

@ -87,6 +87,8 @@ TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine)
TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList) TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList)
TYPE_RECORD(LF_PRECOMP, 0x1509, Precomp)
TYPE_RECORD(LF_ENDPRECOMP, 0x0014, EndPrecomp)
// 16 bit type records. // 16 bit type records.
CV_TYPE(LF_MODIFIER_16t, 0x0001) CV_TYPE(LF_MODIFIER_16t, 0x0001)
@ -106,7 +108,6 @@ CV_TYPE(LF_NOTTRAN, 0x0010)
CV_TYPE(LF_DIMARRAY_16t, 0x0011) CV_TYPE(LF_DIMARRAY_16t, 0x0011)
CV_TYPE(LF_VFTPATH_16t, 0x0012) CV_TYPE(LF_VFTPATH_16t, 0x0012)
CV_TYPE(LF_PRECOMP_16t, 0x0013) CV_TYPE(LF_PRECOMP_16t, 0x0013)
CV_TYPE(LF_ENDPRECOMP, 0x0014)
CV_TYPE(LF_OEM_16t, 0x0015) CV_TYPE(LF_OEM_16t, 0x0015)
CV_TYPE(LF_TYPESERVER_ST, 0x0016) CV_TYPE(LF_TYPESERVER_ST, 0x0016)
@ -181,7 +182,6 @@ CV_TYPE(LF_MANAGED_ST, 0x140f)
CV_TYPE(LF_ST_MAX, 0x1500) CV_TYPE(LF_ST_MAX, 0x1500)
CV_TYPE(LF_TYPESERVER, 0x1501) CV_TYPE(LF_TYPESERVER, 0x1501)
CV_TYPE(LF_DIMARRAY, 0x1508) CV_TYPE(LF_DIMARRAY, 0x1508)
CV_TYPE(LF_PRECOMP, 0x1509)
CV_TYPE(LF_ALIAS, 0x150a) CV_TYPE(LF_ALIAS, 0x150a)
CV_TYPE(LF_DEFARG, 0x150b) CV_TYPE(LF_DEFARG, 0x150b)
CV_TYPE(LF_FRIENDFCN, 0x150c) CV_TYPE(LF_FRIENDFCN, 0x150c)

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,7 @@ struct Section {
yaml::BinaryRef SectionData; yaml::BinaryRef SectionData;
std::vector<CodeViewYAML::YAMLDebugSubsection> DebugS; std::vector<CodeViewYAML::YAMLDebugSubsection> DebugS;
std::vector<CodeViewYAML::LeafRecord> DebugT; std::vector<CodeViewYAML::LeafRecord> DebugT;
std::vector<CodeViewYAML::LeafRecord> DebugP;
Optional<CodeViewYAML::DebugHSection> DebugH; Optional<CodeViewYAML::DebugHSection> DebugH;
std::vector<Relocation> Relocations; std::vector<Relocation> Relocations;
StringRef Name; StringRef Name;

View File

@ -47,7 +47,7 @@ struct DebugHSection {
std::vector<GlobalHash> Hashes; std::vector<GlobalHash> Hashes;
}; };
DebugHSection fromDebugH(ArrayRef<uint8_t> DebugT); DebugHSection fromDebugH(ArrayRef<uint8_t> DebugH);
ArrayRef<uint8_t> toDebugH(const DebugHSection &DebugH, ArrayRef<uint8_t> toDebugH(const DebugHSection &DebugH,
BumpPtrAllocator &Alloc); BumpPtrAllocator &Alloc);

View File

@ -51,8 +51,10 @@ struct LeafRecord {
static Expected<LeafRecord> fromCodeViewRecord(codeview::CVType Type); static Expected<LeafRecord> fromCodeViewRecord(codeview::CVType Type);
}; };
std::vector<LeafRecord> fromDebugT(ArrayRef<uint8_t> DebugT); std::vector<LeafRecord> fromDebugT(ArrayRef<uint8_t> DebugTorP,
ArrayRef<uint8_t> toDebugT(ArrayRef<LeafRecord>, BumpPtrAllocator &Alloc); StringRef SectionName);
ArrayRef<uint8_t> toDebugT(ArrayRef<LeafRecord>, BumpPtrAllocator &Alloc,
StringRef SectionName);
} // end namespace CodeViewYAML } // end namespace CodeViewYAML

View File

@ -524,7 +524,7 @@ void CodeViewDebug::emitTypeInformation() {
if (TypeTable.empty()) if (TypeTable.empty())
return; return;
// Start the .debug$T section with 0x4. // Start the .debug$T or .debug$P section with 0x4.
OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection()); OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection());
emitCodeViewMagicVersion(); emitCodeViewMagicVersion();

View File

@ -239,7 +239,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
} }
/// Emit the magic version number at the start of a CodeView type or symbol /// Emit the magic version number at the start of a CodeView type or symbol
/// section. Appears at the front of every .debug$S or .debug$T section. /// section. Appears at the front of every .debug$S or .debug$T or .debug$P
/// section.
void emitCodeViewMagicVersion(); void emitCodeViewMagicVersion();
void emitTypeInformation(); void emitTypeInformation();

View File

@ -1,323 +1,333 @@
//===- RecordName.cpp ----------------------------------------- *- C++ --*-===// //===- RecordName.cpp ----------------------------------------- *- C++ --*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
// This file is distributed under the University of Illinois Open Source // This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details. // License. See LICENSE.TXT for details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/RecordName.h" #include "llvm/DebugInfo/CodeView/RecordName.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormatVariadic.h"
using namespace llvm; using namespace llvm;
using namespace llvm::codeview; using namespace llvm::codeview;
namespace { namespace {
class TypeNameComputer : public TypeVisitorCallbacks { class TypeNameComputer : public TypeVisitorCallbacks {
/// The type collection. Used to calculate names of nested types. /// The type collection. Used to calculate names of nested types.
TypeCollection &Types; TypeCollection &Types;
TypeIndex CurrentTypeIndex = TypeIndex::None(); TypeIndex CurrentTypeIndex = TypeIndex::None();
/// Name of the current type. Only valid before visitTypeEnd. /// Name of the current type. Only valid before visitTypeEnd.
SmallString<256> Name; SmallString<256> Name;
public: public:
explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {}
StringRef name() const { return Name; } StringRef name() const { return Name; }
/// Paired begin/end actions for all types. Receives all record data, /// Paired begin/end actions for all types. Receives all record data,
/// including the fixed-length record prefix. /// including the fixed-length record prefix.
Error visitTypeBegin(CVType &Record) override; Error visitTypeBegin(CVType &Record) override;
Error visitTypeBegin(CVType &Record, TypeIndex Index) override; Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
Error visitTypeEnd(CVType &Record) override; Error visitTypeEnd(CVType &Record) override;
#define TYPE_RECORD(EnumName, EnumVal, Name) \ #define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD(EnumName, EnumVal, Name) #define MEMBER_RECORD(EnumName, EnumVal, Name)
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
}; };
} // namespace } // namespace
Error TypeNameComputer::visitTypeBegin(CVType &Record) { Error TypeNameComputer::visitTypeBegin(CVType &Record) {
llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) {
// Reset Name to the empty string. If the visitor sets it, we know it. // Reset Name to the empty string. If the visitor sets it, we know it.
Name = ""; Name = "";
CurrentTypeIndex = Index; CurrentTypeIndex = Index;
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
FieldListRecord &FieldList) { FieldListRecord &FieldList) {
Name = "<field list>"; Name = "<field list>";
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
StringIdRecord &String) { StringIdRecord &String) {
Name = String.getString(); Name = String.getString();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
auto Indices = Args.getIndices(); auto Indices = Args.getIndices();
uint32_t Size = Indices.size(); uint32_t Size = Indices.size();
Name = "("; Name = "(";
for (uint32_t I = 0; I < Size; ++I) { for (uint32_t I = 0; I < Size; ++I) {
assert(Indices[I] < CurrentTypeIndex); assert(Indices[I] < CurrentTypeIndex);
Name.append(Types.getTypeName(Indices[I])); Name.append(Types.getTypeName(Indices[I]));
if (I + 1 != Size) if (I + 1 != Size)
Name.append(", "); Name.append(", ");
} }
Name.push_back(')'); Name.push_back(')');
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
StringListRecord &Strings) { StringListRecord &Strings) {
auto Indices = Strings.getIndices(); auto Indices = Strings.getIndices();
uint32_t Size = Indices.size(); uint32_t Size = Indices.size();
Name = "\""; Name = "\"";
for (uint32_t I = 0; I < Size; ++I) { for (uint32_t I = 0; I < Size; ++I) {
Name.append(Types.getTypeName(Indices[I])); Name.append(Types.getTypeName(Indices[I]));
if (I + 1 != Size) if (I + 1 != Size)
Name.append("\" \""); Name.append("\" \"");
} }
Name.push_back('\"'); Name.push_back('\"');
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
Name = Class.getName(); Name = Class.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
Name = Union.getName(); Name = Union.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
Name = Enum.getName(); Name = Enum.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
Name = AT.getName(); Name = AT.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
Name = VFT.getName(); Name = VFT.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
Name = Id.getName(); Name = Id.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
StringRef Ret = Types.getTypeName(Proc.getReturnType()); StringRef Ret = Types.getTypeName(Proc.getReturnType());
StringRef Params = Types.getTypeName(Proc.getArgumentList()); StringRef Params = Types.getTypeName(Proc.getArgumentList());
Name = formatv("{0} {1}", Ret, Params).sstr<256>(); Name = formatv("{0} {1}", Ret, Params).sstr<256>();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
MemberFunctionRecord &MF) { MemberFunctionRecord &MF) {
StringRef Ret = Types.getTypeName(MF.getReturnType()); StringRef Ret = Types.getTypeName(MF.getReturnType());
StringRef Class = Types.getTypeName(MF.getClassType()); StringRef Class = Types.getTypeName(MF.getClassType());
StringRef Params = Types.getTypeName(MF.getArgumentList()); StringRef Params = Types.getTypeName(MF.getArgumentList());
Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
Name = Func.getName(); Name = Func.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
Name = TS.getName(); Name = TS.getName();
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
if (Ptr.isPointerToMember()) { if (Ptr.isPointerToMember()) {
const MemberPointerInfo &MI = Ptr.getMemberInfo(); const MemberPointerInfo &MI = Ptr.getMemberInfo();
StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); StringRef Pointee = Types.getTypeName(Ptr.getReferentType());
StringRef Class = Types.getTypeName(MI.getContainingType()); StringRef Class = Types.getTypeName(MI.getContainingType());
Name = formatv("{0} {1}::*", Pointee, Class); Name = formatv("{0} {1}::*", Pointee, Class);
} else { } else {
Name.append(Types.getTypeName(Ptr.getReferentType())); Name.append(Types.getTypeName(Ptr.getReferentType()));
if (Ptr.getMode() == PointerMode::LValueReference) if (Ptr.getMode() == PointerMode::LValueReference)
Name.append("&"); Name.append("&");
else if (Ptr.getMode() == PointerMode::RValueReference) else if (Ptr.getMode() == PointerMode::RValueReference)
Name.append("&&"); Name.append("&&");
else if (Ptr.getMode() == PointerMode::Pointer) else if (Ptr.getMode() == PointerMode::Pointer)
Name.append("*"); Name.append("*");
// Qualifiers in pointer records apply to the pointer, not the pointee, so // Qualifiers in pointer records apply to the pointer, not the pointee, so
// they go on the right. // they go on the right.
if (Ptr.isConst()) if (Ptr.isConst())
Name.append(" const"); Name.append(" const");
if (Ptr.isVolatile()) if (Ptr.isVolatile())
Name.append(" volatile"); Name.append(" volatile");
if (Ptr.isUnaligned()) if (Ptr.isUnaligned())
Name.append(" __unaligned"); Name.append(" __unaligned");
if (Ptr.isRestrict()) if (Ptr.isRestrict())
Name.append(" __restrict"); Name.append(" __restrict");
} }
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
if (Mods & uint16_t(ModifierOptions::Const)) if (Mods & uint16_t(ModifierOptions::Const))
Name.append("const "); Name.append("const ");
if (Mods & uint16_t(ModifierOptions::Volatile)) if (Mods & uint16_t(ModifierOptions::Volatile))
Name.append("volatile "); Name.append("volatile ");
if (Mods & uint16_t(ModifierOptions::Unaligned)) if (Mods & uint16_t(ModifierOptions::Unaligned))
Name.append("__unaligned "); Name.append("__unaligned ");
Name.append(Types.getTypeName(Mod.getModifiedType())); Name.append(Types.getTypeName(Mod.getModifiedType()));
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
VFTableShapeRecord &Shape) { VFTableShapeRecord &Shape) {
Name = formatv("<vftable {0} methods>", Shape.getEntryCount()); Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord( Error TypeNameComputer::visitKnownRecord(
CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
UdtSourceLineRecord &SourceLine) { UdtSourceLineRecord &SourceLine) {
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
MethodOverloadListRecord &Overloads) { MethodOverloadListRecord &Overloads) {
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
return Error::success(); return Error::success();
} }
Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
return Error::success(); return Error::success();
} }
std::string llvm::codeview::computeTypeName(TypeCollection &Types, Error TypeNameComputer::visitKnownRecord(CVType &CVR,
TypeIndex Index) { PrecompRecord &Precomp) {
TypeNameComputer Computer(Types); return Error::success();
CVType Record = Types.getType(Index); }
if (auto EC = visitTypeRecord(Record, Index, Computer)) {
consumeError(std::move(EC)); Error TypeNameComputer::visitKnownRecord(CVType &CVR,
return "<unknown UDT>"; EndPrecompRecord &EndPrecomp) {
} return Error::success();
return Computer.name(); }
}
std::string llvm::codeview::computeTypeName(TypeCollection &Types,
static int getSymbolNameOffset(CVSymbol Sym) { TypeIndex Index) {
switch (Sym.kind()) { TypeNameComputer Computer(Types);
// See ProcSym CVType Record = Types.getType(Index);
case SymbolKind::S_GPROC32: if (auto EC = visitTypeRecord(Record, Index, Computer)) {
case SymbolKind::S_LPROC32: consumeError(std::move(EC));
case SymbolKind::S_GPROC32_ID: return "<unknown UDT>";
case SymbolKind::S_LPROC32_ID: }
case SymbolKind::S_LPROC32_DPC: return Computer.name();
case SymbolKind::S_LPROC32_DPC_ID: }
return 35;
// See Thunk32Sym static int getSymbolNameOffset(CVSymbol Sym) {
case SymbolKind::S_THUNK32: switch (Sym.kind()) {
return 21; // See ProcSym
// See SectionSym case SymbolKind::S_GPROC32:
case SymbolKind::S_SECTION: case SymbolKind::S_LPROC32:
return 16; case SymbolKind::S_GPROC32_ID:
// See CoffGroupSym case SymbolKind::S_LPROC32_ID:
case SymbolKind::S_COFFGROUP: case SymbolKind::S_LPROC32_DPC:
return 14; case SymbolKind::S_LPROC32_DPC_ID:
// See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym return 35;
case SymbolKind::S_PUB32: // See Thunk32Sym
case SymbolKind::S_FILESTATIC: case SymbolKind::S_THUNK32:
case SymbolKind::S_REGREL32: return 21;
case SymbolKind::S_GDATA32: // See SectionSym
case SymbolKind::S_LDATA32: case SymbolKind::S_SECTION:
case SymbolKind::S_LMANDATA: return 16;
case SymbolKind::S_GMANDATA: // See CoffGroupSym
case SymbolKind::S_LTHREAD32: case SymbolKind::S_COFFGROUP:
case SymbolKind::S_GTHREAD32: return 14;
return 10; // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
// See RegisterSym and LocalSym case SymbolKind::S_PUB32:
case SymbolKind::S_REGISTER: case SymbolKind::S_FILESTATIC:
case SymbolKind::S_LOCAL: case SymbolKind::S_REGREL32:
return 6; case SymbolKind::S_GDATA32:
// See BlockSym case SymbolKind::S_LDATA32:
case SymbolKind::S_BLOCK32: case SymbolKind::S_LMANDATA:
return 18; case SymbolKind::S_GMANDATA:
// See LabelSym case SymbolKind::S_LTHREAD32:
case SymbolKind::S_LABEL32: case SymbolKind::S_GTHREAD32:
return 7; return 10;
// See ObjNameSym, ExportSym, and UDTSym // See RegisterSym and LocalSym
case SymbolKind::S_OBJNAME: case SymbolKind::S_REGISTER:
case SymbolKind::S_EXPORT: case SymbolKind::S_LOCAL:
case SymbolKind::S_UDT: return 6;
return 4; // See BlockSym
// See BPRelativeSym case SymbolKind::S_BLOCK32:
case SymbolKind::S_BPREL32: return 18;
return 8; // See LabelSym
default: case SymbolKind::S_LABEL32:
return -1; return 7;
} // See ObjNameSym, ExportSym, and UDTSym
} case SymbolKind::S_OBJNAME:
case SymbolKind::S_EXPORT:
StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { case SymbolKind::S_UDT:
if (Sym.kind() == SymbolKind::S_CONSTANT) { return 4;
// S_CONSTANT is preceded by an APSInt, which has a variable length. So we // See BPRelativeSym
// have to do a full deserialization. case SymbolKind::S_BPREL32:
BinaryStreamReader Reader(Sym.content(), llvm::support::little); return 8;
// The container doesn't matter for single records. default:
SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); return -1;
ConstantSym Const(SymbolKind::S_CONSTANT); }
cantFail(Mapping.visitSymbolBegin(Sym)); }
cantFail(Mapping.visitKnownRecord(Sym, Const));
cantFail(Mapping.visitSymbolEnd(Sym)); StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
return Const.Name; if (Sym.kind() == SymbolKind::S_CONSTANT) {
} // S_CONSTANT is preceded by an APSInt, which has a variable length. So we
// have to do a full deserialization.
int Offset = getSymbolNameOffset(Sym); BinaryStreamReader Reader(Sym.content(), llvm::support::little);
if (Offset == -1) // The container doesn't matter for single records.
return StringRef(); SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
ConstantSym Const(SymbolKind::S_CONSTANT);
StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); cantFail(Mapping.visitSymbolBegin(Sym));
return StringData.split('\0').first; cantFail(Mapping.visitKnownRecord(Sym, Const));
} cantFail(Mapping.visitSymbolEnd(Sym));
return Const.Name;
}
int Offset = getSymbolNameOffset(Sym);
if (Offset == -1)
return StringRef();
StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
return StringData.split('\0').first;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,482 +1,497 @@
//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===// //===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
// This file is distributed under the University of Illinois Open Source // This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details. // License. See LICENSE.TXT for details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
using namespace llvm; using namespace llvm;
using namespace llvm::codeview; using namespace llvm::codeview;
#define error(X) \ #define error(X) \
if (auto EC = X) \ if (auto EC = X) \
return EC; return EC;
namespace { namespace {
struct MapOneMethodRecord { struct MapOneMethodRecord {
explicit MapOneMethodRecord(bool IsFromOverloadList) explicit MapOneMethodRecord(bool IsFromOverloadList)
: IsFromOverloadList(IsFromOverloadList) {} : IsFromOverloadList(IsFromOverloadList) {}
Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const { Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
error(IO.mapInteger(Method.Attrs.Attrs)); error(IO.mapInteger(Method.Attrs.Attrs));
if (IsFromOverloadList) { if (IsFromOverloadList) {
uint16_t Padding = 0; uint16_t Padding = 0;
error(IO.mapInteger(Padding)); error(IO.mapInteger(Padding));
} }
error(IO.mapInteger(Method.Type)); error(IO.mapInteger(Method.Type));
if (Method.isIntroducingVirtual()) { if (Method.isIntroducingVirtual()) {
error(IO.mapInteger(Method.VFTableOffset)); error(IO.mapInteger(Method.VFTableOffset));
} else if (!IO.isWriting()) } else if (!IO.isWriting())
Method.VFTableOffset = -1; Method.VFTableOffset = -1;
if (!IsFromOverloadList) if (!IsFromOverloadList)
error(IO.mapStringZ(Method.Name)); error(IO.mapStringZ(Method.Name));
return Error::success(); return Error::success();
} }
private: private:
bool IsFromOverloadList; bool IsFromOverloadList;
}; };
} }
static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name, static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
StringRef &UniqueName, bool HasUniqueName) { StringRef &UniqueName, bool HasUniqueName) {
if (IO.isWriting()) { if (IO.isWriting()) {
// Try to be smart about what we write here. We can't write anything too // Try to be smart about what we write here. We can't write anything too
// large, so if we're going to go over the limit, truncate both the name // large, so if we're going to go over the limit, truncate both the name
// and unique name by the same amount. // and unique name by the same amount.
size_t BytesLeft = IO.maxFieldLength(); size_t BytesLeft = IO.maxFieldLength();
if (HasUniqueName) { if (HasUniqueName) {
size_t BytesNeeded = Name.size() + UniqueName.size() + 2; size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
StringRef N = Name; StringRef N = Name;
StringRef U = UniqueName; StringRef U = UniqueName;
if (BytesNeeded > BytesLeft) { if (BytesNeeded > BytesLeft) {
size_t BytesToDrop = (BytesNeeded - BytesLeft); size_t BytesToDrop = (BytesNeeded - BytesLeft);
size_t DropN = std::min(N.size(), BytesToDrop / 2); size_t DropN = std::min(N.size(), BytesToDrop / 2);
size_t DropU = std::min(U.size(), BytesToDrop - DropN); size_t DropU = std::min(U.size(), BytesToDrop - DropN);
N = N.drop_back(DropN); N = N.drop_back(DropN);
U = U.drop_back(DropU); U = U.drop_back(DropU);
} }
error(IO.mapStringZ(N)); error(IO.mapStringZ(N));
error(IO.mapStringZ(U)); error(IO.mapStringZ(U));
} else { } else {
// Cap the length of the string at however many bytes we have available, // Cap the length of the string at however many bytes we have available,
// plus one for the required null terminator. // plus one for the required null terminator.
auto N = StringRef(Name).take_front(BytesLeft - 1); auto N = StringRef(Name).take_front(BytesLeft - 1);
error(IO.mapStringZ(N)); error(IO.mapStringZ(N));
} }
} else { } else {
error(IO.mapStringZ(Name)); error(IO.mapStringZ(Name));
if (HasUniqueName) if (HasUniqueName)
error(IO.mapStringZ(UniqueName)); error(IO.mapStringZ(UniqueName));
} }
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitTypeBegin(CVType &CVR) { Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
assert(!TypeKind.hasValue() && "Already in a type mapping!"); assert(!TypeKind.hasValue() && "Already in a type mapping!");
assert(!MemberKind.hasValue() && "Already in a member mapping!"); assert(!MemberKind.hasValue() && "Already in a member mapping!");
// FieldList and MethodList records can be any length because they can be // FieldList and MethodList records can be any length because they can be
// split with continuation records. All other record types cannot be // split with continuation records. All other record types cannot be
// longer than the maximum record length. // longer than the maximum record length.
Optional<uint32_t> MaxLen; Optional<uint32_t> MaxLen;
if (CVR.Type != TypeLeafKind::LF_FIELDLIST && if (CVR.Type != TypeLeafKind::LF_FIELDLIST &&
CVR.Type != TypeLeafKind::LF_METHODLIST) CVR.Type != TypeLeafKind::LF_METHODLIST)
MaxLen = MaxRecordLength - sizeof(RecordPrefix); MaxLen = MaxRecordLength - sizeof(RecordPrefix);
error(IO.beginRecord(MaxLen)); error(IO.beginRecord(MaxLen));
TypeKind = CVR.Type; TypeKind = CVR.Type;
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitTypeEnd(CVType &Record) { Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
assert(TypeKind.hasValue() && "Not in a type mapping!"); assert(TypeKind.hasValue() && "Not in a type mapping!");
assert(!MemberKind.hasValue() && "Still in a member mapping!"); assert(!MemberKind.hasValue() && "Still in a member mapping!");
error(IO.endRecord()); error(IO.endRecord());
TypeKind.reset(); TypeKind.reset();
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) { Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
assert(TypeKind.hasValue() && "Not in a type mapping!"); assert(TypeKind.hasValue() && "Not in a type mapping!");
assert(!MemberKind.hasValue() && "Already in a member mapping!"); assert(!MemberKind.hasValue() && "Already in a member mapping!");
// The largest possible subrecord is one in which there is a record prefix, // The largest possible subrecord is one in which there is a record prefix,
// followed by the subrecord, followed by a continuation, and that entire // followed by the subrecord, followed by a continuation, and that entire
// sequence spaws `MaxRecordLength` bytes. So the record's length is // sequence spaws `MaxRecordLength` bytes. So the record's length is
// calculated as follows. // calculated as follows.
constexpr uint32_t ContinuationLength = 8; constexpr uint32_t ContinuationLength = 8;
error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) - error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
ContinuationLength)); ContinuationLength));
MemberKind = Record.Kind; MemberKind = Record.Kind;
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) { Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
assert(TypeKind.hasValue() && "Not in a type mapping!"); assert(TypeKind.hasValue() && "Not in a type mapping!");
assert(MemberKind.hasValue() && "Not in a member mapping!"); assert(MemberKind.hasValue() && "Not in a member mapping!");
if (!IO.isWriting()) { if (!IO.isWriting()) {
if (auto EC = IO.skipPadding()) if (auto EC = IO.skipPadding())
return EC; return EC;
} }
MemberKind.reset(); MemberKind.reset();
error(IO.endRecord()); error(IO.endRecord());
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
error(IO.mapInteger(Record.ModifiedType)); error(IO.mapInteger(Record.ModifiedType));
error(IO.mapEnum(Record.Modifiers)); error(IO.mapEnum(Record.Modifiers));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
ProcedureRecord &Record) { ProcedureRecord &Record) {
error(IO.mapInteger(Record.ReturnType)); error(IO.mapInteger(Record.ReturnType));
error(IO.mapEnum(Record.CallConv)); error(IO.mapEnum(Record.CallConv));
error(IO.mapEnum(Record.Options)); error(IO.mapEnum(Record.Options));
error(IO.mapInteger(Record.ParameterCount)); error(IO.mapInteger(Record.ParameterCount));
error(IO.mapInteger(Record.ArgumentList)); error(IO.mapInteger(Record.ArgumentList));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
MemberFunctionRecord &Record) { MemberFunctionRecord &Record) {
error(IO.mapInteger(Record.ReturnType)); error(IO.mapInteger(Record.ReturnType));
error(IO.mapInteger(Record.ClassType)); error(IO.mapInteger(Record.ClassType));
error(IO.mapInteger(Record.ThisType)); error(IO.mapInteger(Record.ThisType));
error(IO.mapEnum(Record.CallConv)); error(IO.mapEnum(Record.CallConv));
error(IO.mapEnum(Record.Options)); error(IO.mapEnum(Record.Options));
error(IO.mapInteger(Record.ParameterCount)); error(IO.mapInteger(Record.ParameterCount));
error(IO.mapInteger(Record.ArgumentList)); error(IO.mapInteger(Record.ArgumentList));
error(IO.mapInteger(Record.ThisPointerAdjustment)); error(IO.mapInteger(Record.ThisPointerAdjustment));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
error(IO.mapVectorN<uint32_t>( error(IO.mapVectorN<uint32_t>(
Record.ArgIndices, Record.ArgIndices,
[](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
StringListRecord &Record) { StringListRecord &Record) {
error(IO.mapVectorN<uint32_t>( error(IO.mapVectorN<uint32_t>(
Record.StringIndices, Record.StringIndices,
[](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
error(IO.mapInteger(Record.ReferentType)); error(IO.mapInteger(Record.ReferentType));
error(IO.mapInteger(Record.Attrs)); error(IO.mapInteger(Record.Attrs));
if (Record.isPointerToMember()) { if (Record.isPointerToMember()) {
if (!IO.isWriting()) if (!IO.isWriting())
Record.MemberInfo.emplace(); Record.MemberInfo.emplace();
MemberPointerInfo &M = *Record.MemberInfo; MemberPointerInfo &M = *Record.MemberInfo;
error(IO.mapInteger(M.ContainingType)); error(IO.mapInteger(M.ContainingType));
error(IO.mapEnum(M.Representation)); error(IO.mapEnum(M.Representation));
} }
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
error(IO.mapInteger(Record.ElementType)); error(IO.mapInteger(Record.ElementType));
error(IO.mapInteger(Record.IndexType)); error(IO.mapInteger(Record.IndexType));
error(IO.mapEncodedInteger(Record.Size)); error(IO.mapEncodedInteger(Record.Size));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) || assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) ||
(CVR.Type == TypeLeafKind::LF_CLASS) || (CVR.Type == TypeLeafKind::LF_CLASS) ||
(CVR.Type == TypeLeafKind::LF_INTERFACE)); (CVR.Type == TypeLeafKind::LF_INTERFACE));
error(IO.mapInteger(Record.MemberCount)); error(IO.mapInteger(Record.MemberCount));
error(IO.mapEnum(Record.Options)); error(IO.mapEnum(Record.Options));
error(IO.mapInteger(Record.FieldList)); error(IO.mapInteger(Record.FieldList));
error(IO.mapInteger(Record.DerivationList)); error(IO.mapInteger(Record.DerivationList));
error(IO.mapInteger(Record.VTableShape)); error(IO.mapInteger(Record.VTableShape));
error(IO.mapEncodedInteger(Record.Size)); error(IO.mapEncodedInteger(Record.Size));
error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
Record.hasUniqueName())); Record.hasUniqueName()));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
error(IO.mapInteger(Record.MemberCount)); error(IO.mapInteger(Record.MemberCount));
error(IO.mapEnum(Record.Options)); error(IO.mapEnum(Record.Options));
error(IO.mapInteger(Record.FieldList)); error(IO.mapInteger(Record.FieldList));
error(IO.mapEncodedInteger(Record.Size)); error(IO.mapEncodedInteger(Record.Size));
error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
Record.hasUniqueName())); Record.hasUniqueName()));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
error(IO.mapInteger(Record.MemberCount)); error(IO.mapInteger(Record.MemberCount));
error(IO.mapEnum(Record.Options)); error(IO.mapEnum(Record.Options));
error(IO.mapInteger(Record.UnderlyingType)); error(IO.mapInteger(Record.UnderlyingType));
error(IO.mapInteger(Record.FieldList)); error(IO.mapInteger(Record.FieldList));
error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
Record.hasUniqueName())); Record.hasUniqueName()));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
error(IO.mapInteger(Record.Type)); error(IO.mapInteger(Record.Type));
error(IO.mapInteger(Record.BitSize)); error(IO.mapInteger(Record.BitSize));
error(IO.mapInteger(Record.BitOffset)); error(IO.mapInteger(Record.BitOffset));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
VFTableShapeRecord &Record) { VFTableShapeRecord &Record) {
uint16_t Size; uint16_t Size;
if (IO.isWriting()) { if (IO.isWriting()) {
ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
Size = Slots.size(); Size = Slots.size();
error(IO.mapInteger(Size)); error(IO.mapInteger(Size));
for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) { for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4; uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
if ((SlotIndex + 1) < Slots.size()) { if ((SlotIndex + 1) < Slots.size()) {
Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]); Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
} }
error(IO.mapInteger(Byte)); error(IO.mapInteger(Byte));
} }
} else { } else {
error(IO.mapInteger(Size)); error(IO.mapInteger(Size));
for (uint16_t I = 0; I < Size; I += 2) { for (uint16_t I = 0; I < Size; I += 2) {
uint8_t Byte; uint8_t Byte;
error(IO.mapInteger(Byte)); error(IO.mapInteger(Byte));
Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF)); Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
if ((I + 1) < Size) if ((I + 1) < Size)
Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4)); Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
} }
} }
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
error(IO.mapInteger(Record.CompleteClass)); error(IO.mapInteger(Record.CompleteClass));
error(IO.mapInteger(Record.OverriddenVFTable)); error(IO.mapInteger(Record.OverriddenVFTable));
error(IO.mapInteger(Record.VFPtrOffset)); error(IO.mapInteger(Record.VFPtrOffset));
uint32_t NamesLen = 0; uint32_t NamesLen = 0;
if (IO.isWriting()) { if (IO.isWriting()) {
for (auto Name : Record.MethodNames) for (auto Name : Record.MethodNames)
NamesLen += Name.size() + 1; NamesLen += Name.size() + 1;
} }
error(IO.mapInteger(NamesLen)); error(IO.mapInteger(NamesLen));
error(IO.mapVectorTail( error(IO.mapVectorTail(
Record.MethodNames, Record.MethodNames,
[](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); })); [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
error(IO.mapInteger(Record.Id)); error(IO.mapInteger(Record.Id));
error(IO.mapStringZ(Record.String)); error(IO.mapStringZ(Record.String));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
UdtSourceLineRecord &Record) { UdtSourceLineRecord &Record) {
error(IO.mapInteger(Record.UDT)); error(IO.mapInteger(Record.UDT));
error(IO.mapInteger(Record.SourceFile)); error(IO.mapInteger(Record.SourceFile));
error(IO.mapInteger(Record.LineNumber)); error(IO.mapInteger(Record.LineNumber));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
UdtModSourceLineRecord &Record) { UdtModSourceLineRecord &Record) {
error(IO.mapInteger(Record.UDT)); error(IO.mapInteger(Record.UDT));
error(IO.mapInteger(Record.SourceFile)); error(IO.mapInteger(Record.SourceFile));
error(IO.mapInteger(Record.LineNumber)); error(IO.mapInteger(Record.LineNumber));
error(IO.mapInteger(Record.Module)); error(IO.mapInteger(Record.Module));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
error(IO.mapInteger(Record.ParentScope)); error(IO.mapInteger(Record.ParentScope));
error(IO.mapInteger(Record.FunctionType)); error(IO.mapInteger(Record.FunctionType));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
MemberFuncIdRecord &Record) { MemberFuncIdRecord &Record) {
error(IO.mapInteger(Record.ClassType)); error(IO.mapInteger(Record.ClassType));
error(IO.mapInteger(Record.FunctionType)); error(IO.mapInteger(Record.FunctionType));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
BuildInfoRecord &Record) { BuildInfoRecord &Record) {
error(IO.mapVectorN<uint16_t>( error(IO.mapVectorN<uint16_t>(
Record.ArgIndices, Record.ArgIndices,
[](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
MethodOverloadListRecord &Record) { MethodOverloadListRecord &Record) {
// TODO: Split the list into multiple records if it's longer than 64KB, using // TODO: Split the list into multiple records if it's longer than 64KB, using
// a subrecord of TypeRecordKind::Index to chain the records together. // a subrecord of TypeRecordKind::Index to chain the records together.
error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true))); error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true)));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
FieldListRecord &Record) { FieldListRecord &Record) {
error(IO.mapByteVectorTail(Record.Data)); error(IO.mapByteVectorTail(Record.Data));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
TypeServer2Record &Record) { TypeServer2Record &Record) {
error(IO.mapGuid(Record.Guid)); error(IO.mapGuid(Record.Guid));
error(IO.mapInteger(Record.Age)); error(IO.mapInteger(Record.Age));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) { Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
error(IO.mapEnum(Record.Mode)); error(IO.mapEnum(Record.Mode));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
BaseClassRecord &Record) { BaseClassRecord &Record) {
error(IO.mapInteger(Record.Attrs.Attrs)); error(IO.mapInteger(Record.Attrs.Attrs));
error(IO.mapInteger(Record.Type)); error(IO.mapInteger(Record.Type));
error(IO.mapEncodedInteger(Record.Offset)); error(IO.mapEncodedInteger(Record.Offset));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
EnumeratorRecord &Record) { EnumeratorRecord &Record) {
error(IO.mapInteger(Record.Attrs.Attrs)); error(IO.mapInteger(Record.Attrs.Attrs));
// FIXME: Handle full APInt such as __int128. // FIXME: Handle full APInt such as __int128.
error(IO.mapEncodedInteger(Record.Value)); error(IO.mapEncodedInteger(Record.Value));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
DataMemberRecord &Record) { DataMemberRecord &Record) {
error(IO.mapInteger(Record.Attrs.Attrs)); error(IO.mapInteger(Record.Attrs.Attrs));
error(IO.mapInteger(Record.Type)); error(IO.mapInteger(Record.Type));
error(IO.mapEncodedInteger(Record.FieldOffset)); error(IO.mapEncodedInteger(Record.FieldOffset));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
OverloadedMethodRecord &Record) { OverloadedMethodRecord &Record) {
error(IO.mapInteger(Record.NumOverloads)); error(IO.mapInteger(Record.NumOverloads));
error(IO.mapInteger(Record.MethodList)); error(IO.mapInteger(Record.MethodList));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
OneMethodRecord &Record) { OneMethodRecord &Record) {
const bool IsFromOverloadList = (TypeKind == LF_METHODLIST); const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
MapOneMethodRecord Mapper(IsFromOverloadList); MapOneMethodRecord Mapper(IsFromOverloadList);
return Mapper(IO, Record); return Mapper(IO, Record);
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
NestedTypeRecord &Record) { NestedTypeRecord &Record) {
uint16_t Padding = 0; uint16_t Padding = 0;
error(IO.mapInteger(Padding)); error(IO.mapInteger(Padding));
error(IO.mapInteger(Record.Type)); error(IO.mapInteger(Record.Type));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
StaticDataMemberRecord &Record) { StaticDataMemberRecord &Record) {
error(IO.mapInteger(Record.Attrs.Attrs)); error(IO.mapInteger(Record.Attrs.Attrs));
error(IO.mapInteger(Record.Type)); error(IO.mapInteger(Record.Type));
error(IO.mapStringZ(Record.Name)); error(IO.mapStringZ(Record.Name));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
VirtualBaseClassRecord &Record) { VirtualBaseClassRecord &Record) {
error(IO.mapInteger(Record.Attrs.Attrs)); error(IO.mapInteger(Record.Attrs.Attrs));
error(IO.mapInteger(Record.BaseType)); error(IO.mapInteger(Record.BaseType));
error(IO.mapInteger(Record.VBPtrType)); error(IO.mapInteger(Record.VBPtrType));
error(IO.mapEncodedInteger(Record.VBPtrOffset)); error(IO.mapEncodedInteger(Record.VBPtrOffset));
error(IO.mapEncodedInteger(Record.VTableIndex)); error(IO.mapEncodedInteger(Record.VTableIndex));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
VFPtrRecord &Record) { VFPtrRecord &Record) {
uint16_t Padding = 0; uint16_t Padding = 0;
error(IO.mapInteger(Padding)); error(IO.mapInteger(Padding));
error(IO.mapInteger(Record.Type)); error(IO.mapInteger(Record.Type));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
ListContinuationRecord &Record) { ListContinuationRecord &Record) {
uint16_t Padding = 0; uint16_t Padding = 0;
error(IO.mapInteger(Padding)); error(IO.mapInteger(Padding));
error(IO.mapInteger(Record.ContinuationIndex)); error(IO.mapInteger(Record.ContinuationIndex));
return Error::success(); return Error::success();
} }
Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
PrecompRecord &Precomp) {
error(IO.mapInteger(Precomp.StartTypeIndex));
error(IO.mapInteger(Precomp.TypesCount));
error(IO.mapInteger(Precomp.Signature));
error(IO.mapStringZ(Precomp.PrecompFilePath));
return Error::success();
}
Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
EndPrecompRecord &EndPrecomp) {
error(IO.mapInteger(EndPrecomp.Signature));
return Error::success();
}

View File

@ -562,14 +562,16 @@ void MappingTraits<COFFYAML::Section>::mapping(IO &IO, COFFYAML::Section &Sec) {
IO.mapOptional("VirtualSize", Sec.Header.VirtualSize, 0U); IO.mapOptional("VirtualSize", Sec.Header.VirtualSize, 0U);
IO.mapOptional("Alignment", Sec.Alignment, 0U); IO.mapOptional("Alignment", Sec.Alignment, 0U);
// If this is a .debug$S .debug$T, or .debug$H section parse the semantic // If this is a .debug$S .debug$T .debug$P, or .debug$H section parse the
// representation of the symbols/types. If it is any other kind of section, // semantic representation of the symbols/types. If it is any other kind
// just deal in raw bytes. // of section, just deal in raw bytes.
IO.mapOptional("SectionData", Sec.SectionData); IO.mapOptional("SectionData", Sec.SectionData);
if (Sec.Name == ".debug$S") if (Sec.Name == ".debug$S")
IO.mapOptional("Subsections", Sec.DebugS); IO.mapOptional("Subsections", Sec.DebugS);
else if (Sec.Name == ".debug$T") else if (Sec.Name == ".debug$T")
IO.mapOptional("Types", Sec.DebugT); IO.mapOptional("Types", Sec.DebugT);
else if (Sec.Name == ".debug$P")
IO.mapOptional("PrecompTypes", Sec.DebugP);
else if (Sec.Name == ".debug$H") else if (Sec.Name == ".debug$H")
IO.mapOptional("GlobalHashes", Sec.DebugH); IO.mapOptional("GlobalHashes", Sec.DebugH);

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,57 @@
RUN: rm -rf %t1/
RUN: mkdir %t1
RUN: obj2yaml %S/Inputs/precomp-a.obj > %t1/precomp-a.yaml
RUN: obj2yaml %S/Inputs/precomp.obj > %t1/precomp.yaml
RUN: yaml2obj %t1/precomp-a.yaml > %t1/a.obj
RUN: yaml2obj %t1/precomp.yaml > %t1/precomp.obj
RUN: llvm-readobj -codeview %t1/a.obj | FileCheck %s -check-prefix PRECOMP
RUN: llvm-readobj -codeview %t1/precomp.obj | FileCheck %s -check-prefix ENDPRECOMP
RUN: llvm-pdbutil dump -types %t1/a.obj | FileCheck %s -check-prefix PDB-PRECOMP
RUN: llvm-pdbutil dump -types %t1/precomp.obj | FileCheck %s -check-prefix PDB-ENDPRECOMP
ENDPRECOMP: CodeViewTypes [
ENDPRECOMP-NEXT: Section: .debug$P (3)
ENDPRECOMP: EndPrecomp (0x1407) {
ENDPRECOMP-NEXT: TypeLeafKind: LF_ENDPRECOMP (0x14)
ENDPRECOMP-NEXT: Signature: 0x1116980E
ENDPRECOMP-NEXT: }
PRECOMP: CodeViewTypes [
PRECOMP-NEXT: Section: .debug$T (3)
PRECOMP-NEXT: Magic: 0x4
PRECOMP-NEXT: Precomp (0x1000) {
PRECOMP-NEXT: TypeLeafKind: LF_PRECOMP (0x1509)
PRECOMP-NEXT: StartIndex: 0x1000
PRECOMP-NEXT: Count: 0x407
PRECOMP-NEXT: Signature: 0x1116980E
PDB-PRECOMP: Types (.debug$T)
PDB-PRECOMP-NEXT: ============================================================
PDB-PRECOMP-NEXT: Showing 0 records
PDB-PRECOMP-NEXT: 0x1000 | LF_PRECOMP [size = 60] start index = 0x1000, types count = 0x407, signature = 0x1116980E, precomp path = f:\svn\lld\test\coff\precomp\precomp.obj
PDB-ENDPRECOMP: Precompiled Types (.debug$P)
PDB-ENDPRECOMP-NEXT: ============================================================
PDB-ENDPRECOMP-NEXT: Showing 0 records
PDB-ENDPRECOMP: 0x1407 | LF_ENDPRECOMP [size = 8] signature = 0x1116980E
# // precomp.h
# #pragma once
# int Function(char A);
#
# // precomp.cpp
# // cl.exe precomp.cpp /Z7 /Ycprecomp.h /c
# #include "precomp.h"
#
# // a.cpp
# #include "precomp.h"
# int main(void) {
# Function('a');
# return 0;
# }
#
# // cl.exe a.cpp /Z7 /Yuprecomp.h /c
#
# // obj2yaml precomp.obj >precomp-precomp.yaml
# // obj2yaml a.obj >precomp-a.yaml

View File

@ -95,7 +95,8 @@ static inline bool isDebugSSection(object::SectionRef Section,
static bool isDebugTSection(SectionRef Section, CVTypeArray &Types) { static bool isDebugTSection(SectionRef Section, CVTypeArray &Types) {
BinaryStreamReader Reader; BinaryStreamReader Reader;
if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader)) if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader) &&
!isCodeViewDebugSubsection(Section, ".debug$P", Reader))
return false; return false;
cantFail(Reader.readArray(Types, Reader.bytesRemaining())); cantFail(Reader.readArray(Types, Reader.bytesRemaining()));
return true; return true;

File diff suppressed because it is too large Load Diff

View File

@ -170,7 +170,11 @@ void COFFDumper::dumpSections(unsigned NumSections) {
if (NewYAMLSection.Name == ".debug$S") if (NewYAMLSection.Name == ".debug$S")
NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC); NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC);
else if (NewYAMLSection.Name == ".debug$T") else if (NewYAMLSection.Name == ".debug$T")
NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData); NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData,
NewYAMLSection.Name);
else if (NewYAMLSection.Name == ".debug$P")
NewYAMLSection.DebugP = CodeViewYAML::fromDebugT(sectionData,
NewYAMLSection.Name);
else if (NewYAMLSection.Name == ".debug$H") else if (NewYAMLSection.Name == ".debug$H")
NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData); NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData);

View File

@ -233,7 +233,10 @@ static bool layoutCOFF(COFFParser &CP) {
} }
} else if (S.Name == ".debug$T") { } else if (S.Name == ".debug$T") {
if (S.SectionData.binary_size() == 0) if (S.SectionData.binary_size() == 0)
S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator); S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator, S.Name);
} else if (S.Name == ".debug$P") {
if (S.SectionData.binary_size() == 0)
S.SectionData = CodeViewYAML::toDebugT(S.DebugP, CP.Allocator, S.Name);
} else if (S.Name == ".debug$H") { } else if (S.Name == ".debug$H") {
if (S.DebugH.hasValue() && S.SectionData.binary_size() == 0) if (S.DebugH.hasValue() && S.SectionData.binary_size() == 0)
S.SectionData = CodeViewYAML::toDebugH(*S.DebugH, CP.Allocator); S.SectionData = CodeViewYAML::toDebugH(*S.DebugH, CP.Allocator);

File diff suppressed because it is too large Load Diff