Skip to content

Commit

Permalink
Fix Bug 30978 by emitting cv file checksums.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Eric Beckmann committed Sep 15, 2017
1 parent 7a183e2 commit 349746f
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 81 deletions.
10 changes: 6 additions & 4 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Expand Up @@ -473,10 +473,12 @@ class DIFile : public DIScope {
friend class MDNode;

public:
// These values must be explictly set, as they end up in the final object
// file.
enum ChecksumKind {
CSK_None,
CSK_MD5,
CSK_SHA1,
CSK_None = 0,
CSK_MD5 = 1,
CSK_SHA1 = 2,
CSK_Last = CSK_SHA1 // Should be last enumeration.
};

Expand Down Expand Up @@ -510,7 +512,7 @@ class DIFile : public DIScope {
ChecksumKind CSK = CSK_None,
StringRef CS = StringRef()),
(Filename, Directory, CSK, CS))
DEFINE_MDNODE_GET(DIFile, (MDString *Filename, MDString *Directory,
DEFINE_MDNODE_GET(DIFile, (MDString * Filename, MDString *Directory,
ChecksumKind CSK = CSK_None,
MDString *CS = nullptr),
(Filename, Directory, CSK, CS))
Expand Down
35 changes: 29 additions & 6 deletions llvm/include/llvm/MC/MCCodeView.h
Expand Up @@ -161,8 +161,8 @@ class CodeViewContext {
~CodeViewContext();

bool isValidFileNumber(unsigned FileNumber) const;
bool addFile(unsigned FileNumber, StringRef Filename);
ArrayRef<StringRef> getFilenames() { return Filenames; }
bool addFile(MCStreamer &OS, unsigned FileNumber, StringRef Filename,
StringRef Checksum, uint8_t ChecksumKind);

/// Records the function id of a normal function. Returns false if the
/// function id has already been used, and true otherwise.
Expand Down Expand Up @@ -273,6 +273,9 @@ class CodeViewContext {
/// Emits the file checksum substream.
void emitFileChecksums(MCObjectStreamer &OS);

/// Emits the offset into the checksum table of the given file number.
void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo);

private:
/// The current CodeView line information from the last .cv_loc directive.
MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true);
Expand All @@ -287,14 +290,30 @@ class CodeViewContext {

MCDataFragment *getStringTableFragment();

/// Add something to the string table.
StringRef addToStringTable(StringRef S);
/// Add something to the string table. Returns the final string as well as
/// offset into the string table.
std::pair<StringRef, unsigned> addToStringTable(StringRef S);

/// Get a string table offset.
unsigned getStringTableOffset(StringRef S);

/// An array of absolute paths. Eventually this may include the file checksum.
SmallVector<StringRef, 4> Filenames;
struct FileInfo {
unsigned StringTableOffset;

// Checksum offset stored as a symbol because it might be requested
// before it has been calculated, so a fixup may be needed.
MCSymbol *ChecksumTableOffset;

// Indicates if this FileInfo corresponds to an actual file, or hasn't been
// set yet.
bool Assigned = false;

std::string Checksum;
uint8_t ChecksumKind;
};

/// Array storing added file information.
SmallVector<FileInfo, 4> Files;

/// The offset of the first and last .cv_loc directive for a given function
/// id.
Expand All @@ -305,6 +324,10 @@ class CodeViewContext {

/// All known functions and inlined call sites, indexed by function id.
std::vector<MCCVFunctionInfo> Functions;

/// Indicate whether we have already laid out the checksum table addresses or
/// not.
bool ChecksumOffsetsAssigned = false;
};

} // end namespace llvm
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCObjectStreamer.h
Expand Up @@ -140,6 +140,7 @@ class MCObjectStreamer : public MCStreamer {
StringRef FixedSizePortion) override;
void EmitCVStringTableDirective() override;
void EmitCVFileChecksumsDirective() override;
void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override;
void EmitDTPRel32Value(const MCExpr *Value) override;
void EmitDTPRel64Value(const MCExpr *Value) override;
void EmitTPRel32Value(const MCExpr *Value) override;
Expand Down
13 changes: 9 additions & 4 deletions llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -729,10 +729,11 @@ class MCStreamer {
unsigned Isa, unsigned Discriminator,
StringRef FileName);

/// \brief Associate a filename with a specified logical file number. This
/// implements the '.cv_file 4 "foo.c"' assembler directive. Returns true on
/// success.
virtual bool EmitCVFileDirective(unsigned FileNo, StringRef Filename);
/// Associate a filename with a specified logical file number, and also
/// specify that file's checksum information. This implements the '.cv_file 4
/// "foo.c"' assembler directive. Returns true on success.
virtual bool EmitCVFileDirective(unsigned FileNo, StringRef Filename,
StringRef Checksum, unsigned ChecksumKind);

/// \brief Introduces a function id for use with .cv_loc.
virtual bool EmitCVFuncIdDirective(unsigned FunctionId);
Expand Down Expand Up @@ -774,6 +775,10 @@ class MCStreamer {
/// \brief This implements the CodeView '.cv_filechecksums' assembler directive.
virtual void EmitCVFileChecksumsDirective() {}

/// This implements the CodeView '.cv_filechecksumoffset' assembler
/// directive.
virtual void EmitCVFileChecksumOffsetDirective(unsigned FileNo) {}

/// Emit the absolute difference between two symbols.
///
/// \pre Offset of \c Hi is greater than the offset \c Lo.
Expand Down
16 changes: 9 additions & 7 deletions llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
Expand Up @@ -159,7 +159,10 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
if (Insertion.second) {
// We have to compute the full filepath and emit a .cv_file directive.
StringRef FullPath = getFullFilepath(F);
bool Success = OS.EmitCVFileDirective(NextId, FullPath);
StringRef Checksum = F->getChecksum();
DIFile::ChecksumKind ChecksumKind = F->getChecksumKind();
bool Success = OS.EmitCVFileDirective(NextId, FullPath, Checksum,
static_cast<unsigned>(ChecksumKind));
(void)Success;
assert(Success && ".cv_file directive failed");
}
Expand Down Expand Up @@ -681,8 +684,10 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
OS.AddComment("Inlinee lines subsection");
MCSymbol *InlineEnd = beginCVSubsection(DebugSubsectionKind::InlineeLines);

// We don't provide any extra file info.
// FIXME: Find out if debuggers use this info.
// We emit the checksum info for files. This is used by debuggers to
// determine if a pdb matches the source before loading it. Visual Studio,
// for instance, will display a warning that the breakpoints are not valid if
// the pdb does not match the source.
OS.AddComment("Inlinee lines signature");
OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4);

Expand All @@ -695,13 +700,10 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
OS.AddComment("Inlined function " + SP->getName() + " starts at " +
SP->getFilename() + Twine(':') + Twine(SP->getLine()));
OS.AddBlankLine();
// The filechecksum table uses 8 byte entries for now, and file ids start at
// 1.
unsigned FileOffset = (FileId - 1) * 8;
OS.AddComment("Type index of inlined function");
OS.EmitIntValue(InlineeIdx.getIndex(), 4);
OS.AddComment("Offset into filechecksum table");
OS.EmitIntValue(FileOffset, 4);
OS.EmitCVFileChecksumOffsetDirective(FileId);
OS.AddComment("Starting line number");
OS.EmitIntValue(SP->getLine(), 4);
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/IR/DebugInfoMetadata.cpp
Expand Up @@ -354,6 +354,8 @@ DISubroutineType *DISubroutineType::getImpl(LLVMContext &Context, DIFlags Flags,
DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops);
}

// FIXME: Implement this string-enum correspondence with a .def file and macros,
// so that the association is explicit rather than implied.
static const char *ChecksumKindName[DIFile::CSK_Last + 1] = {
"CSK_None",
"CSK_MD5",
Expand Down
27 changes: 23 additions & 4 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -225,7 +225,8 @@ class MCAsmStreamer final : public MCStreamer {
StringRef FileName) override;
MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;

bool EmitCVFileDirective(unsigned FileNo, StringRef Filename) override;
bool EmitCVFileDirective(unsigned FileNo, StringRef Filename,
StringRef Checksum, unsigned ChecksumKind) override;
bool EmitCVFuncIdDirective(unsigned FuncId) override;
bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
unsigned IAFile, unsigned IALine,
Expand All @@ -245,6 +246,7 @@ class MCAsmStreamer final : public MCStreamer {
StringRef FixedSizePortion) override;
void EmitCVStringTableDirective() override;
void EmitCVFileChecksumsDirective() override;
void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override;

void EmitIdent(StringRef IdentString) override;
void EmitCFISections(bool EH, bool Debug) override;
Expand Down Expand Up @@ -1120,13 +1122,25 @@ MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
return MCStreamer::getDwarfLineTableSymbol(0);
}

bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
if (!getContext().getCVContext().addFile(FileNo, Filename))
bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename,
StringRef Checksum,
unsigned ChecksumKind) {
if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum,
ChecksumKind))
return false;

OS << "\t.cv_file\t" << FileNo << ' ';

PrintQuotedString(Filename, OS);

if (!ChecksumKind) {
EmitEOL();
return true;
}

OS << ' ';
PrintQuotedString(Checksum, OS);
OS << ' ' << ChecksumKind;

EmitEOL();
return true;
}
Expand Down Expand Up @@ -1228,6 +1242,11 @@ void MCAsmStreamer::EmitCVFileChecksumsDirective() {
EmitEOL();
}

void MCAsmStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) {
OS << "\t.cv_filechecksumoffset\t" << FileNo;
EmitEOL();
}

void MCAsmStreamer::EmitIdent(StringRef IdentString) {
assert(MAI->hasIdentDirective() && ".ident directive not supported");
OS << "\t.ident\t";
Expand Down

0 comments on commit 349746f

Please sign in to comment.