aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-symbolizer
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/tools/llvm-symbolizer
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
downloadsrc-344a3780b2e33f6ca763666c380202b18aab72a3.tar.gz
src-344a3780b2e33f6ca763666c380202b18aab72a3.zip
the upstream release/13.x branch was created.
Diffstat (limited to 'llvm/tools/llvm-symbolizer')
-rw-r--r--llvm/tools/llvm-symbolizer/Opts.td27
-rw-r--r--llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp134
2 files changed, 93 insertions, 68 deletions
diff --git a/llvm/tools/llvm-symbolizer/Opts.td b/llvm/tools/llvm-symbolizer/Opts.td
index ac23639f130e..6026e24d6ffa 100644
--- a/llvm/tools/llvm-symbolizer/Opts.td
+++ b/llvm/tools/llvm-symbolizer/Opts.td
@@ -1,17 +1,20 @@
include "llvm/Option/OptParser.td"
multiclass B<string name, string help1, string help2> {
- def NAME: Flag<["--", "-"], name>, HelpText<help1>;
- def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
+ def NAME: Flag<["--"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--"], "no-" # name>, HelpText<help2>;
}
multiclass Eq<string name, string help> {
- def NAME #_EQ : Joined<["--", "-"], name #"=">,
+ def NAME #_EQ : Joined<["--"], name #"=">,
HelpText<help>;
- def : Separate<["--", "-"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
+ def : Separate<["--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
}
-class F<string name, string help>: Flag<["--", "-"], name>, HelpText<help>;
+class F<string name, string help>: Flag<["--"], name>, HelpText<help>;
+
+def grp_mach_o : OptionGroup<"kind">,
+ HelpText<"llvm-symbolizer Mach-O Specific Options">;
def addresses : F<"addresses", "Show address before line information">;
defm adjust_vma
@@ -19,13 +22,19 @@ defm adjust_vma
MetaVarName<"<offset>">;
def basenames : Flag<["--"], "basenames">, HelpText<"Strip directory names from paths">;
defm debug_file_directory : Eq<"debug-file-directory", "Path to directory where to look for debug files">, MetaVarName<"<dir>">;
-defm default_arch : Eq<"default-arch", "Default architecture (for multi-arch objects)">;
+defm default_arch
+ : Eq<"default-arch", "Default architecture (for multi-arch objects)">,
+ Group<grp_mach_o>;
defm demangle : B<"demangle", "Demangle function names", "Don't demangle function names">;
def functions : F<"functions", "Print function name for a given address">;
def functions_EQ : Joined<["--"], "functions=">, HelpText<"Print function name for a given address">, Values<"none,short,linkage">;
def help : F<"help", "Display this help">;
defm dwp : Eq<"dwp", "Path to DWP file to be use for any split CUs">, MetaVarName<"<file>">;
-defm dsym_hint : Eq<"dsym-hint", "Path to .dSYM bundles to search for debug info for the object files">, MetaVarName<"<dir>">;
+defm dsym_hint
+ : Eq<"dsym-hint",
+ "Path to .dSYM bundles to search for debug info for the object files">,
+ MetaVarName<"<dir>">,
+ Group<grp_mach_o>;
defm fallback_debug_path : Eq<"fallback-debug-path", "Fallback path for debug binaries">, MetaVarName<"<dir>">;
defm inlines : B<"inlines", "Print all inlined frames for a given address",
"Do not print inlined frames">;
@@ -33,9 +42,9 @@ defm obj
: Eq<"obj", "Path to object file to be symbolized (if not provided, "
"object file should be specified for each input line)">, MetaVarName<"<file>">;
defm output_style
- : Eq<"output-style", "Specify print style. Supported styles: LLVM, GNU">,
+ : Eq<"output-style", "Specify print style. Supported styles: LLVM, GNU, JSON">,
MetaVarName<"style">,
- Values<"LLVM,GNU">;
+ Values<"LLVM,GNU,JSON">;
def pretty_print : F<"pretty-print", "Make the output more human friendly">;
defm print_source_context_lines : Eq<"print-source-context-lines", "Print N lines of source file context">;
def relative_address : F<"relative-address", "Interpret addresses as addresses relative to the image base">;
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 9c68acee0ae2..227ce12a6d9a 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -66,23 +66,35 @@ static const opt::OptTable::Info InfoTable[] = {
class SymbolizerOptTable : public opt::OptTable {
public:
- SymbolizerOptTable() : OptTable(InfoTable, true) {}
+ SymbolizerOptTable() : OptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
};
} // namespace
-static cl::list<std::string> ClInputAddresses(cl::Positional,
- cl::desc("<input addresses>..."),
- cl::ZeroOrMore);
+template <typename T>
+static void print(const Request &Request, Expected<T> &ResOrErr,
+ DIPrinter &Printer) {
+ if (ResOrErr) {
+ // No error, print the result.
+ Printer.print(Request, *ResOrErr);
+ return;
+ }
+
+ // Handle the error.
+ bool PrintEmpty = true;
+ handleAllErrors(std::move(ResOrErr.takeError()),
+ [&](const ErrorInfoBase &EI) {
+ PrintEmpty = Printer.printError(
+ Request, EI, "LLVMSymbolizer: error reading file: ");
+ });
-template<typename T>
-static bool error(Expected<T> &ResOrErr) {
- if (ResOrErr)
- return false;
- logAllUnhandledErrors(ResOrErr.takeError(), errs(),
- "LLVMSymbolizer: error reading file: ");
- return true;
+ if (PrintEmpty)
+ Printer.print(Request, T());
}
+enum class OutputStyle { LLVM, GNU, JSON };
+
enum class Command {
Code,
Data,
@@ -136,7 +148,7 @@ static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
}
static void symbolizeInput(const opt::InputArgList &Args, uint64_t AdjustVMA,
- bool IsAddr2Line, DIPrinter::OutputStyle OutputStyle,
+ bool IsAddr2Line, OutputStyle Style,
StringRef InputString, LLVMSymbolizer &Symbolizer,
DIPrinter &Printer) {
Command Cmd;
@@ -144,57 +156,49 @@ static void symbolizeInput(const opt::InputArgList &Args, uint64_t AdjustVMA,
uint64_t Offset = 0;
if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
StringRef(InputString), Cmd, ModuleName, Offset)) {
- outs() << InputString << "\n";
+ Printer.printInvalidCommand({ModuleName, None}, InputString);
return;
}
- if (Args.hasArg(OPT_addresses)) {
- outs() << "0x";
- outs().write_hex(Offset);
- StringRef Delimiter = Args.hasArg(OPT_pretty_print) ? ": " : "\n";
- outs() << Delimiter;
- }
- Offset -= AdjustVMA;
+ uint64_t AdjustedOffset = Offset - AdjustVMA;
if (Cmd == Command::Data) {
- auto ResOrErr = Symbolizer.symbolizeData(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
+ Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(
+ ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
+ print({ModuleName, Offset}, ResOrErr, Printer);
} else if (Cmd == Command::Frame) {
- auto ResOrErr = Symbolizer.symbolizeFrame(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- if (!error(ResOrErr)) {
- for (DILocal Local : *ResOrErr)
- Printer << Local;
- if (ResOrErr->empty())
- outs() << "??\n";
- }
+ Expected<std::vector<DILocal>> ResOrErr = Symbolizer.symbolizeFrame(
+ ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
+ print({ModuleName, Offset}, ResOrErr, Printer);
} else if (Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line)) {
- auto ResOrErr = Symbolizer.symbolizeInlinedCode(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get());
- } else if (OutputStyle == DIPrinter::OutputStyle::GNU) {
+ Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
+ print({ModuleName, Offset}, ResOrErr, Printer);
+ } else if (Style == OutputStyle::GNU) {
// With PrintFunctions == FunctionNameKind::LinkageName (default)
// and UseSymbolTable == true (also default), Symbolizer.symbolizeCode()
// may override the name of an inlined function with the name of the topmost
// caller function in the inlining chain. This contradicts the existing
// behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
// the topmost function, which suits our needs better.
- auto ResOrErr = Symbolizer.symbolizeInlinedCode(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get().getFrame(0));
+ Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
+ Expected<DILineInfo> Res0OrErr =
+ !ResOrErr
+ ? Expected<DILineInfo>(ResOrErr.takeError())
+ : ((ResOrErr->getNumberOfFrames() == 0) ? DILineInfo()
+ : ResOrErr->getFrame(0));
+ print({ModuleName, Offset}, Res0OrErr, Printer);
} else {
- auto ResOrErr = Symbolizer.symbolizeCode(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
+ Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(
+ ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
+ print({ModuleName, Offset}, ResOrErr, Printer);
}
- if (OutputStyle == DIPrinter::OutputStyle::LLVM)
- outs() << "\n";
}
static void printHelp(StringRef ToolName, const SymbolizerOptTable &Tbl,
raw_ostream &OS) {
const char HelpText[] = " [options] addresses...";
- Tbl.PrintHelp(OS, (ToolName + HelpText).str().c_str(),
+ Tbl.printHelp(OS, (ToolName + HelpText).str().c_str(),
ToolName.str().c_str());
// TODO Replace this with OptTable API once it adds extrahelp support.
OS << "\nPass @FILE as argument to read options from FILE.\n";
@@ -204,7 +208,6 @@ static opt::InputArgList parseOptions(int Argc, char *Argv[], bool IsAddr2Line,
StringSaver &Saver,
SymbolizerOptTable &Tbl) {
StringRef ToolName = IsAddr2Line ? "llvm-addr2line" : "llvm-symbolizer";
- Tbl.setGroupedShortOptions(true);
// The environment variable specifies initial options which can be overridden
// by commnad line options.
Tbl.setInitialOptionsFromEnvironment(IsAddr2Line ? "LLVM_ADDR2LINE_OPTS"
@@ -268,7 +271,7 @@ int main(int argc, char **argv) {
LLVMSymbolizer::Options Opts;
uint64_t AdjustVMA;
- unsigned SourceContextLines;
+ PrinterConfig Config;
parseIntArg(Args, OPT_adjust_vma_EQ, AdjustVMA);
if (const opt::Arg *A = Args.getLastArg(OPT_basenames, OPT_relativenames)) {
Opts.PathStyle =
@@ -285,7 +288,8 @@ int main(int argc, char **argv) {
Opts.FallbackDebugPath =
Args.getLastArgValue(OPT_fallback_debug_path_EQ).str();
Opts.PrintFunctions = decideHowToPrintFunctions(Args, IsAddr2Line);
- parseIntArg(Args, OPT_print_source_context_lines_EQ, SourceContextLines);
+ parseIntArg(Args, OPT_print_source_context_lines_EQ,
+ Config.SourceContextLines);
Opts.RelativeAddresses = Args.hasArg(OPT_relative_address);
Opts.UntagAddresses =
Args.hasFlag(OPT_untag_addresses, OPT_no_untag_addresses, !IsAddr2Line);
@@ -297,6 +301,10 @@ int main(int argc, char **argv) {
}
#endif
Opts.UseSymbolTable = true;
+ Config.PrintAddress = Args.hasArg(OPT_addresses);
+ Config.PrintFunctions = Opts.PrintFunctions != FunctionNameKind::None;
+ Config.Pretty = Args.hasArg(OPT_pretty_print);
+ Config.Verbose = Args.hasArg(OPT_verbose);
for (const opt::Arg *A : Args.filtered(OPT_dsym_hint_EQ)) {
StringRef Hint(A->getValue());
@@ -308,18 +316,24 @@ int main(int argc, char **argv) {
}
}
- auto OutputStyle =
- IsAddr2Line ? DIPrinter::OutputStyle::GNU : DIPrinter::OutputStyle::LLVM;
+ auto Style = IsAddr2Line ? OutputStyle::GNU : OutputStyle::LLVM;
if (const opt::Arg *A = Args.getLastArg(OPT_output_style_EQ)) {
- OutputStyle = strcmp(A->getValue(), "GNU") == 0
- ? DIPrinter::OutputStyle::GNU
- : DIPrinter::OutputStyle::LLVM;
+ if (strcmp(A->getValue(), "GNU") == 0)
+ Style = OutputStyle::GNU;
+ else if (strcmp(A->getValue(), "JSON") == 0)
+ Style = OutputStyle::JSON;
+ else
+ Style = OutputStyle::LLVM;
}
LLVMSymbolizer Symbolizer(Opts);
- DIPrinter Printer(outs(), Opts.PrintFunctions != FunctionNameKind::None,
- Args.hasArg(OPT_pretty_print), SourceContextLines,
- Args.hasArg(OPT_verbose), OutputStyle);
+ std::unique_ptr<DIPrinter> Printer;
+ if (Style == OutputStyle::GNU)
+ Printer = std::make_unique<GNUPrinter>(outs(), errs(), Config);
+ else if (Style == OutputStyle::JSON)
+ Printer = std::make_unique<JSONPrinter>(outs(), Config);
+ else
+ Printer = std::make_unique<LLVMPrinter>(outs(), errs(), Config);
std::vector<std::string> InputAddresses = Args.getAllArgValues(OPT_INPUT);
if (InputAddresses.empty()) {
@@ -331,14 +345,16 @@ int main(int argc, char **argv) {
std::string StrippedInputString(InputString);
llvm::erase_if(StrippedInputString,
[](char c) { return c == '\r' || c == '\n'; });
- symbolizeInput(Args, AdjustVMA, IsAddr2Line, OutputStyle,
- StrippedInputString, Symbolizer, Printer);
+ symbolizeInput(Args, AdjustVMA, IsAddr2Line, Style, StrippedInputString,
+ Symbolizer, *Printer);
outs().flush();
}
} else {
+ Printer->listBegin();
for (StringRef Address : InputAddresses)
- symbolizeInput(Args, AdjustVMA, IsAddr2Line, OutputStyle, Address,
- Symbolizer, Printer);
+ symbolizeInput(Args, AdjustVMA, IsAddr2Line, Style, Address, Symbolizer,
+ *Printer);
+ Printer->listEnd();
}
return 0;