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:
parent
8fce7e82b9
commit
325264aa91
@ -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"
|
||||||
|
@ -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
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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
@ -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();
|
||||||
|
}
|
||||||
|
@ -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
BIN
test/DebugInfo/Inputs/precomp-a.obj
Normal file
BIN
test/DebugInfo/Inputs/precomp-a.obj
Normal file
Binary file not shown.
BIN
test/DebugInfo/Inputs/precomp.obj
Normal file
BIN
test/DebugInfo/Inputs/precomp.obj
Normal file
Binary file not shown.
57
test/DebugInfo/precomp.test
Normal file
57
test/DebugInfo/precomp.test
Normal 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
|
@ -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
@ -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);
|
||||||
|
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user