Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
35266 views
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/MemoryBuffer.h"
20
#include "llvm/Support/raw_ostream.h"
21
#include <algorithm>
22
#include <cmath>
23
#include <cstddef>
24
#include <cstdint>
25
#include <memory>
26
#include <string>
27
28
namespace llvm {
29
namespace symbolize {
30
31
class SourceCode {
32
std::unique_ptr<MemoryBuffer> MemBuf;
33
34
std::optional<StringRef>
35
load(StringRef FileName, const std::optional<StringRef> &EmbeddedSource) {
36
if (Lines <= 0)
37
return std::nullopt;
38
39
if (EmbeddedSource)
40
return EmbeddedSource;
41
else {
42
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
43
MemoryBuffer::getFile(FileName);
44
if (!BufOrErr)
45
return std::nullopt;
46
MemBuf = std::move(*BufOrErr);
47
return MemBuf->getBuffer();
48
}
49
}
50
51
std::optional<StringRef> pruneSource(const std::optional<StringRef> &Source) {
52
if (!Source)
53
return std::nullopt;
54
size_t FirstLinePos = StringRef::npos, Pos = 0;
55
for (int64_t L = 1; L <= LastLine; ++L, ++Pos) {
56
if (L == FirstLine)
57
FirstLinePos = Pos;
58
Pos = Source->find('\n', Pos);
59
if (Pos == StringRef::npos)
60
break;
61
}
62
if (FirstLinePos == StringRef::npos)
63
return std::nullopt;
64
return Source->substr(FirstLinePos, (Pos == StringRef::npos)
65
? StringRef::npos
66
: Pos - FirstLinePos);
67
}
68
69
public:
70
const int64_t Line;
71
const int Lines;
72
const int64_t FirstLine;
73
const int64_t LastLine;
74
const std::optional<StringRef> PrunedSource;
75
76
SourceCode(StringRef FileName, int64_t Line, int Lines,
77
const std::optional<StringRef> &EmbeddedSource =
78
std::optional<StringRef>())
79
: Line(Line), Lines(Lines),
80
FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)),
81
LastLine(FirstLine + Lines - 1),
82
PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {}
83
84
void format(raw_ostream &OS) {
85
if (!PrunedSource)
86
return;
87
size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
88
int64_t L = FirstLine;
89
for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) {
90
size_t PosEnd = PrunedSource->find('\n', Pos);
91
StringRef String = PrunedSource->substr(
92
Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));
93
if (String.ends_with("\r"))
94
String = String.drop_back(1);
95
OS << format_decimal(L, MaxLineNumberWidth);
96
if (L == Line)
97
OS << " >: ";
98
else
99
OS << " : ";
100
OS << String << '\n';
101
if (PosEnd == StringRef::npos)
102
break;
103
Pos = PosEnd + 1;
104
}
105
}
106
};
107
108
void PlainPrinterBase::printHeader(std::optional<uint64_t> Address) {
109
if (Address.has_value() && Config.PrintAddress) {
110
OS << "0x";
111
OS.write_hex(*Address);
112
StringRef Delimiter = Config.Pretty ? ": " : "\n";
113
OS << Delimiter;
114
}
115
}
116
117
// Prints source code around in the FileName the Line.
118
void PlainPrinterBase::printContext(SourceCode SourceCode) {
119
SourceCode.format(OS);
120
}
121
122
void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
123
if (Config.PrintFunctions) {
124
if (FunctionName == DILineInfo::BadString)
125
FunctionName = DILineInfo::Addr2LineBadString;
126
StringRef Delimiter = Config.Pretty ? " at " : "\n";
127
StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
128
OS << Prefix << FunctionName << Delimiter;
129
}
130
}
131
132
void LLVMPrinter::printSimpleLocation(StringRef Filename,
133
const DILineInfo &Info) {
134
OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
135
printContext(
136
SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
137
}
138
139
void GNUPrinter::printSimpleLocation(StringRef Filename,
140
const DILineInfo &Info) {
141
OS << Filename << ':' << Info.Line;
142
if (Info.Discriminator)
143
OS << " (discriminator " << Info.Discriminator << ')';
144
OS << '\n';
145
printContext(
146
SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
147
}
148
149
void PlainPrinterBase::printVerbose(StringRef Filename,
150
const DILineInfo &Info) {
151
OS << " Filename: " << Filename << '\n';
152
if (Info.StartLine) {
153
OS << " Function start filename: " << Info.StartFileName << '\n';
154
OS << " Function start line: " << Info.StartLine << '\n';
155
}
156
printStartAddress(Info);
157
OS << " Line: " << Info.Line << '\n';
158
OS << " Column: " << Info.Column << '\n';
159
if (Info.Discriminator)
160
OS << " Discriminator: " << Info.Discriminator << '\n';
161
}
162
163
void LLVMPrinter::printStartAddress(const DILineInfo &Info) {
164
if (Info.StartAddress) {
165
OS << " Function start address: 0x";
166
OS.write_hex(*Info.StartAddress);
167
OS << '\n';
168
}
169
}
170
171
void LLVMPrinter::printFooter() { OS << '\n'; }
172
173
void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
174
printFunctionName(Info.FunctionName, Inlined);
175
StringRef Filename = Info.FileName;
176
if (Filename == DILineInfo::BadString)
177
Filename = DILineInfo::Addr2LineBadString;
178
if (Config.Verbose)
179
printVerbose(Filename, Info);
180
else
181
printSimpleLocation(Filename, Info);
182
}
183
184
void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
185
printHeader(Request.Address);
186
print(Info, false);
187
printFooter();
188
}
189
190
void PlainPrinterBase::print(const Request &Request,
191
const DIInliningInfo &Info) {
192
printHeader(*Request.Address);
193
uint32_t FramesNum = Info.getNumberOfFrames();
194
if (FramesNum == 0)
195
print(DILineInfo(), false);
196
else
197
for (uint32_t I = 0; I < FramesNum; ++I)
198
print(Info.getFrame(I), I > 0);
199
printFooter();
200
}
201
202
void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
203
printHeader(*Request.Address);
204
StringRef Name = Global.Name;
205
if (Name == DILineInfo::BadString)
206
Name = DILineInfo::Addr2LineBadString;
207
OS << Name << "\n";
208
OS << Global.Start << " " << Global.Size << "\n";
209
if (Global.DeclFile.empty())
210
OS << "??:?\n";
211
else
212
OS << Global.DeclFile << ":" << Global.DeclLine << "\n";
213
printFooter();
214
}
215
216
void PlainPrinterBase::print(const Request &Request,
217
const std::vector<DILocal> &Locals) {
218
printHeader(*Request.Address);
219
if (Locals.empty())
220
OS << DILineInfo::Addr2LineBadString << '\n';
221
else
222
for (const DILocal &L : Locals) {
223
if (L.FunctionName.empty())
224
OS << DILineInfo::Addr2LineBadString;
225
else
226
OS << L.FunctionName;
227
OS << '\n';
228
229
if (L.Name.empty())
230
OS << DILineInfo::Addr2LineBadString;
231
else
232
OS << L.Name;
233
OS << '\n';
234
235
if (L.DeclFile.empty())
236
OS << DILineInfo::Addr2LineBadString;
237
else
238
OS << L.DeclFile;
239
240
OS << ':' << L.DeclLine << '\n';
241
242
if (L.FrameOffset)
243
OS << *L.FrameOffset;
244
else
245
OS << DILineInfo::Addr2LineBadString;
246
OS << ' ';
247
248
if (L.Size)
249
OS << *L.Size;
250
else
251
OS << DILineInfo::Addr2LineBadString;
252
OS << ' ';
253
254
if (L.TagOffset)
255
OS << *L.TagOffset;
256
else
257
OS << DILineInfo::Addr2LineBadString;
258
OS << '\n';
259
}
260
printFooter();
261
}
262
263
void PlainPrinterBase::print(const Request &Request,
264
const std::vector<DILineInfo> &Locations) {
265
if (Locations.empty()) {
266
print(Request, DILineInfo());
267
} else {
268
for (const DILineInfo &L : Locations)
269
print(L, false);
270
printFooter();
271
}
272
}
273
274
bool PlainPrinterBase::printError(const Request &Request,
275
const ErrorInfoBase &ErrorInfo) {
276
ErrHandler(ErrorInfo, Request.ModuleName);
277
// Print an empty struct too.
278
return true;
279
}
280
281
static std::string toHex(uint64_t V) {
282
return ("0x" + Twine::utohexstr(V)).str();
283
}
284
285
static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
286
json::Object Json({{"ModuleName", Request.ModuleName.str()}});
287
if (!Request.Symbol.empty())
288
Json["SymName"] = Request.Symbol.str();
289
if (Request.Address)
290
Json["Address"] = toHex(*Request.Address);
291
if (!ErrorMsg.empty())
292
Json["Error"] = json::Object({{"Message", ErrorMsg.str()}});
293
return Json;
294
}
295
296
static json::Object toJSON(const DILineInfo &LineInfo) {
297
return json::Object(
298
{{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString
299
? LineInfo.FunctionName
300
: ""},
301
{"StartFileName", LineInfo.StartFileName != DILineInfo::BadString
302
? LineInfo.StartFileName
303
: ""},
304
{"StartLine", LineInfo.StartLine},
305
{"StartAddress",
306
LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""},
307
{"FileName",
308
LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
309
{"Line", LineInfo.Line},
310
{"Column", LineInfo.Column},
311
{"Discriminator", LineInfo.Discriminator}});
312
}
313
314
void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
315
DIInliningInfo InliningInfo;
316
InliningInfo.addFrame(Info);
317
print(Request, InliningInfo);
318
}
319
320
void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) {
321
json::Array Array;
322
for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) {
323
const DILineInfo &LineInfo = Info.getFrame(I);
324
json::Object Object = toJSON(LineInfo);
325
SourceCode SourceCode(LineInfo.FileName, LineInfo.Line,
326
Config.SourceContextLines, LineInfo.Source);
327
std::string FormattedSource;
328
raw_string_ostream Stream(FormattedSource);
329
SourceCode.format(Stream);
330
if (!FormattedSource.empty())
331
Object["Source"] = std::move(FormattedSource);
332
Array.push_back(std::move(Object));
333
}
334
json::Object Json = toJSON(Request);
335
Json["Symbol"] = std::move(Array);
336
if (ObjectList)
337
ObjectList->push_back(std::move(Json));
338
else
339
printJSON(std::move(Json));
340
}
341
342
void JSONPrinter::print(const Request &Request, const DIGlobal &Global) {
343
json::Object Data(
344
{{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""},
345
{"Start", toHex(Global.Start)},
346
{"Size", toHex(Global.Size)}});
347
json::Object Json = toJSON(Request);
348
Json["Data"] = std::move(Data);
349
if (ObjectList)
350
ObjectList->push_back(std::move(Json));
351
else
352
printJSON(std::move(Json));
353
}
354
355
void JSONPrinter::print(const Request &Request,
356
const std::vector<DILocal> &Locals) {
357
json::Array Frame;
358
for (const DILocal &Local : Locals) {
359
json::Object FrameObject(
360
{{"FunctionName", Local.FunctionName},
361
{"Name", Local.Name},
362
{"DeclFile", Local.DeclFile},
363
{"DeclLine", int64_t(Local.DeclLine)},
364
{"Size", Local.Size ? toHex(*Local.Size) : ""},
365
{"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}});
366
if (Local.FrameOffset)
367
FrameObject["FrameOffset"] = *Local.FrameOffset;
368
Frame.push_back(std::move(FrameObject));
369
}
370
json::Object Json = toJSON(Request);
371
Json["Frame"] = std::move(Frame);
372
if (ObjectList)
373
ObjectList->push_back(std::move(Json));
374
else
375
printJSON(std::move(Json));
376
}
377
378
void JSONPrinter::print(const Request &Request,
379
const std::vector<DILineInfo> &Locations) {
380
json::Array Definitions;
381
for (const DILineInfo &L : Locations)
382
Definitions.push_back(toJSON(L));
383
json::Object Json = toJSON(Request);
384
Json["Loc"] = std::move(Definitions);
385
if (ObjectList)
386
ObjectList->push_back(std::move(Json));
387
else
388
printJSON(std::move(Json));
389
}
390
391
bool JSONPrinter::printError(const Request &Request,
392
const ErrorInfoBase &ErrorInfo) {
393
json::Object Json = toJSON(Request, ErrorInfo.message());
394
if (ObjectList)
395
ObjectList->push_back(std::move(Json));
396
else
397
printJSON(std::move(Json));
398
return false;
399
}
400
401
void JSONPrinter::listBegin() {
402
assert(!ObjectList);
403
ObjectList = std::make_unique<json::Array>();
404
}
405
406
void JSONPrinter::listEnd() {
407
assert(ObjectList);
408
printJSON(std::move(*ObjectList));
409
ObjectList.reset();
410
}
411
412
} // end namespace symbolize
413
} // end namespace llvm
414
415