forked from OSchip/llvm-project
[llvm-readobj] Update readobj to re-use parsing code.
llvm-readobj hand rolls some CodeView parsing code for string tables, so this patch updates it to re-use some of the newly introduced parsing code in LLVMDebugInfoCodeView. Differential Revision: https://reviews.llvm.org/D32772 llvm-svn: 302052
This commit is contained in:
parent
761bcdaf06
commit
2d5c2cd3ce
|
@ -34,9 +34,11 @@ class StringTableRef {
|
||||||
public:
|
public:
|
||||||
StringTableRef();
|
StringTableRef();
|
||||||
|
|
||||||
Error initialize(BinaryStreamReader &Stream);
|
Error initialize(BinaryStreamRef Contents);
|
||||||
|
|
||||||
StringRef getString(uint32_t Offset) const;
|
Expected<StringRef> getString(uint32_t Offset) const;
|
||||||
|
|
||||||
|
bool valid() const { return Stream.valid(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BinaryStreamRef Stream;
|
BinaryStreamRef Stream;
|
||||||
|
|
|
@ -19,13 +19,15 @@ class BinaryStreamReader;
|
||||||
|
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
|
|
||||||
|
class StringTableRef;
|
||||||
|
|
||||||
class SymbolVisitorDelegate {
|
class SymbolVisitorDelegate {
|
||||||
public:
|
public:
|
||||||
virtual ~SymbolVisitorDelegate() = default;
|
virtual ~SymbolVisitorDelegate() = default;
|
||||||
|
|
||||||
virtual uint32_t getRecordOffset(BinaryStreamReader Reader) = 0;
|
virtual uint32_t getRecordOffset(BinaryStreamReader Reader) = 0;
|
||||||
virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0;
|
virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0;
|
||||||
virtual StringRef getStringTable() = 0;
|
virtual StringTableRef getStringTable() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace codeview
|
} // end namespace codeview
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//===- PDBStringTable.h - PDB String Table -------------------------*- C++
|
//===- PDBStringTable.h - PDB String Table -----------------------*- C++-*-===//
|
||||||
//-*-===//
|
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
|
@ -41,8 +40,8 @@ public:
|
||||||
uint32_t getHashVersion() const;
|
uint32_t getHashVersion() const;
|
||||||
uint32_t getSignature() const;
|
uint32_t getSignature() const;
|
||||||
|
|
||||||
StringRef getStringForID(uint32_t ID) const;
|
Expected<StringRef> getStringForID(uint32_t ID) const;
|
||||||
uint32_t getIDForString(StringRef Str) const;
|
Expected<uint32_t> getIDForString(StringRef Str) const;
|
||||||
|
|
||||||
FixedStreamArray<support::ulittle32_t> name_ids() const;
|
FixedStreamArray<support::ulittle32_t> name_ids() const;
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,9 @@ public:
|
||||||
BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
|
BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
|
||||||
uint32_t Length) = delete;
|
uint32_t Length) = delete;
|
||||||
|
|
||||||
|
/// Check if a Stream is valid.
|
||||||
|
bool valid() const { return Stream != nullptr; }
|
||||||
|
|
||||||
/// Given an Offset into this StreamRef and a Size, return a reference to a
|
/// Given an Offset into this StreamRef and a Size, return a reference to a
|
||||||
/// buffer owned by the stream.
|
/// buffer owned by the stream.
|
||||||
///
|
///
|
||||||
|
|
|
@ -18,17 +18,17 @@ using namespace llvm::codeview;
|
||||||
|
|
||||||
StringTableRef::StringTableRef() {}
|
StringTableRef::StringTableRef() {}
|
||||||
|
|
||||||
Error StringTableRef::initialize(BinaryStreamReader &Reader) {
|
Error StringTableRef::initialize(BinaryStreamRef Contents) {
|
||||||
return Reader.readStreamRef(Stream, Reader.bytesRemaining());
|
Stream = Contents;
|
||||||
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef StringTableRef::getString(uint32_t Offset) const {
|
Expected<StringRef> StringTableRef::getString(uint32_t Offset) const {
|
||||||
BinaryStreamReader Reader(Stream);
|
BinaryStreamReader Reader(Stream);
|
||||||
Reader.setOffset(Offset);
|
Reader.setOffset(Offset);
|
||||||
StringRef Result;
|
StringRef Result;
|
||||||
Error EC = Reader.readCString(Result);
|
if (auto EC = Reader.readCString(Result))
|
||||||
assert(!EC);
|
return std::move(EC);
|
||||||
consumeError(std::move(EC));
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
||||||
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||||
|
@ -369,14 +370,14 @@ Error CVSymbolDumperImpl::visitKnownRecord(
|
||||||
DictScope S(W, "DefRangeSubfield");
|
DictScope S(W, "DefRangeSubfield");
|
||||||
|
|
||||||
if (ObjDelegate) {
|
if (ObjDelegate) {
|
||||||
StringRef StringTable = ObjDelegate->getStringTable();
|
StringTableRef Strings = ObjDelegate->getStringTable();
|
||||||
auto ProgramStringTableOffset = DefRangeSubfield.Program;
|
auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program);
|
||||||
if (ProgramStringTableOffset >= StringTable.size())
|
if (!ExpectedProgram) {
|
||||||
|
consumeError(ExpectedProgram.takeError());
|
||||||
return llvm::make_error<CodeViewError>(
|
return llvm::make_error<CodeViewError>(
|
||||||
"String table offset outside of bounds of String Table!");
|
"String table offset outside of bounds of String Table!");
|
||||||
StringRef Program =
|
}
|
||||||
StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
|
W.printString("Program", *ExpectedProgram);
|
||||||
W.printString("Program", Program);
|
|
||||||
}
|
}
|
||||||
W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
|
W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
|
||||||
printLocalVariableAddrRange(DefRangeSubfield.Range,
|
printLocalVariableAddrRange(DefRangeSubfield.Range,
|
||||||
|
@ -390,14 +391,14 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||||
DictScope S(W, "DefRange");
|
DictScope S(W, "DefRange");
|
||||||
|
|
||||||
if (ObjDelegate) {
|
if (ObjDelegate) {
|
||||||
StringRef StringTable = ObjDelegate->getStringTable();
|
StringTableRef Strings = ObjDelegate->getStringTable();
|
||||||
auto ProgramStringTableOffset = DefRange.Program;
|
auto ExpectedProgram = Strings.getString(DefRange.Program);
|
||||||
if (ProgramStringTableOffset >= StringTable.size())
|
if (!ExpectedProgram) {
|
||||||
|
consumeError(ExpectedProgram.takeError());
|
||||||
return llvm::make_error<CodeViewError>(
|
return llvm::make_error<CodeViewError>(
|
||||||
"String table offset outside of bounds of String Table!");
|
"String table offset outside of bounds of String Table!");
|
||||||
StringRef Program =
|
}
|
||||||
StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
|
W.printString("Program", *ExpectedProgram);
|
||||||
W.printString("Program", Program);
|
|
||||||
}
|
}
|
||||||
printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
|
printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
|
||||||
printLocalVariableAddrGap(DefRange.Gaps);
|
printLocalVariableAddrGap(DefRange.Gaps);
|
||||||
|
|
|
@ -42,7 +42,11 @@ Error PDBStringTable::readHeader(BinaryStreamReader &Reader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
|
Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
|
||||||
if (auto EC = Strings.initialize(Reader)) {
|
BinaryStreamRef Stream;
|
||||||
|
if (auto EC = Reader.readStreamRef(Stream))
|
||||||
|
return EC;
|
||||||
|
|
||||||
|
if (auto EC = Strings.initialize(Stream)) {
|
||||||
return joinErrors(std::move(EC),
|
return joinErrors(std::move(EC),
|
||||||
make_error<RawError>(raw_error_code::corrupt_file,
|
make_error<RawError>(raw_error_code::corrupt_file,
|
||||||
"Invalid hash table byte length"));
|
"Invalid hash table byte length"));
|
||||||
|
@ -99,11 +103,11 @@ Error PDBStringTable::reload(BinaryStreamReader &Reader) {
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef PDBStringTable::getStringForID(uint32_t ID) const {
|
Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const {
|
||||||
return Strings.getString(ID);
|
return Strings.getString(ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PDBStringTable::getIDForString(StringRef Str) const {
|
Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const {
|
||||||
uint32_t Hash =
|
uint32_t Hash =
|
||||||
(Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
|
(Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
|
||||||
size_t Count = IDs.size();
|
size_t Count = IDs.size();
|
||||||
|
@ -115,12 +119,14 @@ uint32_t PDBStringTable::getIDForString(StringRef Str) const {
|
||||||
uint32_t Index = (Start + I) % Count;
|
uint32_t Index = (Start + I) % Count;
|
||||||
|
|
||||||
uint32_t ID = IDs[Index];
|
uint32_t ID = IDs[Index];
|
||||||
StringRef S = getStringForID(ID);
|
auto ExpectedStr = getStringForID(ID);
|
||||||
if (S == Str)
|
if (!ExpectedStr)
|
||||||
|
return ExpectedStr.takeError();
|
||||||
|
|
||||||
|
if (*ExpectedStr == Str)
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
// IDs[0] contains the ID of the "invalid" entry.
|
return make_error<RawError>(raw_error_code::no_entry);
|
||||||
return IDs[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const {
|
FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const {
|
||||||
|
|
|
@ -394,11 +394,17 @@ Error DiffStyle::diffStringTable() {
|
||||||
StringRef S1, S2;
|
StringRef S1, S2;
|
||||||
if (I < IdList1.size()) {
|
if (I < IdList1.size()) {
|
||||||
Id1 = IdList1[I];
|
Id1 = IdList1[I];
|
||||||
S1 = ST1.getStringForID(*Id1);
|
if (auto Result = ST1.getStringForID(*Id1))
|
||||||
|
S1 = *Result;
|
||||||
|
else
|
||||||
|
return Result.takeError();
|
||||||
}
|
}
|
||||||
if (I < IdList2.size()) {
|
if (I < IdList2.size()) {
|
||||||
Id2 = IdList2[I];
|
Id2 = IdList2[I];
|
||||||
S2 = ST2.getStringForID(*Id2);
|
if (auto Result = ST2.getStringForID(*Id2))
|
||||||
|
S2 = *Result;
|
||||||
|
else
|
||||||
|
return Result.takeError();
|
||||||
}
|
}
|
||||||
if (Id1 == Id2 && S1 == S2)
|
if (Id1 == Id2 && S1 == S2)
|
||||||
continue;
|
continue;
|
||||||
|
@ -418,10 +424,18 @@ Error DiffStyle::diffStringTable() {
|
||||||
std::vector<StringRef> Strings1, Strings2;
|
std::vector<StringRef> Strings1, Strings2;
|
||||||
Strings1.reserve(IdList1.size());
|
Strings1.reserve(IdList1.size());
|
||||||
Strings2.reserve(IdList2.size());
|
Strings2.reserve(IdList2.size());
|
||||||
for (auto ID : IdList1)
|
for (auto ID : IdList1) {
|
||||||
Strings1.push_back(ST1.getStringForID(ID));
|
auto S = ST1.getStringForID(ID);
|
||||||
for (auto ID : IdList2)
|
if (!S)
|
||||||
Strings2.push_back(ST2.getStringForID(ID));
|
return S.takeError();
|
||||||
|
Strings1.push_back(*S);
|
||||||
|
}
|
||||||
|
for (auto ID : IdList2) {
|
||||||
|
auto S = ST2.getStringForID(ID);
|
||||||
|
if (!S)
|
||||||
|
return S.takeError();
|
||||||
|
Strings2.push_back(*S);
|
||||||
|
}
|
||||||
|
|
||||||
SmallVector<StringRef, 64> OnlyP;
|
SmallVector<StringRef, 64> OnlyP;
|
||||||
SmallVector<StringRef, 64> OnlyQ;
|
SmallVector<StringRef, 64> OnlyQ;
|
||||||
|
|
|
@ -525,15 +525,18 @@ Error LLVMOutputStyle::dumpStringTable() {
|
||||||
|
|
||||||
DictScope D(P, "String Table");
|
DictScope D(P, "String Table");
|
||||||
for (uint32_t I : IS->name_ids()) {
|
for (uint32_t I : IS->name_ids()) {
|
||||||
StringRef S = IS->getStringForID(I);
|
auto ES = IS->getStringForID(I);
|
||||||
if (!S.empty()) {
|
if (!ES)
|
||||||
|
return ES.takeError();
|
||||||
|
|
||||||
|
if (ES->empty())
|
||||||
|
continue;
|
||||||
llvm::SmallString<32> Str;
|
llvm::SmallString<32> Str;
|
||||||
Str.append("'");
|
Str.append("'");
|
||||||
Str.append(S);
|
Str.append(*ES);
|
||||||
Str.append("'");
|
Str.append("'");
|
||||||
P.printString(Str);
|
P.printString(Str);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,8 +691,11 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
||||||
const auto &ST = *ExpectedST;
|
const auto &ST = *ExpectedST;
|
||||||
for (const auto &E : Tpi->getHashAdjusters()) {
|
for (const auto &E : Tpi->getHashAdjusters()) {
|
||||||
DictScope DHA(P);
|
DictScope DHA(P);
|
||||||
StringRef Name = ST.getStringForID(E.first);
|
auto Name = ST.getStringForID(E.first);
|
||||||
P.printString("Type", Name);
|
if (!Name)
|
||||||
|
return Name.takeError();
|
||||||
|
|
||||||
|
P.printString("Type", *Name);
|
||||||
P.printHex("TI", E.second);
|
P.printHex("TI", E.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,9 +233,12 @@ Error YAMLOutputStyle::dumpStringTable() {
|
||||||
|
|
||||||
const auto &ST = ExpectedST.get();
|
const auto &ST = ExpectedST.get();
|
||||||
for (auto ID : ST.name_ids()) {
|
for (auto ID : ST.name_ids()) {
|
||||||
StringRef S = ST.getStringForID(ID);
|
auto S = ST.getStringForID(ID);
|
||||||
if (!S.empty())
|
if (!S)
|
||||||
Obj.StringTable->push_back(S);
|
return S.takeError();
|
||||||
|
if (S->empty())
|
||||||
|
continue;
|
||||||
|
Obj.StringTable->push_back(*S);
|
||||||
}
|
}
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
|
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
||||||
|
@ -124,7 +125,7 @@ private:
|
||||||
StringRef SectionContents, StringRef Block);
|
StringRef SectionContents, StringRef Block);
|
||||||
|
|
||||||
/// Given a .debug$S section, find the string table and file checksum table.
|
/// Given a .debug$S section, find the string table and file checksum table.
|
||||||
void initializeFileAndStringTables(StringRef Data);
|
void initializeFileAndStringTables(BinaryStreamReader &Reader);
|
||||||
|
|
||||||
void cacheRelocations();
|
void cacheRelocations();
|
||||||
|
|
||||||
|
@ -145,8 +146,12 @@ private:
|
||||||
const llvm::object::COFFObjectFile *Obj;
|
const llvm::object::COFFObjectFile *Obj;
|
||||||
bool RelocCached = false;
|
bool RelocCached = false;
|
||||||
RelocMapTy RelocMap;
|
RelocMapTy RelocMap;
|
||||||
StringRef CVFileChecksumTable;
|
|
||||||
StringRef CVStringTable;
|
BinaryByteStream ChecksumContents;
|
||||||
|
VarStreamArray<FileChecksumEntry> CVFileChecksumTable;
|
||||||
|
|
||||||
|
BinaryByteStream StringTableContents;
|
||||||
|
StringTableRef CVStringTable;
|
||||||
|
|
||||||
ScopedPrinter &Writer;
|
ScopedPrinter &Writer;
|
||||||
TypeDatabase TypeDB;
|
TypeDatabase TypeDB;
|
||||||
|
@ -186,7 +191,7 @@ public:
|
||||||
return CD.getFileNameForFileOffset(FileOffset);
|
return CD.getFileNameForFileOffset(FileOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getStringTable() override { return CD.CVStringTable; }
|
StringTableRef getStringTable() override { return CD.CVStringTable; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
COFFDumper &CD;
|
COFFDumper &CD;
|
||||||
|
@ -725,30 +730,35 @@ void COFFDumper::printCodeViewDebugInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void COFFDumper::initializeFileAndStringTables(StringRef Data) {
|
void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {
|
||||||
while (!Data.empty() && (CVFileChecksumTable.data() == nullptr ||
|
while (Reader.bytesRemaining() > 0 &&
|
||||||
CVStringTable.data() == nullptr)) {
|
(!CVFileChecksumTable.valid() || !CVStringTable.valid())) {
|
||||||
// The section consists of a number of subsection in the following format:
|
// The section consists of a number of subsection in the following format:
|
||||||
// |SubSectionType|SubSectionSize|Contents...|
|
// |SubSectionType|SubSectionSize|Contents...|
|
||||||
uint32_t SubType, SubSectionSize;
|
uint32_t SubType, SubSectionSize;
|
||||||
error(consume(Data, SubType));
|
error(Reader.readInteger(SubType));
|
||||||
error(consume(Data, SubSectionSize));
|
error(Reader.readInteger(SubSectionSize));
|
||||||
if (SubSectionSize > Data.size())
|
|
||||||
return error(object_error::parse_failed);
|
StringRef Contents;
|
||||||
|
error(Reader.readFixedString(Contents, SubSectionSize));
|
||||||
|
|
||||||
switch (ModuleDebugFragmentKind(SubType)) {
|
switch (ModuleDebugFragmentKind(SubType)) {
|
||||||
case ModuleDebugFragmentKind::FileChecksums:
|
case ModuleDebugFragmentKind::FileChecksums: {
|
||||||
CVFileChecksumTable = Data.substr(0, SubSectionSize);
|
ChecksumContents = BinaryByteStream(Contents, support::little);
|
||||||
break;
|
BinaryStreamReader CSR(ChecksumContents);
|
||||||
case ModuleDebugFragmentKind::StringTable:
|
error(CSR.readArray(CVFileChecksumTable, CSR.getLength()));
|
||||||
CVStringTable = Data.substr(0, SubSectionSize);
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case ModuleDebugFragmentKind::StringTable: {
|
||||||
|
StringTableContents = BinaryByteStream(Contents, support::little);
|
||||||
|
error(CVStringTable.initialize(StringTableContents));
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PaddedSize = alignTo(SubSectionSize, 4);
|
uint32_t PaddedSize = alignTo(SubSectionSize, 4);
|
||||||
if (PaddedSize > Data.size())
|
error(Reader.skip(PaddedSize - SubSectionSize));
|
||||||
error(object_error::parse_failed);
|
|
||||||
Data = Data.drop_front(PaddedSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +781,9 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
|
||||||
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
||||||
return error(object_error::parse_failed);
|
return error(object_error::parse_failed);
|
||||||
|
|
||||||
initializeFileAndStringTables(Data);
|
BinaryByteStream FileAndStrings(Data, support::little);
|
||||||
|
BinaryStreamReader FSReader(FileAndStrings);
|
||||||
|
initializeFileAndStringTables(FSReader);
|
||||||
|
|
||||||
// TODO: Convert this over to using ModuleSubstreamVisitor.
|
// TODO: Convert this over to using ModuleSubstreamVisitor.
|
||||||
while (!Data.empty()) {
|
while (!Data.empty()) {
|
||||||
|
@ -861,11 +873,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
|
||||||
const FrameData *FD;
|
const FrameData *FD;
|
||||||
error(SR.readObject(FD));
|
error(SR.readObject(FD));
|
||||||
|
|
||||||
if (FD->FrameFunc >= CVStringTable.size())
|
StringRef FrameFunc = error(CVStringTable.getString(FD->FrameFunc));
|
||||||
error(object_error::parse_failed);
|
|
||||||
|
|
||||||
StringRef FrameFunc =
|
|
||||||
CVStringTable.drop_front(FD->FrameFunc).split('\0').first;
|
|
||||||
|
|
||||||
DictScope S(W, "FrameData");
|
DictScope S(W, "FrameData");
|
||||||
W.printHex("RvaStart", FD->RvaStart);
|
W.printHex("RvaStart", FD->RvaStart);
|
||||||
|
@ -971,10 +979,7 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
|
||||||
for (auto &FC : Checksums) {
|
for (auto &FC : Checksums) {
|
||||||
DictScope S(W, "FileChecksum");
|
DictScope S(W, "FileChecksum");
|
||||||
|
|
||||||
if (FC.FileNameOffset >= CVStringTable.size())
|
StringRef Filename = error(CVStringTable.getString(FC.FileNameOffset));
|
||||||
error(object_error::parse_failed);
|
|
||||||
StringRef Filename =
|
|
||||||
CVStringTable.drop_front(FC.FileNameOffset).split('\0').first;
|
|
||||||
W.printHex("Filename", Filename, FC.FileNameOffset);
|
W.printHex("Filename", Filename, FC.FileNameOffset);
|
||||||
W.printHex("ChecksumSize", FC.Checksum.size());
|
W.printHex("ChecksumSize", FC.Checksum.size());
|
||||||
W.printEnum("ChecksumKind", uint8_t(FC.Kind),
|
W.printEnum("ChecksumKind", uint8_t(FC.Kind),
|
||||||
|
@ -1008,23 +1013,16 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
|
||||||
|
|
||||||
StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {
|
StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {
|
||||||
// The file checksum subsection should precede all references to it.
|
// The file checksum subsection should precede all references to it.
|
||||||
if (!CVFileChecksumTable.data() || !CVStringTable.data())
|
if (!CVFileChecksumTable.valid() || !CVStringTable.valid())
|
||||||
error(object_error::parse_failed);
|
error(object_error::parse_failed);
|
||||||
|
|
||||||
|
auto Iter = CVFileChecksumTable.at(FileOffset);
|
||||||
|
|
||||||
// Check if the file checksum table offset is valid.
|
// Check if the file checksum table offset is valid.
|
||||||
if (FileOffset >= CVFileChecksumTable.size())
|
if (Iter == CVFileChecksumTable.end())
|
||||||
error(object_error::parse_failed);
|
error(object_error::parse_failed);
|
||||||
|
|
||||||
// The string table offset comes first before the file checksum.
|
return error(CVStringTable.getString(Iter->FileNameOffset));
|
||||||
StringRef Data = CVFileChecksumTable.drop_front(FileOffset);
|
|
||||||
uint32_t StringOffset;
|
|
||||||
error(consume(Data, StringOffset));
|
|
||||||
|
|
||||||
// Check if the string table offset is valid.
|
|
||||||
if (StringOffset >= CVStringTable.size())
|
|
||||||
error(object_error::parse_failed);
|
|
||||||
|
|
||||||
// Return the null-terminated string.
|
|
||||||
return CVStringTable.drop_front(StringOffset).split('\0').first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
|
void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
|
||||||
|
|
|
@ -25,6 +25,11 @@ namespace llvm {
|
||||||
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
|
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
|
||||||
void error(std::error_code EC);
|
void error(std::error_code EC);
|
||||||
void error(llvm::Error EC);
|
void error(llvm::Error EC);
|
||||||
|
template <typename T> T error(llvm::Expected<T> &&E) {
|
||||||
|
error(E.takeError());
|
||||||
|
return std::move(*E);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T> T unwrapOrError(ErrorOr<T> EO) {
|
template <class T> T unwrapOrError(ErrorOr<T> EO) {
|
||||||
if (EO)
|
if (EO)
|
||||||
return *EO;
|
return *EO;
|
||||||
|
|
|
@ -36,6 +36,18 @@
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EXPECT_EXPECTED_EQ(Val, Exp) \
|
||||||
|
{ \
|
||||||
|
auto Result = Exp; \
|
||||||
|
auto E = Result.takeError(); \
|
||||||
|
EXPECT_FALSE(static_cast<bool>(E)); \
|
||||||
|
if (E) { \
|
||||||
|
consumeError(std::move(E)); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
EXPECT_EQ(Val, *Result); \
|
||||||
|
}
|
||||||
|
|
||||||
#define EXPECT_UNEXPECTED(Exp) \
|
#define EXPECT_UNEXPECTED(Exp) \
|
||||||
{ \
|
{ \
|
||||||
auto E = Exp.takeError(); \
|
auto E = Exp.takeError(); \
|
||||||
|
|
|
@ -25,6 +25,12 @@ namespace {
|
||||||
class StringTableBuilderTest : public ::testing::Test {};
|
class StringTableBuilderTest : public ::testing::Test {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void ExpectExpected(Expected<T> &&E, const T &Value) {
|
||||||
|
EXPECT_EXPECTED(E);
|
||||||
|
EXPECT_EQ(Value, *E);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(StringTableBuilderTest, Simple) {
|
TEST_F(StringTableBuilderTest, Simple) {
|
||||||
// Create /names table contents.
|
// Create /names table contents.
|
||||||
PDBStringTableBuilder Builder;
|
PDBStringTableBuilder Builder;
|
||||||
|
@ -46,10 +52,11 @@ TEST_F(StringTableBuilderTest, Simple) {
|
||||||
|
|
||||||
EXPECT_EQ(3U, Table.getNameCount());
|
EXPECT_EQ(3U, Table.getNameCount());
|
||||||
EXPECT_EQ(1U, Table.getHashVersion());
|
EXPECT_EQ(1U, Table.getHashVersion());
|
||||||
EXPECT_EQ("foo", Table.getStringForID(1));
|
|
||||||
EXPECT_EQ("bar", Table.getStringForID(5));
|
EXPECT_EXPECTED_EQ("foo", Table.getStringForID(1));
|
||||||
EXPECT_EQ("baz", Table.getStringForID(9));
|
EXPECT_EXPECTED_EQ("bar", Table.getStringForID(5));
|
||||||
EXPECT_EQ(1U, Table.getIDForString("foo"));
|
EXPECT_EXPECTED_EQ("baz", Table.getStringForID(9));
|
||||||
EXPECT_EQ(5U, Table.getIDForString("bar"));
|
EXPECT_EXPECTED_EQ(1U, Table.getIDForString("foo"));
|
||||||
EXPECT_EQ(9U, Table.getIDForString("baz"));
|
EXPECT_EXPECTED_EQ(5U, Table.getIDForString("bar"));
|
||||||
|
EXPECT_EXPECTED_EQ(9U, Table.getIDForString("baz"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue