xref: /netbsd-src/external/apache2/llvm/dist/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This utility works much like "addr2line". It is able of transforming
107330f729Sjoerg // tuples (module name, module offset) to code locations (function name,
117330f729Sjoerg // file, line number, column number). It is targeted for compiler-rt tools
127330f729Sjoerg // (especially AddressSanitizer and ThreadSanitizer) that can use it
137330f729Sjoerg // to symbolize stack traces in their error reports.
147330f729Sjoerg //
157330f729Sjoerg //===----------------------------------------------------------------------===//
167330f729Sjoerg 
17*82d56013Sjoerg #include "Opts.inc"
187330f729Sjoerg #include "llvm/ADT/StringRef.h"
19*82d56013Sjoerg #include "llvm/Config/config.h"
207330f729Sjoerg #include "llvm/DebugInfo/Symbolize/DIPrinter.h"
217330f729Sjoerg #include "llvm/DebugInfo/Symbolize/Symbolize.h"
22*82d56013Sjoerg #include "llvm/Option/Arg.h"
23*82d56013Sjoerg #include "llvm/Option/ArgList.h"
24*82d56013Sjoerg #include "llvm/Option/Option.h"
257330f729Sjoerg #include "llvm/Support/COM.h"
267330f729Sjoerg #include "llvm/Support/CommandLine.h"
277330f729Sjoerg #include "llvm/Support/Debug.h"
287330f729Sjoerg #include "llvm/Support/FileSystem.h"
297330f729Sjoerg #include "llvm/Support/InitLLVM.h"
307330f729Sjoerg #include "llvm/Support/Path.h"
31*82d56013Sjoerg #include "llvm/Support/StringSaver.h"
327330f729Sjoerg #include "llvm/Support/raw_ostream.h"
33*82d56013Sjoerg #include <algorithm>
347330f729Sjoerg #include <cstdio>
357330f729Sjoerg #include <cstring>
367330f729Sjoerg #include <string>
377330f729Sjoerg 
387330f729Sjoerg using namespace llvm;
397330f729Sjoerg using namespace symbolize;
407330f729Sjoerg 
41*82d56013Sjoerg namespace {
42*82d56013Sjoerg enum ID {
43*82d56013Sjoerg   OPT_INVALID = 0, // This is not an option ID.
44*82d56013Sjoerg #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
45*82d56013Sjoerg                HELPTEXT, METAVAR, VALUES)                                      \
46*82d56013Sjoerg   OPT_##ID,
47*82d56013Sjoerg #include "Opts.inc"
48*82d56013Sjoerg #undef OPTION
49*82d56013Sjoerg };
507330f729Sjoerg 
51*82d56013Sjoerg #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
52*82d56013Sjoerg #include "Opts.inc"
53*82d56013Sjoerg #undef PREFIX
547330f729Sjoerg 
55*82d56013Sjoerg static const opt::OptTable::Info InfoTable[] = {
56*82d56013Sjoerg #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
57*82d56013Sjoerg                HELPTEXT, METAVAR, VALUES)                                      \
58*82d56013Sjoerg   {                                                                            \
59*82d56013Sjoerg       PREFIX,      NAME,      HELPTEXT,                                        \
60*82d56013Sjoerg       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
61*82d56013Sjoerg       PARAM,       FLAGS,     OPT_##GROUP,                                     \
62*82d56013Sjoerg       OPT_##ALIAS, ALIASARGS, VALUES},
63*82d56013Sjoerg #include "Opts.inc"
64*82d56013Sjoerg #undef OPTION
65*82d56013Sjoerg };
667330f729Sjoerg 
67*82d56013Sjoerg class SymbolizerOptTable : public opt::OptTable {
68*82d56013Sjoerg public:
SymbolizerOptTable()69*82d56013Sjoerg   SymbolizerOptTable() : OptTable(InfoTable, true) {}
70*82d56013Sjoerg };
71*82d56013Sjoerg } // namespace
727330f729Sjoerg 
737330f729Sjoerg template <typename T>
print(const Request & Request,Expected<T> & ResOrErr,DIPrinter & Printer)74*82d56013Sjoerg static void print(const Request &Request, Expected<T> &ResOrErr,
75*82d56013Sjoerg                   DIPrinter &Printer) {
76*82d56013Sjoerg   if (ResOrErr) {
77*82d56013Sjoerg     // No error, print the result.
78*82d56013Sjoerg     Printer.print(Request, *ResOrErr);
79*82d56013Sjoerg     return;
807330f729Sjoerg   }
817330f729Sjoerg 
82*82d56013Sjoerg   // Handle the error.
83*82d56013Sjoerg   bool PrintEmpty = true;
84*82d56013Sjoerg   handleAllErrors(std::move(ResOrErr.takeError()),
85*82d56013Sjoerg                   [&](const ErrorInfoBase &EI) {
86*82d56013Sjoerg                     PrintEmpty = Printer.printError(
87*82d56013Sjoerg                         Request, EI, "LLVMSymbolizer: error reading file: ");
88*82d56013Sjoerg                   });
89*82d56013Sjoerg 
90*82d56013Sjoerg   if (PrintEmpty)
91*82d56013Sjoerg     Printer.print(Request, T());
92*82d56013Sjoerg }
93*82d56013Sjoerg 
94*82d56013Sjoerg enum class OutputStyle { LLVM, GNU, JSON };
95*82d56013Sjoerg 
967330f729Sjoerg enum class Command {
977330f729Sjoerg   Code,
987330f729Sjoerg   Data,
997330f729Sjoerg   Frame,
1007330f729Sjoerg };
1017330f729Sjoerg 
parseCommand(StringRef BinaryName,bool IsAddr2Line,StringRef InputString,Command & Cmd,std::string & ModuleName,uint64_t & ModuleOffset)102*82d56013Sjoerg static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
103*82d56013Sjoerg                          StringRef InputString, Command &Cmd,
1047330f729Sjoerg                          std::string &ModuleName, uint64_t &ModuleOffset) {
1057330f729Sjoerg   const char kDelimiters[] = " \n\r";
1067330f729Sjoerg   ModuleName = "";
1077330f729Sjoerg   if (InputString.consume_front("CODE ")) {
1087330f729Sjoerg     Cmd = Command::Code;
1097330f729Sjoerg   } else if (InputString.consume_front("DATA ")) {
1107330f729Sjoerg     Cmd = Command::Data;
1117330f729Sjoerg   } else if (InputString.consume_front("FRAME ")) {
1127330f729Sjoerg     Cmd = Command::Frame;
1137330f729Sjoerg   } else {
1147330f729Sjoerg     // If no cmd, assume it's CODE.
1157330f729Sjoerg     Cmd = Command::Code;
1167330f729Sjoerg   }
117*82d56013Sjoerg   const char *Pos = InputString.data();
1187330f729Sjoerg   // Skip delimiters and parse input filename (if needed).
119*82d56013Sjoerg   if (BinaryName.empty()) {
120*82d56013Sjoerg     Pos += strspn(Pos, kDelimiters);
121*82d56013Sjoerg     if (*Pos == '"' || *Pos == '\'') {
122*82d56013Sjoerg       char Quote = *Pos;
123*82d56013Sjoerg       Pos++;
124*82d56013Sjoerg       const char *End = strchr(Pos, Quote);
125*82d56013Sjoerg       if (!End)
1267330f729Sjoerg         return false;
127*82d56013Sjoerg       ModuleName = std::string(Pos, End - Pos);
128*82d56013Sjoerg       Pos = End + 1;
1297330f729Sjoerg     } else {
130*82d56013Sjoerg       int NameLength = strcspn(Pos, kDelimiters);
131*82d56013Sjoerg       ModuleName = std::string(Pos, NameLength);
132*82d56013Sjoerg       Pos += NameLength;
1337330f729Sjoerg     }
1347330f729Sjoerg   } else {
135*82d56013Sjoerg     ModuleName = BinaryName.str();
1367330f729Sjoerg   }
1377330f729Sjoerg   // Skip delimiters and parse module offset.
138*82d56013Sjoerg   Pos += strspn(Pos, kDelimiters);
139*82d56013Sjoerg   int OffsetLength = strcspn(Pos, kDelimiters);
140*82d56013Sjoerg   StringRef Offset(Pos, OffsetLength);
141*82d56013Sjoerg   // GNU addr2line assumes the offset is hexadecimal and allows a redundant
142*82d56013Sjoerg   // "0x" or "0X" prefix; do the same for compatibility.
143*82d56013Sjoerg   if (IsAddr2Line)
144*82d56013Sjoerg     Offset.consume_front("0x") || Offset.consume_front("0X");
145*82d56013Sjoerg   return !Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset);
1467330f729Sjoerg }
1477330f729Sjoerg 
symbolizeInput(const opt::InputArgList & Args,uint64_t AdjustVMA,bool IsAddr2Line,OutputStyle Style,StringRef InputString,LLVMSymbolizer & Symbolizer,DIPrinter & Printer)148*82d56013Sjoerg static void symbolizeInput(const opt::InputArgList &Args, uint64_t AdjustVMA,
149*82d56013Sjoerg                            bool IsAddr2Line, OutputStyle Style,
150*82d56013Sjoerg                            StringRef InputString, LLVMSymbolizer &Symbolizer,
1517330f729Sjoerg                            DIPrinter &Printer) {
1527330f729Sjoerg   Command Cmd;
1537330f729Sjoerg   std::string ModuleName;
1547330f729Sjoerg   uint64_t Offset = 0;
155*82d56013Sjoerg   if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
156*82d56013Sjoerg                     StringRef(InputString), Cmd, ModuleName, Offset)) {
157*82d56013Sjoerg     Printer.printInvalidCommand({ModuleName, None}, InputString);
1587330f729Sjoerg     return;
1597330f729Sjoerg   }
1607330f729Sjoerg 
161*82d56013Sjoerg   uint64_t AdjustedOffset = Offset - AdjustVMA;
1627330f729Sjoerg   if (Cmd == Command::Data) {
163*82d56013Sjoerg     Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(
164*82d56013Sjoerg         ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
165*82d56013Sjoerg     print({ModuleName, Offset}, ResOrErr, Printer);
1667330f729Sjoerg   } else if (Cmd == Command::Frame) {
167*82d56013Sjoerg     Expected<std::vector<DILocal>> ResOrErr = Symbolizer.symbolizeFrame(
168*82d56013Sjoerg         ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
169*82d56013Sjoerg     print({ModuleName, Offset}, ResOrErr, Printer);
170*82d56013Sjoerg   } else if (Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line)) {
171*82d56013Sjoerg     Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(
172*82d56013Sjoerg         ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
173*82d56013Sjoerg     print({ModuleName, Offset}, ResOrErr, Printer);
174*82d56013Sjoerg   } else if (Style == OutputStyle::GNU) {
175*82d56013Sjoerg     // With PrintFunctions == FunctionNameKind::LinkageName (default)
176*82d56013Sjoerg     // and UseSymbolTable == true (also default), Symbolizer.symbolizeCode()
1777330f729Sjoerg     // may override the name of an inlined function with the name of the topmost
1787330f729Sjoerg     // caller function in the inlining chain. This contradicts the existing
1797330f729Sjoerg     // behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
1807330f729Sjoerg     // the topmost function, which suits our needs better.
181*82d56013Sjoerg     Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(
182*82d56013Sjoerg         ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
183*82d56013Sjoerg     Expected<DILineInfo> Res0OrErr =
184*82d56013Sjoerg         !ResOrErr
185*82d56013Sjoerg             ? Expected<DILineInfo>(ResOrErr.takeError())
186*82d56013Sjoerg             : ((ResOrErr->getNumberOfFrames() == 0) ? DILineInfo()
187*82d56013Sjoerg                                                     : ResOrErr->getFrame(0));
188*82d56013Sjoerg     print({ModuleName, Offset}, Res0OrErr, Printer);
1897330f729Sjoerg   } else {
190*82d56013Sjoerg     Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(
191*82d56013Sjoerg         ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
192*82d56013Sjoerg     print({ModuleName, Offset}, ResOrErr, Printer);
1937330f729Sjoerg   }
194*82d56013Sjoerg }
195*82d56013Sjoerg 
printHelp(StringRef ToolName,const SymbolizerOptTable & Tbl,raw_ostream & OS)196*82d56013Sjoerg static void printHelp(StringRef ToolName, const SymbolizerOptTable &Tbl,
197*82d56013Sjoerg                       raw_ostream &OS) {
198*82d56013Sjoerg   const char HelpText[] = " [options] addresses...";
199*82d56013Sjoerg   Tbl.PrintHelp(OS, (ToolName + HelpText).str().c_str(),
200*82d56013Sjoerg                 ToolName.str().c_str());
201*82d56013Sjoerg   // TODO Replace this with OptTable API once it adds extrahelp support.
202*82d56013Sjoerg   OS << "\nPass @FILE as argument to read options from FILE.\n";
203*82d56013Sjoerg }
204*82d56013Sjoerg 
parseOptions(int Argc,char * Argv[],bool IsAddr2Line,StringSaver & Saver,SymbolizerOptTable & Tbl)205*82d56013Sjoerg static opt::InputArgList parseOptions(int Argc, char *Argv[], bool IsAddr2Line,
206*82d56013Sjoerg                                       StringSaver &Saver,
207*82d56013Sjoerg                                       SymbolizerOptTable &Tbl) {
208*82d56013Sjoerg   StringRef ToolName = IsAddr2Line ? "llvm-addr2line" : "llvm-symbolizer";
209*82d56013Sjoerg   Tbl.setGroupedShortOptions(true);
210*82d56013Sjoerg   // The environment variable specifies initial options which can be overridden
211*82d56013Sjoerg   // by commnad line options.
212*82d56013Sjoerg   Tbl.setInitialOptionsFromEnvironment(IsAddr2Line ? "LLVM_ADDR2LINE_OPTS"
213*82d56013Sjoerg                                                    : "LLVM_SYMBOLIZER_OPTS");
214*82d56013Sjoerg   bool HasError = false;
215*82d56013Sjoerg   opt::InputArgList Args =
216*82d56013Sjoerg       Tbl.parseArgs(Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
217*82d56013Sjoerg         errs() << ("error: " + Msg + "\n");
218*82d56013Sjoerg         HasError = true;
219*82d56013Sjoerg       });
220*82d56013Sjoerg   if (HasError)
221*82d56013Sjoerg     exit(1);
222*82d56013Sjoerg   if (Args.hasArg(OPT_help)) {
223*82d56013Sjoerg     printHelp(ToolName, Tbl, outs());
224*82d56013Sjoerg     exit(0);
225*82d56013Sjoerg   }
226*82d56013Sjoerg   if (Args.hasArg(OPT_version)) {
227*82d56013Sjoerg     outs() << ToolName << '\n';
228*82d56013Sjoerg     cl::PrintVersionMessage();
229*82d56013Sjoerg     exit(0);
230*82d56013Sjoerg   }
231*82d56013Sjoerg 
232*82d56013Sjoerg   return Args;
233*82d56013Sjoerg }
234*82d56013Sjoerg 
235*82d56013Sjoerg template <typename T>
parseIntArg(const opt::InputArgList & Args,int ID,T & Value)236*82d56013Sjoerg static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value) {
237*82d56013Sjoerg   if (const opt::Arg *A = Args.getLastArg(ID)) {
238*82d56013Sjoerg     StringRef V(A->getValue());
239*82d56013Sjoerg     if (!llvm::to_integer(V, Value, 0)) {
240*82d56013Sjoerg       errs() << A->getSpelling() +
241*82d56013Sjoerg                     ": expected a non-negative integer, but got '" + V + "'";
242*82d56013Sjoerg       exit(1);
243*82d56013Sjoerg     }
244*82d56013Sjoerg   } else {
245*82d56013Sjoerg     Value = 0;
246*82d56013Sjoerg   }
247*82d56013Sjoerg }
248*82d56013Sjoerg 
decideHowToPrintFunctions(const opt::InputArgList & Args,bool IsAddr2Line)249*82d56013Sjoerg static FunctionNameKind decideHowToPrintFunctions(const opt::InputArgList &Args,
250*82d56013Sjoerg                                                   bool IsAddr2Line) {
251*82d56013Sjoerg   if (Args.hasArg(OPT_functions))
252*82d56013Sjoerg     return FunctionNameKind::LinkageName;
253*82d56013Sjoerg   if (const opt::Arg *A = Args.getLastArg(OPT_functions_EQ))
254*82d56013Sjoerg     return StringSwitch<FunctionNameKind>(A->getValue())
255*82d56013Sjoerg         .Case("none", FunctionNameKind::None)
256*82d56013Sjoerg         .Case("short", FunctionNameKind::ShortName)
257*82d56013Sjoerg         .Default(FunctionNameKind::LinkageName);
258*82d56013Sjoerg   return IsAddr2Line ? FunctionNameKind::None : FunctionNameKind::LinkageName;
2597330f729Sjoerg }
2607330f729Sjoerg 
main(int argc,char ** argv)2617330f729Sjoerg int main(int argc, char **argv) {
2627330f729Sjoerg   InitLLVM X(argc, argv);
263*82d56013Sjoerg   sys::InitializeCOMRAII COM(sys::COMThreadingMode::MultiThreaded);
2647330f729Sjoerg 
2657330f729Sjoerg   bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line");
266*82d56013Sjoerg   BumpPtrAllocator A;
267*82d56013Sjoerg   StringSaver Saver(A);
268*82d56013Sjoerg   SymbolizerOptTable Tbl;
269*82d56013Sjoerg   opt::InputArgList Args = parseOptions(argc, argv, IsAddr2Line, Saver, Tbl);
2707330f729Sjoerg 
2717330f729Sjoerg   LLVMSymbolizer::Options Opts;
272*82d56013Sjoerg   uint64_t AdjustVMA;
273*82d56013Sjoerg   PrinterConfig Config;
274*82d56013Sjoerg   parseIntArg(Args, OPT_adjust_vma_EQ, AdjustVMA);
275*82d56013Sjoerg   if (const opt::Arg *A = Args.getLastArg(OPT_basenames, OPT_relativenames)) {
276*82d56013Sjoerg     Opts.PathStyle =
277*82d56013Sjoerg         A->getOption().matches(OPT_basenames)
278*82d56013Sjoerg             ? DILineInfoSpecifier::FileLineInfoKind::BaseNameOnly
279*82d56013Sjoerg             : DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath;
2807330f729Sjoerg   } else {
281*82d56013Sjoerg     Opts.PathStyle = DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath;
282*82d56013Sjoerg   }
283*82d56013Sjoerg   Opts.DebugFileDirectory = Args.getAllArgValues(OPT_debug_file_directory_EQ);
284*82d56013Sjoerg   Opts.DefaultArch = Args.getLastArgValue(OPT_default_arch_EQ).str();
285*82d56013Sjoerg   Opts.Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, !IsAddr2Line);
286*82d56013Sjoerg   Opts.DWPName = Args.getLastArgValue(OPT_dwp_EQ).str();
287*82d56013Sjoerg   Opts.FallbackDebugPath =
288*82d56013Sjoerg       Args.getLastArgValue(OPT_fallback_debug_path_EQ).str();
289*82d56013Sjoerg   Opts.PrintFunctions = decideHowToPrintFunctions(Args, IsAddr2Line);
290*82d56013Sjoerg   parseIntArg(Args, OPT_print_source_context_lines_EQ,
291*82d56013Sjoerg               Config.SourceContextLines);
292*82d56013Sjoerg   Opts.RelativeAddresses = Args.hasArg(OPT_relative_address);
293*82d56013Sjoerg   Opts.UntagAddresses =
294*82d56013Sjoerg       Args.hasFlag(OPT_untag_addresses, OPT_no_untag_addresses, !IsAddr2Line);
295*82d56013Sjoerg   Opts.UseDIA = Args.hasArg(OPT_use_dia);
296*82d56013Sjoerg #if !defined(LLVM_ENABLE_DIA_SDK)
297*82d56013Sjoerg   if (Opts.UseDIA) {
298*82d56013Sjoerg     WithColor::warning() << "DIA not available; using native PDB reader\n";
299*82d56013Sjoerg     Opts.UseDIA = false;
300*82d56013Sjoerg   }
301*82d56013Sjoerg #endif
302*82d56013Sjoerg   Opts.UseSymbolTable = true;
303*82d56013Sjoerg   Config.PrintAddress = Args.hasArg(OPT_addresses);
304*82d56013Sjoerg   Config.PrintFunctions = Opts.PrintFunctions != FunctionNameKind::None;
305*82d56013Sjoerg   Config.Pretty = Args.hasArg(OPT_pretty_print);
306*82d56013Sjoerg   Config.Verbose = Args.hasArg(OPT_verbose);
307*82d56013Sjoerg 
308*82d56013Sjoerg   for (const opt::Arg *A : Args.filtered(OPT_dsym_hint_EQ)) {
309*82d56013Sjoerg     StringRef Hint(A->getValue());
310*82d56013Sjoerg     if (sys::path::extension(Hint) == ".dSYM") {
311*82d56013Sjoerg       Opts.DsymHints.emplace_back(Hint);
312*82d56013Sjoerg     } else {
313*82d56013Sjoerg       errs() << "Warning: invalid dSYM hint: \"" << Hint
314*82d56013Sjoerg              << "\" (must have the '.dSYM' extension).\n";
3157330f729Sjoerg     }
3167330f729Sjoerg   }
317*82d56013Sjoerg 
318*82d56013Sjoerg   auto Style = IsAddr2Line ? OutputStyle::GNU : OutputStyle::LLVM;
319*82d56013Sjoerg   if (const opt::Arg *A = Args.getLastArg(OPT_output_style_EQ)) {
320*82d56013Sjoerg     if (strcmp(A->getValue(), "GNU") == 0)
321*82d56013Sjoerg       Style = OutputStyle::GNU;
322*82d56013Sjoerg     else if (strcmp(A->getValue(), "JSON") == 0)
323*82d56013Sjoerg       Style = OutputStyle::JSON;
324*82d56013Sjoerg     else
325*82d56013Sjoerg       Style = OutputStyle::LLVM;
326*82d56013Sjoerg   }
327*82d56013Sjoerg 
3287330f729Sjoerg   LLVMSymbolizer Symbolizer(Opts);
329*82d56013Sjoerg   std::unique_ptr<DIPrinter> Printer;
330*82d56013Sjoerg   if (Style == OutputStyle::GNU)
331*82d56013Sjoerg     Printer = std::make_unique<GNUPrinter>(outs(), errs(), Config);
332*82d56013Sjoerg   else if (Style == OutputStyle::JSON)
333*82d56013Sjoerg     Printer = std::make_unique<JSONPrinter>(outs(), Config);
334*82d56013Sjoerg   else
335*82d56013Sjoerg     Printer = std::make_unique<LLVMPrinter>(outs(), errs(), Config);
3367330f729Sjoerg 
337*82d56013Sjoerg   std::vector<std::string> InputAddresses = Args.getAllArgValues(OPT_INPUT);
338*82d56013Sjoerg   if (InputAddresses.empty()) {
3397330f729Sjoerg     const int kMaxInputStringLength = 1024;
3407330f729Sjoerg     char InputString[kMaxInputStringLength];
3417330f729Sjoerg 
3427330f729Sjoerg     while (fgets(InputString, sizeof(InputString), stdin)) {
343*82d56013Sjoerg       // Strip newline characters.
344*82d56013Sjoerg       std::string StrippedInputString(InputString);
345*82d56013Sjoerg       llvm::erase_if(StrippedInputString,
346*82d56013Sjoerg                      [](char c) { return c == '\r' || c == '\n'; });
347*82d56013Sjoerg       symbolizeInput(Args, AdjustVMA, IsAddr2Line, Style, StrippedInputString,
348*82d56013Sjoerg                      Symbolizer, *Printer);
3497330f729Sjoerg       outs().flush();
3507330f729Sjoerg     }
3517330f729Sjoerg   } else {
352*82d56013Sjoerg     Printer->listBegin();
353*82d56013Sjoerg     for (StringRef Address : InputAddresses)
354*82d56013Sjoerg       symbolizeInput(Args, AdjustVMA, IsAddr2Line, Style, Address, Symbolizer,
355*82d56013Sjoerg                      *Printer);
356*82d56013Sjoerg     Printer->listEnd();
3577330f729Sjoerg   }
3587330f729Sjoerg 
3597330f729Sjoerg   return 0;
3607330f729Sjoerg }
361