Index: clang/include/clang/Frontend/CodeGenOptions.h =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.h +++ clang/include/clang/Frontend/CodeGenOptions.h @@ -163,6 +163,11 @@ /// file, for example with -save-temps. std::string MainFileName; + /// The name of the primary output file, if non-empty. This is used by some + /// debug info backends that write the name of an output file into the debug + /// info. + std::string OutputFileName; + /// The name for the split debug info file that we'll break out. This is used /// in the backend for setting the name in the skeleton cu. std::string SplitDwarfFile; Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -554,7 +554,11 @@ // Create new compile unit. // FIXME - Eliminate TheCU. + auto &CGOpts = CGM.getCodeGenOpts(); + StringRef OutputFile; + if (CGOpts.EmitCodeView) + OutputFile = CGOpts.OutputFileName; TheCU = DBuilder.createCompileUnit( LangTag, DBuilder.createFile(remapDIPath(MainFileName), @@ -563,7 +567,7 @@ CGOpts.DwarfDebugFlags, RuntimeVers, CGOpts.EnableSplitDwarf ? "" : CGOpts.SplitDwarfFile, EmissionKind, 0 /* DWOid */, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling, - CGOpts.GnuPubnames); + CGOpts.GnuPubnames, OutputFile); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -735,6 +735,7 @@ Opts.PreferVectorWidth = Args.getLastArgValue(OPT_mprefer_vector_width_EQ); Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); + Opts.OutputFileName = Args.getLastArgValue(OPT_o); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard); Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -107,7 +107,7 @@ /// A CompileUnit provides an anchor for all debugging /// information generated during this instance of compilation. /// \param Lang Source programming language, eg. dwarf::DW_LANG_C99 - /// \param File File info. + /// \param File Input File info. /// \param Producer Identify the producer of debugging information /// and code. Usually this is a compiler /// version string. @@ -128,15 +128,15 @@ /// profile collection. /// \param GnuPubnames Whether to emit .debug_gnu_pubnames section instead /// of .debug_pubnames. - DICompileUnit * - createCompileUnit(unsigned Lang, DIFile *File, StringRef Producer, - bool isOptimized, StringRef Flags, unsigned RV, - StringRef SplitName = StringRef(), - DICompileUnit::DebugEmissionKind Kind = - DICompileUnit::DebugEmissionKind::FullDebug, - uint64_t DWOId = 0, bool SplitDebugInlining = true, - bool DebugInfoForProfiling = false, - bool GnuPubnames = false); + /// \param OutputFile Output File name. + DICompileUnit *createCompileUnit( + unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, + StringRef Flags, unsigned RV, StringRef SplitName = StringRef(), + DICompileUnit::DebugEmissionKind Kind = + DICompileUnit::DebugEmissionKind::FullDebug, + uint64_t DWOId = 0, bool SplitDebugInlining = true, + bool DebugInfoForProfiling = false, bool GnuPubnames = false, + StringRef OutputFile = StringRef()); /// Create a file descriptor to hold debugging information for a file. /// \param Filename File name. Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1133,14 +1133,16 @@ DIGlobalVariableExpressionArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, - bool GnuPubnames, StorageType Storage, bool ShouldCreate = true) { + bool GnuPubnames, StringRef OutputFile, StorageType Storage, + bool ShouldCreate = true) { return getImpl( Context, SourceLanguage, File, getCanonicalMDString(Context, Producer), IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion, getCanonicalMDString(Context, SplitDebugFilename), EmissionKind, EnumTypes.get(), RetainedTypes.get(), GlobalVariables.get(), ImportedEntities.get(), Macros.get(), DWOId, SplitDebugInlining, - DebugInfoForProfiling, GnuPubnames, Storage, ShouldCreate); + DebugInfoForProfiling, GnuPubnames, + getCanonicalMDString(Context, OutputFile), Storage, ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, @@ -1149,17 +1151,17 @@ unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, - bool DebugInfoForProfiling, bool GnuPubnames, StorageType Storage, - bool ShouldCreate = true); + bool DebugInfoForProfiling, bool GnuPubnames, MDString *OutputFile, + StorageType Storage, bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { - return getTemporary(getContext(), getSourceLanguage(), getFile(), - getProducer(), isOptimized(), getFlags(), - getRuntimeVersion(), getSplitDebugFilename(), - getEmissionKind(), getEnumTypes(), getRetainedTypes(), - getGlobalVariables(), getImportedEntities(), - getMacros(), DWOId, getSplitDebugInlining(), - getDebugInfoForProfiling(), getGnuPubnames()); + return getTemporary( + getContext(), getSourceLanguage(), getFile(), getProducer(), + isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(), + getEmissionKind(), getEnumTypes(), getRetainedTypes(), + getGlobalVariables(), getImportedEntities(), getMacros(), DWOId, + getSplitDebugInlining(), getDebugInfoForProfiling(), getGnuPubnames(), + getOutputFile()); } public: @@ -1175,11 +1177,11 @@ DIGlobalVariableExpressionArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, - bool GnuPubnames), + bool GnuPubnames, StringRef OutputFile), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, - DebugInfoForProfiling, GnuPubnames)) + DebugInfoForProfiling, GnuPubnames, OutputFile)) DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, @@ -1187,11 +1189,12 @@ MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, - bool SplitDebugInlining, bool DebugInfoForProfiling, bool GnuPubnames), + bool SplitDebugInlining, bool DebugInfoForProfiling, bool GnuPubnames, + MDString *OutputFile), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, - DebugInfoForProfiling, GnuPubnames)) + DebugInfoForProfiling, GnuPubnames, OutputFile)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1206,6 +1209,7 @@ StringRef getProducer() const { return getStringOperand(1); } StringRef getFlags() const { return getStringOperand(2); } StringRef getSplitDebugFilename() const { return getStringOperand(3); } + StringRef getOutputFile() const { return getStringOperand(9); } DICompositeTypeArray getEnumTypes() const { return cast_or_null(getRawEnumTypes()); } @@ -1238,6 +1242,7 @@ Metadata *getRawGlobalVariables() const { return getOperand(6); } Metadata *getRawImportedEntities() const { return getOperand(7); } Metadata *getRawMacros() const { return getOperand(8); } + MDString *getRawOutputFile() const { return getOperandAs(9); } /// Replace arrays. /// Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -724,7 +724,7 @@ } /// parseIndirectSymbol: -/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier +/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier /// OptionalVisibility OptionalDLLStorageClass /// OptionalThreadLocal OptionalUnnamedAddr // 'alias|ifunc' IndirectSymbol @@ -3775,7 +3775,7 @@ Lex.Lex(); return false; } - + template <> bool LLParser::ParseMDField(LocTy Loc, StringRef Name, DwarfAttEncodingField &Result) { @@ -4241,7 +4241,8 @@ OPTIONAL(dwoId, MDUnsignedField, ); \ OPTIONAL(splitDebugInlining, MDBoolField, = true); \ OPTIONAL(debugInfoForProfiling, MDBoolField, = false); \ - OPTIONAL(gnuPubnames, MDBoolField, = false); + OPTIONAL(gnuPubnames, MDBoolField, = false); \ + OPTIONAL(outputFile, MDStringField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS @@ -4249,7 +4250,8 @@ Context, language.Val, file.Val, producer.Val, isOptimized.Val, flags.Val, runtimeVersion.Val, splitDebugFilename.Val, emissionKind.Val, enums.Val, retainedTypes.Val, globals.Val, imports.Val, macros.Val, dwoId.Val, - splitDebugInlining.Val, debugInfoForProfiling.Val, gnuPubnames.Val); + splitDebugInlining.Val, debugInfoForProfiling.Val, gnuPubnames.Val, + outputFile.Val); return false; } Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1380,7 +1380,8 @@ Record.size() <= 14 ? 0 : Record[14], Record.size() <= 16 ? true : Record[16], Record.size() <= 17 ? false : Record[17], - Record.size() <= 18 ? false : Record[18]); + Record.size() <= 18 ? false : Record[18], + Record.size() <= 19 ? nullptr : getMDString(Record[19])); MetadataList.assignValue(CU, NextMetadataNo); NextMetadataNo++; Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -221,6 +221,8 @@ void emitTypeGlobalHashes(); + void emitObjName(); + void emitCompilerInformation(); void emitInlineeLinesSubsection(); Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -73,6 +73,8 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Target/TargetMachine.h" @@ -455,6 +457,7 @@ switchToDebugSectionForSymbol(nullptr); MCSymbol *CompilerInfo = beginCVSubsection(DebugSubsectionKind::Symbols); + emitObjName(); emitCompilerInformation(); endCVSubsection(CompilerInfo); @@ -667,6 +670,35 @@ } } +void CodeViewDebug::emitObjName() { + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + const MDNode *Node = *CUs->operands().begin(); + const auto *CU = cast(Node); + + StringRef F = CU->getOutputFile(); + if (F.empty()) + return; + MCContext &Context = MMI->getContext(); + MCSymbol *ObjBegin = Context.createTempSymbol(), + *ObjEnd = Context.createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(ObjEnd, ObjBegin, 2); + OS.EmitLabel(ObjBegin); + OS.AddComment("Record kind: S_OBJNAME"); + OS.EmitIntValue(SymbolKind::S_OBJNAME, 2); + + SmallString<64> FullPath(F.begin(), F.end()); + llvm::sys::fs::make_absolute(FullPath); + + OS.AddComment("Signature"); + OS.EmitIntValue(0, 4); + + OS.AddComment("Object name"); + emitNullTerminatedSymbolName(OS, FullPath); + + OS.EmitLabel(ObjEnd); +} + void CodeViewDebug::emitCompilerInformation() { MCContext &Context = MMI->getContext(); MCSymbol *CompilerBegin = Context.createTempSymbol(), Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -133,7 +133,8 @@ unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName, DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, - bool SplitDebugInlining, bool DebugInfoForProfiling, bool GnuPubnames) { + bool SplitDebugInlining, bool DebugInfoForProfiling, bool GnuPubnames, + StringRef OutputFile) { assert(((Lang <= dwarf::DW_LANG_Fortran08 && Lang >= dwarf::DW_LANG_C89) || (Lang <= dwarf::DW_LANG_hi_user && Lang >= dwarf::DW_LANG_lo_user)) && @@ -143,7 +144,7 @@ CUNode = DICompileUnit::getDistinct( VMContext, Lang, File, Producer, isOptimized, Flags, RunTimeVer, SplitName, Kind, nullptr, nullptr, nullptr, nullptr, nullptr, DWOId, - SplitDebugInlining, DebugInfoForProfiling, GnuPubnames); + SplitDebugInlining, DebugInfoForProfiling, GnuPubnames, OutputFile); // Create a named metadata so that it is easier to find cu in a module. NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); Index: llvm/lib/IR/DebugInfo.cpp =================================================================== --- llvm/lib/IR/DebugInfo.cpp +++ llvm/lib/IR/DebugInfo.cpp @@ -476,7 +476,8 @@ CU->getSplitDebugFilename(), DICompileUnit::LineTablesOnly, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(), CU->getDWOId(), CU->getSplitDebugInlining(), - CU->getDebugInfoForProfiling(), CU->getGnuPubnames()); + CU->getDebugInfoForProfiling(), CU->getGnuPubnames(), + CU->getOutputFile()); } DILocation *getReplacementMDLocation(DILocation *MLD) { @@ -654,10 +655,10 @@ SmallVector Ops; for (MDNode *Op : NMD.operands()) Ops.push_back(remap(Op)); - + if (!Changed) continue; - + NMD.clearOperands(); for (auto *Op : Ops) if (Op) @@ -730,12 +731,12 @@ auto File = unwrap(FileRef); return wrap(unwrap(Builder)->createCompileUnit( - map_from_llvmDWARFsourcelanguage(Lang), File, - StringRef(Producer, ProducerLen), isOptimized, - StringRef(Flags, FlagsLen), RuntimeVer, - StringRef(SplitName, SplitNameLen), - static_cast(Kind), DWOId, - SplitDebugInlining, DebugInfoForProfiling)); + map_from_llvmDWARFsourcelanguage(Lang), File, + StringRef(Producer, ProducerLen), isOptimized, StringRef(Flags, FlagsLen), + RuntimeVer, StringRef(SplitName, SplitNameLen), + static_cast(Kind), DWOId, + SplitDebugInlining, DebugInfoForProfiling, false, + StringRef())); } LLVMMetadataRef Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -431,16 +431,18 @@ unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, - bool GnuPubnames, StorageType Storage, bool ShouldCreate) { + bool GnuPubnames, MDString *OutputFile, StorageType Storage, + bool ShouldCreate) { assert(Storage != Uniqued && "Cannot unique DICompileUnit"); assert(isCanonical(Producer) && "Expected canonical MDString"); assert(isCanonical(Flags) && "Expected canonical MDString"); assert(isCanonical(SplitDebugFilename) && "Expected canonical MDString"); + assert(isCanonical(OutputFile) && "Expected canonical MDString"); Metadata *Ops[] = { File, Producer, Flags, SplitDebugFilename, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, - Macros}; + Macros, OutputFile}; return storeImpl(new (array_lengthof(Ops)) DICompileUnit( Context, Storage, SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind, DWOId, SplitDebugInlining, @@ -767,7 +769,7 @@ SmallVector Ops; if (DerefBefore) Ops.push_back(dwarf::DW_OP_deref); - + appendOffset(Ops, Offset); if (DerefAfter) Ops.push_back(dwarf::DW_OP_deref); Index: llvm/test/DebugInfo/COFF/buildinfo.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/COFF/buildinfo.ll @@ -0,0 +1,68 @@ +; RUN: llc -filetype=obj < %s > %t.obj +; RUN: llvm-readobj -codeview %t.obj | FileCheck %s + +; CHECK: ObjNameSym { +; CHECK-NEXT: Kind: S_OBJNAME (0x1101) +; CHECK-NEXT: Signature: 0x0 +; CHECK-NEXT: ObjectName: E:{{/|\\}}src{{/|\\}}llvmbuild{{/|\\}}ninja{{/|\\}}t.cpp.obj +; CHECK-NEXT: } +; CHECK-NEXT: Compile3Sym { +; CHECK-NEXT: Kind: S_COMPILE3 (0x113C) +; CHECK-NEXT: Language: Cpp (0x1) +; CHECK-NEXT: Flags [ (0x0) +; CHECK-NEXT: ] +; CHECK-NEXT: Machine: Pentium3 (0x7) +; CHECK-NEXT: FrontendVersion: 7.0.0.0 +; CHECK-NEXT: BackendVersion: 7000.0.0.0 +; CHECK-NEXT: VersionName: clang version 7.0.0 +; CHECK-NEXT: } + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc19.12.25830" + +; Function Attrs: noinline norecurse nounwind optnone +define i32 @main(i32 %argc, i8** %argv) #0 !dbg !8 { +entry: + %retval = alloca i32, align 4 + %argv.addr = alloca i8**, align 4 + %argc.addr = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + store i8** %argv, i8*** %argv.addr, align 4 + call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !15, metadata !DIExpression()), !dbg !16 + store i32 %argc, i32* %argc.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !17, metadata !DIExpression()), !dbg !18 + ret i32 0, !dbg !19 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline norecurse nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 7.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, outputFile: "t.cpp.obj") +!1 = !DIFile(filename: "t.cpp", directory: "E:\5Csrc\5Cllvmbuild\5Cninja", checksumkind: CSK_MD5, checksum: "7a3b27accb97d16236331229590077a7") +!2 = !{} +!3 = !{i32 1, !"NumRegisterParameters", i32 0} +!4 = !{i32 2, !"CodeView", i32 1} +!5 = !{i32 2, !"Debug Info Version", i32 3} +!6 = !{i32 1, !"wchar_size", i32 2} +!7 = !{!"clang version 7.0.0 "} +!8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11, !12} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 32) +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 32) +!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!15 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 1, type: !12) +!16 = !DILocation(line: 1, column: 27, scope: !8) +!17 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 1, type: !11) +!18 = !DILocation(line: 1, column: 14, scope: !8) +!19 = !DILocation(line: 2, column: 3, scope: !8) \ No newline at end of file