2012-10-17 07:46:21 +08:00
|
|
|
//===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm ----------===//
|
2011-09-14 03:42:23 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-09-14 03:42:23 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This program is a utility that works like "dwarfdump".
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2017-09-30 08:22:25 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2012-12-04 18:44:52 +08:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2015-04-24 01:37:47 +08:00
|
|
|
#include "llvm/DebugInfo/DIContext.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
2017-09-15 01:01:53 +08:00
|
|
|
#include "llvm/Object/Archive.h"
|
2015-08-03 08:10:31 +08:00
|
|
|
#include "llvm/Object/MachOUniversal.h"
|
2011-09-14 03:42:23 +08:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
2018-04-14 02:26:06 +08:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2011-09-14 03:42:23 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2015-12-24 05:51:13 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2017-10-04 06:08:22 +08:00
|
|
|
#include "llvm/Support/Regex.h"
|
[dwarfdump] Pretty print location expressions and location lists
Summary:
Based on Fred's patch here: https://reviews.llvm.org/D6771
I can't seem to commandeer the old review, so I'm creating a new one.
With that change the locations exrpessions are pretty printed inline in the
DIE tree. The output looks like this for debug_loc entries:
DW_AT_location [DW_FORM_data4] (0x00000000
0x0000000000000001 - 0x000000000000000b: DW_OP_consts +3
0x000000000000000b - 0x0000000000000012: DW_OP_consts +7
0x0000000000000012 - 0x000000000000001b: DW_OP_reg0 RAX, DW_OP_piece 0x4
0x000000000000001b - 0x0000000000000024: DW_OP_breg5 RDI+0)
And like this for debug_loc.dwo entries:
DW_AT_location [DW_FORM_sec_offset] (0x00000000
Addr idx 2 (w/ length 190): DW_OP_consts +0, DW_OP_stack_value
Addr idx 3 (w/ length 23): DW_OP_reg0 RAX, DW_OP_piece 0x4)
Simple locations without ranges are printed inline:
DW_AT_location [DW_FORM_block1] (DW_OP_reg4 RSI, DW_OP_piece 0x4, DW_OP_bit_piece 0x20 0x0)
The debug_loc(.dwo) dumping in changed accordingly to factor the code.
Reviewers: dblaikie, aprantl, friss
Subscribers: mgorny, javed.absar, hiraditya, llvm-commits, JDevlieghere
Differential Revision: https://reviews.llvm.org/D37123
llvm-svn: 312042
2017-08-30 05:41:21 +08:00
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2017-09-22 17:20:57 +08:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2018-05-24 19:36:57 +08:00
|
|
|
#include "llvm/Support/WithColor.h"
|
2011-09-14 03:42:23 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-11-08 07:22:07 +08:00
|
|
|
|
2011-09-14 03:42:23 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
|
|
|
|
2017-09-16 07:04:04 +08:00
|
|
|
/// 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.
|
|
|
|
/// @{
|
|
|
|
|
2017-09-13 06:32:53 +08:00
|
|
|
namespace {
|
2017-09-16 07:04:04 +08:00
|
|
|
using namespace cl;
|
2017-09-13 06:32:53 +08:00
|
|
|
|
|
|
|
OptionCategory DwarfDumpCategory("Specific Options");
|
|
|
|
static list<std::string>
|
|
|
|
InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
|
|
|
|
ZeroOrMore, cat(DwarfDumpCategory));
|
|
|
|
|
2017-09-16 07:04:04 +08:00
|
|
|
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.");
|
|
|
|
|
2017-09-13 06:32:53 +08:00
|
|
|
static opt<bool> DumpAll("all", desc("Dump all debug info sections"),
|
|
|
|
cat(SectionCategory));
|
|
|
|
static alias DumpAllAlias("a", desc("Alias for -all"), aliasopt(DumpAll));
|
2017-09-12 06:59:45 +08:00
|
|
|
|
2017-09-16 07:04:04 +08:00
|
|
|
// Options for dumping specific sections.
|
2017-09-14 06:09:01 +08:00
|
|
|
static unsigned DumpType = DIDT_Null;
|
2017-09-20 04:58:57 +08:00
|
|
|
static std::array<llvm::Optional<uint64_t>, (unsigned)DIDT_ID_Count>
|
|
|
|
DumpOffsets;
|
2017-09-12 06:59:45 +08:00
|
|
|
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
|
2017-09-16 07:04:04 +08:00
|
|
|
static opt<OffsetOption> Dump##ENUM_NAME( \
|
|
|
|
CMDLINE_NAME, desc("Dump the " ELF_NAME " section"), \
|
|
|
|
cat(SectionCategory));
|
2017-09-12 06:59:45 +08:00
|
|
|
#include "llvm/BinaryFormat/Dwarf.def"
|
|
|
|
#undef HANDLE_DWARF_SECTION
|
2017-09-16 07:04:04 +08:00
|
|
|
|
2017-09-18 22:15:57 +08:00
|
|
|
static alias DumpDebugFrameAlias("eh-frame", desc("Alias for -debug-frame"),
|
2017-09-21 07:29:31 +08:00
|
|
|
NotHidden, cat(SectionCategory),
|
2017-09-18 22:15:57 +08:00
|
|
|
aliasopt(DumpDebugFrame));
|
2017-09-22 00:26:18 +08:00
|
|
|
static list<std::string>
|
|
|
|
ArchFilters("arch",
|
|
|
|
desc("Dump debug information for the specified CPU "
|
|
|
|
"architecture only. Architectures may be specified by "
|
|
|
|
"name or by number. This option can be specified "
|
|
|
|
"multiple times, once for each desired architecture."),
|
|
|
|
cat(DwarfDumpCategory));
|
2017-12-09 07:32:47 +08:00
|
|
|
static opt<bool>
|
|
|
|
Diff("diff",
|
|
|
|
desc("Emit diff-friendly output by omitting offsets and addresses."),
|
|
|
|
cat(DwarfDumpCategory));
|
2017-09-29 02:10:52 +08:00
|
|
|
static list<std::string>
|
|
|
|
Find("find",
|
|
|
|
desc("Search for the exact match for <name> in the accelerator tables "
|
2017-09-30 08:31:15 +08:00
|
|
|
"and print the matching debug information entries. When no "
|
|
|
|
"accelerator tables are available, the slower but more complete "
|
|
|
|
"-name option can be used instead."),
|
2017-09-29 02:10:52 +08:00
|
|
|
value_desc("name"), cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias FindAlias("f", desc("Alias for -find."), aliasopt(Find));
|
2019-06-11 21:51:18 +08:00
|
|
|
static opt<bool> IgnoreCase("ignore-case",
|
|
|
|
desc("Ignore case distinctions when searching."),
|
|
|
|
value_desc("i"), cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias IgnoreCaseAlias("i", desc("Alias for -ignore-case."),
|
2017-10-03 05:21:09 +08:00
|
|
|
aliasopt(IgnoreCase));
|
2017-10-04 06:08:22 +08:00
|
|
|
static list<std::string> Name(
|
|
|
|
"name",
|
|
|
|
desc("Find and print all debug info entries whose name (DW_AT_name "
|
|
|
|
"attribute) matches the exact text in <pattern>. When used with the "
|
|
|
|
"the -regex option <pattern> is interpreted as a regular expression."),
|
|
|
|
value_desc("pattern"), cat(DwarfDumpCategory));
|
2017-09-30 08:22:25 +08:00
|
|
|
static alias NameAlias("n", desc("Alias for -name"), aliasopt(Name));
|
2019-04-24 10:40:20 +08:00
|
|
|
static opt<uint64_t>
|
|
|
|
Lookup("lookup",
|
2018-10-10 02:12:04 +08:00
|
|
|
desc("Lookup <address> in the debug information and print out any "
|
2017-10-26 05:56:41 +08:00
|
|
|
"available file, function, block and line table details."),
|
|
|
|
value_desc("address"), cat(DwarfDumpCategory));
|
2017-09-22 17:20:57 +08:00
|
|
|
static opt<std::string>
|
2019-06-11 18:20:07 +08:00
|
|
|
OutputFilename("o", cl::init("-"),
|
2017-10-07 04:24:35 +08:00
|
|
|
cl::desc("Redirect output to the specified file."),
|
2019-06-11 18:20:07 +08:00
|
|
|
cl::value_desc("filename"), cat(DwarfDumpCategory));
|
|
|
|
static alias OutputFilenameAlias("out-file", desc("Alias for -o."),
|
|
|
|
aliasopt(OutputFilename));
|
2017-10-04 06:08:22 +08:00
|
|
|
static opt<bool>
|
|
|
|
UseRegex("regex",
|
|
|
|
desc("Treat any <pattern> strings as regular expressions when "
|
|
|
|
"searching instead of just as an exact string match."),
|
|
|
|
cat(DwarfDumpCategory));
|
|
|
|
static alias RegexAlias("x", desc("Alias for -regex"), aliasopt(UseRegex));
|
2017-09-17 01:28:00 +08:00
|
|
|
static opt<bool>
|
|
|
|
ShowChildren("show-children",
|
|
|
|
desc("Show a debug info entry's children when selectively "
|
2019-06-14 21:00:09 +08:00
|
|
|
"printing entries."),
|
2017-09-20 04:58:57 +08:00
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias ShowChildrenAlias("c", desc("Alias for -show-children."),
|
2017-09-17 01:28:00 +08:00
|
|
|
aliasopt(ShowChildren));
|
2017-09-19 05:27:44 +08:00
|
|
|
static opt<bool>
|
|
|
|
ShowParents("show-parents",
|
|
|
|
desc("Show a debug info entry's parents when selectively "
|
2019-06-14 21:00:09 +08:00
|
|
|
"printing entries."),
|
2017-09-20 04:58:57 +08:00
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias ShowParentsAlias("p", desc("Alias for -show-parents."),
|
2017-09-19 05:27:44 +08:00
|
|
|
aliasopt(ShowParents));
|
2017-10-03 00:02:04 +08:00
|
|
|
static opt<bool>
|
|
|
|
ShowForm("show-form",
|
|
|
|
desc("Show DWARF form types after the DWARF attribute types."),
|
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias ShowFormAlias("F", desc("Alias for -show-form."),
|
2017-10-03 00:02:04 +08:00
|
|
|
aliasopt(ShowForm), cat(DwarfDumpCategory));
|
2019-05-25 05:11:28 +08:00
|
|
|
static opt<unsigned>
|
|
|
|
ChildRecurseDepth("recurse-depth",
|
|
|
|
desc("Only recurse to a depth of N when displaying "
|
|
|
|
"children of debug info entries."),
|
|
|
|
cat(DwarfDumpCategory), init(-1U), value_desc("N"));
|
|
|
|
static alias ChildRecurseDepthAlias("r", desc("Alias for -recurse-depth."),
|
|
|
|
aliasopt(ChildRecurseDepth));
|
|
|
|
static opt<unsigned>
|
|
|
|
ParentRecurseDepth("parent-recurse-depth",
|
|
|
|
desc("Only recurse to a depth of N when displaying "
|
|
|
|
"parents of debug info entries."),
|
|
|
|
cat(DwarfDumpCategory), init(-1U), value_desc("N"));
|
2017-09-13 06:32:53 +08:00
|
|
|
static opt<bool>
|
2016-10-19 05:09:48 +08:00
|
|
|
SummarizeTypes("summarize-types",
|
2017-10-07 04:24:35 +08:00
|
|
|
desc("Abbreviate the description of type unit entries."),
|
2017-09-20 04:58:57 +08:00
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:34 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
Statistics("statistics",
|
|
|
|
cl::desc("Emit JSON-formatted debug info quality metrics."),
|
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
|
2017-09-13 06:32:53 +08:00
|
|
|
cat(DwarfDumpCategory));
|
|
|
|
static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),
|
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture."),
|
2017-09-30 08:22:25 +08:00
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias DumpUUIDAlias("u", desc("Alias for -uuid."), aliasopt(DumpUUID));
|
2017-09-13 06:32:53 +08:00
|
|
|
static opt<bool> Verbose("verbose",
|
2017-10-07 04:24:35 +08:00
|
|
|
desc("Print more low-level encoding details."),
|
2017-09-13 06:32:53 +08:00
|
|
|
cat(DwarfDumpCategory));
|
2017-10-07 04:24:35 +08:00
|
|
|
static alias VerboseAlias("v", desc("Alias for -verbose."), aliasopt(Verbose),
|
2017-09-13 06:32:53 +08:00
|
|
|
cat(DwarfDumpCategory));
|
2019-06-21 19:49:20 +08:00
|
|
|
static cl::extrahelp
|
|
|
|
HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
|
2017-09-13 06:32:53 +08:00
|
|
|
} // namespace
|
2017-09-16 07:04:04 +08:00
|
|
|
/// @}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-09-22 17:20:57 +08:00
|
|
|
static void error(StringRef Prefix, std::error_code EC) {
|
2015-06-26 07:40:15 +08:00
|
|
|
if (!EC)
|
2015-07-26 13:35:59 +08:00
|
|
|
return;
|
2018-10-24 05:51:44 +08:00
|
|
|
WithColor::error() << Prefix << ": " << EC.message() << "\n";
|
2015-07-26 13:35:59 +08:00
|
|
|
exit(1);
|
2015-06-26 07:40:15 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 07:07:24 +08:00
|
|
|
static DIDumpOptions getDumpOpts() {
|
2017-09-13 17:43:05 +08:00
|
|
|
DIDumpOptions DumpOpts;
|
|
|
|
DumpOpts.DumpType = DumpType;
|
2019-05-25 05:11:28 +08:00
|
|
|
DumpOpts.ChildRecurseDepth = ChildRecurseDepth;
|
|
|
|
DumpOpts.ParentRecurseDepth = ParentRecurseDepth;
|
2017-12-09 07:32:47 +08:00
|
|
|
DumpOpts.ShowAddresses = !Diff;
|
2017-09-17 01:28:00 +08:00
|
|
|
DumpOpts.ShowChildren = ShowChildren;
|
2017-09-19 05:27:44 +08:00
|
|
|
DumpOpts.ShowParents = ShowParents;
|
2017-10-03 00:02:04 +08:00
|
|
|
DumpOpts.ShowForm = ShowForm;
|
2017-09-13 17:43:05 +08:00
|
|
|
DumpOpts.SummarizeTypes = SummarizeTypes;
|
|
|
|
DumpOpts.Verbose = Verbose;
|
2017-09-21 01:44:00 +08:00
|
|
|
// In -verify mode, print DIEs without children in error messages.
|
|
|
|
if (Verify)
|
|
|
|
return DumpOpts.noImplicitRecursion();
|
2017-09-13 17:43:05 +08:00
|
|
|
return DumpOpts;
|
|
|
|
}
|
|
|
|
|
2017-09-22 00:26:18 +08:00
|
|
|
static uint32_t getCPUType(MachOObjectFile &MachO) {
|
|
|
|
if (MachO.is64Bit())
|
|
|
|
return MachO.getHeader64().cputype;
|
|
|
|
else
|
|
|
|
return MachO.getHeader().cputype;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return true if the object file has not been filtered by an --arch option.
|
|
|
|
static bool filterArch(ObjectFile &Obj) {
|
|
|
|
if (ArchFilters.empty())
|
|
|
|
return true;
|
2017-09-30 08:22:21 +08:00
|
|
|
|
2017-09-22 00:26:18 +08:00
|
|
|
if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {
|
|
|
|
for (auto Arch : ArchFilters) {
|
2017-09-30 08:22:21 +08:00
|
|
|
// Match architecture number.
|
2017-09-22 00:26:18 +08:00
|
|
|
unsigned Value;
|
|
|
|
if (!StringRef(Arch).getAsInteger(0, Value))
|
|
|
|
if (Value == getCPUType(*MachO))
|
|
|
|
return true;
|
2019-04-04 23:48:40 +08:00
|
|
|
|
|
|
|
// Match as name.
|
|
|
|
if (MachO->getArchTriple().getArch() == Triple(Arch).getArch())
|
|
|
|
return true;
|
2017-09-22 00:26:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-22 17:20:57 +08:00
|
|
|
using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx, Twine,
|
|
|
|
raw_ostream &)>;
|
2017-09-22 00:26:18 +08:00
|
|
|
|
2018-10-10 04:51:33 +08:00
|
|
|
/// Print only DIEs that have a certain name.
|
|
|
|
static bool filterByName(const StringSet<> &Names, DWARFDie Die,
|
|
|
|
StringRef NameRef, raw_ostream &OS) {
|
|
|
|
std::string Name =
|
|
|
|
(IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str();
|
|
|
|
if (UseRegex) {
|
|
|
|
// Match regular expression.
|
|
|
|
for (auto Pattern : Names.keys()) {
|
|
|
|
Regex RE(Pattern, IgnoreCase ? Regex::IgnoreCase : Regex::NoFlags);
|
|
|
|
std::string Error;
|
|
|
|
if (!RE.isValid(Error)) {
|
|
|
|
errs() << "error in regular expression: " << Error << "\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (RE.match(Name)) {
|
|
|
|
Die.dump(OS, 0, getDumpOpts());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (Names.count(Name)) {
|
|
|
|
// Match full text.
|
|
|
|
Die.dump(OS, 0, getDumpOpts());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-30 08:22:25 +08:00
|
|
|
/// Print only DIEs that have a certain name.
|
|
|
|
static void filterByName(const StringSet<> &Names,
|
2018-08-03 03:29:38 +08:00
|
|
|
DWARFContext::unit_iterator_range CUs,
|
|
|
|
raw_ostream &OS) {
|
2017-09-30 08:22:25 +08:00
|
|
|
for (const auto &CU : CUs)
|
|
|
|
for (const auto &Entry : CU->dies()) {
|
|
|
|
DWARFDie Die = {CU.get(), &Entry};
|
2018-10-10 04:51:33 +08:00
|
|
|
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);
|
2017-09-30 08:22:25 +08:00
|
|
|
}
|
2017-10-26 05:56:41 +08:00
|
|
|
}
|
|
|
|
|
[DWARF/AccelTable] Remove getDIESectionOffset for DWARF v5 entries
Summary:
This method was not correct for entries in DWO files as it assumed it
could just add up the CU and DIE offsets to get the absolute DIE offset.
This is not correct for the DWO files, as here the CU offset will
reference the skeleton unit, whereas the DIE offset will be the offset
in the full unit in the DWO file.
Unfortunately, this means that we are not able to determine the absolute
DIE offset using the information in the .debug_names section alone,
which means we have to offload some of this work to the users of this
class.
To demonstrate how this can be done, I've added/fixed the ability to
lookup entries using accelerator tables in DWO files in llvm-dwarfdump.
To make this happen, I've needed to make two extra changes in other
classes:
- made the DWARFContext method to lookup a CU based on the section
offset public. I've needed this functionality to lookup a CU, and this
seems like a useful thing in general.
- made DWARFUnit::getDWOId call extractDIEsIfNeeded. Before this, the
DWOId was filled in only if the root DIE happened to be parsed
before we called the accessor. Since the lazy parsing is supposed to
happen under the hood, calling extractDIEsIfNeeded seems appropriate.
Reviewers: JDevlieghere, aprantl, dblaikie
Subscribers: mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D48009
llvm-svn: 334578
2018-06-13 16:14:27 +08:00
|
|
|
static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,
|
|
|
|
StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
|
|
|
|
for (const auto &Entry : Accel.equal_range(Name)) {
|
|
|
|
if (llvm::Optional<uint64_t> Off = Entry.getDIESectionOffset()) {
|
|
|
|
if (DWARFDie Die = DICtx.getDIEForOffset(*Off))
|
|
|
|
Dies.push_back(Die);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWARFDie toDie(const DWARFDebugNames::Entry &Entry,
|
|
|
|
DWARFContext &DICtx) {
|
|
|
|
llvm::Optional<uint64_t> CUOff = Entry.getCUOffset();
|
|
|
|
llvm::Optional<uint64_t> Off = Entry.getDIEUnitOffset();
|
|
|
|
if (!CUOff || !Off)
|
|
|
|
return DWARFDie();
|
|
|
|
|
|
|
|
DWARFCompileUnit *CU = DICtx.getCompileUnitForOffset(*CUOff);
|
|
|
|
if (!CU)
|
|
|
|
return DWARFDie();
|
|
|
|
|
2018-06-13 16:29:19 +08:00
|
|
|
if (llvm::Optional<uint64_t> DWOId = CU->getDWOId()) {
|
[DWARF/AccelTable] Remove getDIESectionOffset for DWARF v5 entries
Summary:
This method was not correct for entries in DWO files as it assumed it
could just add up the CU and DIE offsets to get the absolute DIE offset.
This is not correct for the DWO files, as here the CU offset will
reference the skeleton unit, whereas the DIE offset will be the offset
in the full unit in the DWO file.
Unfortunately, this means that we are not able to determine the absolute
DIE offset using the information in the .debug_names section alone,
which means we have to offload some of this work to the users of this
class.
To demonstrate how this can be done, I've added/fixed the ability to
lookup entries using accelerator tables in DWO files in llvm-dwarfdump.
To make this happen, I've needed to make two extra changes in other
classes:
- made the DWARFContext method to lookup a CU based on the section
offset public. I've needed this functionality to lookup a CU, and this
seems like a useful thing in general.
- made DWARFUnit::getDWOId call extractDIEsIfNeeded. Before this, the
DWOId was filled in only if the root DIE happened to be parsed
before we called the accessor. Since the lazy parsing is supposed to
happen under the hood, calling extractDIEsIfNeeded seems appropriate.
Reviewers: JDevlieghere, aprantl, dblaikie
Subscribers: mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D48009
llvm-svn: 334578
2018-06-13 16:14:27 +08:00
|
|
|
// This is a skeleton unit. Look up the DIE in the DWO unit.
|
|
|
|
CU = DICtx.getDWOCompileUnitForHash(*DWOId);
|
|
|
|
if (!CU)
|
|
|
|
return DWARFDie();
|
|
|
|
}
|
|
|
|
|
|
|
|
return CU->getDIEForOffset(CU->getOffset() + *Off);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void getDies(DWARFContext &DICtx, const DWARFDebugNames &Accel,
|
|
|
|
StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
|
|
|
|
for (const auto &Entry : Accel.equal_range(Name)) {
|
|
|
|
if (DWARFDie Die = toDie(Entry, DICtx))
|
|
|
|
Dies.push_back(Die);
|
|
|
|
}
|
2018-05-31 16:47:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Print only DIEs that have a certain name.
|
|
|
|
static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx,
|
|
|
|
raw_ostream &OS) {
|
[DWARF/AccelTable] Remove getDIESectionOffset for DWARF v5 entries
Summary:
This method was not correct for entries in DWO files as it assumed it
could just add up the CU and DIE offsets to get the absolute DIE offset.
This is not correct for the DWO files, as here the CU offset will
reference the skeleton unit, whereas the DIE offset will be the offset
in the full unit in the DWO file.
Unfortunately, this means that we are not able to determine the absolute
DIE offset using the information in the .debug_names section alone,
which means we have to offload some of this work to the users of this
class.
To demonstrate how this can be done, I've added/fixed the ability to
lookup entries using accelerator tables in DWO files in llvm-dwarfdump.
To make this happen, I've needed to make two extra changes in other
classes:
- made the DWARFContext method to lookup a CU based on the section
offset public. I've needed this functionality to lookup a CU, and this
seems like a useful thing in general.
- made DWARFUnit::getDWOId call extractDIEsIfNeeded. Before this, the
DWOId was filled in only if the root DIE happened to be parsed
before we called the accessor. Since the lazy parsing is supposed to
happen under the hood, calling extractDIEsIfNeeded seems appropriate.
Reviewers: JDevlieghere, aprantl, dblaikie
Subscribers: mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D48009
llvm-svn: 334578
2018-06-13 16:14:27 +08:00
|
|
|
SmallVector<DWARFDie, 4> Dies;
|
2018-05-31 16:47:00 +08:00
|
|
|
for (const auto &Name : Names) {
|
[DWARF/AccelTable] Remove getDIESectionOffset for DWARF v5 entries
Summary:
This method was not correct for entries in DWO files as it assumed it
could just add up the CU and DIE offsets to get the absolute DIE offset.
This is not correct for the DWO files, as here the CU offset will
reference the skeleton unit, whereas the DIE offset will be the offset
in the full unit in the DWO file.
Unfortunately, this means that we are not able to determine the absolute
DIE offset using the information in the .debug_names section alone,
which means we have to offload some of this work to the users of this
class.
To demonstrate how this can be done, I've added/fixed the ability to
lookup entries using accelerator tables in DWO files in llvm-dwarfdump.
To make this happen, I've needed to make two extra changes in other
classes:
- made the DWARFContext method to lookup a CU based on the section
offset public. I've needed this functionality to lookup a CU, and this
seems like a useful thing in general.
- made DWARFUnit::getDWOId call extractDIEsIfNeeded. Before this, the
DWOId was filled in only if the root DIE happened to be parsed
before we called the accessor. Since the lazy parsing is supposed to
happen under the hood, calling extractDIEsIfNeeded seems appropriate.
Reviewers: JDevlieghere, aprantl, dblaikie
Subscribers: mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D48009
llvm-svn: 334578
2018-06-13 16:14:27 +08:00
|
|
|
getDies(DICtx, DICtx.getAppleNames(), Name, Dies);
|
|
|
|
getDies(DICtx, DICtx.getAppleTypes(), Name, Dies);
|
|
|
|
getDies(DICtx, DICtx.getAppleNamespaces(), Name, Dies);
|
|
|
|
getDies(DICtx, DICtx.getDebugNames(), Name, Dies);
|
2018-05-31 16:47:00 +08:00
|
|
|
}
|
llvm::sort(C.begin(), C.end(), ...) -> llvm::sort(C, ...)
Summary: The convenience wrapper in STLExtras is available since rL342102.
Reviewers: dblaikie, javed.absar, JDevlieghere, andreadb
Subscribers: MatzeB, sanjoy, arsenm, dschuff, mehdi_amini, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, eraman, aheejin, kbarton, JDevlieghere, javed.absar, gbedwell, jrtc27, mgrang, atanasyan, steven_wu, george.burgess.iv, dexonsmith, kristina, jsji, llvm-commits
Differential Revision: https://reviews.llvm.org/D52573
llvm-svn: 343163
2018-09-27 10:13:45 +08:00
|
|
|
llvm::sort(Dies);
|
[DWARF/AccelTable] Remove getDIESectionOffset for DWARF v5 entries
Summary:
This method was not correct for entries in DWO files as it assumed it
could just add up the CU and DIE offsets to get the absolute DIE offset.
This is not correct for the DWO files, as here the CU offset will
reference the skeleton unit, whereas the DIE offset will be the offset
in the full unit in the DWO file.
Unfortunately, this means that we are not able to determine the absolute
DIE offset using the information in the .debug_names section alone,
which means we have to offload some of this work to the users of this
class.
To demonstrate how this can be done, I've added/fixed the ability to
lookup entries using accelerator tables in DWO files in llvm-dwarfdump.
To make this happen, I've needed to make two extra changes in other
classes:
- made the DWARFContext method to lookup a CU based on the section
offset public. I've needed this functionality to lookup a CU, and this
seems like a useful thing in general.
- made DWARFUnit::getDWOId call extractDIEsIfNeeded. Before this, the
DWOId was filled in only if the root DIE happened to be parsed
before we called the accessor. Since the lazy parsing is supposed to
happen under the hood, calling extractDIEsIfNeeded seems appropriate.
Reviewers: JDevlieghere, aprantl, dblaikie
Subscribers: mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D48009
llvm-svn: 334578
2018-06-13 16:14:27 +08:00
|
|
|
Dies.erase(std::unique(Dies.begin(), Dies.end()), Dies.end());
|
2018-05-31 16:47:00 +08:00
|
|
|
|
[DWARF/AccelTable] Remove getDIESectionOffset for DWARF v5 entries
Summary:
This method was not correct for entries in DWO files as it assumed it
could just add up the CU and DIE offsets to get the absolute DIE offset.
This is not correct for the DWO files, as here the CU offset will
reference the skeleton unit, whereas the DIE offset will be the offset
in the full unit in the DWO file.
Unfortunately, this means that we are not able to determine the absolute
DIE offset using the information in the .debug_names section alone,
which means we have to offload some of this work to the users of this
class.
To demonstrate how this can be done, I've added/fixed the ability to
lookup entries using accelerator tables in DWO files in llvm-dwarfdump.
To make this happen, I've needed to make two extra changes in other
classes:
- made the DWARFContext method to lookup a CU based on the section
offset public. I've needed this functionality to lookup a CU, and this
seems like a useful thing in general.
- made DWARFUnit::getDWOId call extractDIEsIfNeeded. Before this, the
DWOId was filled in only if the root DIE happened to be parsed
before we called the accessor. Since the lazy parsing is supposed to
happen under the hood, calling extractDIEsIfNeeded seems appropriate.
Reviewers: JDevlieghere, aprantl, dblaikie
Subscribers: mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D48009
llvm-svn: 334578
2018-06-13 16:14:27 +08:00
|
|
|
for (DWARFDie Die : Dies)
|
2018-05-31 16:47:00 +08:00
|
|
|
Die.dump(OS, 0, getDumpOpts());
|
|
|
|
}
|
|
|
|
|
2017-10-26 05:56:41 +08:00
|
|
|
/// Handle the --lookup option and dump the DIEs and line info for the given
|
|
|
|
/// address.
|
2019-02-27 21:17:36 +08:00
|
|
|
/// TODO: specified Address for --lookup option could relate for several
|
|
|
|
/// different sections(in case not-linked object file). llvm-dwarfdump
|
|
|
|
/// need to do something with this: extend lookup option with section
|
|
|
|
/// information or probably display all matched entries, or something else...
|
|
|
|
static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
|
|
|
|
raw_ostream &OS) {
|
2017-10-26 05:56:41 +08:00
|
|
|
auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup);
|
|
|
|
|
|
|
|
if (!DIEsForAddr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
DIDumpOptions DumpOpts = getDumpOpts();
|
2019-05-25 05:11:28 +08:00
|
|
|
DumpOpts.ChildRecurseDepth = 0;
|
2017-10-26 05:56:41 +08:00
|
|
|
DIEsForAddr.CompileUnit->dump(OS, DumpOpts);
|
|
|
|
if (DIEsForAddr.FunctionDIE) {
|
|
|
|
DIEsForAddr.FunctionDIE.dump(OS, 2, DumpOpts);
|
|
|
|
if (DIEsForAddr.BlockDIE)
|
|
|
|
DIEsForAddr.BlockDIE.dump(OS, 4, DumpOpts);
|
|
|
|
}
|
|
|
|
|
2019-02-27 21:17:36 +08:00
|
|
|
// TODO: it is neccessary to set proper SectionIndex here.
|
|
|
|
// object::SectionedAddress::UndefSection works for only absolute addresses.
|
|
|
|
if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
|
|
|
|
{Lookup, object::SectionedAddress::UndefSection}))
|
2017-10-26 05:56:41 +08:00
|
|
|
LineInfo.dump(OS);
|
|
|
|
|
|
|
|
return true;
|
2017-09-30 08:22:25 +08:00
|
|
|
}
|
|
|
|
|
2017-10-07 04:24:34 +08:00
|
|
|
bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
|
|
|
|
Twine Filename, raw_ostream &OS);
|
|
|
|
|
2017-09-22 17:20:57 +08:00
|
|
|
static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
|
|
|
|
raw_ostream &OS) {
|
2018-11-24 01:13:06 +08:00
|
|
|
logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
|
|
|
|
Filename.str() + ": ");
|
2017-09-30 08:22:25 +08:00
|
|
|
// The UUID dump already contains all the same information.
|
|
|
|
if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
|
|
|
|
OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
|
|
|
|
|
2017-10-26 05:56:41 +08:00
|
|
|
// Handle the --lookup option.
|
|
|
|
if (Lookup)
|
2019-02-27 21:17:36 +08:00
|
|
|
return lookup(Obj, DICtx, Lookup, OS);
|
2017-10-26 05:56:41 +08:00
|
|
|
|
2017-09-30 08:22:25 +08:00
|
|
|
// Handle the --name option.
|
|
|
|
if (!Name.empty()) {
|
|
|
|
StringSet<> Names;
|
|
|
|
for (auto name : Name)
|
2017-10-04 06:08:22 +08:00
|
|
|
Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);
|
2017-10-03 00:02:04 +08:00
|
|
|
|
2018-10-25 05:51:55 +08:00
|
|
|
filterByName(Names, DICtx.normal_units(), OS);
|
|
|
|
filterByName(Names, DICtx.dwo_units(), OS);
|
2017-09-30 08:22:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-29 02:10:52 +08:00
|
|
|
// Handle the --find option and lower it to --debug-info=<offset>.
|
|
|
|
if (!Find.empty()) {
|
2018-05-31 16:47:00 +08:00
|
|
|
filterByAccelName(Find, DICtx, OS);
|
|
|
|
return true;
|
2017-09-29 02:10:52 +08:00
|
|
|
}
|
2017-10-03 00:02:04 +08:00
|
|
|
|
2015-08-03 08:10:25 +08:00
|
|
|
// Dump the complete DWARF structure.
|
2017-09-22 17:20:57 +08:00
|
|
|
DICtx.dump(OS, getDumpOpts(), DumpOffsets);
|
2017-09-14 07:07:24 +08:00
|
|
|
return true;
|
2015-08-03 08:10:25 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 00:26:18 +08:00
|
|
|
static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
|
2017-09-22 17:20:57 +08:00
|
|
|
Twine Filename, raw_ostream &OS) {
|
2017-05-02 06:07:02 +08:00
|
|
|
// Verify the DWARF and exit with non-zero exit status if verification
|
|
|
|
// fails.
|
2017-09-22 17:20:57 +08:00
|
|
|
raw_ostream &stream = Quiet ? nulls() : OS;
|
2017-05-02 06:07:02 +08:00
|
|
|
stream << "Verifying " << Filename.str() << ":\tfile format "
|
|
|
|
<< Obj.getFileFormatName() << "\n";
|
2017-09-22 00:26:18 +08:00
|
|
|
bool Result = DICtx.verify(stream, getDumpOpts());
|
2017-05-02 06:07:02 +08:00
|
|
|
if (Result)
|
|
|
|
stream << "No errors.\n";
|
|
|
|
else
|
|
|
|
stream << "Errors detected.\n";
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2017-09-15 01:01:53 +08:00
|
|
|
static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
|
2017-09-22 17:20:57 +08:00
|
|
|
HandlerFn HandleObj, raw_ostream &OS);
|
2017-09-15 01:01:53 +08:00
|
|
|
|
|
|
|
static bool handleArchive(StringRef Filename, Archive &Arch,
|
2017-09-22 17:20:57 +08:00
|
|
|
HandlerFn HandleObj, raw_ostream &OS) {
|
2017-09-15 01:01:53 +08:00
|
|
|
bool Result = true;
|
|
|
|
Error Err = Error::success();
|
|
|
|
for (auto Child : Arch.children(Err)) {
|
|
|
|
auto BuffOrErr = Child.getMemoryBufferRef();
|
|
|
|
error(Filename, errorToErrorCode(BuffOrErr.takeError()));
|
|
|
|
auto NameOrErr = Child.getName();
|
|
|
|
error(Filename, errorToErrorCode(NameOrErr.takeError()));
|
|
|
|
std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
|
2017-09-22 17:20:57 +08:00
|
|
|
Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj, OS);
|
2017-09-15 01:01:53 +08:00
|
|
|
}
|
|
|
|
error(Filename, errorToErrorCode(std::move(Err)));
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2017-09-14 07:16:13 +08:00
|
|
|
static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
|
2017-09-22 17:20:57 +08:00
|
|
|
HandlerFn HandleObj, raw_ostream &OS) {
|
2017-09-14 07:16:13 +08:00
|
|
|
Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
|
2017-09-15 01:01:53 +08:00
|
|
|
error(Filename, errorToErrorCode(BinOrErr.takeError()));
|
2017-09-01 00:44:47 +08:00
|
|
|
|
2017-05-02 06:07:02 +08:00
|
|
|
bool Result = true;
|
2017-09-22 00:26:18 +08:00
|
|
|
if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
|
|
|
|
if (filterArch(*Obj)) {
|
|
|
|
std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
|
2017-09-22 17:20:57 +08:00
|
|
|
Result = HandleObj(*Obj, *DICtx, Filename, OS);
|
2017-09-22 00:26:18 +08:00
|
|
|
}
|
|
|
|
}
|
2017-05-02 06:07:02 +08:00
|
|
|
else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
|
|
|
|
for (auto &ObjForArch : Fat->objects()) {
|
2017-09-15 01:01:53 +08:00
|
|
|
std::string ObjName =
|
|
|
|
(Filename + "(" + ObjForArch.getArchFlagName() + ")").str();
|
|
|
|
if (auto MachOOrErr = ObjForArch.getAsObjectFile()) {
|
2017-09-22 00:26:18 +08:00
|
|
|
auto &Obj = **MachOOrErr;
|
|
|
|
if (filterArch(Obj)) {
|
|
|
|
std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(Obj);
|
2017-09-22 17:20:57 +08:00
|
|
|
Result &= HandleObj(Obj, *DICtx, ObjName, OS);
|
2017-09-22 00:26:18 +08:00
|
|
|
}
|
2017-09-15 01:01:53 +08:00
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
consumeError(MachOOrErr.takeError());
|
|
|
|
if (auto ArchiveOrErr = ObjForArch.getAsArchive()) {
|
|
|
|
error(ObjName, errorToErrorCode(ArchiveOrErr.takeError()));
|
2017-09-22 17:20:57 +08:00
|
|
|
Result &= handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj, OS);
|
2017-09-15 01:01:53 +08:00
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
consumeError(ArchiveOrErr.takeError());
|
2017-05-02 06:07:02 +08:00
|
|
|
}
|
2017-09-15 01:01:53 +08:00
|
|
|
else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get()))
|
2017-09-22 17:20:57 +08:00
|
|
|
Result = handleArchive(Filename, *Arch, HandleObj, OS);
|
2017-05-02 06:07:02 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2017-09-22 17:20:57 +08:00
|
|
|
static bool handleFile(StringRef Filename, HandlerFn HandleObj,
|
|
|
|
raw_ostream &OS) {
|
2017-09-14 07:07:24 +08:00
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
|
|
|
|
MemoryBuffer::getFileOrSTDIN(Filename);
|
|
|
|
error(Filename, BuffOrErr.getError());
|
|
|
|
std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
|
2017-09-22 17:20:57 +08:00
|
|
|
return handleBuffer(Filename, *Buffer, HandleObj, OS);
|
2017-09-14 07:07:24 +08:00
|
|
|
}
|
|
|
|
|
2015-12-24 05:51:13 +08:00
|
|
|
/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
|
|
|
|
/// replace it with individual entries for each of the object files inside the
|
|
|
|
/// bundle otherwise return the input path.
|
2016-06-09 03:09:22 +08:00
|
|
|
static std::vector<std::string> expandBundle(const std::string &InputPath) {
|
2015-12-24 05:51:13 +08:00
|
|
|
std::vector<std::string> BundlePaths;
|
|
|
|
SmallString<256> BundlePath(InputPath);
|
2018-02-09 00:31:01 +08:00
|
|
|
// Normalize input path. This is necessary to accept `bundle.dSYM/`.
|
|
|
|
sys::path::remove_dots(BundlePath);
|
2015-12-24 05:51:13 +08:00
|
|
|
// Manually open up the bundle to avoid introducing additional dependencies.
|
|
|
|
if (sys::fs::is_directory(BundlePath) &&
|
|
|
|
sys::path::extension(BundlePath) == ".dSYM") {
|
|
|
|
std::error_code EC;
|
|
|
|
sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
|
|
|
|
for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;
|
|
|
|
Dir != DirEnd && !EC; Dir.increment(EC)) {
|
|
|
|
const std::string &Path = Dir->path();
|
|
|
|
sys::fs::file_status Status;
|
|
|
|
EC = sys::fs::status(Path, Status);
|
|
|
|
error(Path, EC);
|
|
|
|
switch (Status.type()) {
|
|
|
|
case sys::fs::file_type::regular_file:
|
|
|
|
case sys::fs::file_type::symlink_file:
|
|
|
|
case sys::fs::file_type::type_unknown:
|
|
|
|
BundlePaths.push_back(Path);
|
|
|
|
break;
|
|
|
|
default: /*ignore*/;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error(BundlePath, EC);
|
|
|
|
}
|
|
|
|
if (!BundlePaths.size())
|
|
|
|
BundlePaths.push_back(InputPath);
|
|
|
|
return BundlePaths;
|
|
|
|
}
|
|
|
|
|
2011-09-14 03:42:23 +08:00
|
|
|
int main(int argc, char **argv) {
|
2018-04-14 02:26:06 +08:00
|
|
|
InitLLVM X(argc, argv);
|
2011-09-14 03:42:23 +08:00
|
|
|
|
[dwarfdump] Pretty print location expressions and location lists
Summary:
Based on Fred's patch here: https://reviews.llvm.org/D6771
I can't seem to commandeer the old review, so I'm creating a new one.
With that change the locations exrpessions are pretty printed inline in the
DIE tree. The output looks like this for debug_loc entries:
DW_AT_location [DW_FORM_data4] (0x00000000
0x0000000000000001 - 0x000000000000000b: DW_OP_consts +3
0x000000000000000b - 0x0000000000000012: DW_OP_consts +7
0x0000000000000012 - 0x000000000000001b: DW_OP_reg0 RAX, DW_OP_piece 0x4
0x000000000000001b - 0x0000000000000024: DW_OP_breg5 RDI+0)
And like this for debug_loc.dwo entries:
DW_AT_location [DW_FORM_sec_offset] (0x00000000
Addr idx 2 (w/ length 190): DW_OP_consts +0, DW_OP_stack_value
Addr idx 3 (w/ length 23): DW_OP_reg0 RAX, DW_OP_piece 0x4)
Simple locations without ranges are printed inline:
DW_AT_location [DW_FORM_block1] (DW_OP_reg4 RSI, DW_OP_piece 0x4, DW_OP_bit_piece 0x20 0x0)
The debug_loc(.dwo) dumping in changed accordingly to factor the code.
Reviewers: dblaikie, aprantl, friss
Subscribers: mgorny, javed.absar, hiraditya, llvm-commits, JDevlieghere
Differential Revision: https://reviews.llvm.org/D37123
llvm-svn: 312042
2017-08-30 05:41:21 +08:00
|
|
|
llvm::InitializeAllTargetInfos();
|
|
|
|
llvm::InitializeAllTargetMCs();
|
|
|
|
|
2018-05-24 19:36:57 +08:00
|
|
|
HideUnrelatedOptions({&DwarfDumpCategory, &SectionCategory, &ColorCategory});
|
2017-09-13 06:32:53 +08:00
|
|
|
cl::ParseCommandLineOptions(
|
|
|
|
argc, argv,
|
|
|
|
"pretty-print DWARF debug information in object files"
|
|
|
|
" and debug info archives.\n");
|
|
|
|
|
2018-10-24 05:51:44 +08:00
|
|
|
// FIXME: Audit interactions between these two options and make them
|
|
|
|
// compatible.
|
|
|
|
if (Diff && Verbose) {
|
|
|
|
WithColor::error() << "incompatible arguments: specifying both -diff and "
|
|
|
|
"-verbose is currently not supported";
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-27 16:19:36 +08:00
|
|
|
std::error_code EC;
|
2019-10-08 16:21:20 +08:00
|
|
|
ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_Text);
|
2019-03-27 16:19:36 +08:00
|
|
|
error("Unable to open output file" + OutputFilename, EC);
|
|
|
|
// Don't remove output file if we exit with an error.
|
|
|
|
OutputFile.keep();
|
2017-09-22 17:20:57 +08:00
|
|
|
|
2017-11-29 09:12:22 +08:00
|
|
|
bool OffsetRequested = false;
|
2017-09-22 17:20:57 +08:00
|
|
|
|
2017-09-01 00:44:47 +08:00
|
|
|
// Defaults to dumping all sections, unless brief mode is specified in which
|
|
|
|
// case only the .debug_info section in dumped.
|
2017-09-12 06:59:45 +08:00
|
|
|
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
|
2017-09-16 07:04:04 +08:00
|
|
|
if (Dump##ENUM_NAME.IsRequested) { \
|
|
|
|
DumpType |= DIDT_##ENUM_NAME; \
|
2017-11-29 09:12:22 +08:00
|
|
|
if (Dump##ENUM_NAME.HasValue) { \
|
2017-09-16 07:04:04 +08:00
|
|
|
DumpOffsets[DIDT_ID_##ENUM_NAME] = Dump##ENUM_NAME.Val; \
|
2017-11-29 09:12:22 +08:00
|
|
|
OffsetRequested = true; \
|
|
|
|
} \
|
2017-09-16 07:04:04 +08:00
|
|
|
}
|
2017-09-12 06:59:45 +08:00
|
|
|
#include "llvm/BinaryFormat/Dwarf.def"
|
|
|
|
#undef HANDLE_DWARF_SECTION
|
2017-09-14 02:22:59 +08:00
|
|
|
if (DumpUUID)
|
|
|
|
DumpType |= DIDT_UUID;
|
2017-09-12 06:59:45 +08:00
|
|
|
if (DumpAll)
|
|
|
|
DumpType = DIDT_All;
|
2017-09-01 00:44:47 +08:00
|
|
|
if (DumpType == DIDT_Null) {
|
2017-09-12 07:05:20 +08:00
|
|
|
if (Verbose)
|
2017-09-01 00:44:47 +08:00
|
|
|
DumpType = DIDT_All;
|
2017-09-12 07:05:20 +08:00
|
|
|
else
|
|
|
|
DumpType = DIDT_DebugInfo;
|
2017-09-01 00:44:47 +08:00
|
|
|
}
|
|
|
|
|
2017-11-29 09:12:22 +08:00
|
|
|
// Unless dumping a specific DIE, default to --show-children.
|
|
|
|
if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() && Find.empty())
|
|
|
|
ShowChildren = true;
|
|
|
|
|
2011-09-14 03:42:23 +08:00
|
|
|
// Defaults to a.out if no filenames specified.
|
2018-05-08 14:21:12 +08:00
|
|
|
if (InputFilenames.empty())
|
2011-09-14 03:42:23 +08:00
|
|
|
InputFilenames.push_back("a.out");
|
|
|
|
|
2015-12-24 05:51:13 +08:00
|
|
|
// Expand any .dSYM bundles to the individual object files contained therein.
|
|
|
|
std::vector<std::string> Objects;
|
2016-05-27 20:30:51 +08:00
|
|
|
for (const auto &F : InputFilenames) {
|
2015-12-24 05:51:13 +08:00
|
|
|
auto Objs = expandBundle(F);
|
|
|
|
Objects.insert(Objects.end(), Objs.begin(), Objs.end());
|
|
|
|
}
|
|
|
|
|
2017-05-02 06:07:02 +08:00
|
|
|
if (Verify) {
|
|
|
|
// If we encountered errors during verify, exit with a non-zero exit status.
|
2018-10-19 14:12:02 +08:00
|
|
|
if (!all_of(Objects, [&](std::string Object) {
|
2019-03-27 16:19:36 +08:00
|
|
|
return handleFile(Object, verifyObjectFile, OutputFile.os());
|
2017-09-14 07:07:24 +08:00
|
|
|
}))
|
2019-03-27 16:19:36 +08:00
|
|
|
return 1;
|
2017-10-07 04:24:34 +08:00
|
|
|
} else if (Statistics)
|
|
|
|
for (auto Object : Objects)
|
2019-03-27 16:19:36 +08:00
|
|
|
handleFile(Object, collectStatsForObjectFile, OutputFile.os());
|
2017-10-07 04:24:34 +08:00
|
|
|
else
|
2017-09-19 06:11:33 +08:00
|
|
|
for (auto Object : Objects)
|
2019-03-27 16:19:36 +08:00
|
|
|
handleFile(Object, dumpObjectFile, OutputFile.os());
|
2011-09-14 03:42:23 +08:00
|
|
|
|
2015-07-26 13:35:59 +08:00
|
|
|
return EXIT_SUCCESS;
|
2011-09-14 03:42:23 +08:00
|
|
|
}
|