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::(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::() { 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 | |