Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
35266 views
//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the DIPrinter class, which is responsible for printing9// structures defined in DebugInfo/DIContext.h10//11//===----------------------------------------------------------------------===//1213#include "llvm/DebugInfo/Symbolize/DIPrinter.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/DebugInfo/DIContext.h"16#include "llvm/Support/ErrorOr.h"17#include "llvm/Support/Format.h"18#include "llvm/Support/MemoryBuffer.h"19#include "llvm/Support/raw_ostream.h"20#include <algorithm>21#include <cmath>22#include <cstddef>23#include <cstdint>24#include <memory>25#include <string>2627namespace llvm {28namespace symbolize {2930class SourceCode {31std::unique_ptr<MemoryBuffer> MemBuf;3233std::optional<StringRef>34load(StringRef FileName, const std::optional<StringRef> &EmbeddedSource) {35if (Lines <= 0)36return std::nullopt;3738if (EmbeddedSource)39return EmbeddedSource;40else {41ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =42MemoryBuffer::getFile(FileName);43if (!BufOrErr)44return std::nullopt;45MemBuf = std::move(*BufOrErr);46return MemBuf->getBuffer();47}48}4950std::optional<StringRef> pruneSource(const std::optional<StringRef> &Source) {51if (!Source)52return std::nullopt;53size_t FirstLinePos = StringRef::npos, Pos = 0;54for (int64_t L = 1; L <= LastLine; ++L, ++Pos) {55if (L == FirstLine)56FirstLinePos = Pos;57Pos = Source->find('\n', Pos);58if (Pos == StringRef::npos)59break;60}61if (FirstLinePos == StringRef::npos)62return std::nullopt;63return Source->substr(FirstLinePos, (Pos == StringRef::npos)64? StringRef::npos65: Pos - FirstLinePos);66}6768public:69const int64_t Line;70const int Lines;71const int64_t FirstLine;72const int64_t LastLine;73const std::optional<StringRef> PrunedSource;7475SourceCode(StringRef FileName, int64_t Line, int Lines,76const std::optional<StringRef> &EmbeddedSource =77std::optional<StringRef>())78: Line(Line), Lines(Lines),79FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)),80LastLine(FirstLine + Lines - 1),81PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {}8283void format(raw_ostream &OS) {84if (!PrunedSource)85return;86size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));87int64_t L = FirstLine;88for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) {89size_t PosEnd = PrunedSource->find('\n', Pos);90StringRef String = PrunedSource->substr(91Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));92if (String.ends_with("\r"))93String = String.drop_back(1);94OS << format_decimal(L, MaxLineNumberWidth);95if (L == Line)96OS << " >: ";97else98OS << " : ";99OS << String << '\n';100if (PosEnd == StringRef::npos)101break;102Pos = PosEnd + 1;103}104}105};106107void PlainPrinterBase::printHeader(std::optional<uint64_t> Address) {108if (Address.has_value() && Config.PrintAddress) {109OS << "0x";110OS.write_hex(*Address);111StringRef Delimiter = Config.Pretty ? ": " : "\n";112OS << Delimiter;113}114}115116// Prints source code around in the FileName the Line.117void PlainPrinterBase::printContext(SourceCode SourceCode) {118SourceCode.format(OS);119}120121void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {122if (Config.PrintFunctions) {123if (FunctionName == DILineInfo::BadString)124FunctionName = DILineInfo::Addr2LineBadString;125StringRef Delimiter = Config.Pretty ? " at " : "\n";126StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";127OS << Prefix << FunctionName << Delimiter;128}129}130131void LLVMPrinter::printSimpleLocation(StringRef Filename,132const DILineInfo &Info) {133OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';134printContext(135SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));136}137138void GNUPrinter::printSimpleLocation(StringRef Filename,139const DILineInfo &Info) {140OS << Filename << ':' << Info.Line;141if (Info.Discriminator)142OS << " (discriminator " << Info.Discriminator << ')';143OS << '\n';144printContext(145SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));146}147148void PlainPrinterBase::printVerbose(StringRef Filename,149const DILineInfo &Info) {150OS << " Filename: " << Filename << '\n';151if (Info.StartLine) {152OS << " Function start filename: " << Info.StartFileName << '\n';153OS << " Function start line: " << Info.StartLine << '\n';154}155printStartAddress(Info);156OS << " Line: " << Info.Line << '\n';157OS << " Column: " << Info.Column << '\n';158if (Info.Discriminator)159OS << " Discriminator: " << Info.Discriminator << '\n';160}161162void LLVMPrinter::printStartAddress(const DILineInfo &Info) {163if (Info.StartAddress) {164OS << " Function start address: 0x";165OS.write_hex(*Info.StartAddress);166OS << '\n';167}168}169170void LLVMPrinter::printFooter() { OS << '\n'; }171172void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {173printFunctionName(Info.FunctionName, Inlined);174StringRef Filename = Info.FileName;175if (Filename == DILineInfo::BadString)176Filename = DILineInfo::Addr2LineBadString;177if (Config.Verbose)178printVerbose(Filename, Info);179else180printSimpleLocation(Filename, Info);181}182183void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {184printHeader(Request.Address);185print(Info, false);186printFooter();187}188189void PlainPrinterBase::print(const Request &Request,190const DIInliningInfo &Info) {191printHeader(*Request.Address);192uint32_t FramesNum = Info.getNumberOfFrames();193if (FramesNum == 0)194print(DILineInfo(), false);195else196for (uint32_t I = 0; I < FramesNum; ++I)197print(Info.getFrame(I), I > 0);198printFooter();199}200201void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {202printHeader(*Request.Address);203StringRef Name = Global.Name;204if (Name == DILineInfo::BadString)205Name = DILineInfo::Addr2LineBadString;206OS << Name << "\n";207OS << Global.Start << " " << Global.Size << "\n";208if (Global.DeclFile.empty())209OS << "??:?\n";210else211OS << Global.DeclFile << ":" << Global.DeclLine << "\n";212printFooter();213}214215void PlainPrinterBase::print(const Request &Request,216const std::vector<DILocal> &Locals) {217printHeader(*Request.Address);218if (Locals.empty())219OS << DILineInfo::Addr2LineBadString << '\n';220else221for (const DILocal &L : Locals) {222if (L.FunctionName.empty())223OS << DILineInfo::Addr2LineBadString;224else225OS << L.FunctionName;226OS << '\n';227228if (L.Name.empty())229OS << DILineInfo::Addr2LineBadString;230else231OS << L.Name;232OS << '\n';233234if (L.DeclFile.empty())235OS << DILineInfo::Addr2LineBadString;236else237OS << L.DeclFile;238239OS << ':' << L.DeclLine << '\n';240241if (L.FrameOffset)242OS << *L.FrameOffset;243else244OS << DILineInfo::Addr2LineBadString;245OS << ' ';246247if (L.Size)248OS << *L.Size;249else250OS << DILineInfo::Addr2LineBadString;251OS << ' ';252253if (L.TagOffset)254OS << *L.TagOffset;255else256OS << DILineInfo::Addr2LineBadString;257OS << '\n';258}259printFooter();260}261262void PlainPrinterBase::print(const Request &Request,263const std::vector<DILineInfo> &Locations) {264if (Locations.empty()) {265print(Request, DILineInfo());266} else {267for (const DILineInfo &L : Locations)268print(L, false);269printFooter();270}271}272273bool PlainPrinterBase::printError(const Request &Request,274const ErrorInfoBase &ErrorInfo) {275ErrHandler(ErrorInfo, Request.ModuleName);276// Print an empty struct too.277return true;278}279280static std::string toHex(uint64_t V) {281return ("0x" + Twine::utohexstr(V)).str();282}283284static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {285json::Object Json({{"ModuleName", Request.ModuleName.str()}});286if (!Request.Symbol.empty())287Json["SymName"] = Request.Symbol.str();288if (Request.Address)289Json["Address"] = toHex(*Request.Address);290if (!ErrorMsg.empty())291Json["Error"] = json::Object({{"Message", ErrorMsg.str()}});292return Json;293}294295static json::Object toJSON(const DILineInfo &LineInfo) {296return json::Object(297{{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString298? LineInfo.FunctionName299: ""},300{"StartFileName", LineInfo.StartFileName != DILineInfo::BadString301? LineInfo.StartFileName302: ""},303{"StartLine", LineInfo.StartLine},304{"StartAddress",305LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""},306{"FileName",307LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},308{"Line", LineInfo.Line},309{"Column", LineInfo.Column},310{"Discriminator", LineInfo.Discriminator}});311}312313void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {314DIInliningInfo InliningInfo;315InliningInfo.addFrame(Info);316print(Request, InliningInfo);317}318319void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) {320json::Array Array;321for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) {322const DILineInfo &LineInfo = Info.getFrame(I);323json::Object Object = toJSON(LineInfo);324SourceCode SourceCode(LineInfo.FileName, LineInfo.Line,325Config.SourceContextLines, LineInfo.Source);326std::string FormattedSource;327raw_string_ostream Stream(FormattedSource);328SourceCode.format(Stream);329if (!FormattedSource.empty())330Object["Source"] = std::move(FormattedSource);331Array.push_back(std::move(Object));332}333json::Object Json = toJSON(Request);334Json["Symbol"] = std::move(Array);335if (ObjectList)336ObjectList->push_back(std::move(Json));337else338printJSON(std::move(Json));339}340341void JSONPrinter::print(const Request &Request, const DIGlobal &Global) {342json::Object Data(343{{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""},344{"Start", toHex(Global.Start)},345{"Size", toHex(Global.Size)}});346json::Object Json = toJSON(Request);347Json["Data"] = std::move(Data);348if (ObjectList)349ObjectList->push_back(std::move(Json));350else351printJSON(std::move(Json));352}353354void JSONPrinter::print(const Request &Request,355const std::vector<DILocal> &Locals) {356json::Array Frame;357for (const DILocal &Local : Locals) {358json::Object FrameObject(359{{"FunctionName", Local.FunctionName},360{"Name", Local.Name},361{"DeclFile", Local.DeclFile},362{"DeclLine", int64_t(Local.DeclLine)},363{"Size", Local.Size ? toHex(*Local.Size) : ""},364{"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}});365if (Local.FrameOffset)366FrameObject["FrameOffset"] = *Local.FrameOffset;367Frame.push_back(std::move(FrameObject));368}369json::Object Json = toJSON(Request);370Json["Frame"] = std::move(Frame);371if (ObjectList)372ObjectList->push_back(std::move(Json));373else374printJSON(std::move(Json));375}376377void JSONPrinter::print(const Request &Request,378const std::vector<DILineInfo> &Locations) {379json::Array Definitions;380for (const DILineInfo &L : Locations)381Definitions.push_back(toJSON(L));382json::Object Json = toJSON(Request);383Json["Loc"] = std::move(Definitions);384if (ObjectList)385ObjectList->push_back(std::move(Json));386else387printJSON(std::move(Json));388}389390bool JSONPrinter::printError(const Request &Request,391const ErrorInfoBase &ErrorInfo) {392json::Object Json = toJSON(Request, ErrorInfo.message());393if (ObjectList)394ObjectList->push_back(std::move(Json));395else396printJSON(std::move(Json));397return false;398}399400void JSONPrinter::listBegin() {401assert(!ObjectList);402ObjectList = std::make_unique<json::Array>();403}404405void JSONPrinter::listEnd() {406assert(ObjectList);407printJSON(std::move(*ObjectList));408ObjectList.reset();409}410411} // end namespace symbolize412} // end namespace llvm413414415