Index: llvm/trunk/docs/CommandGuide/dsymutil.rst =================================================================== --- llvm/trunk/docs/CommandGuide/dsymutil.rst +++ llvm/trunk/docs/CommandGuide/dsymutil.rst @@ -70,6 +70,13 @@ Specifies a ``path`` to prepend to all debug symbol object file paths. +.. option:: --papertrail + + When running dsymutil as part of your build system, it can be desirable for + warnings to be part of the end product, rather than just being emitted to the + output stream. When enabled warnings are embedded in the linked DWARF debug + information. + .. option:: -s, --symtab Dumps the symbol table found in *executable* or object file(s) and exits. Index: llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp @@ -746,6 +746,7 @@ case dwarf::DW_FORM_block2: Asm->emitInt16(Size); break; case dwarf::DW_FORM_block4: Asm->emitInt32(Size); break; case dwarf::DW_FORM_block: Asm->EmitULEB128(Size); break; + case dwarf::DW_FORM_string: break; case dwarf::DW_FORM_data16: break; } Index: llvm/trunk/test/tools/dsymutil/X86/papertrail-warnings.test =================================================================== --- llvm/trunk/test/tools/dsymutil/X86/papertrail-warnings.test +++ llvm/trunk/test/tools/dsymutil/X86/papertrail-warnings.test @@ -0,0 +1,30 @@ +RUN: RC_DEBUG_OPTIONS=1 dsymutil -f %p/../Inputs/basic.macho.x86_64 -o - | llvm-dwarfdump -v - | FileCheck %s + +CHECK: .debug_info contents: +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit [1] * +CHECK: DW_AT_producer {{.*}}"dsymutil +CHECK: DW_AT_name {{.*}}"/Inputs/basic1.macho.x86_64.o" +CHECK: DW_TAG_constant [2] +CHECK: DW_AT_name {{.*}}"dsymutil_warning" +CHECK: DW_AT_artificial [DW_FORM_flag] (0x01) +CHECK: DW_AT_const_value {{.*}}"unable to open object file: No such file or directory" +CHECK: NULL +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit [1] * +CHECK: DW_AT_producer {{.*}}"dsymutil +CHECK: DW_AT_name {{.*}}"/Inputs/basic2.macho.x86_64.o" +CHECK: DW_TAG_constant [2] +CHECK: DW_AT_name {{.*}}"dsymutil_warning" +CHECK: DW_AT_artificial [DW_FORM_flag] (0x01) +CHECK: DW_AT_const_value {{.*}}"unable to open object file: No such file or directory" +CHECK: NULL +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit [1] * +CHECK: DW_AT_producer {{.*}}"dsymutil +CHECK: DW_AT_name {{.*}}"/Inputs/basic3.macho.x86_64.o" +CHECK: DW_TAG_constant [2] +CHECK: DW_AT_name {{.*}}"dsymutil_warning" +CHECK: DW_AT_artificial [DW_FORM_flag] (0x01) +CHECK: DW_AT_const_value {{.*}}"unable to open object file: No such file or directory" +CHECK: NULL \ No newline at end of file Index: llvm/trunk/test/tools/dsymutil/cmdline.test =================================================================== --- llvm/trunk/test/tools/dsymutil/cmdline.test +++ llvm/trunk/test/tools/dsymutil/cmdline.test @@ -13,6 +13,7 @@ HELP: -num-threads= HELP: -o= HELP: -oso-prepend-path= +HELP: -papertrail HELP: -symtab HELP: -toolchain HELP: -update Index: llvm/trunk/test/tools/dsymutil/debug-map-parsing.test =================================================================== --- llvm/trunk/test/tools/dsymutil/debug-map-parsing.test +++ llvm/trunk/test/tools/dsymutil/debug-map-parsing.test @@ -80,7 +80,7 @@ NOT-FOUND-NEXT: binary-path:{{.*}}/Inputs/basic.macho.x86_64 NOT-FOUND-NEXT: ... -Check that we correctly error out on invalid executatble. +Check that we correctly error out on invalid executable. NO-EXECUTABLE: cannot parse{{.*}}/inexistant': {{[Nn]o}} such file NO-EXECUTABLE-NOT: --- Index: llvm/trunk/tools/dsymutil/DebugMap.h =================================================================== --- llvm/trunk/tools/dsymutil/DebugMap.h +++ llvm/trunk/tools/dsymutil/DebugMap.h @@ -176,6 +176,11 @@ return make_range(Symbols.begin(), Symbols.end()); } + bool empty() const { return Symbols.empty(); } + + void addWarning(StringRef Warning) { Warnings.push_back(Warning); } + const std::vector &getWarnings() const { return Warnings; } + void print(raw_ostream &OS) const; #ifndef NDEBUG void dump() const; @@ -194,6 +199,8 @@ DenseMap AddressToMapping; uint8_t Type; + std::vector Warnings; + /// For YAMLIO support. ///@{ friend yaml::MappingTraits; Index: llvm/trunk/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/trunk/tools/dsymutil/DwarfLinker.cpp +++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp @@ -1481,6 +1481,10 @@ MaxDwarfVersion = Version; } + /// Emit warnings as Dwarf compile units to leave a trail after linking. + bool emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map, + OffsetsStringPool &StringPool); + /// Keeps track of relocations. class RelocationManager { struct ValidReloc { @@ -4118,6 +4122,64 @@ } } +bool DwarfLinker::emitPaperTrailWarnings(const DebugMapObject &DMO, + const DebugMap &Map, + OffsetsStringPool &StringPool) { + if (DMO.getWarnings().empty() || !DMO.empty()) + return false; + + Streamer->switchToDebugInfoSection(/* Version */ 2); + DIE *CUDie = DIE::get(DIEAlloc, dwarf::DW_TAG_compile_unit); + CUDie->setOffset(11); + StringRef Producer = StringPool.internString("dsymutil"); + StringRef File = StringPool.internString(DMO.getObjectFilename()); + CUDie->addValue(DIEAlloc, dwarf::DW_AT_producer, dwarf::DW_FORM_strp, + DIEInteger(StringPool.getStringOffset(Producer))); + DIEBlock *String = new (DIEAlloc) DIEBlock(); + DIEBlocks.push_back(String); + for (auto &C : File) + String->addValue(DIEAlloc, dwarf::Attribute(0), dwarf::DW_FORM_data1, + DIEInteger(C)); + String->addValue(DIEAlloc, dwarf::Attribute(0), dwarf::DW_FORM_data1, + DIEInteger(0)); + + CUDie->addValue(DIEAlloc, dwarf::DW_AT_name, dwarf::DW_FORM_string, String); + for (const auto &Warning : DMO.getWarnings()) { + DIE &ConstDie = CUDie->addChild(DIE::get(DIEAlloc, dwarf::DW_TAG_constant)); + ConstDie.addValue( + DIEAlloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, + DIEInteger(StringPool.getStringOffset("dsymutil_warning"))); + ConstDie.addValue(DIEAlloc, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, + DIEInteger(1)); + ConstDie.addValue(DIEAlloc, dwarf::DW_AT_const_value, dwarf::DW_FORM_strp, + DIEInteger(StringPool.getStringOffset(Warning))); + } + unsigned Size = 4 /* FORM_strp */ + File.size() + 1 + + DMO.getWarnings().size() * (4 + 1 + 4) + + 1 /* End of children */; + DIEAbbrev Abbrev = CUDie->generateAbbrev(); + AssignAbbrev(Abbrev); + CUDie->setAbbrevNumber(Abbrev.getNumber()); + Size += getULEB128Size(Abbrev.getNumber()); + // Abbreviation ordering needed for classic compatibility. + for (auto &Child : CUDie->children()) { + Abbrev = Child.generateAbbrev(); + AssignAbbrev(Abbrev); + Child.setAbbrevNumber(Abbrev.getNumber()); + Size += getULEB128Size(Abbrev.getNumber()); + } + CUDie->setSize(Size); + auto &Asm = Streamer->getAsmPrinter(); + Asm.emitInt32(11 + CUDie->getSize() - 4); + Asm.emitInt16(2); + Asm.emitInt32(0); + Asm.emitInt8(Map.getTriple().isArch64Bit() ? 8 : 4); + Streamer->emitDIE(*CUDie); + OutputDebugInfoSize += 11 /* Header */ + Size; + + return true; +} + bool DwarfLinker::link(const DebugMap &Map) { if (!createStreamer(Map.getTriple(), OutFile)) return false; @@ -4184,8 +4246,10 @@ continue; } - if (!LinkContext.ObjectFile) + if (emitPaperTrailWarnings(LinkContext.DMO, Map, OffsetsStringPool)) + continue; + if (!LinkContext.ObjectFile) continue; // Look for relocations that correspond to debug map entries. @@ -4232,6 +4296,11 @@ } } + // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway, + // to be able to emit papertrail warnings. + if (MaxDwarfVersion == 0) + MaxDwarfVersion = 3; + ThreadPool pool(2); // These variables manage the list of processed object files. Index: llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp =================================================================== --- llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp +++ llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp @@ -24,10 +24,12 @@ class MachODebugMapParser { public: MachODebugMapParser(StringRef BinaryPath, ArrayRef Archs, - StringRef PathPrefix = "", bool Verbose = false) + StringRef PathPrefix = "", + bool PaperTrailWarnings = false, bool Verbose = false) : BinaryPath(BinaryPath), Archs(Archs.begin(), Archs.end()), - PathPrefix(PathPrefix), MainBinaryHolder(Verbose), - CurrentObjectHolder(Verbose), CurrentDebugMapObject(nullptr) {} + PathPrefix(PathPrefix), PaperTrailWarnings(PaperTrailWarnings), + MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose), + CurrentDebugMapObject(nullptr) {} /// Parses and returns the DebugMaps of the input binary. The binary contains /// multiple maps in case it is a universal binary. @@ -42,6 +44,7 @@ std::string BinaryPath; SmallVector Archs; std::string PathPrefix; + bool PaperTrailWarnings; /// Owns the MemoryBuffer for the main binary. BinaryHolder MainBinaryHolder; @@ -102,6 +105,13 @@ warn_ostream() << "(" << MachOUtils::getArchName(Result->getTriple().getArchName()) << ") " << File << " " << Msg << "\n"; + + if (PaperTrailWarnings) { + if (!File.empty()) + Result->addDebugMapObject(File, sys::TimePoint()); + if (Result->end() != Result->begin()) + (*--Result->end())->addWarning(Msg.str()); + } } }; @@ -522,13 +532,14 @@ namespace dsymutil { llvm::ErrorOr>> parseDebugMap(StringRef InputFile, ArrayRef Archs, - StringRef PrependPath, bool Verbose, bool InputIsYAML) { - if (!InputIsYAML) { - MachODebugMapParser Parser(InputFile, Archs, PrependPath, Verbose); - return Parser.parse(); - } else { + StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, + bool InputIsYAML) { + if (InputIsYAML) return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose); - } + + MachODebugMapParser Parser(InputFile, Archs, PrependPath, PaperTrailWarnings, + Verbose); + return Parser.parse(); } bool dumpStab(StringRef InputFile, ArrayRef Archs, Index: llvm/trunk/tools/dsymutil/dsymutil.h =================================================================== --- llvm/trunk/tools/dsymutil/dsymutil.h +++ llvm/trunk/tools/dsymutil/dsymutil.h @@ -59,7 +59,8 @@ /// returned when the file is universal (aka fat) binary. ErrorOr>> parseDebugMap(StringRef InputFile, ArrayRef Archs, - StringRef PrependPath, bool Verbose, bool InputIsYAML); + StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, + bool InputIsYAML); /// Dump the symbol table bool dumpStab(StringRef InputFile, ArrayRef Archs, Index: llvm/trunk/tools/dsymutil/dsymutil.cpp =================================================================== --- llvm/trunk/tools/dsymutil/dsymutil.cpp +++ llvm/trunk/tools/dsymutil/dsymutil.cpp @@ -147,6 +147,11 @@ Toolchain("toolchain", desc("Embed toolchain information in dSYM bundle."), cat(DsymCategory)); +static opt + PaperTrailWarnings("papertrail", + desc("Embed warnings in the linked DWARF debug info."), + cat(DsymCategory)); + static bool createPlistFile(llvm::StringRef Bin, llvm::StringRef BundleRoot) { if (NoOutput) return true; @@ -430,6 +435,12 @@ return 1; } + if (getenv("RC_DEBUG_OPTIONS")) + PaperTrailWarnings = true; + + if (PaperTrailWarnings && InputIsYAMLDebugMap) + warn_ostream() << "Paper trail warnings are not supported for YAML input"; + for (const auto &Arch : ArchFlags) if (Arch != "*" && Arch != "all" && !llvm::object::MachOObjectFile::isValidArch(Arch)) { @@ -445,8 +456,9 @@ continue; } - auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath, - Verbose, InputIsYAMLDebugMap); + auto DebugMapPtrsOrErr = + parseDebugMap(InputFile, ArchFlags, OsoPrependPath, PaperTrailWarnings, + Verbose, InputIsYAMLDebugMap); if (auto EC = DebugMapPtrsOrErr.getError()) { error_ostream() << "cannot parse the debug map for '" << InputFile