Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -367,13 +367,13 @@ Checksum.clear(); if (!CGM.getCodeGenOpts().EmitCodeView) - return llvm::DIFile::CSK_None; + return llvm::DIFile::ChecksumKind::CSK_None; SourceManager &SM = CGM.getContext().getSourceManager(); bool Invalid; llvm::MemoryBuffer *MemBuffer = SM.getBuffer(FID, &Invalid); if (Invalid) - return llvm::DIFile::CSK_None; + return llvm::DIFile::ChecksumKind::CSK_None; llvm::MD5 Hash; llvm::MD5::MD5Result Result; @@ -382,7 +382,7 @@ Hash.final(Result); Hash.stringifyResult(Result, Checksum); - return llvm::DIFile::CSK_MD5; + return llvm::DIFile::ChecksumKind::CSK_MD5; } llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { @@ -473,7 +473,7 @@ void CGDebugInfo::CreateCompileUnit() { SmallString<32> Checksum; - llvm::DIFile::ChecksumKind CSKind = llvm::DIFile::CSK_None; + llvm::DIFile::ChecksumKind CSKind = llvm::DIFile::ChecksumKind::CSK_None; // Should we be asking the SourceManager for the main file name, instead of // accepting it as an argument? This just causes the main file name to Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -129,9 +129,10 @@ /// \param Directory Directory. /// \param CSKind Checksum kind (e.g. CSK_None, CSK_MD5, CSK_SHA1, etc.). /// \param Checksum Checksum data. - DIFile *createFile(StringRef Filename, StringRef Directory, - DIFile::ChecksumKind CSKind = DIFile::CSK_None, - StringRef Checksum = StringRef()); + DIFile * + createFile(StringRef Filename, StringRef Directory, + DIFile::ChecksumKind CSKind = DIFile::ChecksumKind::CSK_None, + StringRef Checksum = StringRef()); /// Create debugging information entry for a macro. /// \param Parent Macro parent (could be nullptr). Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -473,7 +473,7 @@ friend class MDNode; public: - enum ChecksumKind { + enum class ChecksumKind : uint8_t { CSK_None, CSK_MD5, CSK_SHA1, @@ -506,13 +506,15 @@ } public: - DEFINE_MDNODE_GET(DIFile, (StringRef Filename, StringRef Directory, - ChecksumKind CSK = CSK_None, - StringRef CS = StringRef()), + DEFINE_MDNODE_GET(DIFile, + (StringRef Filename, StringRef Directory, + ChecksumKind CSK = ChecksumKind::CSK_None, + StringRef CS = StringRef()), (Filename, Directory, CSK, CS)) - DEFINE_MDNODE_GET(DIFile, (MDString *Filename, MDString *Directory, - ChecksumKind CSK = CSK_None, - MDString *CS = nullptr), + DEFINE_MDNODE_GET(DIFile, + (MDString * Filename, MDString *Directory, + ChecksumKind CSK = ChecksumKind::CSK_None, + MDString *CS = nullptr), (Filename, Directory, CSK, CS)) TempDIFile clone() const { return cloneImpl(); } Index: llvm/include/llvm/MC/MCCodeView.h =================================================================== --- llvm/include/llvm/MC/MCCodeView.h +++ llvm/include/llvm/MC/MCCodeView.h @@ -161,8 +161,8 @@ ~CodeViewContext(); bool isValidFileNumber(unsigned FileNumber) const; - bool addFile(unsigned FileNumber, StringRef Filename); - ArrayRef 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. @@ -273,6 +273,13 @@ /// Emits the file checksum substream. void emitFileChecksums(MCObjectStreamer &OS); + void emitFileChecksumOffset(MCStreamer &OS, unsigned FileNo); + + void emitFileChecksumOffsetAssignment(MCStreamer &OS, MCSymbol *File, + unsigned Offset); + + void emitFileChecksumOffsetAssignments(MCStreamer &OS); + private: /// The current CodeView line information from the last .cv_loc directive. MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true); @@ -280,6 +287,7 @@ /// Map from string to string table offset. StringMap StringTable; + // std::map StringTable; /// The fragment that ultimately holds our strings. MCDataFragment *StrTabFragment = nullptr; @@ -288,13 +296,19 @@ MCDataFragment *getStringTableFragment(); /// Add something to the string table. - StringRef addToStringTable(StringRef S); + std::pair 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 Filenames; + /// Array of string table offset, checksum table offset pairs. + SmallVector, 4> Files; + + // Map from filename to checksum. + // StringMap> Checksums; + // Map from string table offset to checksum + std::map> Checksums; /// The offset of the first and last .cv_loc directive for a given function /// id. @@ -305,6 +319,8 @@ /// All known functions and inlined call sites, indexed by function id. std::vector Functions; + + bool ChecksumOffsetsAssigned = false; }; } // end namespace llvm Index: llvm/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/include/llvm/MC/MCObjectStreamer.h +++ llvm/include/llvm/MC/MCObjectStreamer.h @@ -140,6 +140,10 @@ StringRef FixedSizePortion) override; void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; + void EmitCVFileChecksumOffset(unsigned FileNo) override; + void EmitCVFileChecksumOffsetDirective(MCSymbol *File, + unsigned Offset) override; + void EmitCVFileChecksumOffsetDirectives() override; void EmitDTPRel32Value(const MCExpr *Value) override; void EmitDTPRel64Value(const MCExpr *Value) override; void EmitTPRel32Value(const MCExpr *Value) override; Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -732,7 +732,8 @@ /// \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); + 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); @@ -772,7 +773,14 @@ virtual void EmitCVStringTableDirective() {} /// \brief This implements the CodeView '.cv_filechecksums' assembler directive. - virtual void EmitCVFileChecksumsDirective() {} + virtual void EmitCVFileChecksumsDirective(); + + virtual void EmitCVFileChecksumOffset(unsigned FileNo); + + virtual void EmitCVFileChecksumOffsetDirective(MCSymbol *File, + unsigned Offset) {} + + virtual void EmitCVFileChecksumOffsetDirectives() {} /// Emit the absolute difference between two symbols. /// Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -3525,7 +3525,7 @@ }; struct ChecksumKindField : public MDFieldImpl { - ChecksumKindField() : ImplTy(DIFile::CSK_None) {} + ChecksumKindField() : ImplTy(DIFile::ChecksumKind::CSK_None) {} ChecksumKindField(DIFile::ChecksumKind CSKind) : ImplTy(CSKind) {} }; Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1347,7 +1347,7 @@ GET_OR_DISTINCT( DIFile, (Context, getMDString(Record[1]), getMDString(Record[2]), - Record.size() == 3 ? DIFile::CSK_None + Record.size() == 3 ? DIFile::ChecksumKind::CSK_None : static_cast(Record[3]), Record.size() == 3 ? nullptr : getMDString(Record[4]))), NextMetadataNo); Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1526,7 +1526,7 @@ Record.push_back(N->isDistinct()); Record.push_back(VE.getMetadataOrNullID(N->getRawFilename())); Record.push_back(VE.getMetadataOrNullID(N->getRawDirectory())); - Record.push_back(N->getChecksumKind()); + Record.push_back(static_cast(N->getChecksumKind())); Record.push_back(VE.getMetadataOrNullID(N->getRawChecksum())); Stream.EmitRecord(bitc::METADATA_FILE, Record, Abbrev); Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -159,7 +159,10 @@ 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(ChecksumKind)); (void)Success; assert(Success && ".cv_file directive failed"); } @@ -472,7 +475,9 @@ // This subsection holds a file index to offset in string table table. OS.AddComment("File index to string table offset subsection"); + errs() << "about to EmitCVFileChecksumsDirective\n"; OS.EmitCVFileChecksumsDirective(); + OS.EmitCVFileChecksumOffsetDirectives(); // This subsection holds the string table. OS.AddComment("String table"); @@ -695,13 +700,14 @@ 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; + // The filechecksum table uses 8 bytes entries for now, and file ids start + // at 1. + // unsigned FileOffset = (FileId - 1) * 12; OS.AddComment("Type index of inlined function"); OS.EmitIntValue(InlineeIdx.getIndex(), 4); OS.AddComment("Offset into filechecksum table"); - OS.EmitIntValue(FileOffset, 4); + // OS.EmitIntValue(FileOffset, 4); + OS.EmitCVFileChecksumOffset(FileId); OS.AddComment("Starting line number"); OS.EmitIntValue(SP->getLine(), 4); } Index: llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp @@ -50,9 +50,9 @@ } Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) { + // errs() << "checksum bytes remaining " << Reader.bytesRemaining() << "\n"; if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) return EC; - return Error::success(); } Index: llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -29,16 +29,20 @@ } Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) { + // errs() << "String table bytes remaining " << Reader.bytesRemaining() << + // "\n"; return Reader.readStreamRef(Stream); } Expected DebugStringTableSubsectionRef::getString(uint32_t Offset) const { + // errs() << "DebugStringTableSubsectionRef getString\n"; BinaryStreamReader Reader(Stream); Reader.setOffset(Offset); StringRef Result; if (auto EC = Reader.readCString(Result)) return std::move(EC); + // errs() << "leaving getString\n"; return Result; } Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -1493,7 +1493,7 @@ } void MDFieldPrinter::printChecksumKind(const DIFile *N) { - if (N->getChecksumKind() == DIFile::CSK_None) + if (N->getChecksumKind() == DIFile::ChecksumKind::CSK_None) // Skip CSK_None checksum kind. return; Out << FS << "checksumkind: " << N->getChecksumKindAsString(); Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -354,22 +354,20 @@ DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops); } -static const char *ChecksumKindName[DIFile::CSK_Last + 1] = { - "CSK_None", - "CSK_MD5", - "CSK_SHA1" -}; +static const char * + ChecksumKindName[static_cast(DIFile::ChecksumKind::CSK_Last) + 1] = + {"CSK_None", "CSK_MD5", "CSK_SHA1"}; DIFile::ChecksumKind DIFile::getChecksumKind(StringRef CSKindStr) { return StringSwitch(CSKindStr) - .Case("CSK_MD5", DIFile::CSK_MD5) - .Case("CSK_SHA1", DIFile::CSK_SHA1) - .Default(DIFile::CSK_None); + .Case("CSK_MD5", DIFile::ChecksumKind::CSK_MD5) + .Case("CSK_SHA1", DIFile::ChecksumKind::CSK_SHA1) + .Default(DIFile::ChecksumKind::CSK_None); } StringRef DIFile::getChecksumKindAsString() const { - assert(CSKind <= DIFile::CSK_Last && "Invalid checksum kind"); - return ChecksumKindName[CSKind]; + assert(CSKind <= DIFile::ChecksumKind::CSK_Last && "Invalid checksum kind"); + return ChecksumKindName[static_cast(CSKind)]; } DIFile *DIFile::getImpl(LLVMContext &Context, MDString *Filename, Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -963,8 +963,9 @@ void Verifier::visitDIFile(const DIFile &N) { AssertDI(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N); - AssertDI((N.getChecksumKind() != DIFile::CSK_None || - N.getChecksum().empty()), "invalid checksum kind", &N); + AssertDI((N.getChecksumKind() != DIFile::ChecksumKind::CSK_None || + N.getChecksum().empty()), + "invalid checksum kind", &N); } void Verifier::visitDICompileUnit(const DICompileUnit &N) { Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -225,7 +225,8 @@ 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, @@ -245,6 +246,9 @@ StringRef FixedSizePortion) override; void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; + void EmitCVFileChecksumOffsetDirective(MCSymbol *File, + unsigned Offset) override; + void EmitCVFileChecksumOffsetDirectives() override; void EmitIdent(StringRef IdentString) override; void EmitCFISections(bool EH, bool Debug) override; @@ -1120,13 +1124,25 @@ 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; } @@ -1228,6 +1244,18 @@ EmitEOL(); } +void MCAsmStreamer::EmitCVFileChecksumOffsetDirective(MCSymbol *File, + unsigned Offset) { + OS << "\t.cv_filechecksumoffset\t"; + File->print(OS, MAI); + OS << " " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitCVFileChecksumOffsetDirectives() { + getContext().getCVContext().emitFileChecksumOffsetAssignments(*this); +} + void MCAsmStreamer::EmitIdent(StringRef IdentString) { assert(MAI->hasIdentDirective() && ".ident directive not supported"); OS << "\t.ident\t"; Index: llvm/lib/MC/MCCodeView.cpp =================================================================== --- llvm/lib/MC/MCCodeView.cpp +++ llvm/lib/MC/MCCodeView.cpp @@ -39,29 +39,42 @@ /// 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 std::get<2>(Files[Idx]); return false; } -bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { +bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber, + StringRef Filename, StringRef Checksum, + uint8_t ChecksumKind) { + errs() << "add checksum " << Checksum << "\n"; 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 (std::get<2>(Files[Idx])) 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 OffsetSymbol = + OS.getContext().getOrCreateSymbol("file" + std::to_string(FileNumber)); + errs() << "created symbol " << OffsetSymbol->getName() << "\n"; + Files[Idx] = std::make_tuple(Offset, OffsetSymbol, true); + + Checksums.insert( + std::make_pair(Offset, std::make_pair(Checksum.str(), ChecksumKind))); - Filenames[Idx] = Filename; return true; } @@ -118,17 +131,20 @@ 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(); + StringRef SR = Insertion.first->first(); + unsigned Offset = Insertion.first->second; + std::pair Ret = std::make_pair(SR, Offset); + S = Ret.first; if (Insertion.second) { // The string map key is always null terminated. Contents.append(S.begin(), S.end() + 1); } - return S; + return Ret; } unsigned CodeViewContext::getStringTableOffset(StringRef S) { @@ -140,6 +156,68 @@ return I->second; } +// void CodeViewContext::assignChecksumOffsets(MCStreamer &OS) { +// //errs() << "assigning checksum offsets\n"; + +// if (ChecksumOffsetsAssigned) +// return; + +// ChecksumOffsetsAssigned = true; + +// unsigned CurrentOffset = 0; + +// //MCContext &Ctx = OS.getContext(); + +// for (unsigned i = 0 ; i < Files.size() ; i++) { +// // File.second = CurrentOffset; +// // errs() << "setting " << std::get<1>(File)->getName() << "\n"; +// // Ctx.setSymbolValue(OS, std::get<1>(File)->getName(), CurrentOffset); +// // OS.EmitAssignment(std::get<1>(File), +// // MCConstantExpr::create(CurrentOffset, Ctx)); +// auto File = Files[i]; +// OS.EmitCVFileChecksumOffsetDirective(std::get<1>(File), CurrentOffset); +// //errs() << "assignChecksums assigned offset of " << CurrentOffset << +// "\n"; CurrentOffset += 4; auto Checksum = Checksums[std::get<0>(File)]; +// if (!Checksum.second) { +// CurrentOffset += 4; +// continue; +// } +// errs() << "adding " << Checksum.first.size() << "\n"; +// errs() << "Checksum.first " << Checksum.first << "\n"; +// CurrentOffset += 2; +// CurrentOffset += Checksum.first.size(); +// CurrentOffset = alignTo(CurrentOffset, 4); +// } +// } + +void CodeViewContext::emitFileChecksumOffsetAssignment(MCStreamer &OS, + MCSymbol *File, + unsigned Offset) { + MCContext &Ctx = OS.getContext(); + OS.EmitAssignment(File, MCConstantExpr::create(Offset, Ctx)); + errs() << "made assignment " << File->getName() << "\n"; +} + +void CodeViewContext::emitFileChecksumOffsetAssignments(MCStreamer &OS) { + if (ChecksumOffsetsAssigned) + return; + ChecksumOffsetsAssigned = true; + unsigned CurrentOffset = 0; + for (auto File : Files) { + errs() << "call one offset directive\n"; + OS.EmitCVFileChecksumOffsetDirective(std::get<1>(File), CurrentOffset); + CurrentOffset += 4; + auto Checksum = Checksums[std::get<0>(File)]; + if (!Checksum.second) { + CurrentOffset += 4; + continue; + } + CurrentOffset += 2; + CurrentOffset += Checksum.first.size(); + CurrentOffset = alignTo(CurrentOffset, 4); + } +} + void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { MCContext &Ctx = OS.getContext(); MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false), @@ -162,12 +240,24 @@ OS.EmitLabel(StringEnd); } +// void CodeViewContext::emitFileChecksums(MCStreamer &OS) { +// // Do nothing if there are no file checksums. Microsoft's linker rejects +// empty +// // CodeView substreams. +// if (Files.empty()) +// return; + +// assignChecksumOffsets(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; + // assignChecksumOffsets(OS); + MCContext &Ctx = OS.getContext(); MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false), *FileEnd = Ctx.createTempSymbol("filechecksums_end", false); @@ -179,16 +269,62 @@ // 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); + for (auto File : Files) { + OS.EmitIntValue(std::get<0>(File), 4); + // OS.EmitIntValue(286331153, 4); + + std::pair Checksum = Checksums[std::get<0>(File)]; + if (!Checksum.second) { + // There is no checksum. + OS.EmitIntValue(0, 4); + continue; + } + OS.EmitIntValue(static_cast(Checksum.first.size()), + 1); // checksum size + // OS.EmitIntValue(18, 1); + // OS.EmitIntValue(6, 1); + // OS.EmitIntValue(3, 1); + // OS.EmitIntValue(3147, 6); + OS.EmitIntValue(Checksum.second, 1); // checksum type + OS.EmitBytes(Checksum.first); // actual checksum + OS.EmitValueToAlignment(4); // align } OS.EmitLabel(FileEnd); } +void CodeViewContext::emitFileChecksumOffset(MCStreamer &OS, unsigned FileNo) { + unsigned Idx = FileNo - 1; + + if (Idx >= Files.size()) + Files.resize(Idx + 1); + + if (ChecksumOffsetsAssigned) { + OS.EmitSymbolValue(std::get<1>(Files[Idx]), 4); + return; + } + + // errs() << "FileNo " << FileNo << "\n"; + // errs() << "size " << Files.size() << "\n"; + + // if (!std::get<1>(Files[Idx])) + // std::get<1>(Files[Idx]) = OS.getContext().createTempSymbol("file" + + // std::to_string(Idx), false); + const MCSymbolRefExpr *SRE = + MCSymbolRefExpr::create(std::get<1>(Files[Idx]), OS.getContext()); + + errs() << "make fixup\n"; + errs() << "Idx " << Idx << "\n"; + errs() << std::get<1>(Files[Idx])->getName() << "\n"; + OS.EmitValueImpl(SRE, 4); + + // MCDataFragment *DF = OS.getOrCreateDataFragment(); + // flushPendingLabels(DF, DF->getContents().size()); + + // DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), SRE, + // FK_SecRel_1)); +} + void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId, const MCSymbol *FuncBegin, @@ -211,6 +347,8 @@ OS.EmitIntValue(HaveColumns ? int(LF_HaveColumns) : 0, 2); OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); + // assignChecksumOffsets(); + for (auto I = Locs.begin(), E = Locs.end(); I != E;) { // Emit a file segment for the run of locations that share a file id. unsigned CurFileNum = I->getFileNum(); @@ -219,9 +357,14 @@ 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()[std::get<0>(Files[CurFileNum - 1])]) + + "' begins"); + // OS.EmitIntValue(Files[CurFileNum].second, 4); + OS.EmitCVFileChecksumOffset(CurFileNum); + // OS.EmitIntValue(12 * (CurFileNum - 1), 4); // assumes 8 bytes checksum OS.EmitIntValue(EntryCount, 4); uint32_t SegmentSize = 12; SegmentSize += 8 * EntryCount; @@ -357,6 +500,9 @@ SmallVectorImpl &Buffer = Frag.getContents(); Buffer.clear(); // Clear old contents if we went through relaxation. + + // assignChecksumOffsets(); + for (const MCCVLineEntry &Loc : Locs) { // Exit early if our line table would produce an oversized InlineSiteSym // record. Account for the ChangeCodeLength annotation emitted after the @@ -403,7 +549,15 @@ 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 = 12 * (CurSourceLoc.File - 1); + errs() << "CurSourceLoc.File " << CurSourceLoc.File << "\n"; + unsigned FileOffset = std::get<1>(Files[CurSourceLoc.File - 1]) + ? static_cast( + std::get<1>(Files[CurSourceLoc.File - 1]) + ->getVariableValue()) + ->getValue() + : 8; + errs() << "encoder computed fileoffset " << FileOffset << "\n"; compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); compressAnnotation(FileOffset, Buffer); } Index: llvm/lib/MC/MCContext.cpp =================================================================== --- llvm/lib/MC/MCContext.cpp +++ llvm/lib/MC/MCContext.cpp @@ -125,8 +125,10 @@ assert(!NameRef.empty() && "Normal symbols cannot be unnamed!"); MCSymbol *&Sym = Symbols[NameRef]; - if (!Sym) + if (!Sym) { + // errs() << "symbol " << Name << " not found\n"; Sym = createSymbol(NameRef, false, false); + } return Sym; } Index: llvm/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/lib/MC/MCObjectStreamer.cpp +++ llvm/lib/MC/MCObjectStreamer.cpp @@ -141,6 +141,7 @@ EmitIntValue(AbsValue, Size); return; } + // errs() << "make fixup\n"; DF->getFixups().push_back( MCFixup::create(DF->getContents().size(), Value, MCFixup::getKindForSize(Size, false), Loc)); @@ -423,9 +424,23 @@ getContext().getCVContext().emitStringTable(*this); } void MCObjectStreamer::EmitCVFileChecksumsDirective() { + errs() << "emitcvfilehcecksumdirective object\n"; getContext().getCVContext().emitFileChecksums(*this); } +void MCObjectStreamer::EmitCVFileChecksumOffset(unsigned FileNo) { + getContext().getCVContext().emitFileChecksumOffset(*this, FileNo); +} + +void MCObjectStreamer::EmitCVFileChecksumOffsetDirective(MCSymbol *File, + unsigned Offset) { + getContext().getCVContext().emitFileChecksumOffsetAssignment(*this, File, + Offset); +} + +void MCObjectStreamer::EmitCVFileChecksumOffsetDirectives() { + getContext().getCVContext().emitFileChecksumOffsetAssignments(*this); +} void MCObjectStreamer::EmitBytes(StringRef Data) { MCCVLineEntry::Make(this); Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -501,6 +501,7 @@ DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS, + DK_CV_FILECHECKSUM_OFFSET, DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, @@ -576,6 +577,7 @@ bool parseDirectiveCVDefRange(); bool parseDirectiveCVStringTable(); bool parseDirectiveCVFileChecksums(); + bool parseDirectiveCVFileChecksumOffset(); // .cfi directives bool parseDirectiveCFIRegister(SMLoc DirectiveLoc); @@ -2030,6 +2032,8 @@ return parseDirectiveCVStringTable(); case DK_CV_FILECHECKSUMS: return parseDirectiveCVFileChecksums(); + case DK_CV_FILECHECKSUM_OFFSET: + return parseDirectiveCVFileChecksumOffset(); case DK_CFI_SECTIONS: return parseDirectiveCFISections(); case DK_CFI_STARTPROC: @@ -3457,25 +3461,34 @@ } /// parseDirectiveCVFile -/// ::= .cv_file number filename +/// ::= .cv_file number filename [Checksum] [ChecksumKind] bool AsmParser::parseDirectiveCVFile() { SMLoc FileNumberLoc = getTok().getLoc(); int64_t FileNumber; std::string Filename; + std::string Checksum; + int64_t ChecksumKind = 0; if (parseIntToken(FileNumber, "expected file number in '.cv_file' directive") || check(FileNumber < 1, FileNumberLoc, "file number less than one") || check(getTok().isNot(AsmToken::String), "unexpected token in '.cv_file' directive") || - // Usually directory and filename are together, otherwise just - // directory. Allow the strings to have escaped octal character sequence. - parseEscapedString(Filename) || - parseToken(AsmToken::EndOfStatement, - "unexpected token in '.cv_file' directive")) + parseEscapedString(Filename)) return true; + if (!parseOptionalToken(AsmToken::EndOfStatement)) { + if (check(getTok().isNot(AsmToken::String), + "unexpected token in '.cv_file' directive") || + parseEscapedString(Checksum) || + parseIntToken(ChecksumKind, + "expected checksum kind in '.cv_file' directive") || + parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cv_file' directive")) + return true; + } - if (!getStreamer().EmitCVFileDirective(FileNumber, Filename)) + if (!getStreamer().EmitCVFileDirective(FileNumber, Filename, Checksum, + static_cast(ChecksumKind))) return Error(FileNumberLoc, "file number already allocated"); return false; @@ -3754,6 +3767,23 @@ return false; } +bool AsmParser::parseDirectiveCVFileChecksumOffset() { + SMLoc Loc = getTok().getLoc(); + StringRef FileId; + int64_t Offset; + if (parseTokenLoc(Loc) || + check(parseIdentifier(FileId), Loc, "expected identifier in directive") || + parseIntToken(Offset, + "expected Offset in '.cv_filechecksumoffset' directive")) + return true; + if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement")) + return true; + errs() << "parsed fileid " << FileId << "\n"; + MCSymbol *File = getContext().getOrCreateSymbol(FileId); + getStreamer().EmitCVFileChecksumOffsetDirective(File, Offset); + return false; +} + /// parseDirectiveCFISections /// ::= .cfi_sections section [, section] bool AsmParser::parseDirectiveCFISections() { @@ -5136,6 +5166,7 @@ DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE; DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE; DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS; + DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET; DirectiveKindMap[".sleb128"] = DK_SLEB128; DirectiveKindMap[".uleb128"] = DK_ULEB128; DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS; Index: llvm/lib/MC/MCStreamer.cpp =================================================================== --- llvm/lib/MC/MCStreamer.cpp +++ llvm/lib/MC/MCStreamer.cpp @@ -224,8 +224,11 @@ report_fatal_error("No open frame"); } -bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) { - return getContext().getCVContext().addFile(FileNo, Filename); +bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename, + StringRef Checksum, + unsigned ChecksumKind) { + return getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum, + ChecksumKind); } bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) { @@ -281,6 +284,15 @@ ArrayRef> Ranges, StringRef FixedSizePortion) {} +void MCStreamer::EmitCVFileChecksumsDirective() { + // errs() << "emitcvfilechecksumsdirective\n"; + // getContext().getCVContext().emitFileChecksums(*this); +} + +void MCStreamer::EmitCVFileChecksumOffset(unsigned FileNo) { + getContext().getCVContext().emitFileChecksumOffset(*this, FileNo); +} + void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) { } Index: llvm/lib/MC/WinCOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/WinCOFFObjectWriter.cpp +++ llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -722,6 +722,7 @@ return; } if (A.isTemporary() && A.isUndefined()) { + errs() << "about to report error\n"; Asm.getContext().reportError(Fixup.getLoc(), Twine("assembler label '") + A.getName() + "' can not be undefined"); Index: llvm/test/DebugInfo/COFF/asm.ll =================================================================== --- llvm/test/DebugInfo/COFF/asm.ll +++ llvm/test/DebugInfo/COFF/asm.ll @@ -25,6 +25,7 @@ ; X86: .cv_linetable 0, _f, [[END_OF_F]] ; File index to string table offset subsection ; X86-NEXT: .cv_filechecksums +; X86-NEXT: .cv_filechecksumoffset file1 0 ; String table ; X86-NEXT: .cv_stringtable @@ -85,6 +86,7 @@ ; X64: .cv_linetable 0, f, [[END_OF_F]] ; File index to string table offset subsection ; X64-NEXT: .cv_filechecksums +; X64-NEXT: .cv_filechecksumoffset file1 0 ; String table ; X64-NEXT: .cv_stringtable Index: llvm/test/DebugInfo/COFF/inlining.ll =================================================================== --- llvm/test/DebugInfo/COFF/inlining.ll +++ llvm/test/DebugInfo/COFF/inlining.ll @@ -49,11 +49,11 @@ ; ASM: .long 0 ; ASM: # Inlined function bar starts at t.cpp:8 ; ASM: .long 4098 # Type index of inlined function -; ASM: .long 0 # Offset into filechecksum table +; ASM: .long file1 # Offset into filechecksum table ; ASM: .long 8 # Starting line number ; ASM: # Inlined function foo starts at t.cpp:2 ; ASM: .long 4099 -; ASM: .long 0 +; ASM: .long file1 ; ASM: .long 2 ; ASM: [[inline_end]]: @@ -72,6 +72,9 @@ ; ASM: .short 4430 ; ASM: .short 4430 +; ASM: .cv_filechecksums +; ASM: .cv_filechecksumoffset file1 0 + ; ASM: .section .debug$T,"dr" ; ASM: .long 4 # Debug section magic ; ASM: # ArgList (0x1000) { Index: llvm/test/DebugInfo/COFF/multifile.ll =================================================================== --- llvm/test/DebugInfo/COFF/multifile.ll +++ llvm/test/DebugInfo/COFF/multifile.ll @@ -18,10 +18,10 @@ ; X86-LABEL: _f: ; X86: # BB -; X86: .cv_file 1 "D:\\one.c" +; X86: .cv_file 1 "D:\\one.c" "70b51f534d80639d033ae92c6a856af6" 1 ; X86: .cv_loc 0 1 1 0 is_stmt 0 # one.c:1:0 ; X86: calll _g -; X86: .cv_file 2 "D:\\two.c" +; X86: .cv_file 2 "D:\\two.c" "70b51f534d80639d033ae92c6a856af6" 1 ; X86: .cv_loc 0 2 2 0 # two.c:2:0 ; X86: calll _g ; X86: .cv_loc 0 1 7 0 # one.c:7:0 @@ -34,6 +34,9 @@ ; X86: .cv_linetable 0, _f, [[END_OF_F]] ; File index to string table offset subsection ; X86-NEXT: .cv_filechecksums +; X86-NEXT: .cv_filechecksumoffset file1 0 +; X86-NEXT: .cv_filechecksumoffset file2 40 + ; String table ; X86-NEXT: .cv_stringtable @@ -51,6 +54,28 @@ ; OBJ32-NEXT: ProcEnd { ; OBJ32: } ; OBJ32-NEXT: ] +; OBJ32: Subsection [ +; OBJ32: SubSectionType: FileChecksums (0xF4) +; OBJ32-NEXT: SubSectionSize: 0x50 +; OBJ32-NEXT: FileChecksum { +; OBJ32-NEXT: Filename: D:\one.c (0x1) +; OBJ32-NEXT: ChecksumSize: 0x20 +; OBJ32-NEXT: ChecksumKind: MD5 (0x1) +; OBJ32-NEXT: ChecksumBytes ( +; OBJ32-NEXT: 0000: 37306235 31663533 34643830 36333964 |70b51f534d80639d| +; OBJ32-NEXT: 0010: 30333361 65393263 36613835 36616636 |033ae92c6a856af6| +; OBJ32-NEXT: ) +; OBJ32-NEXT: } +; OBJ32-NEXT: FileChecksum { +; OBJ32-NEXT: Filename: D:\two.c (0xA) +; OBJ32-NEXT: ChecksumSize: 0x20 +; OBJ32-NEXT: ChecksumKind: MD5 (0x1) +; OBJ32-NEXT: ChecksumBytes ( +; OBJ32-NEXT: 0000: 37306235 31663533 34643830 36333964 |70b51f534d80639d| +; OBJ32-NEXT: 0010: 30333361 65393263 36613835 36616636 |033ae92c6a856af6| +; OBJ32-NEXT: ) +; OBJ32-NEXT: } +; OBJ32-NEXT: ] ; OBJ32: FunctionLineTable [ ; OBJ32-NEXT: Name: _f ; OBJ32-NEXT: Flags: 0x0 @@ -88,14 +113,14 @@ ; X64-LABEL: f: ; X64-NEXT: .L{{.*}}:{{$}} -; X64: .cv_file 1 "D:\\input.c" +; X64: .cv_file 1 "D:\\input.c" "70b51f534d80639d033ae92c6a856af6" 1 ; X64: .cv_loc 0 1 3 0 is_stmt 0 # input.c:3:0 ; X64: # BB ; X64: subq $40, %rsp -; X64: .cv_file 2 "D:\\one.c" +; X64: .cv_file 2 "D:\\one.c" "70b51f534d80639d033ae92c6a856af6" 1 ; X64: .cv_loc 0 2 1 0 # one.c:1:0 ; X64: callq g -; X64: .cv_file 3 "D:\\two.c" +; X64: .cv_file 3 "D:\\two.c" "70b51f534d80639d033ae92c6a856af6" 1 ; X64: .cv_loc 0 3 2 0 # two.c:2:0 ; X64: callq g ; X64: .cv_loc 0 2 7 0 # one.c:7:0 @@ -123,6 +148,37 @@ ; OBJ64-NEXT: ProcEnd { ; OBJ64: } ; OBJ64-NEXT: ] +; OBJ64: Subsection [ +; OBJ64: SubSectionType: FileChecksums (0xF4) +; OBJ64-NEXT: SubSectionSize: 0x78 +; OBJ64-NEXT: FileChecksum { +; OBJ64-NEXT: Filename: D:\input.c (0x1) +; OBJ64-NEXT: ChecksumSize: 0x20 +; OBJ64-NEXT: ChecksumKind: MD5 (0x1) +; OBJ64-NEXT: ChecksumBytes ( +; OBJ64-NEXT: 0000: 37306235 31663533 34643830 36333964 |70b51f534d80639d| +; OBJ64-NEXT: 0010: 30333361 65393263 36613835 36616636 |033ae92c6a856af6| +; OBJ64-NEXT: ) +; OBJ64-NEXT: } +; OBJ64-NEXT: FileChecksum { +; OBJ64-NEXT: Filename: D:\one.c (0xC) +; OBJ64-NEXT: ChecksumSize: 0x20 +; OBJ64-NEXT: ChecksumKind: MD5 (0x1) +; OBJ64-NEXT: ChecksumBytes ( +; OBJ64-NEXT: 0000: 37306235 31663533 34643830 36333964 |70b51f534d80639d| +; OBJ64-NEXT: 0010: 30333361 65393263 36613835 36616636 |033ae92c6a856af6| +; OBJ64-NEXT: ) +; OBJ64-NEXT: } +; OBJ64-NEXT: FileChecksum { +; OBJ64-NEXT: Filename: D:\two.c (0x15) +; OBJ64-NEXT: ChecksumSize: 0x20 +; OBJ64-NEXT: ChecksumKind: MD5 (0x1) +; OBJ64-NEXT: ChecksumBytes ( +; OBJ64-NEXT: 0000: 37306235 31663533 34643830 36333964 |70b51f534d80639d| +; OBJ64-NEXT: 0010: 30333361 65393263 36613835 36616636 |033ae92c6a856af6| +; OBJ64-NEXT: ) +; OBJ64-NEXT: } +; OBJ64-NEXT: ] ; OBJ64: FunctionLineTable [ ; OBJ64-NEXT: Name: f ; OBJ64-NEXT: Flags: 0x0 @@ -185,11 +241,11 @@ !llvm.ident = !{!11} !0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5 ", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2) -!1 = !DIFile(filename: "", directory: "D:\5C") +!1 = !DIFile(filename: "", directory: "D:\5C", checksumkind: CSK_MD5, checksum:"70b51f534d80639d033ae92c6a856af6") !2 = !{} !4 = distinct !DISubprogram(name: "f", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !5, scope: !6, type: !7, variables: !2) -!5 = !DIFile(filename: "input.c", directory: "D:\5C") -!6 = !DIFile(filename: "input.c", directory: "D:C") +!5 = !DIFile(filename: "input.c", directory: "D:\5C", checksumkind: CSK_MD5, checksum:"70b51f534d80639d033ae92c6a856af6") +!6 = !DIFile(filename: "input.c", directory: "D:C", checksumkind: CSK_MD5, checksum:"70b51f534d80639d033ae92c6a856af6") !7 = !DISubroutineType(types: !8) !8 = !{null} !9 = !{i32 2, !"CodeView", i32 1} @@ -197,9 +253,9 @@ !11 = !{!"clang version 3.5 "} !12 = !DILocation(line: 1, scope: !13) !13 = !DILexicalBlockFile(discriminator: 0, file: !14, scope: !4) -!14 = !DIFile(filename: "one.c", directory: "D:\5C") +!14 = !DIFile(filename: "one.c", directory: "D:\5C", checksumkind: CSK_MD5, checksum:"70b51f534d80639d033ae92c6a856af6") !15 = !DILocation(line: 2, scope: !16) !16 = !DILexicalBlockFile(discriminator: 0, file: !17, scope: !4) -!17 = !DIFile(filename: "two.c", directory: "D:\5C") +!17 = !DIFile(filename: "two.c", directory: "D:\5C", checksumkind: CSK_MD5, checksum:"70b51f534d80639d033ae92c6a856af6") !18 = !DILocation(line: 7, scope: !13) !19 = !DILocation(line: 8, scope: !13) Index: llvm/test/DebugInfo/COFF/simple.ll =================================================================== --- llvm/test/DebugInfo/COFF/simple.ll +++ llvm/test/DebugInfo/COFF/simple.ll @@ -17,7 +17,7 @@ ; X86-LABEL: _f: ; X86: # BB -; X86: .cv_file 1 "D:\\test.c" +; X86: .cv_file 1 "D:\\test.c" "f310ab26998ca831cbdf169e4eecacfa" 1 ; X86: .cv_loc 0 1 4 2 is_stmt 0 # test.c:4:2 ; X86: calll _g ; X86: .cv_loc 0 1 5 0 # test.c:5:0 @@ -62,6 +62,7 @@ ; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]] ; File index to string table offset subsection ; X86-NEXT: .cv_filechecksums +; X86-NEXT: .cv_filechecksumoffset file1 0 ; String table ; X86-NEXT: .cv_stringtable @@ -85,6 +86,19 @@ ; OBJ32-NEXT: ProcEnd { ; OBJ32: } ; OBJ32-NEXT: ] +; OBJ32: Subsection [ +; OBJ32: SubSectionType: FileChecksums (0xF4) +; OBJ32-NEXT: SubSectionSize: 0x28 +; OBJ32-NEXT: FileChecksum { +; OBJ32-NEXT: Filename: D:\test.c (0x1) +; OBJ32-NEXT: ChecksumSize: 0x20 +; OBJ32-NEXT: ChecksumKind: MD5 (0x1) +; OBJ32-NEXT: ChecksumBytes ( +; OBJ32-NEXT: 0000: 66333130 61623236 39393863 61383331 |f310ab26998ca831| +; OBJ32-NEXT: 0010: 63626466 31363965 34656563 61636661 |cbdf169e4eecacfa| +; OBJ32-NEXT: ) +; OBJ32-NEXT: } +; OBJ32-NEXT: ] ; OBJ32: FunctionLineTable [ ; OBJ32-NEXT: Name: _f ; OBJ32-NEXT: Flags: 0x1 @@ -110,7 +124,7 @@ ; X64-LABEL: f: ; X64-NEXT: .L{{.*}}:{{$}} -; X64: .cv_file 1 "D:\\test.c" +; X64: .cv_file 1 "D:\\test.c" "f310ab26998ca831cbdf169e4eecacfa" 1 ; X64: .cv_loc 0 1 3 0 is_stmt 0 # test.c:3:0 ; X64: # BB ; X64: subq $40, %rsp @@ -159,6 +173,7 @@ ; X64-NEXT: .cv_linetable 0, f, [[END_OF_F]] ; File index to string table offset subsection ; X64-NEXT: .cv_filechecksums +; X64-NEXT: .cv_filechecksumoffset file1 0 ; String table ; X64-NEXT: .cv_stringtable @@ -182,6 +197,19 @@ ; OBJ64-NEXT: ProcEnd { ; OBJ64: } ; OBJ64-NEXT: ] +; OBJ64: Subsection [ +; OBJ64: SubSectionType: FileChecksums (0xF4) +; OBJ64-NEXT: SubSectionSize: 0x28 +; OBJ64-NEXT: FileChecksum { +; OBJ64-NEXT: Filename: D:\test.c (0x1) +; OBJ64-NEXT: ChecksumSize: 0x20 +; OBJ64-NEXT: ChecksumKind: MD5 (0x1) +; OBJ64-NEXT: ChecksumBytes ( +; OBJ64-NEXT: 0000: 66333130 61623236 39393863 61383331 |f310ab26998ca831| +; OBJ64-NEXT: 0010: 63626466 31363965 34656563 61636661 |cbdf169e4eecacfa| +; OBJ64-NEXT: ) +; OBJ64-NEXT: } +; OBJ64-NEXT: ] ; OBJ64: FunctionLineTable [ ; OBJ64-NEXT: Name: f ; OBJ64-NEXT: Flags: 0x1 @@ -232,8 +260,8 @@ !1 = !DIFile(filename: "", directory: "D:\5C") !2 = !{} !4 = distinct !DISubprogram(name: "f", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !5, scope: !6, type: !7, variables: !2) -!5 = !DIFile(filename: "test.c", directory: "D:\5C") -!6 = !DIFile(filename: "test.c", directory: "D:C") +!5 = !DIFile(filename: "test.c", directory: "D:\5C", checksumkind: CSK_MD5, checksum: "f310ab26998ca831cbdf169e4eecacfa") +!6 = !DIFile(filename: "test.c", directory: "D:C", checksumkind: CSK_MD5, checksum: "f310ab26998ca831cbdf169e4eecacfa") !7 = !DISubroutineType(types: !8) !8 = !{null} !9 = !{i32 2, !"CodeView", i32 1} Index: llvm/test/MC/AArch64/coff-debug.ll =================================================================== --- llvm/test/MC/AArch64/coff-debug.ll +++ llvm/test/MC/AArch64/coff-debug.ll @@ -103,7 +103,7 @@ ; CHECK: SubSectionType: FileChecksums (0xF4) ; CHECK: FileChecksum { ; CHECK: ChecksumSize: 0x0 -; CHECK: ChecksumKind: None (0x0) +; CHECK: ChecksumKind: MD5 (0x1) ; CHECK: ChecksumBytes: () ; CHECK: } ; CHECK: ] Index: llvm/test/MC/COFF/cv-loc.s =================================================================== --- llvm/test/MC/COFF/cv-loc.s +++ llvm/test/MC/COFF/cv-loc.s @@ -41,6 +41,8 @@ .section .debug$S .cv_filechecksums +.cv_filechecksumoffset file1 0 +.cv_filechecksumoffset file2 8 .cv_linetable 0, f, .Lfunc_end0 # CHECK: FunctionLineTable [ Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -907,29 +907,41 @@ } void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) { + // errs() << "entered initialize function\n"; while (Reader.bytesRemaining() > 0 && (!CVFileChecksumTable.valid() || !CVStringTable.valid())) { // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...| uint32_t SubType, SubSectionSize; + // errs() << "about to read subtype\n"; error(Reader.readInteger(SubType)); + // errs() << "about to read subsection size\n"; error(Reader.readInteger(SubSectionSize)); + // errs() << "sub section size " << SubSectionSize << "\n"; + // errs() << "sub section type " << SubType << "\n"; StringRef Contents; + // errs() << "about to read contents\n"; error(Reader.readFixedString(Contents, SubSectionSize)); + // errs() << "finished reading contents\n"; BinaryStreamRef ST(Contents, support::little); switch (DebugSubsectionKind(SubType)) { case DebugSubsectionKind::FileChecksums: + // errs() << "about to initialize checksum table\n"; error(CVFileChecksumTable.initialize(ST)); break; case DebugSubsectionKind::StringTable: + // errs() << "initializing string table\n"; error(CVStringTable.initialize(ST)); + // errs() << "initialized string table\n"; break; default: + // errs() << "initializing nothing\n"; break; } + // errs() << "\n\n\n"; uint32_t PaddedSize = alignTo(SubSectionSize, 4); error(Reader.skip(PaddedSize - SubSectionSize)); } @@ -954,9 +966,14 @@ if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); + // errs() << "about to initialize tables\n"; + BinaryStreamReader FSReader(Data, support::little); initializeFileAndStringTables(FSReader); + // errs() << "initialized\n"; + + StringRef ChecksumTable; // TODO: Convert this over to using ModuleSubstreamVisitor. while (!Data.empty()) { // The section consists of a number of subsection in the following format: @@ -1000,6 +1017,7 @@ case DebugSubsectionKind::FileChecksums: printCodeViewFileChecksums(Contents); + ChecksumTable = Contents; break; case DebugSubsectionKind::Lines: { @@ -1083,7 +1101,13 @@ for (const auto &Entry : LineInfo) { ListScope S(W, "FilenameSegment"); + // errs() << "about to pring filename with offset " << Entry.NameIndex << + // "\n"; + auto FileName = reinterpret_cast( + ChecksumTable.data() + Entry.NameIndex); + // printFileNameForOffset("Filename", *FileName); printFileNameForOffset("Filename", Entry.NameIndex); + // errs() << "printed filename\n"; uint32_t ColumnIndex = 0; for (const auto &Line : Entry.LineNumbers) { if (Line.Offset >= LineInfo.header()->CodeSize) { @@ -1187,6 +1211,8 @@ if (Iter == CVFileChecksumTable.end()) error(object_error::parse_failed); + // errs() << "File offset: " << FileOffset << "\n"; + // errs() << "Filename Offset: " << Iter->FileNameOffset << "\n"; return error(CVStringTable.getString(Iter->FileNameOffset)); } Index: llvm/unittests/IR/MetadataTest.cpp =================================================================== --- llvm/unittests/IR/MetadataTest.cpp +++ llvm/unittests/IR/MetadataTest.cpp @@ -1370,7 +1370,7 @@ TEST_F(DIFileTest, get) { StringRef Filename = "file"; StringRef Directory = "dir"; - DIFile::ChecksumKind CSKind = DIFile::CSK_MD5; + DIFile::ChecksumKind CSKind = DIFile::ChecksumKind::CSK_MD5; StringRef Checksum = "000102030405060708090a0b0c0d0e0f"; auto *N = DIFile::get(Context, Filename, Directory, CSKind, Checksum); @@ -1383,7 +1383,8 @@ EXPECT_NE(N, DIFile::get(Context, "other", Directory, CSKind, Checksum)); EXPECT_NE(N, DIFile::get(Context, Filename, "other", CSKind, Checksum)); - EXPECT_NE(N, DIFile::get(Context, Filename, Directory, DIFile::CSK_SHA1, Checksum)); + EXPECT_NE(N, DIFile::get(Context, Filename, Directory, + DIFile::ChecksumKind::CSK_SHA1, Checksum)); EXPECT_NE(N, DIFile::get(Context, Filename, Directory)); TempDIFile Temp = N->clone();