llvm.org GIT mirror llvm / f393f97
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302052 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
14 changed file(s) with 157 addition(s) and 99 deletion(s). Raw diff Collapse all Expand all
3333 public:
3434 StringTableRef();
3535
36 Error initialize(BinaryStreamReader &Stream);
36 Error initialize(BinaryStreamRef Contents);
3737
38 StringRef getString(uint32_t Offset) const;
38 Expected getString(uint32_t Offset) const;
39
40 bool valid() const { return Stream.valid(); }
3941
4042 private:
4143 BinaryStreamRef Stream;
1818
1919 namespace codeview {
2020
21 class StringTableRef;
22
2123 class SymbolVisitorDelegate {
2224 public:
2325 virtual ~SymbolVisitorDelegate() = default;
2426
2527 virtual uint32_t getRecordOffset(BinaryStreamReader Reader) = 0;
2628 virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0;
27 virtual StringRef getStringTable() = 0;
29 virtual StringTableRef getStringTable() = 0;
2830 };
2931
3032 } // end namespace codeview
None //===- PDBStringTable.h - PDB String Table -------------------------*- C++
1 //-*-===//
0 //===- PDBStringTable.h - PDB String Table -----------------------*- C++-*-===//
21 //
32 // The LLVM Compiler Infrastructure
43 //
4039 uint32_t getHashVersion() const;
4140 uint32_t getSignature() const;
4241
43 StringRef getStringForID(uint32_t ID) const;
44 uint32_t getIDForString(StringRef Str) const;
42 Expected getStringForID(uint32_t ID) const;
43 Expected getIDForString(StringRef Str) const;
4544
4645 FixedStreamArray name_ids() const;
4746
9797 BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
9898 uint32_t Length) = delete;
9999
100 /// Check if a Stream is valid.
101 bool valid() const { return Stream != nullptr; }
102
100103 /// Given an Offset into this StreamRef and a Size, return a reference to a
101104 /// buffer owned by the stream.
102105 ///
1717
1818 StringTableRef::StringTableRef() {}
1919
20 Error StringTableRef::initialize(BinaryStreamReader &Reader) {
21 return Reader.readStreamRef(Stream, Reader.bytesRemaining());
20 Error StringTableRef::initialize(BinaryStreamRef Contents) {
21 Stream = Contents;
22 return Error::success();
2223 }
2324
24 StringRef StringTableRef::getString(uint32_t Offset) const {
25 Expected StringTableRef::getString(uint32_t Offset) const {
2526 BinaryStreamReader Reader(Stream);
2627 Reader.setOffset(Offset);
2728 StringRef Result;
28 Error EC = Reader.readCString(Result);
29 assert(!EC);
30 consumeError(std::move(EC));
29 if (auto EC = Reader.readCString(Result))
30 return std::move(EC);
3131 return Result;
3232 }
3333
1212 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
1313 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
1414 #include "llvm/DebugInfo/CodeView/EnumTables.h"
15 #include "llvm/DebugInfo/CodeView/StringTable.h"
1516 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
1617 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
1718 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
368369 DictScope S(W, "DefRangeSubfield");
369370
370371 if (ObjDelegate) {
371 StringRef StringTable = ObjDelegate->getStringTable();
372 auto ProgramStringTableOffset = DefRangeSubfield.Program;
373 if (ProgramStringTableOffset >= StringTable.size())
372 StringTableRef Strings = ObjDelegate->getStringTable();
373 auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program);
374 if (!ExpectedProgram) {
375 consumeError(ExpectedProgram.takeError());
374376 return llvm::make_error(
375377 "String table offset outside of bounds of String Table!");
376 StringRef Program =
377 StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
378 W.printString("Program", Program);
378 }
379 W.printString("Program", *ExpectedProgram);
379380 }
380381 W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
381382 printLocalVariableAddrRange(DefRangeSubfield.Range,
389390 DictScope S(W, "DefRange");
390391
391392 if (ObjDelegate) {
392 StringRef StringTable = ObjDelegate->getStringTable();
393 auto ProgramStringTableOffset = DefRange.Program;
394 if (ProgramStringTableOffset >= StringTable.size())
393 StringTableRef Strings = ObjDelegate->getStringTable();
394 auto ExpectedProgram = Strings.getString(DefRange.Program);
395 if (!ExpectedProgram) {
396 consumeError(ExpectedProgram.takeError());
395397 return llvm::make_error(
396398 "String table offset outside of bounds of String Table!");
397 StringRef Program =
398 StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
399 W.printString("Program", Program);
399 }
400 W.printString("Program", *ExpectedProgram);
400401 }
401402 printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
402403 printLocalVariableAddrGap(DefRange.Gaps);
4141 }
4242
4343 Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
44 if (auto EC = Strings.initialize(Reader)) {
44 BinaryStreamRef Stream;
45 if (auto EC = Reader.readStreamRef(Stream))
46 return EC;
47
48 if (auto EC = Strings.initialize(Stream)) {
4549 return joinErrors(std::move(EC),
4650 make_error(raw_error_code::corrupt_file,
4751 "Invalid hash table byte length"));
98102 return Error::success();
99103 }
100104
101 StringRef PDBStringTable::getStringForID(uint32_t ID) const {
105 Expected PDBStringTable::getStringForID(uint32_t ID) const {
102106 return Strings.getString(ID);
103107 }
104108
105 uint32_t PDBStringTable::getIDForString(StringRef Str) const {
109 Expected PDBStringTable::getIDForString(StringRef Str) const {
106110 uint32_t Hash =
107111 (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
108112 size_t Count = IDs.size();
114118 uint32_t Index = (Start + I) % Count;
115119
116120 uint32_t ID = IDs[Index];
117 StringRef S = getStringForID(ID);
118 if (S == Str)
121 auto ExpectedStr = getStringForID(ID);
122 if (!ExpectedStr)
123 return ExpectedStr.takeError();
124
125 if (*ExpectedStr == Str)
119126 return ID;
120127 }
121 // IDs[0] contains the ID of the "invalid" entry.
122 return IDs[0];
128 return make_error(raw_error_code::no_entry);
123129 }
124130
125131 FixedStreamArray PDBStringTable::name_ids() const {
393393 StringRef S1, S2;
394394 if (I < IdList1.size()) {
395395 Id1 = IdList1[I];
396 S1 = ST1.getStringForID(*Id1);
396 if (auto Result = ST1.getStringForID(*Id1))
397 S1 = *Result;
398 else
399 return Result.takeError();
397400 }
398401 if (I < IdList2.size()) {
399402 Id2 = IdList2[I];
400 S2 = ST2.getStringForID(*Id2);
403 if (auto Result = ST2.getStringForID(*Id2))
404 S2 = *Result;
405 else
406 return Result.takeError();
401407 }
402408 if (Id1 == Id2 && S1 == S2)
403409 continue;
417423 std::vector Strings1, Strings2;
418424 Strings1.reserve(IdList1.size());
419425 Strings2.reserve(IdList2.size());
420 for (auto ID : IdList1)
421 Strings1.push_back(ST1.getStringForID(ID));
422 for (auto ID : IdList2)
423 Strings2.push_back(ST2.getStringForID(ID));
426 for (auto ID : IdList1) {
427 auto S = ST1.getStringForID(ID);
428 if (!S)
429 return S.takeError();
430 Strings1.push_back(*S);
431 }
432 for (auto ID : IdList2) {
433 auto S = ST2.getStringForID(ID);
434 if (!S)
435 return S.takeError();
436 Strings2.push_back(*S);
437 }
424438
425439 SmallVector OnlyP;
426440 SmallVector OnlyQ;
524524
525525 DictScope D(P, "String Table");
526526 for (uint32_t I : IS->name_ids()) {
527 StringRef S = IS->getStringForID(I);
528 if (!S.empty()) {
529 llvm::SmallString<32> Str;
530 Str.append("'");
531 Str.append(S);
532 Str.append("'");
533 P.printString(Str);
534 }
527 auto ES = IS->getStringForID(I);
528 if (!ES)
529 return ES.takeError();
530
531 if (ES->empty())
532 continue;
533 llvm::SmallString<32> Str;
534 Str.append("'");
535 Str.append(*ES);
536 Str.append("'");
537 P.printString(Str);
535538 }
536539 return Error::success();
537540 }
687690 const auto &ST = *ExpectedST;
688691 for (const auto &E : Tpi->getHashAdjusters()) {
689692 DictScope DHA(P);
690 StringRef Name = ST.getStringForID(E.first);
691 P.printString("Type", Name);
693 auto Name = ST.getStringForID(E.first);
694 if (!Name)
695 return Name.takeError();
696
697 P.printString("Type", *Name);
692698 P.printHex("TI", E.second);
693699 }
694700 }
232232
233233 const auto &ST = ExpectedST.get();
234234 for (auto ID : ST.name_ids()) {
235 StringRef S = ST.getStringForID(ID);
236 if (!S.empty())
237 Obj.StringTable->push_back(S);
235 auto S = ST.getStringForID(ID);
236 if (!S)
237 return S.takeError();
238 if (S->empty())
239 continue;
240 Obj.StringTable->push_back(*S);
238241 }
239242 return Error::success();
240243 }
2828 #include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
2929 #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
3030 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
31 #include "llvm/DebugInfo/CodeView/StringTable.h"
3132 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
3233 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
3334 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
123124 StringRef SectionContents, StringRef Block);
124125
125126 /// Given a .debug$S section, find the string table and file checksum table.
126 void initializeFileAndStringTables(StringRef Data);
127 void initializeFileAndStringTables(BinaryStreamReader &Reader);
127128
128129 void cacheRelocations();
129130
144145 const llvm::object::COFFObjectFile *Obj;
145146 bool RelocCached = false;
146147 RelocMapTy RelocMap;
147 StringRef CVFileChecksumTable;
148 StringRef CVStringTable;
148
149 BinaryByteStream ChecksumContents;
150 VarStreamArray CVFileChecksumTable;
151
152 BinaryByteStream StringTableContents;
153 StringTableRef CVStringTable;
149154
150155 ScopedPrinter &Writer;
151156 TypeDatabase TypeDB;
185190 return CD.getFileNameForFileOffset(FileOffset);
186191 }
187192
188 StringRef getStringTable() override { return CD.CVStringTable; }
193 StringTableRef getStringTable() override { return CD.CVStringTable; }
189194
190195 private:
191196 COFFDumper &CD;
724729 }
725730 }
726731
727 void COFFDumper::initializeFileAndStringTables(StringRef Data) {
728 while (!Data.empty() && (CVFileChecksumTable.data() == nullptr ||
729 CVStringTable.data() == nullptr)) {
732 void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {
733 while (Reader.bytesRemaining() > 0 &&
734 (!CVFileChecksumTable.valid() || !CVStringTable.valid())) {
730735 // The section consists of a number of subsection in the following format:
731736 // |SubSectionType|SubSectionSize|Contents...|
732737 uint32_t SubType, SubSectionSize;
733 error(consume(Data, SubType));
734 error(consume(Data, SubSectionSize));
735 if (SubSectionSize > Data.size())
736 return error(object_error::parse_failed);
738 error(Reader.readInteger(SubType));
739 error(Reader.readInteger(SubSectionSize));
740
741 StringRef Contents;
742 error(Reader.readFixedString(Contents, SubSectionSize));
743
737744 switch (ModuleDebugFragmentKind(SubType)) {
738 case ModuleDebugFragmentKind::FileChecksums:
739 CVFileChecksumTable = Data.substr(0, SubSectionSize);
745 case ModuleDebugFragmentKind::FileChecksums: {
746 ChecksumContents = BinaryByteStream(Contents, support::little);
747 BinaryStreamReader CSR(ChecksumContents);
748 error(CSR.readArray(CVFileChecksumTable, CSR.getLength()));
740749 break;
741 case ModuleDebugFragmentKind::StringTable:
742 CVStringTable = Data.substr(0, SubSectionSize);
743 break;
750 }
751 case ModuleDebugFragmentKind::StringTable: {
752 StringTableContents = BinaryByteStream(Contents, support::little);
753 error(CVStringTable.initialize(StringTableContents));
754 } break;
744755 default:
745756 break;
746757 }
758
747759 uint32_t PaddedSize = alignTo(SubSectionSize, 4);
748 if (PaddedSize > Data.size())
749 error(object_error::parse_failed);
750 Data = Data.drop_front(PaddedSize);
760 error(Reader.skip(PaddedSize - SubSectionSize));
751761 }
752762 }
753763
770780 if (Magic != COFF::DEBUG_SECTION_MAGIC)
771781 return error(object_error::parse_failed);
772782
773 initializeFileAndStringTables(Data);
783 BinaryByteStream FileAndStrings(Data, support::little);
784 BinaryStreamReader FSReader(FileAndStrings);
785 initializeFileAndStringTables(FSReader);
774786
775787 // TODO: Convert this over to using ModuleSubstreamVisitor.
776788 while (!Data.empty()) {
860872 const FrameData *FD;
861873 error(SR.readObject(FD));
862874
863 if (FD->FrameFunc >= CVStringTable.size())
864 error(object_error::parse_failed);
865
866 StringRef FrameFunc =
867 CVStringTable.drop_front(FD->FrameFunc).split('\0').first;
875 StringRef FrameFunc = error(CVStringTable.getString(FD->FrameFunc));
868876
869877 DictScope S(W, "FrameData");
870878 W.printHex("RvaStart", FD->RvaStart);
970978 for (auto &FC : Checksums) {
971979 DictScope S(W, "FileChecksum");
972980
973 if (FC.FileNameOffset >= CVStringTable.size())
974 error(object_error::parse_failed);
975 StringRef Filename =
976 CVStringTable.drop_front(FC.FileNameOffset).split('\0').first;
981 StringRef Filename = error(CVStringTable.getString(FC.FileNameOffset));
977982 W.printHex("Filename", Filename, FC.FileNameOffset);
978983 W.printHex("ChecksumSize", FC.Checksum.size());
979984 W.printEnum("ChecksumKind", uint8_t(FC.Kind),
10071012
10081013 StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {
10091014 // The file checksum subsection should precede all references to it.
1010 if (!CVFileChecksumTable.data() || !CVStringTable.data())
1015 if (!CVFileChecksumTable.valid() || !CVStringTable.valid())
10111016 error(object_error::parse_failed);
1017
1018 auto Iter = CVFileChecksumTable.at(FileOffset);
1019
10121020 // Check if the file checksum table offset is valid.
1013 if (FileOffset >= CVFileChecksumTable.size())
1021 if (Iter == CVFileChecksumTable.end())
10141022 error(object_error::parse_failed);
10151023
1016 // The string table offset comes first before the file checksum.
1017 StringRef Data = CVFileChecksumTable.drop_front(FileOffset);
1018 uint32_t StringOffset;
1019 error(consume(Data, StringOffset));
1020
1021 // Check if the string table offset is valid.
1022 if (StringOffset >= CVStringTable.size())
1023 error(object_error::parse_failed);
1024
1025 // Return the null-terminated string.
1026 return CVStringTable.drop_front(StringOffset).split('\0').first;
1024 return error(CVStringTable.getString(Iter->FileNameOffset));
10271025 }
10281026
10291027 void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
2424 LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
2525 void error(std::error_code EC);
2626 void error(llvm::Error EC);
27 template T error(llvm::Expected &&E) {
28 error(E.takeError());
29 return std::move(*E);
30 }
31
2732 template T unwrapOrError(ErrorOr EO) {
2833 if (EO)
2934 return *EO;
3535 } \
3636 }
3737
38 #define EXPECT_EXPECTED_EQ(Val, Exp) \
39 { \
40 auto Result = Exp; \
41 auto E = Result.takeError(); \
42 EXPECT_FALSE(static_cast(E)); \
43 if (E) { \
44 consumeError(std::move(E)); \
45 return; \
46 } \
47 EXPECT_EQ(Val, *Result); \
48 }
49
3850 #define EXPECT_UNEXPECTED(Exp) \
3951 { \
4052 auto E = Exp.takeError(); \
2424 class StringTableBuilderTest : public ::testing::Test {};
2525 }
2626
27 template
28 static void ExpectExpected(Expected &&E, const T &Value) {
29 EXPECT_EXPECTED(E);
30 EXPECT_EQ(Value, *E);
31 }
32
2733 TEST_F(StringTableBuilderTest, Simple) {
2834 // Create /names table contents.
2935 PDBStringTableBuilder Builder;
4551
4652 EXPECT_EQ(3U, Table.getNameCount());
4753 EXPECT_EQ(1U, Table.getHashVersion());
48 EXPECT_EQ("foo", Table.getStringForID(1));
49 EXPECT_EQ("bar", Table.getStringForID(5));
50 EXPECT_EQ("baz", Table.getStringForID(9));
51 EXPECT_EQ(1U, Table.getIDForString("foo"));
52 EXPECT_EQ(5U, Table.getIDForString("bar"));
53 EXPECT_EQ(9U, Table.getIDForString("baz"));
54
55 EXPECT_EXPECTED_EQ("foo", Table.getStringForID(1));
56 EXPECT_EXPECTED_EQ("bar", Table.getStringForID(5));
57 EXPECT_EXPECTED_EQ("baz", Table.getStringForID(9));
58 EXPECT_EXPECTED_EQ(1U, Table.getIDForString("foo"));
59 EXPECT_EXPECTED_EQ(5U, Table.getIDForString("bar"));
60 EXPECT_EXPECTED_EQ(9U, Table.getIDForString("baz"));
5461 }