1d6aa8202SAlexey Samsonov //===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===//
2d6aa8202SAlexey Samsonov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d6aa8202SAlexey Samsonov //
7d6aa8202SAlexey Samsonov //===----------------------------------------------------------------------===//
8d6aa8202SAlexey Samsonov //
9d6aa8202SAlexey Samsonov // This file defines the DIPrinter class, which is responsible for printing
10d6aa8202SAlexey Samsonov // structures defined in DebugInfo/DIContext.h
11d6aa8202SAlexey Samsonov //
12d6aa8202SAlexey Samsonov //===----------------------------------------------------------------------===//
13d6aa8202SAlexey Samsonov 
14d6aa8202SAlexey Samsonov #include "llvm/DebugInfo/Symbolize/DIPrinter.h"
15417d4c50SEugene Zelenko #include "llvm/ADT/StringRef.h"
16d6aa8202SAlexey Samsonov #include "llvm/DebugInfo/DIContext.h"
17417d4c50SEugene Zelenko #include "llvm/Support/ErrorOr.h"
18417d4c50SEugene Zelenko #include "llvm/Support/Format.h"
19417d4c50SEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
20417d4c50SEugene Zelenko #include "llvm/Support/raw_ostream.h"
21417d4c50SEugene Zelenko #include <algorithm>
22417d4c50SEugene Zelenko #include <cmath>
23417d4c50SEugene Zelenko #include <cstddef>
24417d4c50SEugene Zelenko #include <cstdint>
25417d4c50SEugene Zelenko #include <memory>
26417d4c50SEugene Zelenko #include <string>
27d6aa8202SAlexey Samsonov 
28d6aa8202SAlexey Samsonov namespace llvm {
29d6aa8202SAlexey Samsonov namespace symbolize {
30d6aa8202SAlexey Samsonov 
3188a8965aSAlex Orlov class SourceCode {
3288a8965aSAlex Orlov   std::unique_ptr<MemoryBuffer> MemBuf;
3388a8965aSAlex Orlov 
load(StringRef FileName,const Optional<StringRef> & EmbeddedSource)34fb28d6fbSKazu Hirata   Optional<StringRef> load(StringRef FileName,
3588a8965aSAlex Orlov                            const Optional<StringRef> &EmbeddedSource) {
3688a8965aSAlex Orlov     if (Lines <= 0)
3788a8965aSAlex Orlov       return None;
3888a8965aSAlex Orlov 
3988a8965aSAlex Orlov     if (EmbeddedSource)
4088a8965aSAlex Orlov       return EmbeddedSource;
4188a8965aSAlex Orlov     else {
4288a8965aSAlex Orlov       ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
4388a8965aSAlex Orlov           MemoryBuffer::getFile(FileName);
4488a8965aSAlex Orlov       if (!BufOrErr)
4588a8965aSAlex Orlov         return None;
4688a8965aSAlex Orlov       MemBuf = std::move(*BufOrErr);
4788a8965aSAlex Orlov       return MemBuf->getBuffer();
4888a8965aSAlex Orlov     }
4988a8965aSAlex Orlov   }
5088a8965aSAlex Orlov 
pruneSource(const Optional<StringRef> & Source)51fb28d6fbSKazu Hirata   Optional<StringRef> pruneSource(const Optional<StringRef> &Source) {
5288a8965aSAlex Orlov     if (!Source)
5388a8965aSAlex Orlov       return None;
5488a8965aSAlex Orlov     size_t FirstLinePos = StringRef::npos, Pos = 0;
5588a8965aSAlex Orlov     for (int64_t L = 1; L <= LastLine; ++L, ++Pos) {
5688a8965aSAlex Orlov       if (L == FirstLine)
5788a8965aSAlex Orlov         FirstLinePos = Pos;
5888a8965aSAlex Orlov       Pos = Source->find('\n', Pos);
5988a8965aSAlex Orlov       if (Pos == StringRef::npos)
6088a8965aSAlex Orlov         break;
6188a8965aSAlex Orlov     }
6288a8965aSAlex Orlov     if (FirstLinePos == StringRef::npos)
6388a8965aSAlex Orlov       return None;
6488a8965aSAlex Orlov     return Source->substr(FirstLinePos, (Pos == StringRef::npos)
6588a8965aSAlex Orlov                                             ? StringRef::npos
6688a8965aSAlex Orlov                                             : Pos - FirstLinePos);
6788a8965aSAlex Orlov   }
6888a8965aSAlex Orlov 
6988a8965aSAlex Orlov public:
7088a8965aSAlex Orlov   const int64_t Line;
7188a8965aSAlex Orlov   const int Lines;
7288a8965aSAlex Orlov   const int64_t FirstLine;
7388a8965aSAlex Orlov   const int64_t LastLine;
7488a8965aSAlex Orlov   const Optional<StringRef> PrunedSource;
7588a8965aSAlex Orlov 
SourceCode(StringRef FileName,int64_t Line,int Lines,const Optional<StringRef> & EmbeddedSource=Optional<StringRef> (None))7688a8965aSAlex Orlov   SourceCode(
7788a8965aSAlex Orlov       StringRef FileName, int64_t Line, int Lines,
7888a8965aSAlex Orlov       const Optional<StringRef> &EmbeddedSource = Optional<StringRef>(None))
7988a8965aSAlex Orlov       : Line(Line), Lines(Lines),
8088a8965aSAlex Orlov         FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)),
8188a8965aSAlex Orlov         LastLine(FirstLine + Lines - 1),
8288a8965aSAlex Orlov         PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {}
83752385b1SAlex Orlov 
format(raw_ostream & OS)84752385b1SAlex Orlov   void format(raw_ostream &OS) {
85752385b1SAlex Orlov     if (!PrunedSource)
86752385b1SAlex Orlov       return;
87752385b1SAlex Orlov     size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
88752385b1SAlex Orlov     int64_t L = FirstLine;
89752385b1SAlex Orlov     for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) {
90752385b1SAlex Orlov       size_t PosEnd = PrunedSource->find('\n', Pos);
91752385b1SAlex Orlov       StringRef String = PrunedSource->substr(
92752385b1SAlex Orlov           Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));
93752385b1SAlex Orlov       if (String.endswith("\r"))
94752385b1SAlex Orlov         String = String.drop_back(1);
95752385b1SAlex Orlov       OS << format_decimal(L, MaxLineNumberWidth);
96752385b1SAlex Orlov       if (L == Line)
97752385b1SAlex Orlov         OS << " >: ";
98752385b1SAlex Orlov       else
99752385b1SAlex Orlov         OS << "  : ";
100752385b1SAlex Orlov       OS << String << '\n';
101752385b1SAlex Orlov       if (PosEnd == StringRef::npos)
102752385b1SAlex Orlov         break;
103752385b1SAlex Orlov       Pos = PosEnd + 1;
104752385b1SAlex Orlov     }
105752385b1SAlex Orlov   }
10688a8965aSAlex Orlov };
10788a8965aSAlex Orlov 
printHeader(uint64_t Address)1085f57793cSAlex Orlov void PlainPrinterBase::printHeader(uint64_t Address) {
1095f57793cSAlex Orlov   if (Config.PrintAddress) {
1105f57793cSAlex Orlov     OS << "0x";
1115f57793cSAlex Orlov     OS.write_hex(Address);
1125f57793cSAlex Orlov     StringRef Delimiter = Config.Pretty ? ": " : "\n";
1135f57793cSAlex Orlov     OS << Delimiter;
1145f57793cSAlex Orlov   }
1155f57793cSAlex Orlov }
1165f57793cSAlex Orlov 
11717dbc283SMike Aizatsky // Prints source code around in the FileName the Line.
printContext(SourceCode SourceCode)11888a8965aSAlex Orlov void PlainPrinterBase::printContext(SourceCode SourceCode) {
119752385b1SAlex Orlov   SourceCode.format(OS);
12017dbc283SMike Aizatsky }
12117dbc283SMike Aizatsky 
printFunctionName(StringRef FunctionName,bool Inlined)1225f57793cSAlex Orlov void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
1235f57793cSAlex Orlov   if (Config.PrintFunctions) {
1249abf668cSMichael Pozulp     if (FunctionName == DILineInfo::BadString)
1259abf668cSMichael Pozulp       FunctionName = DILineInfo::Addr2LineBadString;
1265f57793cSAlex Orlov     StringRef Delimiter = Config.Pretty ? " at " : "\n";
1275f57793cSAlex Orlov     StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
128bdce12a0SHemant Kulkarni     OS << Prefix << FunctionName << Delimiter;
129d6aa8202SAlexey Samsonov   }
1305f57793cSAlex Orlov }
1315f57793cSAlex Orlov 
printSimpleLocation(StringRef Filename,const DILineInfo & Info)1325f57793cSAlex Orlov void LLVMPrinter::printSimpleLocation(StringRef Filename,
1335f57793cSAlex Orlov                                       const DILineInfo &Info) {
1345f57793cSAlex Orlov   OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
135752385b1SAlex Orlov   printContext(
136752385b1SAlex Orlov       SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
1375f57793cSAlex Orlov }
1385f57793cSAlex Orlov 
printSimpleLocation(StringRef Filename,const DILineInfo & Info)1395f57793cSAlex Orlov void GNUPrinter::printSimpleLocation(StringRef Filename,
1405f57793cSAlex Orlov                                      const DILineInfo &Info) {
1415f57793cSAlex Orlov   OS << Filename << ':' << Info.Line;
1425f57793cSAlex Orlov   if (Info.Discriminator)
1435f57793cSAlex Orlov     OS << " (discriminator " << Info.Discriminator << ')';
1445f57793cSAlex Orlov   OS << '\n';
145752385b1SAlex Orlov   printContext(
146752385b1SAlex Orlov       SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
1475f57793cSAlex Orlov }
1485f57793cSAlex Orlov 
printVerbose(StringRef Filename,const DILineInfo & Info)1495f57793cSAlex Orlov void PlainPrinterBase::printVerbose(StringRef Filename,
1505f57793cSAlex Orlov                                     const DILineInfo &Info) {
1515f57793cSAlex Orlov   OS << "  Filename: " << Filename << '\n';
1525f57793cSAlex Orlov   if (Info.StartLine) {
1535f57793cSAlex Orlov     OS << "  Function start filename: " << Info.StartFileName << '\n';
1545f57793cSAlex Orlov     OS << "  Function start line: " << Info.StartLine << '\n';
1555f57793cSAlex Orlov   }
1564fedb3a6SAlex Orlov   printStartAddress(Info);
1575f57793cSAlex Orlov   OS << "  Line: " << Info.Line << '\n';
1585f57793cSAlex Orlov   OS << "  Column: " << Info.Column << '\n';
1595f57793cSAlex Orlov   if (Info.Discriminator)
1605f57793cSAlex Orlov     OS << "  Discriminator: " << Info.Discriminator << '\n';
1615f57793cSAlex Orlov }
1625f57793cSAlex Orlov 
printStartAddress(const DILineInfo & Info)1634fedb3a6SAlex Orlov void LLVMPrinter::printStartAddress(const DILineInfo &Info) {
1644fedb3a6SAlex Orlov   if (Info.StartAddress) {
1654fedb3a6SAlex Orlov     OS << "  Function start address: 0x";
1664fedb3a6SAlex Orlov     OS.write_hex(*Info.StartAddress);
1674fedb3a6SAlex Orlov     OS << '\n';
1684fedb3a6SAlex Orlov   }
1694fedb3a6SAlex Orlov }
1704fedb3a6SAlex Orlov 
printFooter()1715f57793cSAlex Orlov void LLVMPrinter::printFooter() { OS << '\n'; }
1725f57793cSAlex Orlov 
print(const DILineInfo & Info,bool Inlined)1735f57793cSAlex Orlov void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
1745f57793cSAlex Orlov   printFunctionName(Info.FunctionName, Inlined);
1755f57793cSAlex Orlov   StringRef Filename = Info.FileName;
1769abf668cSMichael Pozulp   if (Filename == DILineInfo::BadString)
1779abf668cSMichael Pozulp     Filename = DILineInfo::Addr2LineBadString;
1785f57793cSAlex Orlov   if (Config.Verbose)
1795f57793cSAlex Orlov     printVerbose(Filename, Info);
1805f57793cSAlex Orlov   else
1815f57793cSAlex Orlov     printSimpleLocation(Filename, Info);
182bdce12a0SHemant Kulkarni }
183bdce12a0SHemant Kulkarni 
print(const Request & Request,const DILineInfo & Info)1845f57793cSAlex Orlov void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
18505d1ae4eSAlex Orlov   printHeader(*Request.Address);
18617dbc283SMike Aizatsky   print(Info, false);
1875f57793cSAlex Orlov   printFooter();
188d6aa8202SAlexey Samsonov }
189d6aa8202SAlexey Samsonov 
print(const Request & Request,const DIInliningInfo & Info)1905f57793cSAlex Orlov void PlainPrinterBase::print(const Request &Request,
1915f57793cSAlex Orlov                              const DIInliningInfo &Info) {
19205d1ae4eSAlex Orlov   printHeader(*Request.Address);
193d6aa8202SAlexey Samsonov   uint32_t FramesNum = Info.getNumberOfFrames();
1945f57793cSAlex Orlov   if (FramesNum == 0)
19517dbc283SMike Aizatsky     print(DILineInfo(), false);
1965f57793cSAlex Orlov   else
1975f57793cSAlex Orlov     for (uint32_t I = 0; I < FramesNum; ++I)
1985f57793cSAlex Orlov       print(Info.getFrame(I), I > 0);
1995f57793cSAlex Orlov   printFooter();
200d6aa8202SAlexey Samsonov }
201d6aa8202SAlexey Samsonov 
print(const Request & Request,const DIGlobal & Global)2025f57793cSAlex Orlov void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
20305d1ae4eSAlex Orlov   printHeader(*Request.Address);
2045f57793cSAlex Orlov   StringRef Name = Global.Name;
2059abf668cSMichael Pozulp   if (Name == DILineInfo::BadString)
2069abf668cSMichael Pozulp     Name = DILineInfo::Addr2LineBadString;
207d6aa8202SAlexey Samsonov   OS << Name << "\n";
208d6aa8202SAlexey Samsonov   OS << Global.Start << " " << Global.Size << "\n";
209*cead4eceSMitch Phillips   if (Global.DeclFile.empty())
210*cead4eceSMitch Phillips     OS << "??:?\n";
211*cead4eceSMitch Phillips   else
212*cead4eceSMitch Phillips     OS << Global.DeclFile << ":" << Global.DeclLine << "\n";
2135f57793cSAlex Orlov   printFooter();
214d6aa8202SAlexey Samsonov }
215d6aa8202SAlexey Samsonov 
print(const Request & Request,const std::vector<DILocal> & Locals)2165f57793cSAlex Orlov void PlainPrinterBase::print(const Request &Request,
2175f57793cSAlex Orlov                              const std::vector<DILocal> &Locals) {
21805d1ae4eSAlex Orlov   printHeader(*Request.Address);
2195f57793cSAlex Orlov   if (Locals.empty())
2205f57793cSAlex Orlov     OS << DILineInfo::Addr2LineBadString << '\n';
2211c33d713SEvgenii Stepanov   else
2225f57793cSAlex Orlov     for (const DILocal &L : Locals) {
2235f57793cSAlex Orlov       if (L.FunctionName.empty())
2245f57793cSAlex Orlov         OS << DILineInfo::Addr2LineBadString;
2255f57793cSAlex Orlov       else
2265f57793cSAlex Orlov         OS << L.FunctionName;
2275f57793cSAlex Orlov       OS << '\n';
2281c33d713SEvgenii Stepanov 
2295f57793cSAlex Orlov       if (L.Name.empty())
2305f57793cSAlex Orlov         OS << DILineInfo::Addr2LineBadString;
2311c33d713SEvgenii Stepanov       else
2325f57793cSAlex Orlov         OS << L.Name;
2335f57793cSAlex Orlov       OS << '\n';
2341c33d713SEvgenii Stepanov 
2355f57793cSAlex Orlov       if (L.DeclFile.empty())
2365f57793cSAlex Orlov         OS << DILineInfo::Addr2LineBadString;
2379c8282a9SPeter Collingbourne       else
2385f57793cSAlex Orlov         OS << L.DeclFile;
2391c33d713SEvgenii Stepanov 
2405f57793cSAlex Orlov       OS << ':' << L.DeclLine << '\n';
2411c33d713SEvgenii Stepanov 
2425f57793cSAlex Orlov       if (L.FrameOffset)
2435f57793cSAlex Orlov         OS << *L.FrameOffset;
2449c8282a9SPeter Collingbourne       else
2455f57793cSAlex Orlov         OS << DILineInfo::Addr2LineBadString;
2465f57793cSAlex Orlov       OS << ' ';
2471c33d713SEvgenii Stepanov 
2485f57793cSAlex Orlov       if (L.Size)
2495f57793cSAlex Orlov         OS << *L.Size;
2509c8282a9SPeter Collingbourne       else
2515f57793cSAlex Orlov         OS << DILineInfo::Addr2LineBadString;
2525f57793cSAlex Orlov       OS << ' ';
2535f57793cSAlex Orlov 
2545f57793cSAlex Orlov       if (L.TagOffset)
2555f57793cSAlex Orlov         OS << *L.TagOffset;
2565f57793cSAlex Orlov       else
2575f57793cSAlex Orlov         OS << DILineInfo::Addr2LineBadString;
2585f57793cSAlex Orlov       OS << '\n';
2595f57793cSAlex Orlov     }
2605f57793cSAlex Orlov   printFooter();
2615f57793cSAlex Orlov }
2625f57793cSAlex Orlov 
printInvalidCommand(const Request & Request,StringRef Command)2635f57793cSAlex Orlov void PlainPrinterBase::printInvalidCommand(const Request &Request,
26405d1ae4eSAlex Orlov                                            StringRef Command) {
26505d1ae4eSAlex Orlov   OS << Command << '\n';
2665f57793cSAlex Orlov }
2675f57793cSAlex Orlov 
printError(const Request & Request,const ErrorInfoBase & ErrorInfo,StringRef ErrorBanner)2685f57793cSAlex Orlov bool PlainPrinterBase::printError(const Request &Request,
2695f57793cSAlex Orlov                                   const ErrorInfoBase &ErrorInfo,
2705f57793cSAlex Orlov                                   StringRef ErrorBanner) {
2715f57793cSAlex Orlov   ES << ErrorBanner;
2725f57793cSAlex Orlov   ErrorInfo.log(ES);
2735f57793cSAlex Orlov   ES << '\n';
2745f57793cSAlex Orlov   // Print an empty struct too.
2755f57793cSAlex Orlov   return true;
2769c8282a9SPeter Collingbourne }
2779c8282a9SPeter Collingbourne 
toHex(uint64_t V)27805d1ae4eSAlex Orlov static std::string toHex(uint64_t V) {
27905d1ae4eSAlex Orlov   return ("0x" + Twine::utohexstr(V)).str();
28005d1ae4eSAlex Orlov }
28105d1ae4eSAlex Orlov 
toJSON(const Request & Request,StringRef ErrorMsg="")28205d1ae4eSAlex Orlov static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
28305d1ae4eSAlex Orlov   json::Object Json({{"ModuleName", Request.ModuleName.str()}});
28405d1ae4eSAlex Orlov   if (Request.Address)
28505d1ae4eSAlex Orlov     Json["Address"] = toHex(*Request.Address);
28605d1ae4eSAlex Orlov   if (!ErrorMsg.empty())
28705d1ae4eSAlex Orlov     Json["Error"] = json::Object({{"Message", ErrorMsg.str()}});
28805d1ae4eSAlex Orlov   return Json;
28905d1ae4eSAlex Orlov }
29005d1ae4eSAlex Orlov 
print(const Request & Request,const DILineInfo & Info)29105d1ae4eSAlex Orlov void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
29205d1ae4eSAlex Orlov   DIInliningInfo InliningInfo;
29305d1ae4eSAlex Orlov   InliningInfo.addFrame(Info);
29405d1ae4eSAlex Orlov   print(Request, InliningInfo);
29505d1ae4eSAlex Orlov }
29605d1ae4eSAlex Orlov 
print(const Request & Request,const DIInliningInfo & Info)29705d1ae4eSAlex Orlov void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) {
29805d1ae4eSAlex Orlov   json::Array Array;
29905d1ae4eSAlex Orlov   for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) {
30005d1ae4eSAlex Orlov     const DILineInfo &LineInfo = Info.getFrame(I);
301752385b1SAlex Orlov     json::Object Object(
30205d1ae4eSAlex Orlov         {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString
30305d1ae4eSAlex Orlov                               ? LineInfo.FunctionName
30405d1ae4eSAlex Orlov                               : ""},
30505d1ae4eSAlex Orlov          {"StartFileName", LineInfo.StartFileName != DILineInfo::BadString
30605d1ae4eSAlex Orlov                                ? LineInfo.StartFileName
30705d1ae4eSAlex Orlov                                : ""},
30805d1ae4eSAlex Orlov          {"StartLine", LineInfo.StartLine},
3094fedb3a6SAlex Orlov          {"StartAddress",
3104fedb3a6SAlex Orlov           LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""},
31105d1ae4eSAlex Orlov          {"FileName",
31205d1ae4eSAlex Orlov           LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
31305d1ae4eSAlex Orlov          {"Line", LineInfo.Line},
31405d1ae4eSAlex Orlov          {"Column", LineInfo.Column},
315752385b1SAlex Orlov          {"Discriminator", LineInfo.Discriminator}});
316752385b1SAlex Orlov     SourceCode SourceCode(LineInfo.FileName, LineInfo.Line,
317752385b1SAlex Orlov                           Config.SourceContextLines, LineInfo.Source);
318752385b1SAlex Orlov     std::string FormattedSource;
319752385b1SAlex Orlov     raw_string_ostream Stream(FormattedSource);
320752385b1SAlex Orlov     SourceCode.format(Stream);
321752385b1SAlex Orlov     if (!FormattedSource.empty())
322752385b1SAlex Orlov       Object["Source"] = std::move(FormattedSource);
323752385b1SAlex Orlov     Array.push_back(std::move(Object));
32405d1ae4eSAlex Orlov   }
32505d1ae4eSAlex Orlov   json::Object Json = toJSON(Request);
32605d1ae4eSAlex Orlov   Json["Symbol"] = std::move(Array);
32705d1ae4eSAlex Orlov   if (ObjectList)
32805d1ae4eSAlex Orlov     ObjectList->push_back(std::move(Json));
32905d1ae4eSAlex Orlov   else
33005d1ae4eSAlex Orlov     printJSON(std::move(Json));
33105d1ae4eSAlex Orlov }
33205d1ae4eSAlex Orlov 
print(const Request & Request,const DIGlobal & Global)33305d1ae4eSAlex Orlov void JSONPrinter::print(const Request &Request, const DIGlobal &Global) {
33405d1ae4eSAlex Orlov   json::Object Data(
33505d1ae4eSAlex Orlov       {{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""},
33605d1ae4eSAlex Orlov        {"Start", toHex(Global.Start)},
33705d1ae4eSAlex Orlov        {"Size", toHex(Global.Size)}});
33805d1ae4eSAlex Orlov   json::Object Json = toJSON(Request);
33905d1ae4eSAlex Orlov   Json["Data"] = std::move(Data);
34005d1ae4eSAlex Orlov   if (ObjectList)
34105d1ae4eSAlex Orlov     ObjectList->push_back(std::move(Json));
34205d1ae4eSAlex Orlov   else
34305d1ae4eSAlex Orlov     printJSON(std::move(Json));
34405d1ae4eSAlex Orlov }
34505d1ae4eSAlex Orlov 
print(const Request & Request,const std::vector<DILocal> & Locals)34605d1ae4eSAlex Orlov void JSONPrinter::print(const Request &Request,
34705d1ae4eSAlex Orlov                         const std::vector<DILocal> &Locals) {
34805d1ae4eSAlex Orlov   json::Array Frame;
34905d1ae4eSAlex Orlov   for (const DILocal &Local : Locals) {
35005d1ae4eSAlex Orlov     json::Object FrameObject(
35105d1ae4eSAlex Orlov         {{"FunctionName", Local.FunctionName},
35205d1ae4eSAlex Orlov          {"Name", Local.Name},
35305d1ae4eSAlex Orlov          {"DeclFile", Local.DeclFile},
35405d1ae4eSAlex Orlov          {"DeclLine", int64_t(Local.DeclLine)},
35505d1ae4eSAlex Orlov          {"Size", Local.Size ? toHex(*Local.Size) : ""},
35605d1ae4eSAlex Orlov          {"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}});
35705d1ae4eSAlex Orlov     if (Local.FrameOffset)
35805d1ae4eSAlex Orlov       FrameObject["FrameOffset"] = *Local.FrameOffset;
35905d1ae4eSAlex Orlov     Frame.push_back(std::move(FrameObject));
36005d1ae4eSAlex Orlov   }
36105d1ae4eSAlex Orlov   json::Object Json = toJSON(Request);
36205d1ae4eSAlex Orlov   Json["Frame"] = std::move(Frame);
36305d1ae4eSAlex Orlov   if (ObjectList)
36405d1ae4eSAlex Orlov     ObjectList->push_back(std::move(Json));
36505d1ae4eSAlex Orlov   else
36605d1ae4eSAlex Orlov     printJSON(std::move(Json));
36705d1ae4eSAlex Orlov }
36805d1ae4eSAlex Orlov 
printInvalidCommand(const Request & Request,StringRef Command)36905d1ae4eSAlex Orlov void JSONPrinter::printInvalidCommand(const Request &Request,
37005d1ae4eSAlex Orlov                                       StringRef Command) {
37105d1ae4eSAlex Orlov   printError(Request,
37205d1ae4eSAlex Orlov              StringError("unable to parse arguments: " + Command,
37305d1ae4eSAlex Orlov                          std::make_error_code(std::errc::invalid_argument)),
37405d1ae4eSAlex Orlov              "");
37505d1ae4eSAlex Orlov }
37605d1ae4eSAlex Orlov 
printError(const Request & Request,const ErrorInfoBase & ErrorInfo,StringRef ErrorBanner)37705d1ae4eSAlex Orlov bool JSONPrinter::printError(const Request &Request,
37805d1ae4eSAlex Orlov                              const ErrorInfoBase &ErrorInfo,
37905d1ae4eSAlex Orlov                              StringRef ErrorBanner) {
38005d1ae4eSAlex Orlov   json::Object Json = toJSON(Request, ErrorInfo.message());
38105d1ae4eSAlex Orlov   if (ObjectList)
38205d1ae4eSAlex Orlov     ObjectList->push_back(std::move(Json));
38305d1ae4eSAlex Orlov   else
38405d1ae4eSAlex Orlov     printJSON(std::move(Json));
38505d1ae4eSAlex Orlov   return false;
38605d1ae4eSAlex Orlov }
38705d1ae4eSAlex Orlov 
listBegin()38805d1ae4eSAlex Orlov void JSONPrinter::listBegin() {
38905d1ae4eSAlex Orlov   assert(!ObjectList);
39005d1ae4eSAlex Orlov   ObjectList = std::make_unique<json::Array>();
39105d1ae4eSAlex Orlov }
39205d1ae4eSAlex Orlov 
listEnd()39305d1ae4eSAlex Orlov void JSONPrinter::listEnd() {
39405d1ae4eSAlex Orlov   assert(ObjectList);
39505d1ae4eSAlex Orlov   printJSON(std::move(*ObjectList));
39685a96d82SVitaly Buka   ObjectList.reset();
39705d1ae4eSAlex Orlov }
39805d1ae4eSAlex Orlov 
399417d4c50SEugene Zelenko } // end namespace symbolize
400417d4c50SEugene Zelenko } // end namespace llvm
401