[dsymutil] Upstream emitting of papertrail warnings.

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. This patch upstreams that functionality.

Differential revision: https://reviews.llvm.org/D44639

llvm-svn: 328965
This commit is contained in:
Jonas Devlieghere 2018-04-02 10:40:43 +00:00
parent 3f0bda296d
commit 9e3e7a99e8
10 changed files with 153 additions and 14 deletions

View File

@ -70,6 +70,13 @@ OPTIONS
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.

View File

@ -746,6 +746,7 @@ void DIEBlock::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const {
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;
}

View File

@ -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

View File

@ -13,6 +13,7 @@ HELP: -no-swiftmodule-timestamp
HELP: -num-threads=<n>
HELP: -o=<filename>
HELP: -oso-prepend-path=<path>
HELP: -papertrail
HELP: -symtab
HELP: -toolchain
HELP: -update

View File

@ -80,7 +80,7 @@ NOT-FOUND-NEXT: triple: 'x86_64-apple-darwin'
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: ---

View File

@ -176,6 +176,11 @@ public:
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;
@ -194,6 +199,8 @@ private:
DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
uint8_t Type;
std::vector<std::string> Warnings;
/// For YAMLIO support.
///@{
friend yaml::MappingTraits<dsymutil::DebugMapObject>;

View File

@ -1481,6 +1481,10 @@ private:
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 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(
}
}
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 @@ bool DwarfLinker::link(const DebugMap &Map) {
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 @@ bool DwarfLinker::link(const DebugMap &Map) {
}
}
// 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.

View File

@ -24,10 +24,12 @@ using namespace llvm::object;
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.
@ -42,6 +44,7 @@ private:
std::string BinaryPath;
SmallVector<StringRef, 1> Archs;
std::string PathPrefix;
bool PaperTrailWarnings;
/// Owns the MemoryBuffer for the main binary.
BinaryHolder MainBinaryHolder;
@ -102,6 +105,13 @@ private:
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());
}
}
};
@ -522,13 +532,14 @@ namespace llvm {
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,

View File

@ -147,6 +147,11 @@ static opt<std::string>
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;
@ -430,6 +435,12 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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

View File

@ -59,7 +59,8 @@ struct LinkOptions {
/// 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,