From 197838dd0ca0427d34b3702525f2afd5d24b7a68 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Wed, 21 Mar 2018 11:46:37 +0000 Subject: [PATCH] [dwarf] Unify unknown dwarf enum formatting code Summary: We have had at least three pieces of code (in DWARFAbbreviationDeclaration, DWARFAcceleratorTable and DWARFDie) that have hand-rolled support for dumping unknown dwarf enum values. While not terrible, they are a bit distracting and enable small differences to creep in (Unknown_ffff vs. Unknown_0xffff). I ended up needing to add a fourth place (DWARFVerifier), so it seems it would be a good time to centralize. This patch creates an alternative to the XXXString dumping functions in the BinaryFormat library, which formats an unknown value as DW_TYPE_unknown_1234, instead of just an empty string. It is based on the formatv function, as that allows us to avoid materializing the string for unknown values (and because this way I don't have to invent a name for the new functions :P). In this patch I add formatters for dwarf attributes, forms, tags, and index attributes as these are the ones in use currently, but adding other enums is straight-forward. Reviewers: dblaikie, JDevlieghere, aprantl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D44570 llvm-svn: 328090 --- include/llvm/BinaryFormat/Dwarf.h | 44 ++++++++++++++++++- lib/BinaryFormat/Dwarf.cpp | 5 +++ .../DWARF/DWARFAbbreviationDeclaration.cpp | 20 ++------- lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 42 +++++------------- lib/DebugInfo/DWARF/DWARFDie.cpp | 26 +++-------- unittests/BinaryFormat/DwarfTest.cpp | 11 +++++ 6 files changed, 79 insertions(+), 69 deletions(-) diff --git a/include/llvm/BinaryFormat/Dwarf.h b/include/llvm/BinaryFormat/Dwarf.h index b7e255e3e3c..3ba83dbd0c8 100644 --- a/include/llvm/BinaryFormat/Dwarf.h +++ b/include/llvm/BinaryFormat/Dwarf.h @@ -24,6 +24,8 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadicDetails.h" namespace llvm { class StringRef; @@ -405,8 +407,8 @@ enum GDBIndexEntryLinkage { GIEL_EXTERNAL, GIEL_STATIC }; /// \defgroup DwarfConstantsDumping Dwarf constants dumping functions /// /// All these functions map their argument's value back to the -/// corresponding enumerator name or return nullptr if the value isn't -/// known. +/// corresponding enumerator name or return an empty StringRef if the value +/// isn't known. /// /// @{ StringRef TagString(unsigned Tag); @@ -573,8 +575,46 @@ private: }; }; +template struct EnumTraits : public std::false_type {}; + +template <> struct EnumTraits : public std::true_type { + static constexpr char Type[] = "AT"; + static constexpr StringRef (*StringFn)(unsigned) = &AttributeString; +}; + +template <> struct EnumTraits
: public std::true_type { + static constexpr char Type[] = "FORM"; + static constexpr StringRef (*StringFn)(unsigned) = &FormEncodingString; +}; + +template <> struct EnumTraits : public std::true_type { + static constexpr char Type[] = "IDX"; + static constexpr StringRef (*StringFn)(unsigned) = &IndexString; +}; + +template <> struct EnumTraits : public std::true_type { + static constexpr char Type[] = "TAG"; + static constexpr StringRef (*StringFn)(unsigned) = &TagString; +}; } // End of namespace dwarf +/// Dwarf constants format_provider +/// +/// Specialization of the format_provider template for dwarf enums. Unlike the +/// dumping functions above, these format unknown enumerator values as +/// DW_TYPE_unknown_1234 (e.g. DW_TAG_unknown_ffff). +template +struct format_provider< + Enum, typename std::enable_if::value>::type> { + static void format(const Enum &E, raw_ostream &OS, StringRef Style) { + StringRef Str = dwarf::EnumTraits::StringFn(E); + if (Str.empty()) { + OS << "DW_" << dwarf::EnumTraits::Type << "_unknown_" + << llvm::format("%x", E); + } else + OS << Str; + } +}; } // End of namespace llvm #endif diff --git a/lib/BinaryFormat/Dwarf.cpp b/lib/BinaryFormat/Dwarf.cpp index 1a809a178fe..3a97ddebf8e 100644 --- a/lib/BinaryFormat/Dwarf.cpp +++ b/lib/BinaryFormat/Dwarf.cpp @@ -675,3 +675,8 @@ bool llvm::dwarf::isValidFormForVersion(Form F, unsigned Version, } return ExtensionsOk; } + +const char llvm::dwarf::EnumTraits::Type[]; +const char llvm::dwarf::EnumTraits::Type[]; +const char llvm::dwarf::EnumTraits::Type[]; +const char llvm::dwarf::EnumTraits::Type[]; diff --git a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index 688a85c9da3..adada672af0 100644 --- a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -126,26 +127,11 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, } void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { - auto tagString = TagString(getTag()); OS << '[' << getCode() << "] "; - if (!tagString.empty()) - OS << tagString; - else - OS << format("DW_TAG_Unknown_%x", getTag()); + OS << formatv("{0}", getTag()); OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; for (const AttributeSpec &Spec : AttributeSpecs) { - OS << '\t'; - auto attrString = AttributeString(Spec.Attr); - if (!attrString.empty()) - OS << attrString; - else - OS << format("DW_AT_Unknown_%x", Spec.Attr); - OS << '\t'; - auto formString = FormEncodingString(Spec.Form); - if (!formString.empty()) - OS << formString; - else - OS << format("DW_FORM_Unknown_%x", Spec.Form); + OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form); if (Spec.isImplicitConst()) OS << '\t' << Spec.getImplicitConstValue(); OS << '\n'; diff --git a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 2bde3d6d034..3b9662067c3 100644 --- a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/DJB.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include @@ -24,35 +25,19 @@ using namespace llvm; namespace { -struct DwarfConstant { - StringRef (*StringFn)(unsigned); - StringRef Type; +struct Atom { unsigned Value; }; -static raw_ostream &operator<<(raw_ostream &OS, const DwarfConstant &C) { - StringRef Str = C.StringFn(C.Value); +static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) { + StringRef Str = dwarf::AtomTypeString(A.Value); if (!Str.empty()) return OS << Str; - return OS << "DW_" << C.Type << "_Unknown_0x" << format("%x", C.Value); + return OS << "DW_ATOM_unknown_" << format("%x", A.Value); } } // namespace -static DwarfConstant formatTag(unsigned Tag) { - return {dwarf::TagString, "TAG", Tag}; -} - -static DwarfConstant formatForm(unsigned Form) { - return {dwarf::FormEncodingString, "FORM", Form}; -} - -static DwarfConstant formatIndex(unsigned Idx) { - return {dwarf::IndexString, "IDX", Idx}; -} - -static DwarfConstant formatAtom(unsigned Atom) { - return {dwarf::AtomTypeString, "ATOM", Atom}; -} +static Atom formatAtom(unsigned Atom) { return {Atom}; } DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; @@ -226,7 +211,7 @@ LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { for (const auto &Atom : HdrData.Atoms) { DictScope AtomScope(W, ("Atom " + Twine(i++)).str()); W.startLine() << "Type: " << formatAtom(Atom.first) << '\n'; - W.startLine() << "Form: " << formatForm(Atom.second) << '\n'; + W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n'; AtomForms.push_back(DWARFFormValue(Atom.second)); } } @@ -415,12 +400,10 @@ llvm::Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str()); - W.startLine() << "Tag: " << formatTag(Tag) << '\n'; + W.startLine() << formatv("Tag: {0}\n", Tag); - for (const auto &Attr : Attributes) { - W.startLine() << formatIndex(Attr.Index) << ": " << formatForm(Attr.Form) - << '\n'; - } + for (const auto &Attr : Attributes) + W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form); } static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() { @@ -583,11 +566,10 @@ Optional DWARFDebugNames::Entry::getDIESectionOffset() const { void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { W.printHex("Abbrev", Abbr->Code); - W.startLine() << "Tag: " << formatTag(Abbr->Tag) << "\n"; - + W.startLine() << formatv("Tag: {0}\n", Abbr->Tag); assert(Abbr->Attributes.size() == Values.size()); for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) { - W.startLine() << formatIndex(std::get<0>(Tuple).Index) << ": "; + W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index); std::get<1>(Tuple).dump(W.getOStream()); W.getOStream() << '\n'; } diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp index 82f373e9c5c..7ae38e6e053 100644 --- a/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -21,6 +21,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" @@ -188,20 +189,10 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, const char BaseIndent[] = " "; OS << BaseIndent; OS.indent(Indent + 2); - auto attrString = AttributeString(Attr); - if (!attrString.empty()) - WithColor(OS, HighlightColor::Attribute) << attrString; - else - WithColor(OS, HighlightColor::Attribute).get() - << format("DW_AT_Unknown_%x", Attr); + WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr); - if (DumpOpts.Verbose || DumpOpts.ShowForm) { - auto formString = FormEncodingString(Form); - if (!formString.empty()) - OS << " [" << formString << ']'; - else - OS << format(" [DW_FORM_Unknown_%x]", Form); - } + if (DumpOpts.Verbose || DumpOpts.ShowForm) + OS << formatv(" [{0}]", Form); DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue formValue(Form); @@ -465,13 +456,8 @@ void DWARFDie::dump(raw_ostream &OS, unsigned Indent, if (abbrCode) { auto AbbrevDecl = getAbbreviationDeclarationPtr(); if (AbbrevDecl) { - auto tagString = TagString(getTag()); - if (!tagString.empty()) - WithColor(OS, HighlightColor::Tag).get().indent(Indent) << tagString; - else - WithColor(OS, HighlightColor::Tag).get().indent(Indent) - << format("DW_TAG_Unknown_%x", getTag()); - + WithColor(OS, HighlightColor::Tag).get().indent(Indent) + << formatv("{0}", getTag()); if (DumpOpts.Verbose) OS << format(" [%u] %c", abbrCode, AbbrevDecl->hasChildren() ? '*' : ' '); diff --git a/unittests/BinaryFormat/DwarfTest.cpp b/unittests/BinaryFormat/DwarfTest.cpp index c30910aa856..08a731f6174 100644 --- a/unittests/BinaryFormat/DwarfTest.cpp +++ b/unittests/BinaryFormat/DwarfTest.cpp @@ -9,6 +9,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" #include "gtest/gtest.h" using namespace llvm; @@ -192,4 +193,14 @@ TEST(DwarfTest, FixedFormSizes) { EXPECT_EQ(*RefSize, 8); } +TEST(DwarfTest, format_provider) { + EXPECT_EQ("DW_AT_name", formatv("{0}", DW_AT_name).str()); + EXPECT_EQ("DW_AT_unknown_3fff", formatv("{0}", DW_AT_hi_user).str()); + EXPECT_EQ("DW_FORM_addr", formatv("{0}", DW_FORM_addr).str()); + EXPECT_EQ("DW_FORM_unknown_1f00", formatv("{0}", DW_FORM_lo_user).str()); + EXPECT_EQ("DW_IDX_compile_unit", formatv("{0}", DW_IDX_compile_unit).str()); + EXPECT_EQ("DW_IDX_unknown_3fff", formatv("{0}", DW_IDX_hi_user).str()); + EXPECT_EQ("DW_TAG_compile_unit", formatv("{0}", DW_TAG_compile_unit).str()); + EXPECT_EQ("DW_TAG_unknown_ffff", formatv("{0}", DW_TAG_hi_user).str()); +} } // end namespace