From 349746f044302eb4c793fbcb7e5fdbada6858cd9 Mon Sep 17 00:00:00 2001 From: Eric Beckmann Date: Fri, 15 Sep 2017 18:20:28 +0000 Subject: Fix Bug 30978 by emitting cv file checksums. Summary: The checksums had already been placed in the IR, this patch allows MCCodeView to actually write it out to an MCStreamer. Subscribers: llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D37157 llvm-svn: 313374 --- llvm/lib/MC/MCCodeView.cpp | 119 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 29 deletions(-) (limited to 'llvm/lib/MC/MCCodeView.cpp') diff --git a/llvm/lib/MC/MCCodeView.cpp b/llvm/lib/MC/MCCodeView.cpp index 92b1e12da55..ad6d9e5a5d8 100644 --- a/llvm/lib/MC/MCCodeView.cpp +++ b/llvm/lib/MC/MCCodeView.cpp @@ -39,29 +39,39 @@ CodeViewContext::~CodeViewContext() { /// for it. bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { unsigned Idx = FileNumber - 1; - if (Idx < Filenames.size()) - return !Filenames[Idx].empty(); + if (Idx < Files.size()) + return Files[Idx].Assigned; return false; } -bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { +bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber, + StringRef Filename, StringRef Checksum, + uint8_t ChecksumKind) { assert(FileNumber > 0); - Filename = addToStringTable(Filename); + auto FilenameOffset = addToStringTable(Filename); + Filename = FilenameOffset.first; unsigned Idx = FileNumber - 1; - if (Idx >= Filenames.size()) - Filenames.resize(Idx + 1); + if (Idx >= Files.size()) + Files.resize(Idx + 1); if (Filename.empty()) Filename = ""; - if (!Filenames[Idx].empty()) + if (Files[Idx].Assigned) return false; - // FIXME: We should store the string table offset of the filename, rather than - // the filename itself for efficiency. - Filename = addToStringTable(Filename); + FilenameOffset = addToStringTable(Filename); + Filename = FilenameOffset.first; + unsigned Offset = FilenameOffset.second; + + auto ChecksumOffsetSymbol = + OS.getContext().createTempSymbol("checksum_offset", false); + Files[Idx].StringTableOffset = Offset; + Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol; + Files[Idx].Assigned = true; + Files[Idx].Checksum = Checksum.str(); + Files[Idx].ChecksumKind = ChecksumKind; - Filenames[Idx] = Filename; return true; } @@ -118,17 +128,18 @@ MCDataFragment *CodeViewContext::getStringTableFragment() { return StrTabFragment; } -StringRef CodeViewContext::addToStringTable(StringRef S) { +std::pair CodeViewContext::addToStringTable(StringRef S) { SmallVectorImpl &Contents = getStringTableFragment()->getContents(); auto Insertion = StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); // Return the string from the table, since it is stable. - S = Insertion.first->first(); + std::pair Ret = + std::make_pair(Insertion.first->first(), Insertion.first->second); if (Insertion.second) { // The string map key is always null terminated. - Contents.append(S.begin(), S.end() + 1); + Contents.append(Ret.first.begin(), Ret.first.end() + 1); } - return S; + return Ret; } unsigned CodeViewContext::getStringTableOffset(StringRef S) { @@ -165,7 +176,7 @@ void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { // Do nothing if there are no file checksums. Microsoft's linker rejects empty // CodeView substreams. - if (Filenames.empty()) + if (Files.empty()) return; MCContext &Ctx = OS.getContext(); @@ -176,17 +187,63 @@ void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); OS.EmitLabel(FileBegin); + unsigned CurrentOffset = 0; + // Emit an array of FileChecksum entries. We index into this table using the - // user-provided file number. Each entry is currently 8 bytes, as we don't - // emit checksums. - for (StringRef Filename : Filenames) { - OS.EmitIntValue(getStringTableOffset(Filename), 4); - // Zero the next two fields and align back to 4 bytes. This indicates that - // no checksum is present. - OS.EmitIntValue(0, 4); + // user-provided file number. Each entry may be a variable number of bytes + // determined by the checksum kind and size. + for (auto File : Files) { + OS.EmitAssignment(File.ChecksumTableOffset, + MCConstantExpr::create(CurrentOffset, Ctx)); + CurrentOffset += 4; // String table offset. + if (!File.ChecksumKind) { + CurrentOffset += + 4; // One byte each for checksum size and kind, then align to 4 bytes. + } else { + CurrentOffset += 2; // One byte each for checksum size and kind. + CurrentOffset += File.Checksum.size(); + CurrentOffset = alignTo(CurrentOffset, 4); + } + + OS.EmitIntValue(File.StringTableOffset, 4); + + if (!File.ChecksumKind) { + // There is no checksum. Therefore zero the next two fields and align + // back to 4 bytes. + OS.EmitIntValue(0, 4); + continue; + } + OS.EmitIntValue(static_cast(File.Checksum.size()), 1); + OS.EmitIntValue(File.ChecksumKind, 1); + OS.EmitBytes(File.Checksum); + OS.EmitValueToAlignment(4); } OS.EmitLabel(FileEnd); + + ChecksumOffsetsAssigned = true; +} + +// Output checksum table offset of the given file number. It is possible that +// not all files have been registered yet, and so the offset cannot be +// calculated. In this case a symbol representing the offset is emitted, and +// the value of this symbol will be fixed up at a later time. +void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS, + unsigned FileNo) { + unsigned Idx = FileNo - 1; + + if (Idx >= Files.size()) + Files.resize(Idx + 1); + + if (ChecksumOffsetsAssigned) { + OS.EmitSymbolValue(Files[Idx].ChecksumTableOffset, 4); + return; + } + + const MCSymbolRefExpr *SRE = + MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext()); + + OS.EmitValueImpl(SRE, 4); } void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, @@ -219,9 +276,12 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, return Loc.getFileNum() != CurFileNum; }); unsigned EntryCount = FileSegEnd - I; - OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) + - "' begins"); - OS.EmitIntValue(8 * (CurFileNum - 1), 4); + OS.AddComment( + "Segment for file '" + + Twine(getStringTableFragment() + ->getContents()[Files[CurFileNum - 1].StringTableOffset]) + + "' begins"); + OS.EmitCVFileChecksumOffsetDirective(CurFileNum); OS.EmitIntValue(EntryCount, 4); uint32_t SegmentSize = 12; SegmentSize += 8 * EntryCount; @@ -401,9 +461,10 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, HaveOpenRange = true; if (CurSourceLoc.File != LastSourceLoc.File) { - // File ids are 1 based, and each file checksum table entry is 8 bytes - // long. See emitFileChecksums above. - unsigned FileOffset = 8 * (CurSourceLoc.File - 1); + unsigned FileOffset = static_cast( + Files[CurSourceLoc.File - 1] + .ChecksumTableOffset->getVariableValue()) + ->getValue(); compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); compressAnnotation(FileOffset, Buffer); } -- cgit v1.2.3