xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the DIPrinter class, which is responsible for printing
100b57cec5SDimitry Andric // structures defined in DebugInfo/DIContext.h
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/DebugInfo/Symbolize/DIPrinter.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/DIContext.h"
170b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
180b57cec5SDimitry Andric #include "llvm/Support/Format.h"
190b57cec5SDimitry Andric #include "llvm/Support/LineIterator.h"
200b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
210b57cec5SDimitry Andric #include "llvm/Support/Path.h"
220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
230b57cec5SDimitry Andric #include <algorithm>
240b57cec5SDimitry Andric #include <cmath>
250b57cec5SDimitry Andric #include <cstddef>
260b57cec5SDimitry Andric #include <cstdint>
270b57cec5SDimitry Andric #include <memory>
280b57cec5SDimitry Andric #include <string>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric namespace llvm {
310b57cec5SDimitry Andric namespace symbolize {
320b57cec5SDimitry Andric 
33*fe6060f1SDimitry Andric class SourceCode {
34*fe6060f1SDimitry Andric   std::unique_ptr<MemoryBuffer> MemBuf;
350b57cec5SDimitry Andric 
36*fe6060f1SDimitry Andric   const Optional<StringRef> load(StringRef FileName,
37*fe6060f1SDimitry Andric                                  const Optional<StringRef> &EmbeddedSource) {
38*fe6060f1SDimitry Andric     if (Lines <= 0)
39*fe6060f1SDimitry Andric       return None;
40*fe6060f1SDimitry Andric 
41*fe6060f1SDimitry Andric     if (EmbeddedSource)
42*fe6060f1SDimitry Andric       return EmbeddedSource;
43*fe6060f1SDimitry Andric     else {
440b57cec5SDimitry Andric       ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
450b57cec5SDimitry Andric           MemoryBuffer::getFile(FileName);
460b57cec5SDimitry Andric       if (!BufOrErr)
47*fe6060f1SDimitry Andric         return None;
48*fe6060f1SDimitry Andric       MemBuf = std::move(*BufOrErr);
49*fe6060f1SDimitry Andric       return MemBuf->getBuffer();
50*fe6060f1SDimitry Andric     }
51*fe6060f1SDimitry Andric   }
52*fe6060f1SDimitry Andric 
53*fe6060f1SDimitry Andric   const Optional<StringRef> pruneSource(const Optional<StringRef> &Source) {
54*fe6060f1SDimitry Andric     if (!Source)
55*fe6060f1SDimitry Andric       return None;
56*fe6060f1SDimitry Andric     size_t FirstLinePos = StringRef::npos, Pos = 0;
57*fe6060f1SDimitry Andric     for (int64_t L = 1; L <= LastLine; ++L, ++Pos) {
58*fe6060f1SDimitry Andric       if (L == FirstLine)
59*fe6060f1SDimitry Andric         FirstLinePos = Pos;
60*fe6060f1SDimitry Andric       Pos = Source->find('\n', Pos);
61*fe6060f1SDimitry Andric       if (Pos == StringRef::npos)
62*fe6060f1SDimitry Andric         break;
63*fe6060f1SDimitry Andric     }
64*fe6060f1SDimitry Andric     if (FirstLinePos == StringRef::npos)
65*fe6060f1SDimitry Andric       return None;
66*fe6060f1SDimitry Andric     return Source->substr(FirstLinePos, (Pos == StringRef::npos)
67*fe6060f1SDimitry Andric                                             ? StringRef::npos
68*fe6060f1SDimitry Andric                                             : Pos - FirstLinePos);
69*fe6060f1SDimitry Andric   }
70*fe6060f1SDimitry Andric 
71*fe6060f1SDimitry Andric public:
72*fe6060f1SDimitry Andric   const int64_t Line;
73*fe6060f1SDimitry Andric   const int Lines;
74*fe6060f1SDimitry Andric   const int64_t FirstLine;
75*fe6060f1SDimitry Andric   const int64_t LastLine;
76*fe6060f1SDimitry Andric   const Optional<StringRef> PrunedSource;
77*fe6060f1SDimitry Andric 
78*fe6060f1SDimitry Andric   SourceCode(
79*fe6060f1SDimitry Andric       StringRef FileName, int64_t Line, int Lines,
80*fe6060f1SDimitry Andric       const Optional<StringRef> &EmbeddedSource = Optional<StringRef>(None))
81*fe6060f1SDimitry Andric       : Line(Line), Lines(Lines),
82*fe6060f1SDimitry Andric         FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)),
83*fe6060f1SDimitry Andric         LastLine(FirstLine + Lines - 1),
84*fe6060f1SDimitry Andric         PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {}
85*fe6060f1SDimitry Andric 
86*fe6060f1SDimitry Andric   void format(raw_ostream &OS) {
87*fe6060f1SDimitry Andric     if (!PrunedSource)
880b57cec5SDimitry Andric       return;
890b57cec5SDimitry Andric     size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
90*fe6060f1SDimitry Andric     int64_t L = FirstLine;
91*fe6060f1SDimitry Andric     for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) {
92*fe6060f1SDimitry Andric       size_t PosEnd = PrunedSource->find('\n', Pos);
93*fe6060f1SDimitry Andric       StringRef String = PrunedSource->substr(
94*fe6060f1SDimitry Andric           Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));
95*fe6060f1SDimitry Andric       if (String.endswith("\r"))
96*fe6060f1SDimitry Andric         String = String.drop_back(1);
970b57cec5SDimitry Andric       OS << format_decimal(L, MaxLineNumberWidth);
980b57cec5SDimitry Andric       if (L == Line)
990b57cec5SDimitry Andric         OS << " >: ";
1000b57cec5SDimitry Andric       else
1010b57cec5SDimitry Andric         OS << "  : ";
102*fe6060f1SDimitry Andric       OS << String << '\n';
103*fe6060f1SDimitry Andric       if (PosEnd == StringRef::npos)
104*fe6060f1SDimitry Andric         break;
105*fe6060f1SDimitry Andric       Pos = PosEnd + 1;
1060b57cec5SDimitry Andric     }
1070b57cec5SDimitry Andric   }
108*fe6060f1SDimitry Andric };
109*fe6060f1SDimitry Andric 
110*fe6060f1SDimitry Andric void PlainPrinterBase::printHeader(uint64_t Address) {
111*fe6060f1SDimitry Andric   if (Config.PrintAddress) {
112*fe6060f1SDimitry Andric     OS << "0x";
113*fe6060f1SDimitry Andric     OS.write_hex(Address);
114*fe6060f1SDimitry Andric     StringRef Delimiter = Config.Pretty ? ": " : "\n";
115*fe6060f1SDimitry Andric     OS << Delimiter;
116*fe6060f1SDimitry Andric   }
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
119*fe6060f1SDimitry Andric // Prints source code around in the FileName the Line.
120*fe6060f1SDimitry Andric void PlainPrinterBase::printContext(SourceCode SourceCode) {
121*fe6060f1SDimitry Andric   SourceCode.format(OS);
122*fe6060f1SDimitry Andric }
123*fe6060f1SDimitry Andric 
124*fe6060f1SDimitry Andric void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
125*fe6060f1SDimitry Andric   if (Config.PrintFunctions) {
1268bcb0991SDimitry Andric     if (FunctionName == DILineInfo::BadString)
1278bcb0991SDimitry Andric       FunctionName = DILineInfo::Addr2LineBadString;
128*fe6060f1SDimitry Andric     StringRef Delimiter = Config.Pretty ? " at " : "\n";
129*fe6060f1SDimitry Andric     StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
1300b57cec5SDimitry Andric     OS << Prefix << FunctionName << Delimiter;
1310b57cec5SDimitry Andric   }
132*fe6060f1SDimitry Andric }
133*fe6060f1SDimitry Andric 
134*fe6060f1SDimitry Andric void LLVMPrinter::printSimpleLocation(StringRef Filename,
135*fe6060f1SDimitry Andric                                       const DILineInfo &Info) {
136*fe6060f1SDimitry Andric   OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
137*fe6060f1SDimitry Andric   printContext(
138*fe6060f1SDimitry Andric       SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
139*fe6060f1SDimitry Andric }
140*fe6060f1SDimitry Andric 
141*fe6060f1SDimitry Andric void GNUPrinter::printSimpleLocation(StringRef Filename,
142*fe6060f1SDimitry Andric                                      const DILineInfo &Info) {
143*fe6060f1SDimitry Andric   OS << Filename << ':' << Info.Line;
144*fe6060f1SDimitry Andric   if (Info.Discriminator)
145*fe6060f1SDimitry Andric     OS << " (discriminator " << Info.Discriminator << ')';
146*fe6060f1SDimitry Andric   OS << '\n';
147*fe6060f1SDimitry Andric   printContext(
148*fe6060f1SDimitry Andric       SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
149*fe6060f1SDimitry Andric }
150*fe6060f1SDimitry Andric 
151*fe6060f1SDimitry Andric void PlainPrinterBase::printVerbose(StringRef Filename,
152*fe6060f1SDimitry Andric                                     const DILineInfo &Info) {
153*fe6060f1SDimitry Andric   OS << "  Filename: " << Filename << '\n';
154*fe6060f1SDimitry Andric   if (Info.StartLine) {
155*fe6060f1SDimitry Andric     OS << "  Function start filename: " << Info.StartFileName << '\n';
156*fe6060f1SDimitry Andric     OS << "  Function start line: " << Info.StartLine << '\n';
157*fe6060f1SDimitry Andric   }
158*fe6060f1SDimitry Andric   printStartAddress(Info);
159*fe6060f1SDimitry Andric   OS << "  Line: " << Info.Line << '\n';
160*fe6060f1SDimitry Andric   OS << "  Column: " << Info.Column << '\n';
161*fe6060f1SDimitry Andric   if (Info.Discriminator)
162*fe6060f1SDimitry Andric     OS << "  Discriminator: " << Info.Discriminator << '\n';
163*fe6060f1SDimitry Andric }
164*fe6060f1SDimitry Andric 
165*fe6060f1SDimitry Andric void LLVMPrinter::printStartAddress(const DILineInfo &Info) {
166*fe6060f1SDimitry Andric   if (Info.StartAddress) {
167*fe6060f1SDimitry Andric     OS << "  Function start address: 0x";
168*fe6060f1SDimitry Andric     OS.write_hex(*Info.StartAddress);
169*fe6060f1SDimitry Andric     OS << '\n';
170*fe6060f1SDimitry Andric   }
171*fe6060f1SDimitry Andric }
172*fe6060f1SDimitry Andric 
173*fe6060f1SDimitry Andric void LLVMPrinter::printFooter() { OS << '\n'; }
174*fe6060f1SDimitry Andric 
175*fe6060f1SDimitry Andric void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
176*fe6060f1SDimitry Andric   printFunctionName(Info.FunctionName, Inlined);
177*fe6060f1SDimitry Andric   StringRef Filename = Info.FileName;
1788bcb0991SDimitry Andric   if (Filename == DILineInfo::BadString)
1798bcb0991SDimitry Andric     Filename = DILineInfo::Addr2LineBadString;
180*fe6060f1SDimitry Andric   if (Config.Verbose)
181*fe6060f1SDimitry Andric     printVerbose(Filename, Info);
182*fe6060f1SDimitry Andric   else
183*fe6060f1SDimitry Andric     printSimpleLocation(Filename, Info);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
186*fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
187*fe6060f1SDimitry Andric   printHeader(*Request.Address);
1880b57cec5SDimitry Andric   print(Info, false);
189*fe6060f1SDimitry Andric   printFooter();
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
192*fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request,
193*fe6060f1SDimitry Andric                              const DIInliningInfo &Info) {
194*fe6060f1SDimitry Andric   printHeader(*Request.Address);
1950b57cec5SDimitry Andric   uint32_t FramesNum = Info.getNumberOfFrames();
196*fe6060f1SDimitry Andric   if (FramesNum == 0)
1970b57cec5SDimitry Andric     print(DILineInfo(), false);
198*fe6060f1SDimitry Andric   else
199*fe6060f1SDimitry Andric     for (uint32_t I = 0; I < FramesNum; ++I)
200*fe6060f1SDimitry Andric       print(Info.getFrame(I), I > 0);
201*fe6060f1SDimitry Andric   printFooter();
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
204*fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
205*fe6060f1SDimitry Andric   printHeader(*Request.Address);
206*fe6060f1SDimitry Andric   StringRef Name = Global.Name;
2078bcb0991SDimitry Andric   if (Name == DILineInfo::BadString)
2088bcb0991SDimitry Andric     Name = DILineInfo::Addr2LineBadString;
2090b57cec5SDimitry Andric   OS << Name << "\n";
2100b57cec5SDimitry Andric   OS << Global.Start << " " << Global.Size << "\n";
211*fe6060f1SDimitry Andric   printFooter();
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
214*fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request,
215*fe6060f1SDimitry Andric                              const std::vector<DILocal> &Locals) {
216*fe6060f1SDimitry Andric   printHeader(*Request.Address);
217*fe6060f1SDimitry Andric   if (Locals.empty())
218*fe6060f1SDimitry Andric     OS << DILineInfo::Addr2LineBadString << '\n';
219480093f4SDimitry Andric   else
220*fe6060f1SDimitry Andric     for (const DILocal &L : Locals) {
221*fe6060f1SDimitry Andric       if (L.FunctionName.empty())
222*fe6060f1SDimitry Andric         OS << DILineInfo::Addr2LineBadString;
223480093f4SDimitry Andric       else
224*fe6060f1SDimitry Andric         OS << L.FunctionName;
225*fe6060f1SDimitry Andric       OS << '\n';
226480093f4SDimitry Andric 
227*fe6060f1SDimitry Andric       if (L.Name.empty())
228*fe6060f1SDimitry Andric         OS << DILineInfo::Addr2LineBadString;
2290b57cec5SDimitry Andric       else
230*fe6060f1SDimitry Andric         OS << L.Name;
231*fe6060f1SDimitry Andric       OS << '\n';
232480093f4SDimitry Andric 
233*fe6060f1SDimitry Andric       if (L.DeclFile.empty())
234*fe6060f1SDimitry Andric         OS << DILineInfo::Addr2LineBadString;
235*fe6060f1SDimitry Andric       else
236*fe6060f1SDimitry Andric         OS << L.DeclFile;
237*fe6060f1SDimitry Andric 
238*fe6060f1SDimitry Andric       OS << ':' << L.DeclLine << '\n';
239*fe6060f1SDimitry Andric 
240*fe6060f1SDimitry Andric       if (L.FrameOffset)
241*fe6060f1SDimitry Andric         OS << *L.FrameOffset;
242*fe6060f1SDimitry Andric       else
243*fe6060f1SDimitry Andric         OS << DILineInfo::Addr2LineBadString;
244*fe6060f1SDimitry Andric       OS << ' ';
245*fe6060f1SDimitry Andric 
246*fe6060f1SDimitry Andric       if (L.Size)
247*fe6060f1SDimitry Andric         OS << *L.Size;
248*fe6060f1SDimitry Andric       else
249*fe6060f1SDimitry Andric         OS << DILineInfo::Addr2LineBadString;
250*fe6060f1SDimitry Andric       OS << ' ';
251*fe6060f1SDimitry Andric 
252*fe6060f1SDimitry Andric       if (L.TagOffset)
253*fe6060f1SDimitry Andric         OS << *L.TagOffset;
254*fe6060f1SDimitry Andric       else
255*fe6060f1SDimitry Andric         OS << DILineInfo::Addr2LineBadString;
256*fe6060f1SDimitry Andric       OS << '\n';
257*fe6060f1SDimitry Andric     }
258*fe6060f1SDimitry Andric   printFooter();
259*fe6060f1SDimitry Andric }
260*fe6060f1SDimitry Andric 
261*fe6060f1SDimitry Andric void PlainPrinterBase::printInvalidCommand(const Request &Request,
262*fe6060f1SDimitry Andric                                            StringRef Command) {
263*fe6060f1SDimitry Andric   OS << Command << '\n';
264*fe6060f1SDimitry Andric }
265*fe6060f1SDimitry Andric 
266*fe6060f1SDimitry Andric bool PlainPrinterBase::printError(const Request &Request,
267*fe6060f1SDimitry Andric                                   const ErrorInfoBase &ErrorInfo,
268*fe6060f1SDimitry Andric                                   StringRef ErrorBanner) {
269*fe6060f1SDimitry Andric   ES << ErrorBanner;
270*fe6060f1SDimitry Andric   ErrorInfo.log(ES);
271*fe6060f1SDimitry Andric   ES << '\n';
272*fe6060f1SDimitry Andric   // Print an empty struct too.
273*fe6060f1SDimitry Andric   return true;
274*fe6060f1SDimitry Andric }
275*fe6060f1SDimitry Andric 
276*fe6060f1SDimitry Andric static std::string toHex(uint64_t V) {
277*fe6060f1SDimitry Andric   return ("0x" + Twine::utohexstr(V)).str();
278*fe6060f1SDimitry Andric }
279*fe6060f1SDimitry Andric 
280*fe6060f1SDimitry Andric static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
281*fe6060f1SDimitry Andric   json::Object Json({{"ModuleName", Request.ModuleName.str()}});
282*fe6060f1SDimitry Andric   if (Request.Address)
283*fe6060f1SDimitry Andric     Json["Address"] = toHex(*Request.Address);
284*fe6060f1SDimitry Andric   if (!ErrorMsg.empty())
285*fe6060f1SDimitry Andric     Json["Error"] = json::Object({{"Message", ErrorMsg.str()}});
286*fe6060f1SDimitry Andric   return Json;
287*fe6060f1SDimitry Andric }
288*fe6060f1SDimitry Andric 
289*fe6060f1SDimitry Andric void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
290*fe6060f1SDimitry Andric   DIInliningInfo InliningInfo;
291*fe6060f1SDimitry Andric   InliningInfo.addFrame(Info);
292*fe6060f1SDimitry Andric   print(Request, InliningInfo);
293*fe6060f1SDimitry Andric }
294*fe6060f1SDimitry Andric 
295*fe6060f1SDimitry Andric void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) {
296*fe6060f1SDimitry Andric   json::Array Array;
297*fe6060f1SDimitry Andric   for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) {
298*fe6060f1SDimitry Andric     const DILineInfo &LineInfo = Info.getFrame(I);
299*fe6060f1SDimitry Andric     json::Object Object(
300*fe6060f1SDimitry Andric         {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString
301*fe6060f1SDimitry Andric                               ? LineInfo.FunctionName
302*fe6060f1SDimitry Andric                               : ""},
303*fe6060f1SDimitry Andric          {"StartFileName", LineInfo.StartFileName != DILineInfo::BadString
304*fe6060f1SDimitry Andric                                ? LineInfo.StartFileName
305*fe6060f1SDimitry Andric                                : ""},
306*fe6060f1SDimitry Andric          {"StartLine", LineInfo.StartLine},
307*fe6060f1SDimitry Andric          {"StartAddress",
308*fe6060f1SDimitry Andric           LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""},
309*fe6060f1SDimitry Andric          {"FileName",
310*fe6060f1SDimitry Andric           LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
311*fe6060f1SDimitry Andric          {"Line", LineInfo.Line},
312*fe6060f1SDimitry Andric          {"Column", LineInfo.Column},
313*fe6060f1SDimitry Andric          {"Discriminator", LineInfo.Discriminator}});
314*fe6060f1SDimitry Andric     SourceCode SourceCode(LineInfo.FileName, LineInfo.Line,
315*fe6060f1SDimitry Andric                           Config.SourceContextLines, LineInfo.Source);
316*fe6060f1SDimitry Andric     std::string FormattedSource;
317*fe6060f1SDimitry Andric     raw_string_ostream Stream(FormattedSource);
318*fe6060f1SDimitry Andric     SourceCode.format(Stream);
319*fe6060f1SDimitry Andric     if (!FormattedSource.empty())
320*fe6060f1SDimitry Andric       Object["Source"] = std::move(FormattedSource);
321*fe6060f1SDimitry Andric     Array.push_back(std::move(Object));
322*fe6060f1SDimitry Andric   }
323*fe6060f1SDimitry Andric   json::Object Json = toJSON(Request);
324*fe6060f1SDimitry Andric   Json["Symbol"] = std::move(Array);
325*fe6060f1SDimitry Andric   if (ObjectList)
326*fe6060f1SDimitry Andric     ObjectList->push_back(std::move(Json));
327*fe6060f1SDimitry Andric   else
328*fe6060f1SDimitry Andric     printJSON(std::move(Json));
329*fe6060f1SDimitry Andric }
330*fe6060f1SDimitry Andric 
331*fe6060f1SDimitry Andric void JSONPrinter::print(const Request &Request, const DIGlobal &Global) {
332*fe6060f1SDimitry Andric   json::Object Data(
333*fe6060f1SDimitry Andric       {{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""},
334*fe6060f1SDimitry Andric        {"Start", toHex(Global.Start)},
335*fe6060f1SDimitry Andric        {"Size", toHex(Global.Size)}});
336*fe6060f1SDimitry Andric   json::Object Json = toJSON(Request);
337*fe6060f1SDimitry Andric   Json["Data"] = std::move(Data);
338*fe6060f1SDimitry Andric   if (ObjectList)
339*fe6060f1SDimitry Andric     ObjectList->push_back(std::move(Json));
340*fe6060f1SDimitry Andric   else
341*fe6060f1SDimitry Andric     printJSON(std::move(Json));
342*fe6060f1SDimitry Andric }
343*fe6060f1SDimitry Andric 
344*fe6060f1SDimitry Andric void JSONPrinter::print(const Request &Request,
345*fe6060f1SDimitry Andric                         const std::vector<DILocal> &Locals) {
346*fe6060f1SDimitry Andric   json::Array Frame;
347*fe6060f1SDimitry Andric   for (const DILocal &Local : Locals) {
348*fe6060f1SDimitry Andric     json::Object FrameObject(
349*fe6060f1SDimitry Andric         {{"FunctionName", Local.FunctionName},
350*fe6060f1SDimitry Andric          {"Name", Local.Name},
351*fe6060f1SDimitry Andric          {"DeclFile", Local.DeclFile},
352*fe6060f1SDimitry Andric          {"DeclLine", int64_t(Local.DeclLine)},
353*fe6060f1SDimitry Andric          {"Size", Local.Size ? toHex(*Local.Size) : ""},
354*fe6060f1SDimitry Andric          {"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}});
3550b57cec5SDimitry Andric     if (Local.FrameOffset)
356*fe6060f1SDimitry Andric       FrameObject["FrameOffset"] = *Local.FrameOffset;
357*fe6060f1SDimitry Andric     Frame.push_back(std::move(FrameObject));
358*fe6060f1SDimitry Andric   }
359*fe6060f1SDimitry Andric   json::Object Json = toJSON(Request);
360*fe6060f1SDimitry Andric   Json["Frame"] = std::move(Frame);
361*fe6060f1SDimitry Andric   if (ObjectList)
362*fe6060f1SDimitry Andric     ObjectList->push_back(std::move(Json));
3630b57cec5SDimitry Andric   else
364*fe6060f1SDimitry Andric     printJSON(std::move(Json));
365*fe6060f1SDimitry Andric }
366480093f4SDimitry Andric 
367*fe6060f1SDimitry Andric void JSONPrinter::printInvalidCommand(const Request &Request,
368*fe6060f1SDimitry Andric                                       StringRef Command) {
369*fe6060f1SDimitry Andric   printError(Request,
370*fe6060f1SDimitry Andric              StringError("unable to parse arguments: " + Command,
371*fe6060f1SDimitry Andric                          std::make_error_code(std::errc::invalid_argument)),
372*fe6060f1SDimitry Andric              "");
373*fe6060f1SDimitry Andric }
374480093f4SDimitry Andric 
375*fe6060f1SDimitry Andric bool JSONPrinter::printError(const Request &Request,
376*fe6060f1SDimitry Andric                              const ErrorInfoBase &ErrorInfo,
377*fe6060f1SDimitry Andric                              StringRef ErrorBanner) {
378*fe6060f1SDimitry Andric   json::Object Json = toJSON(Request, ErrorInfo.message());
379*fe6060f1SDimitry Andric   if (ObjectList)
380*fe6060f1SDimitry Andric     ObjectList->push_back(std::move(Json));
3810b57cec5SDimitry Andric   else
382*fe6060f1SDimitry Andric     printJSON(std::move(Json));
383*fe6060f1SDimitry Andric   return false;
384*fe6060f1SDimitry Andric }
385*fe6060f1SDimitry Andric 
386*fe6060f1SDimitry Andric void JSONPrinter::listBegin() {
387*fe6060f1SDimitry Andric   assert(!ObjectList);
388*fe6060f1SDimitry Andric   ObjectList = std::make_unique<json::Array>();
389*fe6060f1SDimitry Andric }
390*fe6060f1SDimitry Andric 
391*fe6060f1SDimitry Andric void JSONPrinter::listEnd() {
392*fe6060f1SDimitry Andric   assert(ObjectList);
393*fe6060f1SDimitry Andric   printJSON(std::move(*ObjectList));
394*fe6060f1SDimitry Andric   ObjectList.reset();
3950b57cec5SDimitry Andric }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric } // end namespace symbolize
3980b57cec5SDimitry Andric } // end namespace llvm
399