Index: test/tools/llvm-dwp/X86/dwos_list_from_exec_simple.test =================================================================== --- /dev/null +++ test/tools/llvm-dwp/X86/dwos_list_from_exec_simple.test @@ -0,0 +1,55 @@ +RUN: llvm-dwp -e %p/../Inputs/dwos_list_from_exec/main -o %t +RUN: llvm-dwarfdump %t | FileCheck %s + +FIXME: For some reason, piping straight from llvm-dwp to llvm-dwarfdump doesn't behave well - looks like dwarfdump is reading/closes before dwp has finished. + +DWP from non-type-unit debug info for these two translation units: +a.cpp: + struct foo { }; + foo a; + +b.cpp: + struct bar { }; + void b(bar) { + } + int main() { + return 0; + } + +CHECK-LABEL: .debug_abbrev.dwo contents: +CHECK-LABEL: Abbrev table for offset: +CHECK: 0x0000[[AAOFF:.*]] +CHECK: DW_TAG_compile_unit +CHECK: DW_TAG_variable +CHECK: DW_TAG_structure_type +CHECK-LABEL: Abbrev table for offset: +CHECK: 0x0000[[BAOFF:.*]] +CHECK: DW_TAG_compile_unit +CHECK: DW_TAG_subprogram +CHECK: DW_TAG_formal_parameter +CHECK: DW_TAG_subprogram +CHECK: DW_TAG_base_type +CHECK: DW_TAG_structure_type + +CHECK: .debug_info.dwo contents: +CHECK: [[AOFF:0x[0-9a-f]*]]: +CHECK-LABEL: Compile Unit: length = {{.*}} version = 0x0004 abbr_offset = +CHECK: 0x[[AAOFF]] addr_size = 0x08 (next unit at [[BOFF:.*]]) +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name {{.*}} "a.cpp" +CHECK: DW_AT_GNU_dwo_id {{.*}} ([[DWOA:.*]]) +CHECK: DW_TAG_variable +CHECK: DW_AT_name {{.*}} "a" +CHECK: DW_TAG_structure_type +CHECK: DW_AT_name {{.*}} "foo" + +CHECK: [[BOFF]]: +CHECK-LABEL: Compile Unit: length = {{.*}} version = 0x0004 abbr_offset = +CHECK: 0x[[BAOFF]] addr_size = 0x08 (next unit at [[XOFF:.*]]) +CHECK: DW_AT_name {{.*}} "b.cpp" +CHECK: DW_AT_GNU_dwo_id {{.*}} ([[DWOB:.*]]) +CHECK: DW_TAG_subprogram +CHECK: DW_AT_name {{.*}} "b" +CHECK: DW_TAG_formal_parameter +CHECK: DW_TAG_structure_type +CHECK: DW_AT_name {{.*}} "bar" Index: tools/llvm-dwp/llvm-dwp.cpp =================================================================== --- tools/llvm-dwp/llvm-dwp.cpp +++ tools/llvm-dwp/llvm-dwp.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/MC/MCAsmInfo.h" @@ -36,6 +37,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Options.h" +#include "llvm/Support/Path.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" @@ -49,9 +51,14 @@ using namespace cl; OptionCategory DwpCategory("Specific Options"); -static list InputFiles(Positional, OneOrMore, +static list InputFiles(Positional, ZeroOrMore, desc(""), cat(DwpCategory)); +static opt ExecFilename( + cl::Optional, "e", + desc("Specify the executable/library file to get the list of *.dwo from"), + value_desc("filename"), cat(DwpCategory)); + static opt OutputFilename(Required, "o", desc("Specify the output file."), value_desc("filename"), @@ -113,7 +120,7 @@ }; static Expected -getIndexedString(dwarf::Form Form, DataExtractor InfoData, +getIndexedString(dwarf::Form Form, DataExtractor InfoData, uint32_t &InfoOffset, StringRef StrOffsets, StringRef Str) { if (Form == dwarf::DW_FORM_string) return InfoData.getCStr(&InfoOffset); @@ -463,6 +470,34 @@ " and " + buildDWODescription(ID.Name, DWPName, ID.DWOName)); } +static Expected> +getDWOFilenames(StringRef ExecFilename) { + auto ErrOrObj = object::ObjectFile::createObjectFile(ExecFilename); + if (!ErrOrObj) + return ErrOrObj.takeError(); + const ObjectFile &Obj = *ErrOrObj.get().getBinary(); + std::unique_ptr DWARFCtx = DWARFContext::create(Obj); + SmallVector DWOPaths; + for (const auto &CU : DWARFCtx->compile_units()) { + const DWARFDie &Die = CU->getUnitDIE(); + std::string DWOName = dwarf::toString( + Die.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); + if (DWOName.empty()) + continue; + std::string DWOCompDir = + dwarf::toString(Die.find(dwarf::DW_AT_comp_dir), ""); + if (!DWOCompDir.empty()) { + SmallVector DWOPath; + DWOPath.reserve(DWOCompDir.size() + DWOName.size() + 1); + sys::path::append(DWOPath, DWOCompDir, DWOName); + DWOPaths.emplace_back(DWOPath.data()); + } else { + DWOPaths.push_back(std::move(DWOName)); + } + } + return std::move(DWOPaths); +} + static Error write(MCStreamer &Out, ArrayRef Inputs) { const auto &MCOFI = *Out.getContext().getObjectFileInfo(); MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); @@ -676,7 +711,20 @@ if (!MS) return error("no object streamer for target " + TripleName, Context); - if (auto Err = write(*MS, InputFiles)) { + SmallVector DWOFilenames; + if (ExecFilename.getNumOccurrences()) { + auto DWOs = getDWOFilenames(ExecFilename); + if (auto Error = DWOs.takeError()) { + logAllUnhandledErrors(std::move(Error), errs(), "error: "); + return 1; + } + DWOFilenames = std::move(*DWOs); + } + + ArrayRef DWOs = DWOFilenames.empty() + ? ArrayRef(InputFiles) + : ArrayRef(DWOFilenames); + if (auto Err = write(*MS, DWOs)) { logAllUnhandledErrors(std::move(Err), errs(), "error: "); return 1; }