Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -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 #include @@ -489,7 +490,8 @@ /// 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); Index: llvm/include/llvm/MC/MCDwarf.h =================================================================== --- llvm/include/llvm/MC/MCDwarf.h +++ llvm/include/llvm/MC/MCDwarf.h @@ -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 #include #include @@ -50,6 +51,10 @@ // \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 @@ SmallVector MCDwarfFiles; StringMap 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 Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params) const; std::pair @@ -223,8 +229,9 @@ 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 @@ 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; Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -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 @@ -755,6 +756,7 @@ /// 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 Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -141,7 +141,8 @@ 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(); Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -95,14 +95,15 @@ } 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 @@ // 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, Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1378,7 +1378,7 @@ unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID(); Src = static_cast(*InfoHolder.getUnits()[CUID]) - .getOrCreateSourceID(Fn, Dir); + .getOrCreateSourceID(Fn, Dir, nullptr); } Asm->OutStreamer->EmitDwarfLocDirective(Src, Line, Col, Flags, 0, Discriminator, Fn); @@ -1975,7 +1975,8 @@ 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); Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -308,7 +308,8 @@ /// 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 @@ 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: Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -263,9 +263,12 @@ 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 @@ 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 @@ // 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); Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -217,6 +217,7 @@ 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, @@ -1086,12 +1087,13 @@ 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()) Index: llvm/lib/MC/MCContext.cpp =================================================================== --- llvm/lib/MC/MCContext.cpp +++ llvm/lib/MC/MCContext.cpp @@ -535,9 +535,10 @@ /// 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 Index: llvm/lib/MC/MCDwarf.cpp =================================================================== --- llvm/lib/MC/MCDwarf.cpp +++ llvm/lib/MC/MCDwarf.cpp @@ -284,7 +284,7 @@ emitV5FileDirTables(MCStreamer *MCOS, const SmallVectorImpl &MCDwarfDirs, const SmallVectorImpl &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 @@ // 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(Cksum->Bytes.data()), + Cksum->Bytes.size())); + } } } @@ -384,7 +393,8 @@ // 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 @@ } 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 @@ 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 @@ File.Name = FileName; File.DirIndex = DirIndex; + File.Checksum = Checksum; + if (Checksum) + HasMD5 = true; // return the allocated FileNumber. return FileNumber; Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -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 @@ } /// 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 @@ 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"); } Index: llvm/lib/MC/MCStreamer.cpp =================================================================== --- llvm/lib/MC/MCStreamer.cpp +++ llvm/lib/MC/MCStreamer.cpp @@ -205,8 +205,10 @@ 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, Index: llvm/test/MC/ELF/debug-md5-err.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/debug-md5-err.s @@ -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" Index: llvm/test/MC/ELF/debug-md5.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/debug-md5.s @@ -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