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.
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;
}
--- /dev/null
+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
HELP: -num-threads=<n>
HELP: -o=<filename>
HELP: -oso-prepend-path=<path>
+HELP: -papertrail
HELP: -symtab
HELP: -toolchain
HELP: -update
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: ---
return make_range(Symbols.begin(), Symbols.end());
}
+ bool empty() const { return Symbols.empty(); }
+
+ void addWarning(StringRef Warning) { Warnings.push_back(Warning); }
+ const std::vector<std::string> &getWarnings() const { return Warnings; }
+
void print(raw_ostream &OS) const;
#ifndef NDEBUG
void dump() const;
DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
uint8_t Type;
+ std::vector<std::string> Warnings;
+
/// For YAMLIO support.
///@{
friend yaml::MappingTraits<dsymutil::DebugMapObject>;
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 {
}
}
+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;
continue;
}
- if (!LinkContext.ObjectFile)
+ if (emitPaperTrailWarnings(LinkContext.DMO, Map, OffsetsStringPool))
+ continue;
+ if (!LinkContext.ObjectFile)
continue;
// Look for relocations that correspond to debug map entries.
}
}
+ // 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.
class MachODebugMapParser {
public:
MachODebugMapParser(StringRef BinaryPath, ArrayRef<std::string> 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.
std::string BinaryPath;
SmallVector<StringRef, 1> Archs;
std::string PathPrefix;
+ bool PaperTrailWarnings;
/// Owns the MemoryBuffer for the main binary.
BinaryHolder MainBinaryHolder;
warn_ostream() << "("
<< MachOUtils::getArchName(Result->getTriple().getArchName())
<< ") " << File << " " << Msg << "\n";
+
+ if (PaperTrailWarnings) {
+ if (!File.empty())
+ Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>());
+ if (Result->end() != Result->begin())
+ (*--Result->end())->addWarning(Msg.str());
+ }
}
};
namespace dsymutil {
llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(StringRef InputFile, ArrayRef<std::string> 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<std::string> Archs,
Toolchain("toolchain", desc("Embed toolchain information in dSYM bundle."),
cat(DsymCategory));
+static opt<bool>
+ 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;
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)) {
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
/// returned when the file is universal (aka fat) binary.
ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath, bool Verbose, bool InputIsYAML);
+ StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+ bool InputIsYAML);
/// Dump the symbol table
bool dumpStab(StringRef InputFile, ArrayRef<std::string> Archs,