1//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the DIPrinter class, which is responsible for printing
10// structures defined in DebugInfo/DIContext.h
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/DebugInfo/DIContext.h"
17#include "llvm/Support/ErrorOr.h"
18#include "llvm/Support/Format.h"
19#include "llvm/Support/LineIterator.h"
20#include "llvm/Support/MemoryBuffer.h"
21#include "llvm/Support/Path.h"
22#include "llvm/Support/raw_ostream.h"
23#include <algorithm>
24#include <cmath>
25#include <cstddef>
26#include <cstdint>
27#include <memory>
28#include <string>
29
30namespace llvm {
31namespace symbolize {
32
33void PlainPrinterBase::printHeader(uint64_t Address) {
34 if (Config.PrintAddress) {
35 OS << "0x";
36 OS.write_hex(Address);
37 StringRef Delimiter = Config.Pretty ? ": " : "\n";
38 OS << Delimiter;
39 }
40}
41
42// Prints source code around in the FileName the Line.
43void PlainPrinterBase::printContext(StringRef FileName, int64_t Line) {
44 if (Config.SourceContextLines <= 0)
45 return;
46
47 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
48 MemoryBuffer::getFile(FileName);
49 if (!BufOrErr)
50 return;
51
52 std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
53 int64_t FirstLine =
54 std::max(static_cast<int64_t>(1), Line - Config.SourceContextLines / 2);
55 int64_t LastLine = FirstLine + Config.SourceContextLines;
56 size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
57
58 for (line_iterator I = line_iterator(*Buf, false);
59 !I.is_at_eof() && I.line_number() <= LastLine; ++I) {
60 int64_t L = I.line_number();
61 if (L >= FirstLine && L <= LastLine) {
62 OS << format_decimal(L, MaxLineNumberWidth);
63 if (L == Line)
64 OS << " >: ";
65 else
66 OS << " : ";
67 OS << *I << "\n";
68 }
69 }
70}
71
72void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
73 if (Config.PrintFunctions) {
74 if (FunctionName == DILineInfo::BadString)
75 FunctionName = DILineInfo::Addr2LineBadString;
76 StringRef Delimiter = Config.Pretty ? " at " : "\n";
77 StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
78 OS << Prefix << FunctionName << Delimiter;
79 }
80}
81
82void LLVMPrinter::printSimpleLocation(StringRef Filename,
83 const DILineInfo &Info) {
84 OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
85 printContext(Filename, Info.Line);
86}
87
88void GNUPrinter::printSimpleLocation(StringRef Filename,
89 const DILineInfo &Info) {
90 OS << Filename << ':' << Info.Line;
91 if (Info.Discriminator)
92 OS << " (discriminator " << Info.Discriminator << ')';
93 OS << '\n';
94 printContext(Filename, Info.Line);
95}
96
97void PlainPrinterBase::printVerbose(StringRef Filename,
98 const DILineInfo &Info) {
99 OS << " Filename: " << Filename << '\n';
100 if (Info.StartLine) {
101 OS << " Function start filename: " << Info.StartFileName << '\n';
102 OS << " Function start line: " << Info.StartLine << '\n';
103 }
104 OS << " Line: " << Info.Line << '\n';
105 OS << " Column: " << Info.Column << '\n';
106 if (Info.Discriminator)
107 OS << " Discriminator: " << Info.Discriminator << '\n';
108}
109
110void LLVMPrinter::printFooter() { OS << '\n'; }
111
112void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
113 printFunctionName(Info.FunctionName, Inlined);
114 StringRef Filename = Info.FileName;
115 if (Filename == DILineInfo::BadString)
116 Filename = DILineInfo::Addr2LineBadString;
117 if (Config.Verbose)
118 printVerbose(Filename, Info);
119 else
120 printSimpleLocation(Filename, Info);
121}
122
123void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
124 printHeader(Request.Address);
125 print(Info, false);
126 printFooter();
127}
128
129void PlainPrinterBase::print(const Request &Request,
130 const DIInliningInfo &Info) {
131 printHeader(Request.Address);
132 uint32_t FramesNum = Info.getNumberOfFrames();
133 if (FramesNum == 0)
134 print(DILineInfo(), false);
135 else
136 for (uint32_t I = 0; I < FramesNum; ++I)
137 print(Info.getFrame(I), I > 0);
138 printFooter();
139}
140
141void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
142 printHeader(Request.Address);
143 StringRef Name = Global.Name;
144 if (Name == DILineInfo::BadString)
145 Name = DILineInfo::Addr2LineBadString;
146 OS << Name << "\n";
147 OS << Global.Start << " " << Global.Size << "\n";
148 printFooter();
149}
150
151void PlainPrinterBase::print(const Request &Request,
152 const std::vector<DILocal> &Locals) {
153 printHeader(Request.Address);
154 if (Locals.empty())
155 OS << DILineInfo::Addr2LineBadString << '\n';
156 else
157 for (const DILocal &L : Locals) {
158 if (L.FunctionName.empty())
159 OS << DILineInfo::Addr2LineBadString;
160 else
161 OS << L.FunctionName;
162 OS << '\n';
163
164 if (L.Name.empty())
165 OS << DILineInfo::Addr2LineBadString;
166 else
167 OS << L.Name;
168 OS << '\n';
169
170 if (L.DeclFile.empty())
171 OS << DILineInfo::Addr2LineBadString;
172 else
173 OS << L.DeclFile;
174
175 OS << ':' << L.DeclLine << '\n';
176
177 if (L.FrameOffset)
178 OS << *L.FrameOffset;
179 else
180 OS << DILineInfo::Addr2LineBadString;
181 OS << ' ';
182
183 if (L.Size)
184 OS << *L.Size;
185 else
186 OS << DILineInfo::Addr2LineBadString;
187 OS << ' ';
188
189 if (L.TagOffset)
190 OS << *L.TagOffset;
191 else
192 OS << DILineInfo::Addr2LineBadString;
193 OS << '\n';
194 }
195 printFooter();
196}
197
198void PlainPrinterBase::printInvalidCommand(const Request &Request,
199 const ErrorInfoBase &ErrorInfo) {
200 OS << ErrorInfo.message() << '\n';
201}
202
203bool PlainPrinterBase::printError(const Request &Request,
204 const ErrorInfoBase &ErrorInfo,
205 StringRef ErrorBanner) {
206 ES << ErrorBanner;
207 ErrorInfo.log(ES);
208 ES << '\n';
209 // Print an empty struct too.
210 return true;
211}
212
213} // end namespace symbolize
214} // end namespace llvm
215