diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp --- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -12,6 +12,7 @@ #include "llvm-dwarfdump.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DIContext.h" @@ -181,6 +182,15 @@ value_desc("pattern"), cat(DwarfDumpCategory)); static alias NameAlias("n", desc("Alias for --name"), aliasopt(Name), cl::NotHidden); + +static list + Tag("tag", + desc("Find and print all debug info entries whose tag (DW_AT_tag " + "attribute) matches the exact text in ."), + value_desc("tag"), cat(DwarfDumpCategory)); +static alias TypeAlias("t", desc("Alias for --tag"), aliasopt(Tag), + cl::NotHidden); + static opt Lookup("lookup", desc("Lookup
in the debug information and print out any " @@ -325,10 +335,8 @@ using HandlerFn = std::function; -/// Print only DIEs that have a certain name. -static bool filterByName(const StringSet<> &Names, DWARFDie Die, - StringRef NameRef, raw_ostream &OS) { - DIDumpOptions DumpOpts = getDumpOpts(Die.getDwarfUnit()->getContext()); +/// Return true if a name in `Names` matches `NameRef`. +static bool filterByName(const StringSet<> &Names, StringRef NameRef) { std::string Name = (IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str(); if (UseRegex) { @@ -341,31 +349,21 @@ exit(1); } if (RE.match(Name)) { - Die.dump(OS, 0, DumpOpts); return true; } } } else if (Names.count(Name)) { // Match full text. - Die.dump(OS, 0, DumpOpts); return true; } return false; } -/// Print only DIEs that have a certain name. -static void filterByName(const StringSet<> &Names, - DWARFContext::unit_iterator_range CUs, - raw_ostream &OS) { +static void getDies(DWARFContext::unit_iterator_range CUs, + SmallVectorImpl &Dies) { for (const auto &CU : CUs) - for (const auto &Entry : CU->dies()) { - DWARFDie Die = {CU.get(), &Entry}; - if (const char *Name = Die.getName(DINameKind::ShortName)) - if (filterByName(Names, Die, Name, OS)) - continue; - if (const char *Name = Die.getName(DINameKind::LinkageName)) - filterByName(Names, Die, Name, OS); - } + for (const auto &Entry : CU->dies()) + Dies.push_back({CU.get(), &Entry}); } static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel, @@ -456,6 +454,20 @@ return true; } +static bool dieNameFilter(const StringSet<> &Names, const DWARFDie &Die) { + if (const char *Name = Die.getName(DINameKind::ShortName)) + if (filterByName(Names, Name)) + return true; + if (const char *Name = Die.getName(DINameKind::LinkageName)) + return filterByName(Names, Name); + return false; +} + +static bool dieTagFilter(const SmallSet &Tags, + const DWARFDie &Die) { + return Tags.count(Die.getTag()); +} + static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, const Twine &Filename, raw_ostream &OS) { logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(), @@ -468,14 +480,36 @@ if (Lookup) return lookup(Obj, DICtx, Lookup, OS); - // Handle the --name option. - if (!Name.empty()) { + // Handle the --name and --tag options. + if (!Name.empty() || !Tag.empty()) { StringSet<> Names; for (auto name : Name) Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name); - filterByName(Names, DICtx.normal_units(), OS); - filterByName(Names, DICtx.dwo_units(), OS); + SmallSet Tags; + for (auto tag : Tag) + Tags.insert(dwarf::getTag(StringRef("DW_TAG_" + StringRef(tag).lower()))); + + SmallVector Dies; + getDies(DICtx.normal_units(), Dies); + getDies(DICtx.dwo_units(), Dies); + + if (!Names.empty() && !Tags.empty()) { + auto Filter = [&](DWARFDie Die) { + return (dieNameFilter(Names, Die) && dieTagFilter(Tags, Die)); + }; + for (const auto Die : make_filter_range(Dies, Filter)) + Die.dump(OS, 0, getDumpOpts(DICtx)); + } else if (!Names.empty()) { + auto Filter = [&](DWARFDie Die) { return dieNameFilter(Names, Die); }; + for (const auto Die : make_filter_range(Dies, Filter)) + Die.dump(OS, 0, getDumpOpts(DICtx)); + } else { + auto Filter = [&](DWARFDie Die) { return dieTagFilter(Tags, Die); }; + for (const auto Die : make_filter_range(Dies, Filter)) + Die.dump(OS, 0, getDumpOpts(DICtx)); + } + return true; }