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 
30 namespace llvm {
31 namespace symbolize {
32 
33 void 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.
43 void 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 
72 void 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 
82 void LLVMPrinter::printSimpleLocation(StringRef Filename,
83                                       const DILineInfo &Info) {
84   OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
85   printContext(Filename, Info.Line);
86 }
87 
88 void 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 
97 void 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 
110 void LLVMPrinter::printFooter() { OS << '\n'; }
111 
112 void 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 
123 void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
124   printHeader(Request.Address);
125   print(Info, false);
126   printFooter();
127 }
128 
129 void 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 
141 void 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 
151 void 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 
198 void PlainPrinterBase::printInvalidCommand(const Request &Request,
199                                            const ErrorInfoBase &ErrorInfo) {
200   OS << ErrorInfo.message() << '\n';
201 }
202 
203 bool 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