forked from OSchip/llvm-project
[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
69a2e18b4a
commit
d9e96741c4
|
@ -22,8 +22,8 @@
|
|||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
/// Distinguishes individual records in .debug$T section or PDB type stream. The
|
||||
/// documentation and headers talk about this as the "leaf" type.
|
||||
/// Distinguishes individual records in .debug$T or .debug$P section or PDB type
|
||||
/// stream. The documentation and headers talk about this as the "leaf" type.
|
||||
enum class TypeRecordKind : uint16_t {
|
||||
#define TYPE_RECORD(lf_ename, value, name) name = value,
|
||||
#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_PRECOMP, 0x1509, Precomp)
|
||||
TYPE_RECORD(LF_ENDPRECOMP, 0x0014, EndPrecomp)
|
||||
|
||||
// 16 bit type records.
|
||||
CV_TYPE(LF_MODIFIER_16t, 0x0001)
|
||||
|
@ -106,7 +108,6 @@ CV_TYPE(LF_NOTTRAN, 0x0010)
|
|||
CV_TYPE(LF_DIMARRAY_16t, 0x0011)
|
||||
CV_TYPE(LF_VFTPATH_16t, 0x0012)
|
||||
CV_TYPE(LF_PRECOMP_16t, 0x0013)
|
||||
CV_TYPE(LF_ENDPRECOMP, 0x0014)
|
||||
CV_TYPE(LF_OEM_16t, 0x0015)
|
||||
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_TYPESERVER, 0x1501)
|
||||
CV_TYPE(LF_DIMARRAY, 0x1508)
|
||||
CV_TYPE(LF_PRECOMP, 0x1509)
|
||||
CV_TYPE(LF_ALIAS, 0x150a)
|
||||
CV_TYPE(LF_DEFARG, 0x150b)
|
||||
CV_TYPE(LF_FRIENDFCN, 0x150c)
|
||||
|
|
|
@ -896,6 +896,33 @@ public:
|
|||
TypeIndex ContinuationIndex;
|
||||
};
|
||||
|
||||
// LF_PRECOMP
|
||||
class PrecompRecord : public TypeRecord {
|
||||
public:
|
||||
PrecompRecord() = default;
|
||||
explicit PrecompRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
uint32_t getStartTypeIndex() const { return StartTypeIndex; }
|
||||
uint32_t getTypesCount() const { return TypesCount; }
|
||||
uint32_t getSignature() const { return Signature; }
|
||||
StringRef getPrecompFilePath() const { return PrecompFilePath; }
|
||||
|
||||
uint32_t StartTypeIndex;
|
||||
uint32_t TypesCount;
|
||||
uint32_t Signature;
|
||||
StringRef PrecompFilePath;
|
||||
};
|
||||
|
||||
// LF_ENDPRECOMP
|
||||
class EndPrecompRecord : public TypeRecord {
|
||||
public:
|
||||
EndPrecompRecord() = default;
|
||||
explicit EndPrecompRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
uint32_t getSignature() const { return Signature; }
|
||||
|
||||
uint32_t Signature;
|
||||
};
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ struct Section {
|
|||
yaml::BinaryRef SectionData;
|
||||
std::vector<CodeViewYAML::YAMLDebugSubsection> DebugS;
|
||||
std::vector<CodeViewYAML::LeafRecord> DebugT;
|
||||
std::vector<CodeViewYAML::LeafRecord> DebugP;
|
||||
Optional<CodeViewYAML::DebugHSection> DebugH;
|
||||
std::vector<Relocation> Relocations;
|
||||
StringRef Name;
|
||||
|
|
|
@ -47,7 +47,7 @@ struct DebugHSection {
|
|||
std::vector<GlobalHash> Hashes;
|
||||
};
|
||||
|
||||
DebugHSection fromDebugH(ArrayRef<uint8_t> DebugT);
|
||||
DebugHSection fromDebugH(ArrayRef<uint8_t> DebugH);
|
||||
ArrayRef<uint8_t> toDebugH(const DebugHSection &DebugH,
|
||||
BumpPtrAllocator &Alloc);
|
||||
|
||||
|
|
|
@ -51,8 +51,10 @@ struct LeafRecord {
|
|||
static Expected<LeafRecord> fromCodeViewRecord(codeview::CVType Type);
|
||||
};
|
||||
|
||||
std::vector<LeafRecord> fromDebugT(ArrayRef<uint8_t> DebugT);
|
||||
ArrayRef<uint8_t> toDebugT(ArrayRef<LeafRecord>, BumpPtrAllocator &Alloc);
|
||||
std::vector<LeafRecord> fromDebugT(ArrayRef<uint8_t> DebugTorP,
|
||||
StringRef SectionName);
|
||||
ArrayRef<uint8_t> toDebugT(ArrayRef<LeafRecord>, BumpPtrAllocator &Alloc,
|
||||
StringRef SectionName);
|
||||
|
||||
} // end namespace CodeViewYAML
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ void CodeViewDebug::emitTypeInformation() {
|
|||
if (TypeTable.empty())
|
||||
return;
|
||||
|
||||
// Start the .debug$T section with 0x4.
|
||||
// Start the .debug$T or .debug$P section with 0x4.
|
||||
OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection());
|
||||
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
|
||||
/// 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 emitTypeInformation();
|
||||
|
|
|
@ -236,6 +236,16 @@ Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error TypeNameComputer::visitKnownRecord(CVType &CVR,
|
||||
PrecompRecord &Precomp) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error TypeNameComputer::visitKnownRecord(CVType &CVR,
|
||||
EndPrecompRecord &EndPrecomp) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::string llvm::codeview::computeTypeName(TypeCollection &Types,
|
||||
TypeIndex Index) {
|
||||
TypeNameComputer Computer(Types);
|
||||
|
|
|
@ -553,3 +553,18 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) {
|
|||
W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
PrecompRecord &Precomp) {
|
||||
W->printHex("StartIndex", Precomp.getStartTypeIndex());
|
||||
W->printHex("Count", Precomp.getTypesCount());
|
||||
W->printHex("Signature", Precomp.getSignature());
|
||||
W->printString("PrecompFile", Precomp.getPrecompFilePath());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
EndPrecompRecord &EndPrecomp) {
|
||||
W->printHex("Signature", EndPrecomp.getSignature());
|
||||
return Error::success();
|
||||
}
|
||||
|
|
|
@ -480,3 +480,18 @@ Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
|
|||
|
||||
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("Alignment", Sec.Alignment, 0U);
|
||||
|
||||
// If this is a .debug$S .debug$T, or .debug$H section parse the semantic
|
||||
// representation of the symbols/types. If it is any other kind of section,
|
||||
// just deal in raw bytes.
|
||||
// If this is a .debug$S .debug$T .debug$P, or .debug$H section parse the
|
||||
// semantic representation of the symbols/types. If it is any other kind
|
||||
// of section, just deal in raw bytes.
|
||||
IO.mapOptional("SectionData", Sec.SectionData);
|
||||
if (Sec.Name == ".debug$S")
|
||||
IO.mapOptional("Subsections", Sec.DebugS);
|
||||
else if (Sec.Name == ".debug$T")
|
||||
IO.mapOptional("Types", Sec.DebugT);
|
||||
else if (Sec.Name == ".debug$P")
|
||||
IO.mapOptional("PrecompTypes", Sec.DebugP);
|
||||
else if (Sec.Name == ".debug$H")
|
||||
IO.mapOptional("GlobalHashes", Sec.DebugH);
|
||||
|
||||
|
|
|
@ -595,6 +595,17 @@ template <> void LeafRecordImpl<MethodOverloadListRecord>::map(IO &IO) {
|
|||
IO.mapRequired("Methods", Record.Methods);
|
||||
}
|
||||
|
||||
template <> void LeafRecordImpl<PrecompRecord>::map(IO &IO) {
|
||||
IO.mapRequired("StartTypeIndex", Record.StartTypeIndex);
|
||||
IO.mapRequired("TypesCount", Record.TypesCount);
|
||||
IO.mapRequired("Signature", Record.Signature);
|
||||
IO.mapRequired("PrecompFilePath", Record.PrecompFilePath);
|
||||
}
|
||||
|
||||
template <> void LeafRecordImpl<EndPrecompRecord>::map(IO &IO) {
|
||||
IO.mapRequired("Signature", Record.Signature);
|
||||
}
|
||||
|
||||
template <> void MemberRecordImpl<OneMethodRecord>::map(IO &IO) {
|
||||
MappingTraits<OneMethodRecord>::mapping(IO, Record);
|
||||
}
|
||||
|
@ -763,14 +774,16 @@ void MappingTraits<MemberRecord>::mapping(IO &IO, MemberRecord &Obj) {
|
|||
}
|
||||
|
||||
std::vector<LeafRecord>
|
||||
llvm::CodeViewYAML::fromDebugT(ArrayRef<uint8_t> DebugT) {
|
||||
ExitOnError Err("Invalid .debug$T section!");
|
||||
BinaryStreamReader Reader(DebugT, support::little);
|
||||
llvm::CodeViewYAML::fromDebugT(ArrayRef<uint8_t> DebugTorP,
|
||||
StringRef SectionName) {
|
||||
ExitOnError Err("Invalid " + std::string(SectionName) + " section!");
|
||||
BinaryStreamReader Reader(DebugTorP, support::little);
|
||||
CVTypeArray Types;
|
||||
uint32_t Magic;
|
||||
|
||||
Err(Reader.readInteger(Magic));
|
||||
assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$T section!");
|
||||
assert(Magic == COFF::DEBUG_SECTION_MAGIC &&
|
||||
"Invalid .debug$T or .debug$P section!");
|
||||
|
||||
std::vector<LeafRecord> Result;
|
||||
Err(Reader.readArray(Types, Reader.bytesRemaining()));
|
||||
|
@ -782,7 +795,8 @@ llvm::CodeViewYAML::fromDebugT(ArrayRef<uint8_t> DebugT) {
|
|||
}
|
||||
|
||||
ArrayRef<uint8_t> llvm::CodeViewYAML::toDebugT(ArrayRef<LeafRecord> Leafs,
|
||||
BumpPtrAllocator &Alloc) {
|
||||
BumpPtrAllocator &Alloc,
|
||||
StringRef SectionName) {
|
||||
AppendingTypeTableBuilder TS(Alloc);
|
||||
uint32_t Size = sizeof(uint32_t);
|
||||
for (const auto &Leaf : Leafs) {
|
||||
|
@ -793,7 +807,8 @@ ArrayRef<uint8_t> llvm::CodeViewYAML::toDebugT(ArrayRef<LeafRecord> Leafs,
|
|||
uint8_t *ResultBuffer = Alloc.Allocate<uint8_t>(Size);
|
||||
MutableArrayRef<uint8_t> Output(ResultBuffer, Size);
|
||||
BinaryStreamWriter Writer(Output, support::little);
|
||||
ExitOnError Err("Error writing type record to .debug$T section");
|
||||
ExitOnError Err("Error writing type record to " + std::string(SectionName) +
|
||||
" section");
|
||||
Err(Writer.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC));
|
||||
for (const auto &R : TS.records()) {
|
||||
Err(Writer.writeBytes(R));
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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) {
|
||||
BinaryStreamReader Reader;
|
||||
if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader))
|
||||
if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader) &&
|
||||
!isCodeViewDebugSubsection(Section, ".debug$P", Reader))
|
||||
return false;
|
||||
cantFail(Reader.readArray(Types, Reader.bytesRemaining()));
|
||||
return true;
|
||||
|
|
|
@ -467,6 +467,21 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
PrecompRecord &Precomp) {
|
||||
P.format(" start index = {0:X+}, types count = {1:X+}, signature = {2:X+},"
|
||||
" precomp path = {3}",
|
||||
Precomp.StartTypeIndex, Precomp.TypesCount, Precomp.Signature,
|
||||
Precomp.PrecompFilePath);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
EndPrecompRecord &EP) {
|
||||
P.format(" signature = {0:X+}", EP.Signature);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
NestedTypeRecord &Nested) {
|
||||
P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
|
||||
|
|
|
@ -170,7 +170,11 @@ void COFFDumper::dumpSections(unsigned NumSections) {
|
|||
if (NewYAMLSection.Name == ".debug$S")
|
||||
NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC);
|
||||
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")
|
||||
NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData);
|
||||
|
||||
|
|
|
@ -233,7 +233,10 @@ static bool layoutCOFF(COFFParser &CP) {
|
|||
}
|
||||
} else if (S.Name == ".debug$T") {
|
||||
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") {
|
||||
if (S.DebugH.hasValue() && S.SectionData.binary_size() == 0)
|
||||
S.SectionData = CodeViewYAML::toDebugH(*S.DebugH, CP.Allocator);
|
||||
|
|
|
@ -580,3 +580,16 @@ TEST_F(TypeIndexIteratorTest, CallerSym) {
|
|||
checkTypeReferences(2, TypeIndex(7), TypeIndex(8), TypeIndex(9));
|
||||
}
|
||||
|
||||
TEST_F(TypeIndexIteratorTest, Precomp) {
|
||||
PrecompRecord P(TypeRecordKind::Precomp);
|
||||
P.StartTypeIndex = TypeIndex::FirstNonSimpleIndex;
|
||||
P.TypesCount = 100;
|
||||
P.Signature = 0x12345678;
|
||||
P.PrecompFilePath = "C:/precomp.obj";
|
||||
|
||||
EndPrecompRecord EP(TypeRecordKind::EndPrecomp);
|
||||
EP.Signature = P.Signature;
|
||||
|
||||
writeTypeRecords(P, EP);
|
||||
checkTypeReferences(0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue