Index: tools/llvm-readobj/COFFDumper.cpp =================================================================== --- tools/llvm-readobj/COFFDumper.cpp +++ tools/llvm-readobj/COFFDumper.cpp @@ -136,8 +136,8 @@ StringRef CVFileChecksumTable; StringRef CVStringTable; - /// All user defined type records in .debug$T live in here. Type indices - /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to + /// All user-defined type records in .debug$T live in here. Type indices + /// greater than 0x1000 are user-defined. Subtract 0x1000 from the index to /// index into this vector. SmallVector CVUDTNames; @@ -1850,19 +1850,9 @@ } } -StringRef getRemainingTypeBytes(const TypeRecordPrefix *Rec, const char *Start) { - ptrdiff_t StartOffset = Start - reinterpret_cast(Rec); - size_t RecSize = Rec->Len + 2; - assert(StartOffset >= 0 && "negative start-offset!"); - assert(static_cast(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 getLeafDataBytesAsString(StringRef LeafData) { StringRef Leading, Trailing; - std::tie(Leading, Trailing) = Remaining.split('\0'); + std::tie(Leading, Trailing) = LeafData.split('\0'); return Leading; } @@ -1976,42 +1966,125 @@ 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 SectionRef &Section) + : Data(), Magic(0), Current(), AtEnd(false) { + const std::error_code Error = Section.getContents(Data); + if (Error) + throw Error; + if (Data.size() >= 4) { + Magic = *reinterpret_cast(Data.data()); + Data = Data.drop_front(4); + } + Next(); // Prime the pump + } + + CodeViewTypeIterator() : Data(), Magic(0), Current(), 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. + bool operator==(const CodeViewTypeIterator &other) const { + return (Data.begin() == other.Data.begin()) || (AtEnd && other.AtEnd); + } + + bool operator!=(const CodeViewTypeIterator &other) const { + return !(*this == other); + } + + 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->operator++(); + 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; + std::error_code Error = consumeObject(Data, Rec); + if (Error) + return; + Current.Length = Rec->Len; + Current.Leaf = static_cast(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; + TypeRecord Current; + bool AtEnd; +}; + 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)); W.printBinaryBlock("Data", Data); - unsigned Magic = *reinterpret_cast(Data.data()); - W.printHex("Magic", Magic); - - Data = Data.drop_front(4); - - while (!Data.empty()) { - const TypeRecordPrefix *Rec; - error(consumeObject(Data, Rec)); - auto Leaf = static_cast(uint16_t(Rec->Leaf)); + CodeViewTypeIterator Iter(Section); + W.printHex("Magic", Iter.getMagic()); - // 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()); + CodeViewTypeIterator End; + for (; Iter != 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; } @@ -2019,7 +2092,7 @@ 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; @@ -2027,7 +2100,7 @@ } 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); @@ -2073,7 +2146,7 @@ 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); @@ -2095,7 +2168,7 @@ 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); @@ -2350,11 +2423,6 @@ 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. } }