Re-land "Fix Bug 30978 by emitting cv file checksums."

This reverts r313431 and brings back r313374 with a fix to write
checksums as binary data and not ASCII hex strings.

llvm-svn: 313657
This commit is contained in:
Reid Kleckner
2017-09-19 18:14:45 +00:00
parent 0a84b1ac80
commit 26fa1bf4da
16 changed files with 305 additions and 81 deletions

View File

@@ -13,6 +13,7 @@
#include "llvm/MC/MCCodeView.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
@@ -39,29 +40,40 @@ 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,
ArrayRef<uint8_t> ChecksumBytes,
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 = "<stdin>";
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 = ChecksumBytes;
Files[Idx].ChecksumKind = ChecksumKind;
Filenames[Idx] = Filename;
return true;
}
@@ -118,17 +130,18 @@ MCDataFragment *CodeViewContext::getStringTableFragment() {
return StrTabFragment;
}
StringRef CodeViewContext::addToStringTable(StringRef S) {
std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) {
SmallVectorImpl<char> &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<StringRef, unsigned> 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 +178,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 +189,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<uint8_t>(File.Checksum.size()), 1);
OS.EmitIntValue(File.ChecksumKind, 1);
OS.EmitBytes(toStringRef(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 +278,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 +463,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<const MCConstantExpr *>(
Files[CurSourceLoc.File - 1]
.ChecksumTableOffset->getVariableValue())
->getValue();
compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
compressAnnotation(FileOffset, Buffer);
}