llvm.org GIT mirror llvm / ff94599
[CodeView] Use actual strings for dealing with checksums and lines. The raw CodeView format references strings by "offsets", but it's confusing what table the offset refers to. In the case of line number information, it's an offset into a buffer of records, and an indirection is required to get another offset into a different table to find the final string. And in the case of checksum information, there is no indirection, and the offset refers directly to the location of the string in another buffer. This would be less confusing if we always just referred to the strings by their value, and have the library be smart enough to correctly resolve the offsets on its own from the right location. This patch makes that possible. When either reading or writing, all the user deals with are strings, and the library does the appropriate translations behind the scenes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302053 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 3 years ago
11 changed file(s) with 87 addition(s) and 66 deletion(s). Raw diff Collapse all Expand all
1919
2020 namespace llvm {
2121 namespace codeview {
22
23 class StringTable;
2224
2325 struct FileChecksumEntry {
2426 uint32_t FileNameOffset; // Byte offset of filename in global stringtable.
6567
6668 class ModuleDebugFileChecksumFragment final : public ModuleDebugFragment {
6769 public:
68 ModuleDebugFileChecksumFragment();
70 explicit ModuleDebugFileChecksumFragment(StringTable &Strings);
6971
7072 static bool classof(const ModuleDebugFragment *S) {
7173 return S->kind() == ModuleDebugFragmentKind::FileChecksums;
7274 }
7375
74 void addChecksum(uint32_t StringTableOffset, FileChecksumKind Kind,
76 void addChecksum(StringRef FileName, FileChecksumKind Kind,
7577 ArrayRef Bytes);
7678
7779 uint32_t calculateSerializedLength() override;
7880 Error commit(BinaryStreamWriter &Writer) override;
79 uint32_t mapChecksumOffset(uint32_t StringTableOffset) const;
81 uint32_t mapChecksumOffset(StringRef FileName) const;
8082
8183 private:
84 StringTable &Strings;
85
8286 DenseMap OffsetMap;
8387 uint32_t SerializedSize = 0;
8488 llvm::BumpPtrAllocator Storage;
1919 namespace codeview {
2020
2121 class ModuleDebugInlineeLineFragmentRef;
22 class ModuleDebugFileChecksumFragment;
23 class StringTable;
2224
2325 enum class InlineeLinesSignature : uint32_t {
2426 Normal, // CV_INLINEE_SOURCE_LINE_SIGNATURE
7274
7375 class ModuleDebugInlineeLineFragment final : public ModuleDebugFragment {
7476 public:
75 explicit ModuleDebugInlineeLineFragment(bool HasExtraFiles);
77 ModuleDebugInlineeLineFragment(ModuleDebugFileChecksumFragment &Checksums,
78 StringTable &Strings, bool HasExtraFiles);
7679
7780 static bool classof(const ModuleDebugFragment *S) {
7881 return S->kind() == ModuleDebugFragmentKind::InlineeLines;
8184 Error commit(BinaryStreamWriter &Writer) override;
8285 uint32_t calculateSerializedLength() override;
8386
84 void addInlineSite(TypeIndex FuncId, uint32_t FileOffset,
85 uint32_t SourceLine);
86 void addExtraFile(uint32_t FileOffset);
87 void addInlineSite(TypeIndex FuncId, StringRef FileName, uint32_t SourceLine);
88 void addExtraFile(StringRef FileName);
8789
8890 private:
91 ModuleDebugFileChecksumFragment &Checksums;
92 StringTable &Strings;
93
8994 bool HasExtraFiles = false;
9095 uint32_t ExtraFileCount = 0;
9196
1717
1818 namespace llvm {
1919 namespace codeview {
20
21 class ModuleDebugFileChecksumFragment;
22 class StringTable;
2023
2124 // Corresponds to the `CV_DebugSLinesHeader_t` structure.
2225 struct LineFragmentHeader {
103106 };
104107
105108 public:
106 ModuleDebugLineFragment();
109 ModuleDebugLineFragment(ModuleDebugFileChecksumFragment &Checksums,
110 StringTable &Strings);
107111
108112 static bool classof(const ModuleDebugFragment *S) {
109113 return S->kind() == ModuleDebugFragmentKind::Lines;
110114 }
111115
112 void createBlock(uint32_t ChecksumBufferOffset);
116 void createBlock(StringRef FileName);
113117 void addLineInfo(uint32_t Offset, const LineInfo &Line);
114118 void addLineAndColumnInfo(uint32_t Offset, const LineInfo &Line,
115119 uint32_t ColStart, uint32_t ColEnd);
124128 bool hasColumnInfo() const;
125129
126130 private:
131 ModuleDebugFileChecksumFragment &Checksums;
132 StringTable &Strings;
133
127134 uint16_t RelocOffset = 0;
128135 uint16_t RelocSegment = 0;
129136 uint32_t CodeSize = 0;
5252 // Returns the ID for S.
5353 uint32_t insert(StringRef S);
5454
55 // Return the ID for string S. Assumes S exists in the table.
56 uint32_t getStringId(StringRef S) const;
57
5558 uint32_t calculateSerializedSize() const;
5659 Error commit(BinaryStreamWriter &Writer) const;
5760
4040 uint32_t calculateSerializedSize() const;
4141 Error commit(BinaryStreamWriter &Writer) const;
4242
43 codeview::StringTable &getStrings() { return Strings; }
44 const codeview::StringTable &getStrings() const { return Strings; }
45
4346 private:
4447 uint32_t calculateHashTableSize() const;
4548 Error writeHeader(BinaryStreamWriter &Writer) const;
222222 return Iterator(*this, Ctx, Stream, HadError);
223223 }
224224
225 bool valid() const { return Stream.valid(); }
226
225227 Iterator end() const { return Iterator(Ctx); }
226228
227229 bool empty() const { return Stream.getLength() == 0; }
99 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
1010
1111 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
12 #include "llvm/DebugInfo/CodeView/StringTable.h"
1213 #include "llvm/Support/BinaryStreamReader.h"
1314
1415 using namespace llvm;
4849 return Error::success();
4950 }
5051
51 ModuleDebugFileChecksumFragment::ModuleDebugFileChecksumFragment()
52 : ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums) {}
52 ModuleDebugFileChecksumFragment::ModuleDebugFileChecksumFragment(
53 StringTable &Strings)
54 : ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums),
55 Strings(Strings) {}
5356
54 void ModuleDebugFileChecksumFragment::addChecksum(uint32_t StringTableOffset,
57 void ModuleDebugFileChecksumFragment::addChecksum(StringRef FileName,
5558 FileChecksumKind Kind,
5659 ArrayRef Bytes) {
5760 FileChecksumEntry Entry;
6063 ::memcpy(Copy, Bytes.data(), Bytes.size());
6164 Entry.Checksum = makeArrayRef(Copy, Bytes.size());
6265 }
63 Entry.FileNameOffset = StringTableOffset;
66
67 Entry.FileNameOffset = Strings.insert(FileName);
6468 Entry.Kind = Kind;
6569 Checksums.push_back(Entry);
6670
6771 // This maps the offset of this string in the string table to the offset
6872 // of this checksum entry in the checksum buffer.
69 OffsetMap[StringTableOffset] = SerializedSize;
73 OffsetMap[Entry.FileNameOffset] = SerializedSize;
7074 assert(SerializedSize % 4 == 0);
7175
7276 uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
9397 return Error::success();
9498 }
9599
96 uint32_t ModuleDebugFileChecksumFragment::mapChecksumOffset(
97 uint32_t StringTableOffset) const {
98 auto Iter = OffsetMap.find(StringTableOffset);
100 uint32_t
101 ModuleDebugFileChecksumFragment::mapChecksumOffset(StringRef FileName) const {
102 uint32_t Offset = Strings.getStringId(FileName);
103 auto Iter = OffsetMap.find(Offset);
99104 assert(Iter != OffsetMap.end());
100105 return Iter->second;
101106 }
99 #include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
1010
1111 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
12 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
1213 #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
14 #include "llvm/DebugInfo/CodeView/StringTable.h"
1315
1416 using namespace llvm;
1517 using namespace llvm::codeview;
5456 }
5557
5658 ModuleDebugInlineeLineFragment::ModuleDebugInlineeLineFragment(
59 ModuleDebugFileChecksumFragment &Checksums, StringTable &Strings,
5760 bool HasExtraFiles)
5861 : ModuleDebugFragment(ModuleDebugFragmentKind::InlineeLines),
59 HasExtraFiles(HasExtraFiles) {}
62 Checksums(Checksums), Strings(Strings), HasExtraFiles(HasExtraFiles) {}
6063
6164 uint32_t ModuleDebugInlineeLineFragment::calculateSerializedLength() {
6265 // 4 bytes for the signature
99102 return Error::success();
100103 }
101104
102 void ModuleDebugInlineeLineFragment::addExtraFile(uint32_t FileOffset) {
105 void ModuleDebugInlineeLineFragment::addExtraFile(StringRef FileName) {
106 uint32_t Offset = Checksums.mapChecksumOffset(FileName);
107
103108 auto &Entry = Entries.back();
104 Entry.ExtraFiles.push_back(ulittle32_t(FileOffset));
109 Entry.ExtraFiles.push_back(ulittle32_t(Offset));
105110 ++ExtraFileCount;
106111 }
107112
108113 void ModuleDebugInlineeLineFragment::addInlineSite(TypeIndex FuncId,
109 uint32_t FileOffset,
114 StringRef FileName,
110115 uint32_t SourceLine) {
116 uint32_t Offset = Checksums.mapChecksumOffset(FileName);
117
111118 Entries.emplace_back();
112119 auto &Entry = Entries.back();
113 Entry.Header.FileID = FileOffset;
120 Entry.Header.FileID = Offset;
114121 Entry.Header.SourceLineNum = SourceLine;
115122 Entry.Header.Inlinee = FuncId;
116123 }
99 #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
1010
1111 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
12 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
1213 #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
14 #include "llvm/DebugInfo/CodeView/StringTable.h"
1315
1416 using namespace llvm;
1517 using namespace llvm::codeview;
6466 return !!(Header->Flags & LF_HaveColumns);
6567 }
6668
67 ModuleDebugLineFragment::ModuleDebugLineFragment()
68 : ModuleDebugFragment(ModuleDebugFragmentKind::Lines) {}
69 ModuleDebugLineFragment::ModuleDebugLineFragment(
70 ModuleDebugFileChecksumFragment &Checksums, StringTable &Strings)
71 : ModuleDebugFragment(ModuleDebugFragmentKind::Lines), Checksums(Checksums),
72 Strings(Strings) {}
6973
70 void ModuleDebugLineFragment::createBlock(uint32_t ChecksumBufferOffset) {
71 Blocks.emplace_back(ChecksumBufferOffset);
74 void ModuleDebugLineFragment::createBlock(StringRef FileName) {
75 uint32_t Offset = Checksums.mapChecksumOffset(FileName);
76
77 Blocks.emplace_back(Offset);
7278 }
7379
7480 void ModuleDebugLineFragment::addLineInfo(uint32_t Offset,
6262 }
6363
6464 uint32_t StringTable::size() const { return Strings.size(); }
65
66 uint32_t StringTable::getStringId(StringRef S) const {
67 auto P = Strings.find(S);
68 assert(P != Strings.end());
69 return P->second;
70 }
423423
424424 static ExitOnError ExitOnErr;
425425
426 static uint32_t
427 getFileChecksumOffset(StringRef FileName,
428 ModuleDebugFileChecksumFragment &Checksums,
429 PDBStringTableBuilder &Strings) {
430 // The offset in the line info record is the offset of the checksum
431 // entry for the corresponding file. That entry then contains an
432 // offset into the global string table of the file name. So to
433 // compute the proper offset to write into the line info record, we
434 // must first get its offset in the global string table, then ask the
435 // checksum builder to find the offset in its serialized buffer that
436 // it mapped that filename string table offset to.
437 uint32_t StringOffset = Strings.insert(FileName);
438 return Checksums.mapChecksumOffset(StringOffset);
439 }
440
441426 static void yamlToPdb(StringRef Path) {
442427 BumpPtrAllocator Allocator;
443428 ErrorOr> ErrorOrBuffer =
489474 for (auto F : Info.Features)
490475 InfoBuilder.addFeature(F);
491476
477 auto &Strings = Builder.getStringTableBuilder().getStrings();
478
492479 const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
493480 auto &DbiBuilder = Builder.getDbiBuilder();
494481 DbiBuilder.setAge(Dbi.Age);
515502 // File Checksums must be emitted before line information, because line
516503 // info records use offsets into the checksum buffer to reference a file's
517504 // source file name.
518 auto Checksums = llvm::make_unique();
505 auto Checksums =
506 llvm::make_unique(Strings);
519507 auto &ChecksumRef = *Checksums;
520508 if (!FLI.FileChecksums.empty()) {
521 auto &Strings = Builder.getStringTableBuilder();
522 for (auto &FC : FLI.FileChecksums) {
523 uint32_t STOffset = Strings.insert(FC.FileName);
524 Checksums->addChecksum(STOffset, FC.Kind, FC.ChecksumBytes.Bytes);
525 }
509 for (auto &FC : FLI.FileChecksums)
510 Checksums->addChecksum(FC.FileName, FC.Kind, FC.ChecksumBytes.Bytes);
526511 }
527512 ModiBuilder.setC13FileChecksums(std::move(Checksums));
528513
529 // FIXME: StringTable / StringTableBuilder should really be in
530 // DebugInfoCodeView. This would allow us to construct the
531 // ModuleDebugLineFragment with a reference to the string table,
532 // and we could just pass strings around rather than having to
533 // remember how to calculate the right offset.
534 auto &Strings = Builder.getStringTableBuilder();
535
536514 for (const auto &Fragment : FLI.LineFragments) {
537 auto Lines = llvm::make_unique();
515 auto Lines =
516 llvm::make_unique(ChecksumRef, Strings);
538517 Lines->setCodeSize(Fragment.CodeSize);
539518 Lines->setRelocationAddress(Fragment.RelocSegment,
540519 Fragment.RelocOffset);
541520 Lines->setFlags(Fragment.Flags);
542521 for (const auto &LC : Fragment.Blocks) {
543 uint32_t ChecksumOffset =
544 getFileChecksumOffset(LC.FileName, ChecksumRef, Strings);
545
546 Lines->createBlock(ChecksumOffset);
522 Lines->createBlock(LC.FileName);
547523 if (Lines->hasColumnInfo()) {
548524 for (const auto &Item : zip(LC.Lines, LC.Columns)) {
549525 auto &L = std::get<0>(Item);
566542
567543 for (const auto &Inlinee : FLI.Inlinees) {
568544 auto Inlinees = llvm::make_unique(
569 Inlinee.HasExtraFiles);
545 ChecksumRef, Strings, Inlinee.HasExtraFiles);
570546 for (const auto &Site : Inlinee.Sites) {
571 uint32_t FileOff =
572 getFileChecksumOffset(Site.FileName, ChecksumRef, Strings);
573
574 Inlinees->addInlineSite(Site.Inlinee, FileOff, Site.SourceLineNum);
547 Inlinees->addInlineSite(Site.Inlinee, Site.FileName,
548 Site.SourceLineNum);
575549 if (!Inlinee.HasExtraFiles)
576550 continue;
577551
578552 for (auto EF : Site.ExtraFiles) {
579 FileOff = getFileChecksumOffset(EF, ChecksumRef, Strings);
580 Inlinees->addExtraFile(FileOff);
553 Inlinees->addExtraFile(EF);
581554 }
582555 }
583556 ModiBuilder.addC13Fragment(std::move(Inlinees));