aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp')
-rw-r--r--llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp134
1 files changed, 75 insertions, 59 deletions
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;