[DWARFv5] MC support for MD5 file checksums

Extend .file directive syntax to allow specifying an MD5 checksum for
the source file.  Emit the checksums in DWARF v5 line tables.

llvm-svn: 322134
This commit is contained in:
Paul Robinson 2018-01-09 23:31:48 +00:00
parent d72f78e7c8
commit 29f5f987f1
15 changed files with 147 additions and 39 deletions

View File

@ -23,6 +23,7 @@
#include "llvm/MC/SectionKind.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@ -489,7 +490,8 @@ namespace llvm {
/// Creates an entry in the dwarf file and directory tables.
unsigned getDwarfFile(StringRef Directory, StringRef FileName,
unsigned FileNumber, unsigned CUID);
unsigned FileNumber, MD5::MD5Result *Checksum,
unsigned CUID);
bool isValidDwarfFileNumber(unsigned FileNumber, unsigned CUID = 0);

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCSection.h"
#include "llvm/Support/MD5.h"
#include <cassert>
#include <cstdint>
#include <string>
@ -50,6 +51,10 @@ struct MCDwarfFile {
// \brief The index into the list of directory names for this file name.
unsigned DirIndex;
/// The MD5 checksum, if there is one. Non-owning pointer to data allocated
/// in MCContext.
MD5::MD5Result *Checksum = nullptr;
};
/// \brief Instances of this class represent the information from a
@ -203,11 +208,12 @@ struct MCDwarfLineTableHeader {
SmallVector<MCDwarfFile, 3> MCDwarfFiles;
StringMap<unsigned> SourceIdMap;
StringRef CompilationDir;
bool HasMD5 = false;
MCDwarfLineTableHeader() = default;
unsigned getFile(StringRef &Directory, StringRef &FileName,
unsigned FileNumber = 0);
MD5::MD5Result *Checksum, unsigned FileNumber = 0);
std::pair<MCSymbol *, MCSymbol *> Emit(MCStreamer *MCOS,
MCDwarfLineTableParams Params) const;
std::pair<MCSymbol *, MCSymbol *>
@ -223,8 +229,9 @@ public:
Header.CompilationDir = CompilationDir;
}
unsigned getFile(StringRef Directory, StringRef FileName) {
return Header.getFile(Directory, FileName);
unsigned getFile(StringRef Directory, StringRef FileName,
MD5::MD5Result *Checksum) {
return Header.getFile(Directory, FileName, Checksum);
}
void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params) const;
@ -242,7 +249,7 @@ public:
void EmitCU(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params) const;
unsigned getFile(StringRef &Directory, StringRef &FileName,
unsigned FileNumber = 0);
MD5::MD5Result *Checksum, unsigned FileNumber = 0);
MCSymbol *getLabel() const {
return Header.Label;

View File

@ -23,6 +23,7 @@
#include "llvm/MC/MCLinkerOptimizationHint.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCWinEH.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/TargetParser.h"
#include <cassert>
@ -754,6 +755,7 @@ public:
/// implements the DWARF2 '.file 4 "foo.c"' assembler directive.
virtual unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory,
StringRef Filename,
MD5::MD5Result *Checksum = nullptr,
unsigned CUID = 0);
/// \brief This implements the DWARF2 '.loc fileno lineno ...' assembler

View File

@ -95,14 +95,15 @@ void DwarfCompileUnit::addLocalLabelAddress(DIE &Die,
}
unsigned DwarfCompileUnit::getOrCreateSourceID(StringRef FileName,
StringRef DirName) {
StringRef DirName,
MD5::MD5Result *Checksum) {
// If we print assembly, we can't separate .file entries according to
// compile units. Thus all files will belong to the default compile unit.
// FIXME: add a better feature test than hasRawTextSupport. Even better,
// extend .file to support this.
return Asm->OutStreamer->EmitDwarfFileDirective(
0, DirName, FileName,
0, DirName, FileName, Checksum,
Asm->OutStreamer->hasRawTextSupport() ? 0 : getUniqueID());
}
@ -443,7 +444,7 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope) {
// Add the call site information to the DIE.
const DILocation *IA = Scope->getInlinedAt();
addUInt(*ScopeDIE, dwarf::DW_AT_call_file, None,
getOrCreateSourceID(IA->getFilename(), IA->getDirectory()));
getOrCreateSourceID(IA->getFilename(), IA->getDirectory(), nullptr));
addUInt(*ScopeDIE, dwarf::DW_AT_call_line, None, IA->getLine());
if (IA->getDiscriminator() && DD->getDwarfVersion() >= 4)
addUInt(*ScopeDIE, dwarf::DW_AT_GNU_discriminator, None,

View File

@ -141,7 +141,8 @@ public:
DwarfCompileUnit &getCU() override { return *this; }
unsigned getOrCreateSourceID(StringRef FileName, StringRef DirName) override;
unsigned getOrCreateSourceID(StringRef FileName, StringRef DirName,
MD5::MD5Result *Checksum) override;
void addImportedEntity(const DIImportedEntity* IE) {
DIScope *Scope = IE->getScope();

View File

@ -1378,7 +1378,7 @@ void DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S,
unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID();
Src = static_cast<DwarfCompileUnit &>(*InfoHolder.getUnits()[CUID])
.getOrCreateSourceID(Fn, Dir);
.getOrCreateSourceID(Fn, Dir, nullptr);
}
Asm->OutStreamer->EmitDwarfLocDirective(Src, Line, Col, Flags, 0,
Discriminator, Fn);
@ -1975,7 +1975,8 @@ void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) {
Asm->EmitULEB128(F.getLine());
DIFile *File = F.getFile();
unsigned FID =
U.getOrCreateSourceID(File->getFilename(), File->getDirectory());
U.getOrCreateSourceID(File->getFilename(), File->getDirectory(),
nullptr); // FIXME: MD5?
Asm->EmitULEB128(FID);
handleMacroNodes(F.getElements(), U);
Asm->EmitULEB128(dwarf::DW_MACINFO_end_file);

View File

@ -263,9 +263,12 @@ void DwarfUnit::addSectionOffset(DIE &Die, dwarf::Attribute Attribute,
addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer);
}
unsigned DwarfTypeUnit::getOrCreateSourceID(StringRef FileName, StringRef DirName) {
return SplitLineTable ? SplitLineTable->getFile(DirName, FileName)
: getCU().getOrCreateSourceID(FileName, DirName);
unsigned DwarfTypeUnit::getOrCreateSourceID(StringRef FileName,
StringRef DirName,
MD5::MD5Result *Checksum) {
return SplitLineTable
? SplitLineTable->getFile(DirName, FileName, Checksum)
: getCU().getOrCreateSourceID(FileName, DirName, Checksum);
}
void DwarfUnit::addOpAddress(DIELoc &Die, const MCSymbol *Sym) {
@ -340,7 +343,7 @@ void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, StringRef File,
if (Line == 0)
return;
unsigned FileID = getOrCreateSourceID(File, Directory);
unsigned FileID = getOrCreateSourceID(File, Directory, nullptr);
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
@ -1161,9 +1164,10 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP,
// Look at the Decl's linkage name only if we emitted it.
if (DD->useAllLinkageNames())
DeclLinkageName = SPDecl->getLinkageName();
unsigned DeclID =
getOrCreateSourceID(SPDecl->getFilename(), SPDecl->getDirectory());
unsigned DefID = getOrCreateSourceID(SP->getFilename(), SP->getDirectory());
unsigned DeclID = getOrCreateSourceID(SPDecl->getFilename(),
SPDecl->getDirectory(), nullptr);
unsigned DefID =
getOrCreateSourceID(SP->getFilename(), SP->getDirectory(), nullptr);
if (DeclID != DefID)
addUInt(SPDie, dwarf::DW_AT_decl_file, None, DefID);

View File

@ -308,7 +308,8 @@ protected:
/// Look up the source ID with the given directory and source file names. If
/// none currently exists, create a new ID and insert it in the line table.
virtual unsigned getOrCreateSourceID(StringRef File, StringRef Directory) = 0;
virtual unsigned getOrCreateSourceID(StringRef File, StringRef Directory,
MD5::MD5Result *Checksum) = 0;
/// Look in the DwarfDebug map for the MDNode that corresponds to the
/// reference.
@ -358,7 +359,8 @@ class DwarfTypeUnit final : public DwarfUnit {
DwarfCompileUnit &CU;
MCDwarfDwoLineTable *SplitLineTable;
unsigned getOrCreateSourceID(StringRef File, StringRef Directory) override;
unsigned getOrCreateSourceID(StringRef File, StringRef Directory,
MD5::MD5Result *Checksum) override;
bool isDwoUnit() const override;
public:

View File

@ -212,6 +212,7 @@ public:
void EmitFileDirective(StringRef Filename) override;
unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory,
StringRef Filename,
MD5::MD5Result *Checksum = 0,
unsigned CUID = 0) override;
void EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
unsigned Column, unsigned Flags,
@ -1068,12 +1069,13 @@ void MCAsmStreamer::EmitFileDirective(StringRef Filename) {
unsigned MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo,
StringRef Directory,
StringRef Filename,
MD5::MD5Result *Checksum,
unsigned CUID) {
assert(CUID == 0);
MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
unsigned NumFiles = Table.getMCDwarfFiles().size();
FileNo = Table.getFile(Directory, Filename, FileNo);
FileNo = Table.getFile(Directory, Filename, Checksum, FileNo);
if (FileNo == 0)
return 0;
if (NumFiles == Table.getMCDwarfFiles().size())

View File

@ -535,9 +535,10 @@ MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) {
/// error and zero is returned and the client reports the error, else the
/// allocated file number is returned. The file numbers may be in any order.
unsigned MCContext::getDwarfFile(StringRef Directory, StringRef FileName,
unsigned FileNumber, unsigned CUID) {
unsigned FileNumber, MD5::MD5Result *Checksum,
unsigned CUID) {
MCDwarfLineTable &Table = MCDwarfLineTablesCUMap[CUID];
return Table.getFile(Directory, FileName, FileNumber);
return Table.getFile(Directory, FileName, Checksum, FileNumber);
}
/// isValidDwarfFileNumber - takes a dwarf file number and returns true if it

View File

@ -284,7 +284,7 @@ static void
emitV5FileDirTables(MCStreamer *MCOS,
const SmallVectorImpl<std::string> &MCDwarfDirs,
const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles,
StringRef CompilationDir) {
StringRef CompilationDir, bool HasMD5) {
// The directory format, which is just inline null-terminated strings.
MCOS->EmitIntValue(1, 1);
MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path);
@ -300,20 +300,29 @@ emitV5FileDirTables(MCStreamer *MCOS,
// The file format, which is the inline null-terminated filename and a
// directory index. We don't track file size/timestamp so don't emit them
// in the v5 table.
// FIXME: Arrange to emit MD5 signatures for the source files.
MCOS->EmitIntValue(2, 1);
// in the v5 table. Emit MD5 checksums if we have them.
MCOS->EmitIntValue(HasMD5 ? 3 : 2, 1);
MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path);
MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string);
MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_directory_index);
MCOS->EmitULEB128IntValue(dwarf::DW_FORM_udata);
// Then the list of file names. These start at 1 for some reason.
if (HasMD5) {
MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_MD5);
MCOS->EmitULEB128IntValue(dwarf::DW_FORM_data16);
}
// Then the list of file names. These start at 1.
MCOS->EmitULEB128IntValue(MCDwarfFiles.size() - 1);
for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) {
assert(!MCDwarfFiles[i].Name.empty());
MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName and...
MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); // Directory number.
if (HasMD5) {
MD5::MD5Result *Cksum = MCDwarfFiles[i].Checksum;
MCOS->EmitBinaryData(
StringRef(reinterpret_cast<const char *>(Cksum->Bytes.data()),
Cksum->Bytes.size()));
}
}
}
@ -384,7 +393,8 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
// Put out the directory and file tables. The formats vary depending on
// the version.
if (LineTableVersion >= 5)
emitV5FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles, CompilationDir);
emitV5FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles, CompilationDir,
HasMD5);
else
emitV2FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles);
@ -409,12 +419,14 @@ void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS,
}
unsigned MCDwarfLineTable::getFile(StringRef &Directory, StringRef &FileName,
MD5::MD5Result *Checksum,
unsigned FileNumber) {
return Header.getFile(Directory, FileName, FileNumber);
return Header.getFile(Directory, FileName, Checksum, FileNumber);
}
unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory,
StringRef &FileName,
MD5::MD5Result *Checksum,
unsigned FileNumber) {
if (Directory == CompilationDir)
Directory = "";
@ -445,6 +457,10 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory,
if (!File.Name.empty())
return 0;
// If any files have an MD5 checksum, they all must.
if (FileNumber > 1)
assert(HasMD5 == (Checksum != nullptr));
if (Directory.empty()) {
// Separate the directory part from the basename of the FileName.
StringRef tFileName = sys::path::filename(FileName);
@ -478,6 +494,9 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory,
File.Name = FileName;
File.DirIndex = DirIndex;
File.Checksum = Checksum;
if (Checksum)
HasMD5 = true;
// return the allocated FileNumber.
return FileNumber;

View File

@ -50,6 +50,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SMLoc.h"
@ -3294,8 +3295,8 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
}
/// parseDirectiveFile
/// ::= .file [number] filename
/// ::= .file number directory filename
/// ::= .file filename
/// ::= .file number [directory] filename [md5 checksum]
bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {
// FIXME: I'm not sure what this is.
int64_t FileNumber = -1;
@ -3331,19 +3332,43 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {
Filename = Path;
}
if (parseToken(AsmToken::EndOfStatement,
"unexpected token in '.file' directive"))
return true;
std::string Checksum;
if (!parseOptionalToken(AsmToken::EndOfStatement)) {
StringRef Keyword;
if (check(getTok().isNot(AsmToken::Identifier),
"unexpected token in '.file' directive") ||
parseIdentifier(Keyword) ||
check(Keyword != "md5", "unexpected token in '.file' directive"))
return true;
if (getLexer().is(AsmToken::String) &&
check(FileNumber == -1, "MD5 checksum specified, but no file number"))
return true;
if (check(getTok().isNot(AsmToken::String),
"unexpected token in '.file' directive") ||
parseEscapedString(Checksum) ||
check(Checksum.size() != 32, "invalid MD5 checksum specified") ||
parseToken(AsmToken::EndOfStatement,
"unexpected token in '.file' directive"))
return true;
}
if (FileNumber == -1)
getStreamer().EmitFileDirective(Filename);
else {
MD5::MD5Result *CKMem = nullptr;
if (!Checksum.empty()) {
Checksum = fromHex(Checksum);
if (check(Checksum.size() != 16, "invalid MD5 checksum specified"))
return true;
CKMem = (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1);
memcpy(&CKMem->Bytes, Checksum.data(), 16);
}
// If there is -g option as well as debug info from directive file,
// we turn off -g option, directly use the existing debug info instead.
if (getContext().getGenDwarfForAssembly())
getContext().setGenDwarfForAssembly(false);
else if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename) ==
0)
else if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory,
Filename, CKMem) == 0)
return Error(FileNumberLoc, "file number already allocated");
}

View File

@ -194,8 +194,10 @@ void MCStreamer::EmitZeros(uint64_t NumBytes) {
unsigned MCStreamer::EmitDwarfFileDirective(unsigned FileNo,
StringRef Directory,
StringRef Filename, unsigned CUID) {
return getContext().getDwarfFile(Directory, Filename, FileNo, CUID);
StringRef Filename,
MD5::MD5Result *Checksum,
unsigned CUID) {
return getContext().getDwarfFile(Directory, Filename, FileNo, Checksum, CUID);
}
void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line,

View File

@ -0,0 +1,21 @@
# RUN: not llvm-mc -triple x86_64-unknown-unknown -dwarf-version 5 -filetype=asm %s -o /dev/null 2>&1 | FileCheck %s
# This is syntactically legal, looks like no checksum provided.
# CHECK-NOT: [[@LINE+1]]:{{[0-9]+}}: error:
.file 1 "dir1/foo" "00112233445566778899aabbccddeeff"
# Missing md5 keyword.
# CHECK: [[@LINE+1]]:{{[0-9]+}}: error: unexpected token in '.file' directive
.file 2 "dir1" "foo" "00112233445566778899aabbccddeeff"
# Bad length.
# CHECK: [[@LINE+1]]:{{[0-9]+}}: error: invalid MD5 checksum specified
.file 3 "dir2" "bar" md5 "ff"
# Not a string.
# CHECK: [[@LINE+1]]:{{[0-9]+}}: error: unexpected token in '.file' directive
.file 4 "dir3" "foo" md5 ffeeddccbbaa99887766554433221100
# Non-DWARF .file syntax with checksum.
# CHECK: [[@LINE+1]]:{{[0-9]+}}: error: MD5 checksum specified, but no file number
.file "baz" md5 "ffeeddccbbaa998877665544332211gg"

View File

@ -0,0 +1,18 @@
// RUN: llvm-mc -triple x86_64-unknown-unknown -dwarf-version 5 -filetype=obj %s -o -| llvm-dwarfdump --debug-line - | FileCheck %s
.file 1 "dir1/foo" md5 "00112233445566778899aabbccddeeff"
.file 2 "dir2" "bar" md5 "ffeeddccbbaa99887766554433221100"
.loc 1 1 0
nop
.loc 2 1 0
nop
# CHECK: debug_line[0x00000000]
# CHECK: version: 5
# CHECK: include_directories[ 1] = ''
# CHECK: include_directories[ 2] = 'dir1'
# CHECK: include_directories[ 3] = 'dir2'
# CHECK-NOT: include_directories
# CHECK: Dir MD5 Checksum File Name
# CHECK: file_names[ 1] 1 00112233445566778899aabbccddeeff foo
# CHECK: file_names[ 2] 2 ffeeddccbbaa99887766554433221100 bar