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/MemoryBuffer.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 210b57cec5SDimitry Andric #include <algorithm> 220b57cec5SDimitry Andric #include <cmath> 230b57cec5SDimitry Andric #include <cstddef> 240b57cec5SDimitry Andric #include <cstdint> 250b57cec5SDimitry Andric #include <memory> 260b57cec5SDimitry Andric #include <string> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace llvm { 290b57cec5SDimitry Andric namespace symbolize { 300b57cec5SDimitry Andric 31fe6060f1SDimitry Andric class SourceCode { 32fe6060f1SDimitry Andric std::unique_ptr<MemoryBuffer> MemBuf; 330b57cec5SDimitry Andric 34bdd1243dSDimitry Andric std::optional<StringRef> 35bdd1243dSDimitry Andric load(StringRef FileName, const std::optional<StringRef> &EmbeddedSource) { 36fe6060f1SDimitry Andric if (Lines <= 0) 37bdd1243dSDimitry Andric return std::nullopt; 38fe6060f1SDimitry Andric 39fe6060f1SDimitry Andric if (EmbeddedSource) 40fe6060f1SDimitry Andric return EmbeddedSource; 41fe6060f1SDimitry Andric else { 420b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 430b57cec5SDimitry Andric MemoryBuffer::getFile(FileName); 440b57cec5SDimitry Andric if (!BufOrErr) 45bdd1243dSDimitry Andric return std::nullopt; 46fe6060f1SDimitry Andric MemBuf = std::move(*BufOrErr); 47fe6060f1SDimitry Andric return MemBuf->getBuffer(); 48fe6060f1SDimitry Andric } 49fe6060f1SDimitry Andric } 50fe6060f1SDimitry Andric 51bdd1243dSDimitry Andric std::optional<StringRef> pruneSource(const std::optional<StringRef> &Source) { 52fe6060f1SDimitry Andric if (!Source) 53bdd1243dSDimitry Andric return std::nullopt; 54fe6060f1SDimitry Andric size_t FirstLinePos = StringRef::npos, Pos = 0; 55fe6060f1SDimitry Andric for (int64_t L = 1; L <= LastLine; ++L, ++Pos) { 56fe6060f1SDimitry Andric if (L == FirstLine) 57fe6060f1SDimitry Andric FirstLinePos = Pos; 58fe6060f1SDimitry Andric Pos = Source->find('\n', Pos); 59fe6060f1SDimitry Andric if (Pos == StringRef::npos) 60fe6060f1SDimitry Andric break; 61fe6060f1SDimitry Andric } 62fe6060f1SDimitry Andric if (FirstLinePos == StringRef::npos) 63bdd1243dSDimitry Andric return std::nullopt; 64fe6060f1SDimitry Andric return Source->substr(FirstLinePos, (Pos == StringRef::npos) 65fe6060f1SDimitry Andric ? StringRef::npos 66fe6060f1SDimitry Andric : Pos - FirstLinePos); 67fe6060f1SDimitry Andric } 68fe6060f1SDimitry Andric 69fe6060f1SDimitry Andric public: 70fe6060f1SDimitry Andric const int64_t Line; 71fe6060f1SDimitry Andric const int Lines; 72fe6060f1SDimitry Andric const int64_t FirstLine; 73fe6060f1SDimitry Andric const int64_t LastLine; 74bdd1243dSDimitry Andric const std::optional<StringRef> PrunedSource; 75fe6060f1SDimitry Andric 76bdd1243dSDimitry Andric SourceCode(StringRef FileName, int64_t Line, int Lines, 77bdd1243dSDimitry Andric const std::optional<StringRef> &EmbeddedSource = 78bdd1243dSDimitry Andric std::optional<StringRef>()) 79fe6060f1SDimitry Andric : Line(Line), Lines(Lines), 80fe6060f1SDimitry Andric FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)), 81fe6060f1SDimitry Andric LastLine(FirstLine + Lines - 1), 82fe6060f1SDimitry Andric PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {} 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric void format(raw_ostream &OS) { 85fe6060f1SDimitry Andric if (!PrunedSource) 860b57cec5SDimitry Andric return; 870b57cec5SDimitry Andric size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine)); 88fe6060f1SDimitry Andric int64_t L = FirstLine; 89fe6060f1SDimitry Andric for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) { 90fe6060f1SDimitry Andric size_t PosEnd = PrunedSource->find('\n', Pos); 91fe6060f1SDimitry Andric StringRef String = PrunedSource->substr( 92fe6060f1SDimitry Andric Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos)); 93fe6060f1SDimitry Andric if (String.endswith("\r")) 94fe6060f1SDimitry Andric String = String.drop_back(1); 950b57cec5SDimitry Andric OS << format_decimal(L, MaxLineNumberWidth); 960b57cec5SDimitry Andric if (L == Line) 970b57cec5SDimitry Andric OS << " >: "; 980b57cec5SDimitry Andric else 990b57cec5SDimitry Andric OS << " : "; 100fe6060f1SDimitry Andric OS << String << '\n'; 101fe6060f1SDimitry Andric if (PosEnd == StringRef::npos) 102fe6060f1SDimitry Andric break; 103fe6060f1SDimitry Andric Pos = PosEnd + 1; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric } 106fe6060f1SDimitry Andric }; 107fe6060f1SDimitry Andric 108fe6060f1SDimitry Andric void PlainPrinterBase::printHeader(uint64_t Address) { 109fe6060f1SDimitry Andric if (Config.PrintAddress) { 110fe6060f1SDimitry Andric OS << "0x"; 111fe6060f1SDimitry Andric OS.write_hex(Address); 112fe6060f1SDimitry Andric StringRef Delimiter = Config.Pretty ? ": " : "\n"; 113fe6060f1SDimitry Andric OS << Delimiter; 114fe6060f1SDimitry Andric } 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 117fe6060f1SDimitry Andric // Prints source code around in the FileName the Line. 118fe6060f1SDimitry Andric void PlainPrinterBase::printContext(SourceCode SourceCode) { 119fe6060f1SDimitry Andric SourceCode.format(OS); 120fe6060f1SDimitry Andric } 121fe6060f1SDimitry Andric 122fe6060f1SDimitry Andric void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) { 123fe6060f1SDimitry Andric if (Config.PrintFunctions) { 1248bcb0991SDimitry Andric if (FunctionName == DILineInfo::BadString) 1258bcb0991SDimitry Andric FunctionName = DILineInfo::Addr2LineBadString; 126fe6060f1SDimitry Andric StringRef Delimiter = Config.Pretty ? " at " : "\n"; 127fe6060f1SDimitry Andric StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : ""; 1280b57cec5SDimitry Andric OS << Prefix << FunctionName << Delimiter; 1290b57cec5SDimitry Andric } 130fe6060f1SDimitry Andric } 131fe6060f1SDimitry Andric 132fe6060f1SDimitry Andric void LLVMPrinter::printSimpleLocation(StringRef Filename, 133fe6060f1SDimitry Andric const DILineInfo &Info) { 134fe6060f1SDimitry Andric OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n'; 135fe6060f1SDimitry Andric printContext( 136fe6060f1SDimitry Andric SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source)); 137fe6060f1SDimitry Andric } 138fe6060f1SDimitry Andric 139fe6060f1SDimitry Andric void GNUPrinter::printSimpleLocation(StringRef Filename, 140fe6060f1SDimitry Andric const DILineInfo &Info) { 141fe6060f1SDimitry Andric OS << Filename << ':' << Info.Line; 142fe6060f1SDimitry Andric if (Info.Discriminator) 143fe6060f1SDimitry Andric OS << " (discriminator " << Info.Discriminator << ')'; 144fe6060f1SDimitry Andric OS << '\n'; 145fe6060f1SDimitry Andric printContext( 146fe6060f1SDimitry Andric SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source)); 147fe6060f1SDimitry Andric } 148fe6060f1SDimitry Andric 149fe6060f1SDimitry Andric void PlainPrinterBase::printVerbose(StringRef Filename, 150fe6060f1SDimitry Andric const DILineInfo &Info) { 151fe6060f1SDimitry Andric OS << " Filename: " << Filename << '\n'; 152fe6060f1SDimitry Andric if (Info.StartLine) { 153fe6060f1SDimitry Andric OS << " Function start filename: " << Info.StartFileName << '\n'; 154fe6060f1SDimitry Andric OS << " Function start line: " << Info.StartLine << '\n'; 155fe6060f1SDimitry Andric } 156fe6060f1SDimitry Andric printStartAddress(Info); 157fe6060f1SDimitry Andric OS << " Line: " << Info.Line << '\n'; 158fe6060f1SDimitry Andric OS << " Column: " << Info.Column << '\n'; 159fe6060f1SDimitry Andric if (Info.Discriminator) 160fe6060f1SDimitry Andric OS << " Discriminator: " << Info.Discriminator << '\n'; 161fe6060f1SDimitry Andric } 162fe6060f1SDimitry Andric 163fe6060f1SDimitry Andric void LLVMPrinter::printStartAddress(const DILineInfo &Info) { 164fe6060f1SDimitry Andric if (Info.StartAddress) { 165fe6060f1SDimitry Andric OS << " Function start address: 0x"; 166fe6060f1SDimitry Andric OS.write_hex(*Info.StartAddress); 167fe6060f1SDimitry Andric OS << '\n'; 168fe6060f1SDimitry Andric } 169fe6060f1SDimitry Andric } 170fe6060f1SDimitry Andric 171fe6060f1SDimitry Andric void LLVMPrinter::printFooter() { OS << '\n'; } 172fe6060f1SDimitry Andric 173fe6060f1SDimitry Andric void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) { 174fe6060f1SDimitry Andric printFunctionName(Info.FunctionName, Inlined); 175fe6060f1SDimitry Andric StringRef Filename = Info.FileName; 1768bcb0991SDimitry Andric if (Filename == DILineInfo::BadString) 1778bcb0991SDimitry Andric Filename = DILineInfo::Addr2LineBadString; 178fe6060f1SDimitry Andric if (Config.Verbose) 179fe6060f1SDimitry Andric printVerbose(Filename, Info); 180fe6060f1SDimitry Andric else 181fe6060f1SDimitry Andric printSimpleLocation(Filename, Info); 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 184fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) { 185fe6060f1SDimitry Andric printHeader(*Request.Address); 1860b57cec5SDimitry Andric print(Info, false); 187fe6060f1SDimitry Andric printFooter(); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 190fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request, 191fe6060f1SDimitry Andric const DIInliningInfo &Info) { 192fe6060f1SDimitry Andric printHeader(*Request.Address); 1930b57cec5SDimitry Andric uint32_t FramesNum = Info.getNumberOfFrames(); 194fe6060f1SDimitry Andric if (FramesNum == 0) 1950b57cec5SDimitry Andric print(DILineInfo(), false); 196fe6060f1SDimitry Andric else 197fe6060f1SDimitry Andric for (uint32_t I = 0; I < FramesNum; ++I) 198fe6060f1SDimitry Andric print(Info.getFrame(I), I > 0); 199fe6060f1SDimitry Andric printFooter(); 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 202fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) { 203fe6060f1SDimitry Andric printHeader(*Request.Address); 204fe6060f1SDimitry Andric StringRef Name = Global.Name; 2058bcb0991SDimitry Andric if (Name == DILineInfo::BadString) 2068bcb0991SDimitry Andric Name = DILineInfo::Addr2LineBadString; 2070b57cec5SDimitry Andric OS << Name << "\n"; 2080b57cec5SDimitry Andric OS << Global.Start << " " << Global.Size << "\n"; 20981ad6265SDimitry Andric if (Global.DeclFile.empty()) 21081ad6265SDimitry Andric OS << "??:?\n"; 21181ad6265SDimitry Andric else 21281ad6265SDimitry Andric OS << Global.DeclFile << ":" << Global.DeclLine << "\n"; 213fe6060f1SDimitry Andric printFooter(); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 216fe6060f1SDimitry Andric void PlainPrinterBase::print(const Request &Request, 217fe6060f1SDimitry Andric const std::vector<DILocal> &Locals) { 218fe6060f1SDimitry Andric printHeader(*Request.Address); 219fe6060f1SDimitry Andric if (Locals.empty()) 220fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString << '\n'; 221480093f4SDimitry Andric else 222fe6060f1SDimitry Andric for (const DILocal &L : Locals) { 223fe6060f1SDimitry Andric if (L.FunctionName.empty()) 224fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString; 225480093f4SDimitry Andric else 226fe6060f1SDimitry Andric OS << L.FunctionName; 227fe6060f1SDimitry Andric OS << '\n'; 228480093f4SDimitry Andric 229fe6060f1SDimitry Andric if (L.Name.empty()) 230fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString; 2310b57cec5SDimitry Andric else 232fe6060f1SDimitry Andric OS << L.Name; 233fe6060f1SDimitry Andric OS << '\n'; 234480093f4SDimitry Andric 235fe6060f1SDimitry Andric if (L.DeclFile.empty()) 236fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString; 237fe6060f1SDimitry Andric else 238fe6060f1SDimitry Andric OS << L.DeclFile; 239fe6060f1SDimitry Andric 240fe6060f1SDimitry Andric OS << ':' << L.DeclLine << '\n'; 241fe6060f1SDimitry Andric 242fe6060f1SDimitry Andric if (L.FrameOffset) 243fe6060f1SDimitry Andric OS << *L.FrameOffset; 244fe6060f1SDimitry Andric else 245fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString; 246fe6060f1SDimitry Andric OS << ' '; 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric if (L.Size) 249fe6060f1SDimitry Andric OS << *L.Size; 250fe6060f1SDimitry Andric else 251fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString; 252fe6060f1SDimitry Andric OS << ' '; 253fe6060f1SDimitry Andric 254fe6060f1SDimitry Andric if (L.TagOffset) 255fe6060f1SDimitry Andric OS << *L.TagOffset; 256fe6060f1SDimitry Andric else 257fe6060f1SDimitry Andric OS << DILineInfo::Addr2LineBadString; 258fe6060f1SDimitry Andric OS << '\n'; 259fe6060f1SDimitry Andric } 260fe6060f1SDimitry Andric printFooter(); 261fe6060f1SDimitry Andric } 262fe6060f1SDimitry Andric 263fe6060f1SDimitry Andric void PlainPrinterBase::printInvalidCommand(const Request &Request, 264fe6060f1SDimitry Andric StringRef Command) { 265fe6060f1SDimitry Andric OS << Command << '\n'; 266fe6060f1SDimitry Andric } 267fe6060f1SDimitry Andric 268fe6060f1SDimitry Andric bool PlainPrinterBase::printError(const Request &Request, 269*06c3fb27SDimitry Andric const ErrorInfoBase &ErrorInfo) { 270*06c3fb27SDimitry Andric ErrHandler(ErrorInfo, Request.ModuleName); 271fe6060f1SDimitry Andric // Print an empty struct too. 272fe6060f1SDimitry Andric return true; 273fe6060f1SDimitry Andric } 274fe6060f1SDimitry Andric 275fe6060f1SDimitry Andric static std::string toHex(uint64_t V) { 276fe6060f1SDimitry Andric return ("0x" + Twine::utohexstr(V)).str(); 277fe6060f1SDimitry Andric } 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") { 280fe6060f1SDimitry Andric json::Object Json({{"ModuleName", Request.ModuleName.str()}}); 281fe6060f1SDimitry Andric if (Request.Address) 282fe6060f1SDimitry Andric Json["Address"] = toHex(*Request.Address); 283fe6060f1SDimitry Andric if (!ErrorMsg.empty()) 284fe6060f1SDimitry Andric Json["Error"] = json::Object({{"Message", ErrorMsg.str()}}); 285fe6060f1SDimitry Andric return Json; 286fe6060f1SDimitry Andric } 287fe6060f1SDimitry Andric 288*06c3fb27SDimitry Andric static json::Object toJSON(const DILineInfo &LineInfo) { 289*06c3fb27SDimitry Andric return json::Object( 290fe6060f1SDimitry Andric {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString 291fe6060f1SDimitry Andric ? LineInfo.FunctionName 292fe6060f1SDimitry Andric : ""}, 293fe6060f1SDimitry Andric {"StartFileName", LineInfo.StartFileName != DILineInfo::BadString 294fe6060f1SDimitry Andric ? LineInfo.StartFileName 295fe6060f1SDimitry Andric : ""}, 296fe6060f1SDimitry Andric {"StartLine", LineInfo.StartLine}, 297fe6060f1SDimitry Andric {"StartAddress", 298fe6060f1SDimitry Andric LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""}, 299fe6060f1SDimitry Andric {"FileName", 300fe6060f1SDimitry Andric LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""}, 301fe6060f1SDimitry Andric {"Line", LineInfo.Line}, 302fe6060f1SDimitry Andric {"Column", LineInfo.Column}, 303fe6060f1SDimitry Andric {"Discriminator", LineInfo.Discriminator}}); 304*06c3fb27SDimitry Andric } 305*06c3fb27SDimitry Andric 306*06c3fb27SDimitry Andric void JSONPrinter::print(const Request &Request, const DILineInfo &Info) { 307*06c3fb27SDimitry Andric DIInliningInfo InliningInfo; 308*06c3fb27SDimitry Andric InliningInfo.addFrame(Info); 309*06c3fb27SDimitry Andric print(Request, InliningInfo); 310*06c3fb27SDimitry Andric } 311*06c3fb27SDimitry Andric 312*06c3fb27SDimitry Andric void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) { 313*06c3fb27SDimitry Andric json::Array Array; 314*06c3fb27SDimitry Andric for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) { 315*06c3fb27SDimitry Andric const DILineInfo &LineInfo = Info.getFrame(I); 316*06c3fb27SDimitry Andric json::Object Object = toJSON(LineInfo); 317fe6060f1SDimitry Andric SourceCode SourceCode(LineInfo.FileName, LineInfo.Line, 318fe6060f1SDimitry Andric Config.SourceContextLines, LineInfo.Source); 319fe6060f1SDimitry Andric std::string FormattedSource; 320fe6060f1SDimitry Andric raw_string_ostream Stream(FormattedSource); 321fe6060f1SDimitry Andric SourceCode.format(Stream); 322fe6060f1SDimitry Andric if (!FormattedSource.empty()) 323fe6060f1SDimitry Andric Object["Source"] = std::move(FormattedSource); 324fe6060f1SDimitry Andric Array.push_back(std::move(Object)); 325fe6060f1SDimitry Andric } 326fe6060f1SDimitry Andric json::Object Json = toJSON(Request); 327fe6060f1SDimitry Andric Json["Symbol"] = std::move(Array); 328fe6060f1SDimitry Andric if (ObjectList) 329fe6060f1SDimitry Andric ObjectList->push_back(std::move(Json)); 330fe6060f1SDimitry Andric else 331fe6060f1SDimitry Andric printJSON(std::move(Json)); 332fe6060f1SDimitry Andric } 333fe6060f1SDimitry Andric 334fe6060f1SDimitry Andric void JSONPrinter::print(const Request &Request, const DIGlobal &Global) { 335fe6060f1SDimitry Andric json::Object Data( 336fe6060f1SDimitry Andric {{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""}, 337fe6060f1SDimitry Andric {"Start", toHex(Global.Start)}, 338fe6060f1SDimitry Andric {"Size", toHex(Global.Size)}}); 339fe6060f1SDimitry Andric json::Object Json = toJSON(Request); 340fe6060f1SDimitry Andric Json["Data"] = std::move(Data); 341fe6060f1SDimitry Andric if (ObjectList) 342fe6060f1SDimitry Andric ObjectList->push_back(std::move(Json)); 343fe6060f1SDimitry Andric else 344fe6060f1SDimitry Andric printJSON(std::move(Json)); 345fe6060f1SDimitry Andric } 346fe6060f1SDimitry Andric 347fe6060f1SDimitry Andric void JSONPrinter::print(const Request &Request, 348fe6060f1SDimitry Andric const std::vector<DILocal> &Locals) { 349fe6060f1SDimitry Andric json::Array Frame; 350fe6060f1SDimitry Andric for (const DILocal &Local : Locals) { 351fe6060f1SDimitry Andric json::Object FrameObject( 352fe6060f1SDimitry Andric {{"FunctionName", Local.FunctionName}, 353fe6060f1SDimitry Andric {"Name", Local.Name}, 354fe6060f1SDimitry Andric {"DeclFile", Local.DeclFile}, 355fe6060f1SDimitry Andric {"DeclLine", int64_t(Local.DeclLine)}, 356fe6060f1SDimitry Andric {"Size", Local.Size ? toHex(*Local.Size) : ""}, 357fe6060f1SDimitry Andric {"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}}); 3580b57cec5SDimitry Andric if (Local.FrameOffset) 359fe6060f1SDimitry Andric FrameObject["FrameOffset"] = *Local.FrameOffset; 360fe6060f1SDimitry Andric Frame.push_back(std::move(FrameObject)); 361fe6060f1SDimitry Andric } 362fe6060f1SDimitry Andric json::Object Json = toJSON(Request); 363fe6060f1SDimitry Andric Json["Frame"] = std::move(Frame); 364fe6060f1SDimitry Andric if (ObjectList) 365fe6060f1SDimitry Andric ObjectList->push_back(std::move(Json)); 3660b57cec5SDimitry Andric else 367fe6060f1SDimitry Andric printJSON(std::move(Json)); 368fe6060f1SDimitry Andric } 369480093f4SDimitry Andric 370fe6060f1SDimitry Andric void JSONPrinter::printInvalidCommand(const Request &Request, 371fe6060f1SDimitry Andric StringRef Command) { 372fe6060f1SDimitry Andric printError(Request, 373fe6060f1SDimitry Andric StringError("unable to parse arguments: " + Command, 374*06c3fb27SDimitry Andric std::make_error_code(std::errc::invalid_argument))); 375fe6060f1SDimitry Andric } 376480093f4SDimitry Andric 377fe6060f1SDimitry Andric bool JSONPrinter::printError(const Request &Request, 378*06c3fb27SDimitry Andric const ErrorInfoBase &ErrorInfo) { 379fe6060f1SDimitry Andric json::Object Json = toJSON(Request, ErrorInfo.message()); 380fe6060f1SDimitry Andric if (ObjectList) 381fe6060f1SDimitry Andric ObjectList->push_back(std::move(Json)); 3820b57cec5SDimitry Andric else 383fe6060f1SDimitry Andric printJSON(std::move(Json)); 384fe6060f1SDimitry Andric return false; 385fe6060f1SDimitry Andric } 386fe6060f1SDimitry Andric 387fe6060f1SDimitry Andric void JSONPrinter::listBegin() { 388fe6060f1SDimitry Andric assert(!ObjectList); 389fe6060f1SDimitry Andric ObjectList = std::make_unique<json::Array>(); 390fe6060f1SDimitry Andric } 391fe6060f1SDimitry Andric 392fe6060f1SDimitry Andric void JSONPrinter::listEnd() { 393fe6060f1SDimitry Andric assert(ObjectList); 394fe6060f1SDimitry Andric printJSON(std::move(*ObjectList)); 395fe6060f1SDimitry Andric ObjectList.reset(); 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric } // end namespace symbolize 3990b57cec5SDimitry Andric } // end namespace llvm 400