llvm-dwarfdump: Add support for -debug-info=<offset>.

This is the first of many commits that enable selectively dumping just
one record from the debug info.

This reapplies r313412 with some extra qualification to appease GCC and MSVC.

llvm-svn: 313419
This commit is contained in:
Adrian Prantl 2017-09-15 23:04:04 +00:00
parent 8cd7b0cd2c
commit 057d336c0d
5 changed files with 151 additions and 59 deletions

View File

@ -114,7 +114,6 @@ struct DILineInfoSpecifier {
/// This is just a helper to programmatically construct DIDumpType.
enum DIDumpTypeCounter {
DIDT_ID_Null = 0,
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
DIDT_ID_##ENUM_NAME,
#include "llvm/BinaryFormat/Dwarf.def"
@ -129,10 +128,10 @@ enum DIDumpType : unsigned {
DIDT_Null,
DIDT_All = ~0U,
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
DIDT_##ENUM_NAME = 1U << (DIDT_ID_##ENUM_NAME - 1),
DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME,
#include "llvm/BinaryFormat/Dwarf.def"
#undef HANDLE_DWARF_SECTION
DIDT_UUID = 1 << (DIDT_ID_UUID - 1),
DIDT_UUID = 1 << DIDT_ID_UUID,
};
/// Container for dump options that control which debug information will be

View File

@ -121,7 +121,15 @@ public:
return DICtx->getKind() == CK_DWARF;
}
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override;
/// Dump a textual representation to \p OS. If any \p DumpOffsets are present,
/// dump only the record at the specified offset.
void dump(raw_ostream &OS, DIDumpOptions DumpOpts,
std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets);
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override {
std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets;
dump(OS, DumpOpts, DumpOffsets);
}
bool verify(raw_ostream &OS, unsigned DumpType = DIDT_All,
DIDumpOptions DumpOpts = {}) override;

View File

@ -216,7 +216,11 @@ static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
}
}
void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
void DWARFContext::dump(
raw_ostream &OS, DIDumpOptions DumpOpts,
std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
Optional<uint64_t> DumpOffset;
uint64_t DumpType = DumpOpts.DumpType;
bool DumpEH = DumpOpts.DumpEH;
@ -230,37 +234,41 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
// Print a header for each explicitly-requested section.
// Otherwise just print one for non-empty sections.
// Only print empty .dwo section headers when dumping a .dwo file.
bool Explicit = DumpType != DIDT_All && !IsDWO;
auto shouldDump = [&](bool IsExplicit, const char *Name,
unsigned DIDT_Section, StringRef Section) {
bool Should = (DumpType & DIDT_Section) && (IsExplicit || !Section.empty());
bool ExplicitDWO = Explicit && IsDWO;
auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID,
StringRef Section) {
DumpOffset = DumpOffsets[ID];
unsigned Mask = 1U << ID;
bool Should = (DumpType & Mask) && (Explicit || !Section.empty());
if (Should)
OS << '\n' << Name << " contents:\n";
OS << "\n" << Name << " contents:\n";
return Should;
};
// Only print empty .dwo section headers when dumping a .dwo file.
bool ExplicitDWO = Explicit && IsDWO;
// Dump individual sections.
if (shouldDump(Explicit, ".debug_abbrev", DIDT_DebugAbbrev,
DObj->getAbbrevSection())) {
if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev,
DObj->getAbbrevSection()))
getDebugAbbrev()->dump(OS);
}
if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_DebugAbbrev,
DObj->getAbbrevDWOSection())) {
if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev,
DObj->getAbbrevDWOSection()))
getDebugAbbrevDWO()->dump(OS);
}
if (shouldDump(Explicit, ".debug_info", DIDT_DebugInfo,
DObj->getInfoSection().Data)) {
for (const auto &CU : compile_units())
CU->dump(OS, DumpOpts);
}
if (shouldDump(ExplicitDWO, ".debug_info.dwo", DIDT_DebugInfo,
DObj->getInfoDWOSection().Data)) {
for (const auto &DWOCU : dwo_compile_units())
DWOCU->dump(OS, DumpOpts);
}
auto dumpDebugInfo = [&](bool IsExplicit, const char *Name,
DWARFSection Section, cu_iterator_range CUs) {
if (shouldDump(IsExplicit, Name, DIDT_ID_DebugInfo, Section.Data)) {
for (const auto &CU : CUs)
if (DumpOffset)
CU->getDIEForOffset(DumpOffset.getValue()).dump(OS, 0);
else
CU->dump(OS, DumpOpts);
}
};
dumpDebugInfo(Explicit, ".debug_info", DObj->getInfoSection(),
compile_units());
dumpDebugInfo(ExplicitDWO, ".debug_info.dwo", DObj->getInfoDWOSection(),
dwo_compile_units());
if ((DumpType & DIDT_DebugTypes)) {
if (Explicit || getNumTypeUnits()) {
@ -277,16 +285,16 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
}
if (shouldDump(Explicit, ".debug_loc", DIDT_DebugLoc,
if (shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
DObj->getLocSection().Data)) {
getDebugLoc()->dump(OS, getRegisterInfo());
}
if (shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_DebugLoc,
if (shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
DObj->getLocDWOSection().Data)) {
getDebugLocDWO()->dump(OS, getRegisterInfo());
}
if (shouldDump(Explicit, ".debug_frame", DIDT_DebugFrames,
if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrames,
DObj->getDebugFrameSection())) {
getDebugFrame()->dump(OS);
}
@ -302,7 +310,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
}
if (shouldDump(Explicit, ".debug_aranges", DIDT_DebugAranges,
if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges,
DObj->getARangeSection())) {
uint32_t offset = 0;
DataExtractor arangesData(DObj->getARangeSection(), isLittleEndian(), 0);
@ -312,7 +320,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
uint8_t savedAddressByteSize = 0;
if (shouldDump(Explicit, ".debug_line", DIDT_DebugLine,
if (shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine,
DObj->getLineSection().Data)) {
for (const auto &CU : compile_units()) {
savedAddressByteSize = CU->getAddressByteSize();
@ -335,7 +343,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
savedAddressByteSize = CU->getAddressByteSize();
break;
}
if (shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_DebugLine,
if (shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine,
DObj->getLineDWOSection().Data)) {
unsigned stmtOffset = 0;
DWARFDataExtractor lineData(*DObj, DObj->getLineDWOSection(),
@ -347,17 +355,17 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
}
if (shouldDump(Explicit, ".debug_cu_index", DIDT_DebugCUIndex,
if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
DObj->getCUIndexSection())) {
getCUIndex().dump(OS);
}
if (shouldDump(Explicit, ".debug_tu_index", DIDT_DebugTUIndex,
if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex,
DObj->getTUIndexSection())) {
getTUIndex().dump(OS);
}
if (shouldDump(Explicit, ".debug_str", DIDT_DebugStr,
if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr,
DObj->getStringSection())) {
DataExtractor strData(DObj->getStringSection(), isLittleEndian(), 0);
uint32_t offset = 0;
@ -367,7 +375,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
strOffset = offset;
}
}
if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_DebugStr,
if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr,
DObj->getStringDWOSection())) {
DataExtractor strDWOData(DObj->getStringDWOSection(), isLittleEndian(), 0);
uint32_t offset = 0;
@ -378,7 +386,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
}
if (shouldDump(Explicit, ".debug_ranges", DIDT_DebugRanges,
if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
DObj->getRangeSection().Data)) {
// In fact, different compile units may have different address byte
// sizes, but for simplicity we just use the address byte size of the
@ -393,60 +401,60 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
rangeList.dump(OS);
}
if (shouldDump(Explicit, ".debug_pubnames", DIDT_DebugPubnames,
if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
DObj->getPubNamesSection()))
DWARFDebugPubTable(DObj->getPubNamesSection(), isLittleEndian(), false)
.dump(OS);
if (shouldDump(Explicit, ".debug_pubtypes", DIDT_DebugPubtypes,
if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
DObj->getPubTypesSection()))
DWARFDebugPubTable(DObj->getPubTypesSection(), isLittleEndian(), false)
.dump(OS);
if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_DebugGnuPubnames,
if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
DObj->getGnuPubNamesSection()))
DWARFDebugPubTable(DObj->getGnuPubNamesSection(), isLittleEndian(),
true /* GnuStyle */)
.dump(OS);
if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_DebugGnuPubtypes,
if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
DObj->getGnuPubTypesSection()))
DWARFDebugPubTable(DObj->getGnuPubTypesSection(), isLittleEndian(),
true /* GnuStyle */)
.dump(OS);
if (shouldDump(Explicit, ".debug_str_offsets", DIDT_DebugStrOffsets,
if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
DObj->getStringOffsetSection().Data))
dumpStringOffsetsSection(
OS, "debug_str_offsets", *DObj, DObj->getStringOffsetSection(),
DObj->getStringSection(), isLittleEndian(), getMaxVersion());
if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_DebugStrOffsets,
if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
DObj->getStringOffsetDWOSection().Data))
dumpStringOffsetsSection(
OS, "debug_str_offsets.dwo", *DObj, DObj->getStringOffsetDWOSection(),
DObj->getStringDWOSection(), isLittleEndian(), getMaxVersion());
if (shouldDump(Explicit, ".gnu_index", DIDT_GdbIndex,
if (shouldDump(Explicit, ".gnu_index", DIDT_ID_GdbIndex,
DObj->getGdbIndexSection())) {
getGdbIndex().dump(OS);
}
if (shouldDump(Explicit, ".apple_names", DIDT_AppleNames,
if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
DObj->getAppleNamesSection().Data))
dumpAccelSection(OS, *DObj, DObj->getAppleNamesSection(),
DObj->getStringSection(), isLittleEndian());
if (shouldDump(Explicit, ".apple_types", DIDT_AppleTypes,
if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
DObj->getAppleTypesSection().Data))
dumpAccelSection(OS, *DObj, DObj->getAppleTypesSection(),
DObj->getStringSection(), isLittleEndian());
if (shouldDump(Explicit, ".apple_namespaces", DIDT_AppleNamespaces,
if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces,
DObj->getAppleNamespacesSection().Data))
dumpAccelSection(OS, *DObj, DObj->getAppleNamespacesSection(),
DObj->getStringSection(), isLittleEndian());
if (shouldDump(Explicit, ".apple_objc", DIDT_AppleObjC,
if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
DObj->getAppleObjCSection().Data))
dumpAccelSection(OS, *DObj, DObj->getAppleObjCSection(),
DObj->getStringSection(), isLittleEndian());

View File

@ -0,0 +1,10 @@
RUN: llvm-mc %S/brief.s -filetype obj -triple x86_64-apple-darwin -o - \
RUN: | llvm-dwarfdump -debug-info=0x0000000b - | FileCheck %s
CHECK: .debug_info contents:
CHECK: 0x0000000b: DW_TAG_compile_unit
CHECK: DW_AT_name
CHECK-NOT: {{:}}
RUN: llvm-mc %S/brief.s -filetype obj -triple x86_64-apple-darwin -o - \
RUN: | llvm-dwarfdump -debug-info=0 - | FileCheck --allow-empty --check-prefix=EMPTY %s
EMPTY-NOT: DW_TAG

View File

@ -37,8 +37,63 @@
using namespace llvm;
using namespace object;
/// Parser for options that take an optional offest argument.
/// @{
struct OffsetOption {
uint64_t Val = 0;
bool HasValue = false;
bool IsRequested = false;
};
namespace llvm {
namespace cl {
template <>
class parser<OffsetOption> final : public basic_parser<OffsetOption> {
public:
parser(Option &O) : basic_parser(O) {}
/// Return true on error.
bool parse(Option &O, StringRef ArgName, StringRef Arg, OffsetOption &Val) {
if (Arg == "") {
Val.Val = 0;
Val.HasValue = false;
Val.IsRequested = true;
return false;
}
if (Arg.getAsInteger(0, Val.Val))
return O.error("'" + Arg + "' value invalid for integer argument!");
Val.HasValue = true;
Val.IsRequested = true;
return false;
}
enum ValueExpected getValueExpectedFlagDefault() const {
return ValueOptional;
}
void printOptionInfo(const Option &O, size_t GlobalWidth) const {
outs() << " -" << O.ArgStr;
Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
}
void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,
size_t GlobalWidth) const {
printOptionName(O, GlobalWidth);
outs() << "[=offset]";
}
// An out-of-line virtual method to provide a 'home' for this class.
void anchor() override {};
};
} // cl
} // llvm
/// @}
/// Command line options.
/// @{
namespace {
using namespace llvm::cl;
using namespace cl;
OptionCategory DwarfDumpCategory("Specific Options");
static opt<bool> Help("h", desc("Alias for -help"), Hidden,
@ -47,20 +102,26 @@ static list<std::string>
InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
ZeroOrMore, cat(DwarfDumpCategory));
cl::OptionCategory
SectionCategory("Section-specific Dump Options",
"These control which sections are dumped.");
cl::OptionCategory SectionCategory("Section-specific Dump Options",
"These control which sections are dumped. "
"Where applicable these parameters take an "
"optional =<offset> argument to dump only "
"the entry at the specified offset.");
static opt<bool> DumpAll("all", desc("Dump all debug info sections"),
cat(SectionCategory));
static alias DumpAllAlias("a", desc("Alias for -all"), aliasopt(DumpAll));
// Options for dumping specific sections.
static unsigned DumpType = DIDT_Null;
static std::array<llvm::Optional<uint64_t>, (unsigned)DIDT_ID_Count> DumpOffsets;
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
static opt<bool> Dump##ENUM_NAME(CMDLINE_NAME, \
desc("Dump the " ELF_NAME " section"), \
cat(SectionCategory));
static opt<OffsetOption> Dump##ENUM_NAME( \
CMDLINE_NAME, desc("Dump the " ELF_NAME " section"), \
cat(SectionCategory));
#include "llvm/BinaryFormat/Dwarf.def"
#undef HANDLE_DWARF_SECTION
static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture"),
cat(DwarfDumpCategory));
static alias DumpUUIDAlias("u", desc("Alias for -uuid"), aliasopt(DumpUUID));
@ -78,6 +139,9 @@ static opt<bool> Verbose("verbose",
static alias VerboseAlias("v", desc("Alias for -verbose"), aliasopt(Verbose),
cat(DwarfDumpCategory));
} // namespace
/// @}
//===----------------------------------------------------------------------===//
static void error(StringRef Filename, std::error_code EC) {
if (!EC)
@ -103,7 +167,7 @@ static bool dumpObjectFile(ObjectFile &Obj, Twine Filename) {
outs() << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
// Dump the complete DWARF structure.
DICtx->dump(outs(), getDumpOpts());
DICtx->dump(outs(), getDumpOpts(), DumpOffsets);
return true;
}
@ -237,8 +301,11 @@ int main(int argc, char **argv) {
// Defaults to dumping all sections, unless brief mode is specified in which
// case only the .debug_info section in dumped.
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
if (Dump##ENUM_NAME) \
DumpType |= DIDT_##ENUM_NAME;
if (Dump##ENUM_NAME.IsRequested) { \
DumpType |= DIDT_##ENUM_NAME; \
if (Dump##ENUM_NAME.HasValue) \
DumpOffsets[DIDT_ID_##ENUM_NAME] = Dump##ENUM_NAME.Val; \
}
#include "llvm/BinaryFormat/Dwarf.def"
#undef HANDLE_DWARF_SECTION
if (DumpUUID)