forked from OSchip/llvm-project
NFC: An iterator for stepping through CodeView type stream in llvm-readobj
This is a small refactoring step toward moving CodeView type stream logic from llvm-readobj to a library. It abstracts the logic of stepping through the stream into an iterator class and updates llvm-readobj to use that iterator. This has no functional change; llvm-readobj produces identical output. The next step is to abstract the parsing of the different leaf types and then move that and the iterator into a library. Since this is my first contrib outside LLDB, please let me know if I'm messing up on any of the LLVM style guidelines, idioms, or patterns. Differential Revision: http://reviews.llvm.org/D19746 llvm-svn: 268334
This commit is contained in:
parent
dd368fcb05
commit
963a331a7e
|
@ -1866,19 +1866,9 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
|
|||
}
|
||||
}
|
||||
|
||||
StringRef getRemainingTypeBytes(const TypeRecordPrefix *Rec, const char *Start) {
|
||||
ptrdiff_t StartOffset = Start - reinterpret_cast<const char *>(Rec);
|
||||
size_t RecSize = Rec->Len + 2;
|
||||
assert(StartOffset >= 0 && "negative start-offset!");
|
||||
assert(static_cast<size_t>(StartOffset) <= RecSize &&
|
||||
"Start beyond the end of Rec");
|
||||
return StringRef(Start, RecSize - StartOffset);
|
||||
}
|
||||
|
||||
StringRef getRemainingBytesAsString(const TypeRecordPrefix *Rec, const char *Start) {
|
||||
StringRef Remaining = getRemainingTypeBytes(Rec, Start);
|
||||
StringRef Leading, Trailing;
|
||||
std::tie(Leading, Trailing) = Remaining.split('\0');
|
||||
StringRef getLeafDataBytesAsString(StringRef LeafData) {
|
||||
StringRef Leading;
|
||||
std::tie(Leading, std::ignore) = LeafData.split('\0');
|
||||
return Leading;
|
||||
}
|
||||
|
||||
|
@ -1992,47 +1982,148 @@ static StringRef getLeafTypeName(TypeLeafKind LT) {
|
|||
return "UnknownLeaf";
|
||||
}
|
||||
|
||||
// A const input iterator interface to the CodeView type stream.
|
||||
class CodeViewTypeIterator {
|
||||
public:
|
||||
struct TypeRecord {
|
||||
std::size_t Length;
|
||||
TypeLeafKind Leaf;
|
||||
StringRef LeafData;
|
||||
};
|
||||
|
||||
explicit CodeViewTypeIterator(const StringRef &SectionData)
|
||||
: Data(SectionData), AtEnd(false) {
|
||||
if (Data.size() >= 4) {
|
||||
Magic = *reinterpret_cast<const ulittle32_t *>(Data.data());
|
||||
Data = Data.drop_front(4);
|
||||
}
|
||||
next(); // Prime the pump
|
||||
}
|
||||
|
||||
CodeViewTypeIterator() : AtEnd(true) {}
|
||||
|
||||
// For iterators to compare equal, they must both point at the same record
|
||||
// in the same data stream, or they must both be at the end of a stream.
|
||||
friend bool operator==(const CodeViewTypeIterator &lhs,
|
||||
const CodeViewTypeIterator &rhs);
|
||||
|
||||
friend bool operator!=(const CodeViewTypeIterator &lhs,
|
||||
const CodeViewTypeIterator &rhs);
|
||||
|
||||
unsigned getMagic() const { return Magic; }
|
||||
|
||||
const TypeRecord &operator*() const {
|
||||
assert(!AtEnd);
|
||||
return Current;
|
||||
}
|
||||
|
||||
const TypeRecord *operator->() const {
|
||||
assert(!AtEnd);
|
||||
return &Current;
|
||||
}
|
||||
|
||||
CodeViewTypeIterator operator++() {
|
||||
next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CodeViewTypeIterator operator++(int) {
|
||||
CodeViewTypeIterator Original = *this;
|
||||
++*this;
|
||||
return Original;
|
||||
}
|
||||
|
||||
private:
|
||||
void next() {
|
||||
assert(!AtEnd && "Attempted to advance more than one past the last rec");
|
||||
if (Data.empty()) {
|
||||
// We've advanced past the last record.
|
||||
AtEnd = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const TypeRecordPrefix *Rec;
|
||||
if (consumeObject(Data, Rec))
|
||||
return;
|
||||
Current.Length = Rec->Len;
|
||||
Current.Leaf = static_cast<TypeLeafKind>(uint16_t(Rec->Leaf));
|
||||
Current.LeafData = Data.substr(0, Current.Length - 2);
|
||||
|
||||
// The next record starts immediately after this one.
|
||||
Data = Data.drop_front(Current.LeafData.size());
|
||||
|
||||
// FIXME: The stream contains LF_PAD bytes that we need to ignore, but those
|
||||
// are typically included in LeafData. We may need to call skipPadding() if
|
||||
// we ever find a record that doesn't count those bytes.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Data;
|
||||
unsigned Magic = 0;
|
||||
TypeRecord Current;
|
||||
bool AtEnd;
|
||||
};
|
||||
|
||||
bool operator==(const CodeViewTypeIterator &lhs,
|
||||
const CodeViewTypeIterator &rhs) {
|
||||
return (lhs.Data.begin() == rhs.Data.begin()) || (lhs.AtEnd && rhs.AtEnd);
|
||||
}
|
||||
|
||||
bool operator!=(const CodeViewTypeIterator &lhs,
|
||||
const CodeViewTypeIterator &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
struct CodeViewTypeStream {
|
||||
CodeViewTypeIterator begin;
|
||||
CodeViewTypeIterator end;
|
||||
unsigned Magic;
|
||||
};
|
||||
|
||||
CodeViewTypeStream CreateCodeViewTypeIter(const StringRef &Data) {
|
||||
CodeViewTypeStream Stream;
|
||||
Stream.begin = CodeViewTypeIterator(Data);
|
||||
Stream.end = CodeViewTypeIterator();
|
||||
Stream.Magic = Stream.begin.getMagic();
|
||||
|
||||
return Stream;
|
||||
}
|
||||
|
||||
void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
|
||||
const SectionRef &Section) {
|
||||
ListScope D(W, "CodeViewTypes");
|
||||
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
|
||||
|
||||
StringRef Data;
|
||||
error(Section.getContents(Data));
|
||||
if (opts::CodeViewSubsectionBytes)
|
||||
W.printBinaryBlock("Data", Data);
|
||||
|
||||
unsigned Magic = *reinterpret_cast<const ulittle32_t *>(Data.data());
|
||||
W.printHex("Magic", Magic);
|
||||
|
||||
Data = Data.drop_front(4);
|
||||
|
||||
CVTD.dump(Data);
|
||||
}
|
||||
|
||||
void CVTypeDumper::dump(StringRef Data) {
|
||||
while (!Data.empty()) {
|
||||
const TypeRecordPrefix *Rec;
|
||||
error(consumeObject(Data, Rec));
|
||||
auto Leaf = static_cast<TypeLeafKind>(uint16_t(Rec->Leaf));
|
||||
CodeViewTypeStream Stream = CreateCodeViewTypeIter(Data);
|
||||
W.printHex("Magic", Stream.Magic);
|
||||
|
||||
// This record is 'Len - 2' bytes, and the next one starts immediately
|
||||
// afterwards.
|
||||
StringRef LeafData = Data.substr(0, Rec->Len - 2);
|
||||
StringRef RemainingData = Data.drop_front(LeafData.size());
|
||||
for (auto Iter = Stream.begin; Iter != Stream.end; ++Iter) {
|
||||
StringRef LeafData = Iter->LeafData;
|
||||
|
||||
// Find the name of this leaf type.
|
||||
StringRef LeafName = getLeafTypeName(Leaf);
|
||||
StringRef LeafName = getLeafTypeName(Iter->Leaf);
|
||||
DictScope S(W, LeafName);
|
||||
unsigned NextTypeIndex = 0x1000 + CVUDTNames.size();
|
||||
W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames));
|
||||
W.printEnum("TypeLeafKind", unsigned(Iter->Leaf),
|
||||
makeArrayRef(LeafTypeNames));
|
||||
W.printHex("TypeIndex", NextTypeIndex);
|
||||
|
||||
// Fill this in inside the switch to get something in CVUDTNames.
|
||||
StringRef Name;
|
||||
|
||||
switch (Leaf) {
|
||||
switch (Iter->Leaf) {
|
||||
default: {
|
||||
W.printHex("Size", Rec->Len);
|
||||
W.printHex("Size", Iter->Length);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2040,7 +2131,7 @@ void CVTypeDumper::dump(StringRef Data) {
|
|||
const StringId *String;
|
||||
error(consumeObject(LeafData, String));
|
||||
W.printHex("Id", String->id.getIndex());
|
||||
StringRef StringData = getRemainingBytesAsString(Rec, LeafData.data());
|
||||
StringRef StringData = getLeafDataBytesAsString(LeafData);
|
||||
W.printString("StringData", StringData);
|
||||
// Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
|
||||
Name = StringData;
|
||||
|
@ -2048,7 +2139,7 @@ void CVTypeDumper::dump(StringRef Data) {
|
|||
}
|
||||
|
||||
case LF_FIELDLIST: {
|
||||
W.printHex("Size", Rec->Len);
|
||||
W.printHex("Size", Iter->Length);
|
||||
// FieldList has no fixed prefix that can be described with a struct. All
|
||||
// the bytes must be interpreted as more records.
|
||||
printCodeViewFieldList(LeafData);
|
||||
|
@ -2094,7 +2185,7 @@ void CVTypeDumper::dump(StringRef Data) {
|
|||
std::tie(Name, LinkageName) = LeafData.split('\0');
|
||||
W.printString("Name", Name);
|
||||
if (Props & uint16_t(ClassOptions::HasUniqueName)) {
|
||||
LinkageName = getRemainingBytesAsString(Rec, LinkageName.data());
|
||||
LinkageName = getLeafDataBytesAsString(LinkageName);
|
||||
if (LinkageName.empty())
|
||||
return error(object_error::parse_failed);
|
||||
W.printString("LinkageName", LinkageName);
|
||||
|
@ -2116,7 +2207,7 @@ void CVTypeDumper::dump(StringRef Data) {
|
|||
std::tie(Name, LinkageName) = LeafData.split('\0');
|
||||
W.printString("Name", Name);
|
||||
if (Props & uint16_t(ClassOptions::HasUniqueName)) {
|
||||
LinkageName = getRemainingBytesAsString(Rec, LinkageName.data());
|
||||
LinkageName = getLeafDataBytesAsString(LinkageName);
|
||||
if (LinkageName.empty())
|
||||
return error(object_error::parse_failed);
|
||||
W.printString("LinkageName", LinkageName);
|
||||
|
@ -2371,11 +2462,6 @@ void CVTypeDumper::dump(StringRef Data) {
|
|||
W.printBinaryBlock("LeafData", LeafData);
|
||||
|
||||
CVUDTNames.push_back(Name);
|
||||
|
||||
Data = RemainingData;
|
||||
// FIXME: The stream contains LF_PAD bytes that we need to ignore, but those
|
||||
// are typically included in LeafData. We may need to call skipPadding() if
|
||||
// we ever find a record that doesn't count those bytes.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue