forked from OSchip/llvm-project
[CodeView] Properly align symbol records on read/write.
Object files have symbol records not aligned to any particular boundary (e.g. 1-byte aligned), while PDB files have symbol records padded to 4-byte aligned boundaries. Since they share the same reading / writing code, we have to provide an option to specify the alignment and propagate it up to the producer or consumer who knows what the alignment is supposed to be for the given container type. Added a test for this by modifying the existing PDB -> YAML -> PDB round-tripping code to round trip symbol records as well as types. Differential Revision: https://reviews.llvm.org/D33785 llvm-svn: 304484
This commit is contained in:
parent
678aa336fa
commit
ebd3ae8371
|
@ -157,7 +157,8 @@ static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
|
||||||
fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");
|
fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");
|
||||||
|
|
||||||
TypeDatabase TDB(0);
|
TypeDatabase TDB(0);
|
||||||
CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
|
CVSymbolDumper SymbolDumper(W, TDB, CodeViewContainer::ObjectFile, nullptr,
|
||||||
|
false);
|
||||||
if (auto EC = SymbolDumper.dump(Symbols))
|
if (auto EC = SymbolDumper.dump(Symbols))
|
||||||
fatal(EC, "CVSymbolDumper::dump failed");
|
fatal(EC, "CVSymbolDumper::dump failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -574,6 +574,14 @@ struct FrameData {
|
||||||
IsFunctionStart = 1 << 2,
|
IsFunctionStart = 1 << 2,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CodeViewContainer { ObjectFile, Pdb };
|
||||||
|
|
||||||
|
inline uint32_t alignOf(CodeViewContainer Container) {
|
||||||
|
if (Container == CodeViewContainer::ObjectFile)
|
||||||
|
return 1;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,7 @@ public:
|
||||||
Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);
|
Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);
|
||||||
Error mapByteVectorTail(std::vector<uint8_t> &Bytes);
|
Error mapByteVectorTail(std::vector<uint8_t> &Bytes);
|
||||||
|
|
||||||
|
Error padToAlignment(uint32_t Align);
|
||||||
Error skipPadding();
|
Error skipPadding();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -31,26 +31,31 @@ struct DebugSubsectionHeader {
|
||||||
class DebugSubsectionRecord {
|
class DebugSubsectionRecord {
|
||||||
public:
|
public:
|
||||||
DebugSubsectionRecord();
|
DebugSubsectionRecord();
|
||||||
DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data);
|
DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data,
|
||||||
|
CodeViewContainer Container);
|
||||||
|
|
||||||
static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info);
|
static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info,
|
||||||
|
CodeViewContainer Container);
|
||||||
|
|
||||||
uint32_t getRecordLength() const;
|
uint32_t getRecordLength() const;
|
||||||
DebugSubsectionKind kind() const;
|
DebugSubsectionKind kind() const;
|
||||||
BinaryStreamRef getRecordData() const;
|
BinaryStreamRef getRecordData() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CodeViewContainer Container;
|
||||||
DebugSubsectionKind Kind;
|
DebugSubsectionKind Kind;
|
||||||
BinaryStreamRef Data;
|
BinaryStreamRef Data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DebugSubsectionRecordBuilder {
|
class DebugSubsectionRecordBuilder {
|
||||||
public:
|
public:
|
||||||
DebugSubsectionRecordBuilder(DebugSubsectionKind Kind, DebugSubsection &Frag);
|
DebugSubsectionRecordBuilder(DebugSubsectionKind Kind, DebugSubsection &Frag,
|
||||||
|
CodeViewContainer Container);
|
||||||
uint32_t calculateSerializedLength();
|
uint32_t calculateSerializedLength();
|
||||||
Error commit(BinaryStreamWriter &Writer);
|
Error commit(BinaryStreamWriter &Writer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CodeViewContainer Container;
|
||||||
DebugSubsectionKind Kind;
|
DebugSubsectionKind Kind;
|
||||||
DebugSubsection &Frag;
|
DebugSubsection &Frag;
|
||||||
};
|
};
|
||||||
|
@ -62,7 +67,12 @@ template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
|
||||||
|
|
||||||
static Error extract(BinaryStreamRef Stream, uint32_t &Length,
|
static Error extract(BinaryStreamRef Stream, uint32_t &Length,
|
||||||
codeview::DebugSubsectionRecord &Info) {
|
codeview::DebugSubsectionRecord &Info) {
|
||||||
if (auto EC = codeview::DebugSubsectionRecord::initialize(Stream, Info))
|
// FIXME: We need to pass the container type through to this function, but
|
||||||
|
// VarStreamArray doesn't easily support stateful contexts. In practice
|
||||||
|
// this isn't super important since the subsection header describes its
|
||||||
|
// length and we can just skip it. It's more important when writing.
|
||||||
|
if (auto EC = codeview::DebugSubsectionRecord::initialize(
|
||||||
|
Stream, Info, codeview::CodeViewContainer::Pdb))
|
||||||
return EC;
|
return EC;
|
||||||
Length = Info.getRecordLength();
|
Length = Info.getRecordLength();
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
|
|
@ -24,9 +24,9 @@ namespace codeview {
|
||||||
class SymbolVisitorDelegate;
|
class SymbolVisitorDelegate;
|
||||||
class SymbolDeserializer : public SymbolVisitorCallbacks {
|
class SymbolDeserializer : public SymbolVisitorCallbacks {
|
||||||
struct MappingInfo {
|
struct MappingInfo {
|
||||||
explicit MappingInfo(ArrayRef<uint8_t> RecordData)
|
MappingInfo(ArrayRef<uint8_t> RecordData, CodeViewContainer Container)
|
||||||
: Stream(RecordData, llvm::support::little), Reader(Stream),
|
: Stream(RecordData, llvm::support::little), Reader(Stream),
|
||||||
Mapping(Reader) {}
|
Mapping(Reader, Container) {}
|
||||||
|
|
||||||
BinaryByteStream Stream;
|
BinaryByteStream Stream;
|
||||||
BinaryStreamReader Reader;
|
BinaryStreamReader Reader;
|
||||||
|
@ -35,7 +35,9 @@ class SymbolDeserializer : public SymbolVisitorCallbacks {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename T> static Error deserializeAs(CVSymbol Symbol, T &Record) {
|
template <typename T> static Error deserializeAs(CVSymbol Symbol, T &Record) {
|
||||||
SymbolDeserializer S(nullptr);
|
// If we're just deserializing one record, then don't worry about alignment
|
||||||
|
// as there's nothing that comes after.
|
||||||
|
SymbolDeserializer S(nullptr, CodeViewContainer::ObjectFile);
|
||||||
if (auto EC = S.visitSymbolBegin(Symbol))
|
if (auto EC = S.visitSymbolBegin(Symbol))
|
||||||
return EC;
|
return EC;
|
||||||
if (auto EC = S.visitKnownRecord(Symbol, Record))
|
if (auto EC = S.visitKnownRecord(Symbol, Record))
|
||||||
|
@ -45,12 +47,13 @@ public:
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate)
|
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate,
|
||||||
: Delegate(Delegate) {}
|
CodeViewContainer Container)
|
||||||
|
: Delegate(Delegate), Container(Container) {}
|
||||||
|
|
||||||
Error visitSymbolBegin(CVSymbol &Record) override {
|
Error visitSymbolBegin(CVSymbol &Record) override {
|
||||||
assert(!Mapping && "Already in a symbol mapping!");
|
assert(!Mapping && "Already in a symbol mapping!");
|
||||||
Mapping = llvm::make_unique<MappingInfo>(Record.content());
|
Mapping = llvm::make_unique<MappingInfo>(Record.content(), Container);
|
||||||
return Mapping->Mapping.visitSymbolBegin(Record);
|
return Mapping->Mapping.visitSymbolBegin(Record);
|
||||||
}
|
}
|
||||||
Error visitSymbolEnd(CVSymbol &Record) override {
|
Error visitSymbolEnd(CVSymbol &Record) override {
|
||||||
|
@ -77,6 +80,7 @@ private:
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeViewContainer Container;
|
||||||
SymbolVisitorDelegate *Delegate;
|
SymbolVisitorDelegate *Delegate;
|
||||||
std::unique_ptr<MappingInfo> Mapping;
|
std::unique_ptr<MappingInfo> Mapping;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,9 +26,11 @@ class TypeCollection;
|
||||||
class CVSymbolDumper {
|
class CVSymbolDumper {
|
||||||
public:
|
public:
|
||||||
CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
|
CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
|
||||||
|
CodeViewContainer Container,
|
||||||
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
|
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
|
||||||
bool PrintRecordBytes)
|
bool PrintRecordBytes)
|
||||||
: W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)),
|
: W(W), Types(Types), Container(Container),
|
||||||
|
ObjDelegate(std::move(ObjDelegate)),
|
||||||
PrintRecordBytes(PrintRecordBytes) {}
|
PrintRecordBytes(PrintRecordBytes) {}
|
||||||
|
|
||||||
/// Dumps one type record. Returns false if there was a type parsing error,
|
/// Dumps one type record. Returns false if there was a type parsing error,
|
||||||
|
@ -44,6 +46,7 @@ public:
|
||||||
private:
|
private:
|
||||||
ScopedPrinter &W;
|
ScopedPrinter &W;
|
||||||
TypeCollection &Types;
|
TypeCollection &Types;
|
||||||
|
CodeViewContainer Container;
|
||||||
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
|
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
|
||||||
|
|
||||||
bool PrintRecordBytes;
|
bool PrintRecordBytes;
|
||||||
|
|
|
@ -20,8 +20,12 @@ class BinaryStreamWriter;
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
class SymbolRecordMapping : public SymbolVisitorCallbacks {
|
class SymbolRecordMapping : public SymbolVisitorCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit SymbolRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {}
|
explicit SymbolRecordMapping(BinaryStreamReader &Reader,
|
||||||
explicit SymbolRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {}
|
CodeViewContainer Container)
|
||||||
|
: IO(Reader), Container(Container) {}
|
||||||
|
explicit SymbolRecordMapping(BinaryStreamWriter &Writer,
|
||||||
|
CodeViewContainer Container)
|
||||||
|
: IO(Writer), Container(Container) {}
|
||||||
|
|
||||||
Error visitSymbolBegin(CVSymbol &Record) override;
|
Error visitSymbolBegin(CVSymbol &Record) override;
|
||||||
Error visitSymbolEnd(CVSymbol &Record) override;
|
Error visitSymbolEnd(CVSymbol &Record) override;
|
||||||
|
@ -34,6 +38,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Optional<SymbolKind> Kind;
|
Optional<SymbolKind> Kind;
|
||||||
|
|
||||||
|
CodeViewContainer Container;
|
||||||
CodeViewRecordIO IO;
|
CodeViewRecordIO IO;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,17 +46,18 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename SymType>
|
template <typename SymType>
|
||||||
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage) {
|
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage,
|
||||||
|
CodeViewContainer Container) {
|
||||||
CVSymbol Result;
|
CVSymbol Result;
|
||||||
Result.Type = static_cast<SymbolKind>(Sym.Kind);
|
Result.Type = static_cast<SymbolKind>(Sym.Kind);
|
||||||
SymbolSerializer Serializer(Storage);
|
SymbolSerializer Serializer(Storage, Container);
|
||||||
consumeError(Serializer.visitSymbolBegin(Result));
|
consumeError(Serializer.visitSymbolBegin(Result));
|
||||||
consumeError(Serializer.visitKnownRecord(Result, Sym));
|
consumeError(Serializer.visitKnownRecord(Result, Sym));
|
||||||
consumeError(Serializer.visitSymbolEnd(Result));
|
consumeError(Serializer.visitSymbolEnd(Result));
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit SymbolSerializer(BumpPtrAllocator &Storage);
|
SymbolSerializer(BumpPtrAllocator &Storage, CodeViewContainer Container);
|
||||||
|
|
||||||
virtual Error visitSymbolBegin(CVSymbol &Record) override;
|
virtual Error visitSymbolBegin(CVSymbol &Record) override;
|
||||||
virtual Error visitSymbolEnd(CVSymbol &Record) override;
|
virtual Error visitSymbolEnd(CVSymbol &Record) override;
|
||||||
|
|
|
@ -28,7 +28,9 @@ struct SymbolRecordBase;
|
||||||
struct SymbolRecord {
|
struct SymbolRecord {
|
||||||
std::shared_ptr<detail::SymbolRecordBase> Symbol;
|
std::shared_ptr<detail::SymbolRecordBase> Symbol;
|
||||||
|
|
||||||
codeview::CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator) const;
|
codeview::CVSymbol
|
||||||
|
toCodeViewSymbol(BumpPtrAllocator &Allocator,
|
||||||
|
codeview::CodeViewContainer Container) const;
|
||||||
static Expected<SymbolRecord> fromCodeViewSymbol(codeview::CVSymbol Symbol);
|
static Expected<SymbolRecord> fromCodeViewSymbol(codeview::CVSymbol Symbol);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,14 @@ Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
|
||||||
Error CodeViewRecordIO::endRecord() {
|
Error CodeViewRecordIO::endRecord() {
|
||||||
assert(!Limits.empty() && "Not in a record!");
|
assert(!Limits.empty() && "Not in a record!");
|
||||||
Limits.pop_back();
|
Limits.pop_back();
|
||||||
|
// We would like to assert that we actually read / wrote all the bytes that we
|
||||||
|
// expected to for this record, but unfortunately we can't do this. Some
|
||||||
|
// producers such as MASM over-allocate for certain types of records and
|
||||||
|
// commit the extraneous data, so when reading we can't be sure every byte
|
||||||
|
// will have been read. And when writing we over-allocate temporarily since
|
||||||
|
// we don't know how big the record is until we're finished writing it, so
|
||||||
|
// even though we don't commit the extraneous data, we still can't guarantee
|
||||||
|
// we're at the end of the allocated data.
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +57,12 @@ uint32_t CodeViewRecordIO::maxFieldLength() const {
|
||||||
return *Min;
|
return *Min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error CodeViewRecordIO::padToAlignment(uint32_t Align) {
|
||||||
|
if (isReading())
|
||||||
|
return Reader->padToAlignment(Align);
|
||||||
|
return Writer->padToAlignment(Align);
|
||||||
|
}
|
||||||
|
|
||||||
Error CodeViewRecordIO::skipPadding() {
|
Error CodeViewRecordIO::skipPadding() {
|
||||||
assert(!isWriting() && "Cannot skip padding while writing!");
|
assert(!isWriting() && "Cannot skip padding while writing!");
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,17 @@ using namespace llvm;
|
||||||
using namespace llvm::codeview;
|
using namespace llvm::codeview;
|
||||||
|
|
||||||
DebugSubsectionRecord::DebugSubsectionRecord()
|
DebugSubsectionRecord::DebugSubsectionRecord()
|
||||||
: Kind(DebugSubsectionKind::None) {}
|
: Kind(DebugSubsectionKind::None),
|
||||||
|
Container(CodeViewContainer::ObjectFile) {}
|
||||||
|
|
||||||
DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
|
DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
|
||||||
BinaryStreamRef Data)
|
BinaryStreamRef Data,
|
||||||
: Kind(Kind), Data(Data) {}
|
CodeViewContainer Container)
|
||||||
|
: Kind(Kind), Data(Data), Container(Container) {}
|
||||||
|
|
||||||
Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
|
Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
|
||||||
DebugSubsectionRecord &Info) {
|
DebugSubsectionRecord &Info,
|
||||||
|
CodeViewContainer Container) {
|
||||||
const DebugSubsectionHeader *Header;
|
const DebugSubsectionHeader *Header;
|
||||||
BinaryStreamReader Reader(Stream);
|
BinaryStreamReader Reader(Stream);
|
||||||
if (auto EC = Reader.readObject(Header))
|
if (auto EC = Reader.readObject(Header))
|
||||||
|
@ -41,13 +44,14 @@ Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
|
||||||
}
|
}
|
||||||
if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
|
if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
|
||||||
return EC;
|
return EC;
|
||||||
|
Info.Container = Container;
|
||||||
Info.Kind = Kind;
|
Info.Kind = Kind;
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t DebugSubsectionRecord::getRecordLength() const {
|
uint32_t DebugSubsectionRecord::getRecordLength() const {
|
||||||
uint32_t Result = sizeof(DebugSubsectionHeader) + Data.getLength();
|
uint32_t Result = sizeof(DebugSubsectionHeader) + Data.getLength();
|
||||||
assert(Result % 4 == 0);
|
assert(Result % alignOf(Container) == 0);
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,16 +60,20 @@ DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
|
||||||
BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
|
BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
|
||||||
|
|
||||||
DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
|
DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
|
||||||
DebugSubsectionKind Kind, DebugSubsection &Frag)
|
DebugSubsectionKind Kind, DebugSubsection &Frag,
|
||||||
: Kind(Kind), Frag(Frag) {}
|
CodeViewContainer Container)
|
||||||
|
: Kind(Kind), Frag(Frag), Container(Container) {}
|
||||||
|
|
||||||
uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
|
uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
|
||||||
uint32_t Size = sizeof(DebugSubsectionHeader) +
|
uint32_t Size = sizeof(DebugSubsectionHeader) +
|
||||||
alignTo(Frag.calculateSerializedSize(), 4);
|
alignTo(Frag.calculateSerializedSize(), alignOf(Container));
|
||||||
return Size;
|
return Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) {
|
Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) {
|
||||||
|
assert(Writer.getOffset() % alignOf(Container) == 0 &&
|
||||||
|
"Debug Subsection not properly aligned");
|
||||||
|
|
||||||
DebugSubsectionHeader Header;
|
DebugSubsectionHeader Header;
|
||||||
Header.Kind = uint32_t(Kind);
|
Header.Kind = uint32_t(Kind);
|
||||||
Header.Length = calculateSerializedLength() - sizeof(DebugSubsectionHeader);
|
Header.Length = calculateSerializedLength() - sizeof(DebugSubsectionHeader);
|
||||||
|
@ -74,7 +82,7 @@ Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) {
|
||||||
return EC;
|
return EC;
|
||||||
if (auto EC = Frag.commit(Writer))
|
if (auto EC = Frag.commit(Writer))
|
||||||
return EC;
|
return EC;
|
||||||
if (auto EC = Writer.padToAlignment(4))
|
if (auto EC = Writer.padToAlignment(alignOf(Container)))
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
|
|
@ -668,7 +668,7 @@ Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
|
||||||
|
|
||||||
Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
||||||
SymbolVisitorCallbackPipeline Pipeline;
|
SymbolVisitorCallbackPipeline Pipeline;
|
||||||
SymbolDeserializer Deserializer(ObjDelegate.get());
|
SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
|
||||||
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
||||||
|
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
|
@ -679,7 +679,7 @@ Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
||||||
|
|
||||||
Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
|
Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
|
||||||
SymbolVisitorCallbackPipeline Pipeline;
|
SymbolVisitorCallbackPipeline Pipeline;
|
||||||
SymbolDeserializer Deserializer(ObjDelegate.get());
|
SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
|
||||||
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
||||||
|
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
|
|
|
@ -40,6 +40,7 @@ Error SymbolRecordMapping::visitSymbolBegin(CVSymbol &Record) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SymbolRecordMapping::visitSymbolEnd(CVSymbol &Record) {
|
Error SymbolRecordMapping::visitSymbolEnd(CVSymbol &Record) {
|
||||||
|
error(IO.padToAlignment(alignOf(Container)));
|
||||||
error(IO.endRecord());
|
error(IO.endRecord());
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::codeview;
|
using namespace llvm::codeview;
|
||||||
|
|
||||||
SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator)
|
SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator,
|
||||||
: Storage(Allocator), RecordBuffer(MaxRecordLength), Stream(RecordBuffer, llvm::support::little),
|
CodeViewContainer Container)
|
||||||
Writer(Stream), Mapping(Writer) { }
|
: Storage(Allocator), RecordBuffer(MaxRecordLength),
|
||||||
|
Stream(RecordBuffer, llvm::support::little), Writer(Stream),
|
||||||
|
Mapping(Writer, Container) {}
|
||||||
|
|
||||||
Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) {
|
Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) {
|
||||||
assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!");
|
assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!");
|
||||||
|
|
|
@ -66,7 +66,11 @@ void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {
|
||||||
|
|
||||||
void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
|
void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
|
||||||
Symbols.push_back(Symbol);
|
Symbols.push_back(Symbol);
|
||||||
SymbolByteSize += Symbol.data().size();
|
// Symbols written to a PDB file are required to be 4 byte aligned. The same
|
||||||
|
// is not true of object files.
|
||||||
|
assert(Symbol.length() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||||||
|
"Invalid Symbol alignment!");
|
||||||
|
SymbolByteSize += Symbol.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
|
void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
|
||||||
|
@ -153,7 +157,8 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
|
||||||
if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
|
if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
|
||||||
return EC;
|
return EC;
|
||||||
// TODO: Write C11 Line data
|
// TODO: Write C11 Line data
|
||||||
|
assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||||||
|
"Invalid debug section alignment!");
|
||||||
for (const auto &Builder : C13Builders) {
|
for (const auto &Builder : C13Builders) {
|
||||||
assert(Builder && "Empty C13 Fragment Builder!");
|
assert(Builder && "Empty C13 Fragment Builder!");
|
||||||
if (auto EC = Builder->commit(SymbolWriter))
|
if (auto EC = Builder->commit(SymbolWriter))
|
||||||
|
@ -179,8 +184,8 @@ void DbiModuleDescriptorBuilder::addC13Fragment(
|
||||||
C13Builders.push_back(nullptr);
|
C13Builders.push_back(nullptr);
|
||||||
|
|
||||||
this->LineInfo.push_back(std::move(Lines));
|
this->LineInfo.push_back(std::move(Lines));
|
||||||
C13Builders.push_back(
|
C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||||
llvm::make_unique<DebugSubsectionRecordBuilder>(Frag.kind(), Frag));
|
Frag.kind(), Frag, CodeViewContainer::Pdb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DbiModuleDescriptorBuilder::addC13Fragment(
|
void DbiModuleDescriptorBuilder::addC13Fragment(
|
||||||
|
@ -193,8 +198,8 @@ void DbiModuleDescriptorBuilder::addC13Fragment(
|
||||||
C13Builders.push_back(nullptr);
|
C13Builders.push_back(nullptr);
|
||||||
|
|
||||||
this->Inlinees.push_back(std::move(Inlinees));
|
this->Inlinees.push_back(std::move(Inlinees));
|
||||||
C13Builders.push_back(
|
C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||||
llvm::make_unique<DebugSubsectionRecordBuilder>(Frag.kind(), Frag));
|
Frag.kind(), Frag, CodeViewContainer::Pdb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DbiModuleDescriptorBuilder::setC13FileChecksums(
|
void DbiModuleDescriptorBuilder::setC13FileChecksums(
|
||||||
|
@ -206,5 +211,5 @@ void DbiModuleDescriptorBuilder::setC13FileChecksums(
|
||||||
|
|
||||||
ChecksumInfo = std::move(Checksums);
|
ChecksumInfo = std::move(Checksums);
|
||||||
C13Builders[0] = llvm::make_unique<DebugSubsectionRecordBuilder>(
|
C13Builders[0] = llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||||
ChecksumInfo->kind(), *ChecksumInfo);
|
ChecksumInfo->kind(), *ChecksumInfo, CodeViewContainer::Pdb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,8 @@ struct SymbolRecordBase {
|
||||||
virtual ~SymbolRecordBase() {}
|
virtual ~SymbolRecordBase() {}
|
||||||
virtual void map(yaml::IO &io) = 0;
|
virtual void map(yaml::IO &io) = 0;
|
||||||
virtual codeview::CVSymbol
|
virtual codeview::CVSymbol
|
||||||
toCodeViewSymbol(BumpPtrAllocator &Allocator) const = 0;
|
toCodeViewSymbol(BumpPtrAllocator &Allocator,
|
||||||
|
CodeViewContainer Container) const = 0;
|
||||||
virtual Error fromCodeViewSymbol(codeview::CVSymbol Type) = 0;
|
virtual Error fromCodeViewSymbol(codeview::CVSymbol Type) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,8 +160,9 @@ template <typename T> struct SymbolRecordImpl : public SymbolRecordBase {
|
||||||
void map(yaml::IO &io) override;
|
void map(yaml::IO &io) override;
|
||||||
|
|
||||||
codeview::CVSymbol
|
codeview::CVSymbol
|
||||||
toCodeViewSymbol(BumpPtrAllocator &Allocator) const override {
|
toCodeViewSymbol(BumpPtrAllocator &Allocator,
|
||||||
return SymbolSerializer::writeOneSymbol(Symbol, Allocator);
|
CodeViewContainer Container) const override {
|
||||||
|
return SymbolSerializer::writeOneSymbol(Symbol, Allocator, Container);
|
||||||
}
|
}
|
||||||
Error fromCodeViewSymbol(codeview::CVSymbol CVS) override {
|
Error fromCodeViewSymbol(codeview::CVSymbol CVS) override {
|
||||||
return SymbolDeserializer::deserializeAs<T>(CVS, Symbol);
|
return SymbolDeserializer::deserializeAs<T>(CVS, Symbol);
|
||||||
|
@ -429,8 +431,8 @@ template <> void SymbolRecordImpl<ThreadLocalDataSym>::map(IO &IO) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CVSymbol CodeViewYAML::SymbolRecord::toCodeViewSymbol(
|
CVSymbol CodeViewYAML::SymbolRecord::toCodeViewSymbol(
|
||||||
BumpPtrAllocator &Allocator) const {
|
BumpPtrAllocator &Allocator, CodeViewContainer Container) const {
|
||||||
return Symbol->toCodeViewSymbol(Allocator);
|
return Symbol->toCodeViewSymbol(Allocator, Container);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
; (for example if we don't write the entire stream)
|
; (for example if we don't write the entire stream)
|
||||||
;
|
;
|
||||||
; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory \
|
; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory \
|
||||||
; RUN: -pdb-stream -tpi-stream %p/Inputs/empty.pdb > %t.1
|
; RUN: -pdb-stream -tpi-stream -dbi-module-syms %p/Inputs/empty.pdb > %t.1
|
||||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
|
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
|
||||||
; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \
|
; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \
|
||||||
; RUN: -no-file-headers %p/Inputs/empty.pdb > %t.3
|
; RUN: -dbi-module-syms -no-file-headers %p/Inputs/empty.pdb > %t.3
|
||||||
; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \
|
; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \
|
||||||
; RUN: -no-file-headers %t.2 > %t.4
|
; RUN: -dbi-module-syms -no-file-headers %t.2 > %t.4
|
||||||
; RUN: diff %t.3 %t.4
|
; RUN: diff %t.3 %t.4
|
||||||
|
|
|
@ -804,7 +804,8 @@ Error LLVMOutputStyle::dumpDbiStream() {
|
||||||
auto &Types = *ExpectedTypes;
|
auto &Types = *ExpectedTypes;
|
||||||
|
|
||||||
ListScope SS(P, "Symbols");
|
ListScope SS(P, "Symbols");
|
||||||
codeview::CVSymbolDumper SD(P, Types, nullptr, false);
|
codeview::CVSymbolDumper SD(P, Types, CodeViewContainer::Pdb, nullptr,
|
||||||
|
false);
|
||||||
bool HadError = false;
|
bool HadError = false;
|
||||||
for (auto S : ModS.symbols(&HadError)) {
|
for (auto S : ModS.symbols(&HadError)) {
|
||||||
DictScope LL(P, "");
|
DictScope LL(P, "");
|
||||||
|
@ -952,7 +953,7 @@ Error LLVMOutputStyle::dumpPublicsStream() {
|
||||||
return ExpectedTypes.takeError();
|
return ExpectedTypes.takeError();
|
||||||
auto &Tpi = *ExpectedTypes;
|
auto &Tpi = *ExpectedTypes;
|
||||||
|
|
||||||
codeview::CVSymbolDumper SD(P, Tpi, nullptr, false);
|
codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr, false);
|
||||||
bool HadError = false;
|
bool HadError = false;
|
||||||
for (auto S : Publics->getSymbols(&HadError)) {
|
for (auto S : Publics->getSymbols(&HadError)) {
|
||||||
DictScope DD(P, "");
|
DictScope DD(P, "");
|
||||||
|
|
|
@ -535,8 +535,10 @@ static void yamlToPdb(StringRef Path) {
|
||||||
ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
|
ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
|
||||||
if (MI.Modi.hasValue()) {
|
if (MI.Modi.hasValue()) {
|
||||||
const auto &ModiStream = *MI.Modi;
|
const auto &ModiStream = *MI.Modi;
|
||||||
for (auto Symbol : ModiStream.Symbols)
|
for (auto Symbol : ModiStream.Symbols) {
|
||||||
ModiBuilder.addSymbol(Symbol.toCodeViewSymbol(Allocator));
|
ModiBuilder.addSymbol(
|
||||||
|
Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (MI.FileLineInfo.hasValue()) {
|
if (MI.FileLineInfo.hasValue()) {
|
||||||
const auto &FLI = *MI.FileLineInfo;
|
const auto &FLI = *MI.FileLineInfo;
|
||||||
|
|
|
@ -978,7 +978,8 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
|
||||||
Subsection.bytes_end());
|
Subsection.bytes_end());
|
||||||
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
|
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
|
||||||
SectionContents);
|
SectionContents);
|
||||||
CVSymbolDumper CVSD(W, Types, std::move(CODD), opts::CodeViewSubsectionBytes);
|
CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD),
|
||||||
|
opts::CodeViewSubsectionBytes);
|
||||||
CVSymbolArray Symbols;
|
CVSymbolArray Symbols;
|
||||||
BinaryStreamReader Reader(BinaryData, llvm::support::little);
|
BinaryStreamReader Reader(BinaryData, llvm::support::little);
|
||||||
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
|
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
|
||||||
|
|
Loading…
Reference in New Issue