Skip to content

Commit d4152c5

Browse files
author
Andres Villegas
authored
[NFC][sanitizer_symbolizer]Add StackTracePrinter class (llvm#66530)
Introduce a new virtual class StackTracePrinter and an implementation FormattedStackTracePrinter in preparation of enabling symbolizer markup for linux. This change allows us to implement other behaviour under the same api for StackTracePrinter, for example, MarkupStackTracePrinter.
1 parent 1f15e39 commit d4152c5

10 files changed

+228
-135
lines changed

compiler-rt/lib/hwasan/hwasan_report.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,10 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
246246
frame_desc.append(" record_addr:0x%zx record:0x%zx",
247247
reinterpret_cast<uptr>(record_addr), record);
248248
if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
249-
RenderFrame(&frame_desc, " %F %L", 0, frame->info.address, &frame->info,
250-
common_flags()->symbolize_vs_style,
251-
common_flags()->strip_path_prefix);
249+
StackTracePrinter::GetOrInit()->RenderFrame(
250+
&frame_desc, " %F %L", 0, frame->info.address, &frame->info,
251+
common_flags()->symbolize_vs_style,
252+
common_flags()->strip_path_prefix);
252253
frame->ClearAll();
253254
}
254255
Printf("%s\n", frame_desc.data());

compiler-rt/lib/msan/msan_report.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ void DescribeMemoryRange(const void *x, uptr size) {
269269

270270
void ReportUMRInsideAddressRange(const char *function, const void *start,
271271
uptr size, uptr offset) {
272-
function = StripFunctionName(function);
272+
function = StackTracePrinter::GetOrInit()->StripFunctionName(function);
273273
Decorator d;
274274
Printf("%s", d.Warning());
275275
Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",

compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class StackTraceTextPrinter {
2929
frame_delimiter_(frame_delimiter),
3030
output_(output),
3131
dedup_token_(dedup_token),
32-
symbolize_(RenderNeedsSymbolization(stack_trace_fmt)) {}
32+
symbolize_(StackTracePrinter::GetOrInit()->RenderNeedsSymbolization(
33+
stack_trace_fmt)) {}
3334

3435
bool ProcessAddressFrames(uptr pc) {
3536
SymbolizedStack *frames = symbolize_
@@ -40,10 +41,10 @@ class StackTraceTextPrinter {
4041

4142
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
4243
uptr prev_len = output_->length();
43-
RenderFrame(output_, stack_trace_fmt_, frame_num_++, cur->info.address,
44-
symbolize_ ? &cur->info : nullptr,
45-
common_flags()->symbolize_vs_style,
46-
common_flags()->strip_path_prefix);
44+
StackTracePrinter::GetOrInit()->RenderFrame(
45+
output_, stack_trace_fmt_, frame_num_++, cur->info.address,
46+
symbolize_ ? &cur->info : nullptr, common_flags()->symbolize_vs_style,
47+
common_flags()->strip_path_prefix);
4748

4849
if (prev_len != output_->length())
4950
output_->append("%c", frame_delimiter_);
@@ -210,7 +211,8 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
210211
DataInfo DI;
211212
if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
212213
InternalScopedString data_desc;
213-
RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
214+
StackTracePrinter::GetOrInit()->RenderData(&data_desc, fmt, &DI,
215+
common_flags()->strip_path_prefix);
214216
internal_strncpy(out_buf, data_desc.data(), out_buf_size);
215217
out_buf[out_buf_size - 1] = 0;
216218
}

compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,30 @@
1212

1313
#include "sanitizer_stacktrace_printer.h"
1414

15+
#include "sanitizer_common.h"
1516
#include "sanitizer_file.h"
1617
#include "sanitizer_flags.h"
1718
#include "sanitizer_fuchsia.h"
1819

1920
namespace __sanitizer {
2021

21-
const char *StripFunctionName(const char *function) {
22+
23+
StackTracePrinter *StackTracePrinter::GetOrInit() {
24+
static StackTracePrinter *stacktrace_printer;
25+
static StaticSpinMutex init_mu;
26+
SpinMutexLock l(&init_mu);
27+
if (stacktrace_printer)
28+
return stacktrace_printer;
29+
30+
stacktrace_printer =
31+
new (GetGlobalLowLevelAllocator()) FormattedStackTracePrinter();
32+
33+
CHECK(stacktrace_printer);
34+
return stacktrace_printer;
35+
}
36+
37+
const char *FormattedStackTracePrinter::StripFunctionName(
38+
const char *function) {
2239
if (!common_flags()->demangle)
2340
return function;
2441
if (!function)
@@ -141,9 +158,12 @@ static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,
141158

142159
static const char kDefaultFormat[] = " #%n %p %F %L";
143160

144-
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
145-
uptr address, const AddressInfo *info, bool vs_style,
146-
const char *strip_path_prefix) {
161+
void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
162+
const char *format, int frame_no,
163+
uptr address,
164+
const AddressInfo *info,
165+
bool vs_style,
166+
const char *strip_path_prefix) {
147167
// info will be null in the case where symbolization is not needed for the
148168
// given format. This ensures that the code below will get a hard failure
149169
// rather than print incorrect information in case RenderNeedsSymbolization
@@ -250,7 +270,7 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
250270
}
251271
}
252272

253-
bool RenderNeedsSymbolization(const char *format) {
273+
bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format) {
254274
if (0 == internal_strcmp(format, "DEFAULT"))
255275
format = kDefaultFormat;
256276
for (const char *p = format; *p != '\0'; p++) {
@@ -273,8 +293,10 @@ bool RenderNeedsSymbolization(const char *format) {
273293
return false;
274294
}
275295

276-
void RenderData(InternalScopedString *buffer, const char *format,
277-
const DataInfo *DI, const char *strip_path_prefix) {
296+
void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
297+
const char *format,
298+
const DataInfo *DI,
299+
const char *strip_path_prefix) {
278300
for (const char *p = format; *p != '\0'; p++) {
279301
if (*p != '%') {
280302
buffer->append("%c", *p);
@@ -304,9 +326,9 @@ void RenderData(InternalScopedString *buffer, const char *format,
304326

305327
#endif // !SANITIZER_SYMBOLIZER_MARKUP
306328

307-
void RenderSourceLocation(InternalScopedString *buffer, const char *file,
308-
int line, int column, bool vs_style,
309-
const char *strip_path_prefix) {
329+
void FormattedStackTracePrinter::RenderSourceLocation(
330+
InternalScopedString *buffer, const char *file, int line, int column,
331+
bool vs_style, const char *strip_path_prefix) {
310332
if (vs_style && line > 0) {
311333
buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
312334
if (column > 0)
@@ -323,9 +345,9 @@ void RenderSourceLocation(InternalScopedString *buffer, const char *file,
323345
}
324346
}
325347

326-
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
327-
uptr offset, ModuleArch arch,
328-
const char *strip_path_prefix) {
348+
void FormattedStackTracePrinter::RenderModuleLocation(
349+
InternalScopedString *buffer, const char *module, uptr offset,
350+
ModuleArch arch, const char *strip_path_prefix) {
329351
buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
330352
if (arch != kModuleArchUnknown) {
331353
buffer->append(":%s", ModuleArchToString(arch));

compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h

Lines changed: 97 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,61 +13,107 @@
1313
#define SANITIZER_STACKTRACE_PRINTER_H
1414

1515
#include "sanitizer_common.h"
16+
#include "sanitizer_internal_defs.h"
1617
#include "sanitizer_symbolizer.h"
1718

1819
namespace __sanitizer {
1920

20-
// Strip interceptor prefixes from function name.
21-
const char *StripFunctionName(const char *function);
22-
23-
// Render the contents of "info" structure, which represents the contents of
24-
// stack frame "frame_no" and appends it to the "buffer". "format" is a
25-
// string with placeholders, which is copied to the output with
26-
// placeholders substituted with the contents of "info". For example,
27-
// format string
28-
// " frame %n: function %F at %S"
29-
// will be turned into
30-
// " frame 10: function foo::bar() at my/file.cc:10"
31-
// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
32-
// source files and modules.
33-
// Here's the full list of available placeholders:
34-
// %% - represents a '%' character;
35-
// %n - frame number (copy of frame_no);
36-
// %p - PC in hex format;
37-
// %m - path to module (binary or shared object);
38-
// %o - offset in the module in hex format;
39-
// %f - function name;
40-
// %q - offset in the function in hex format (*if available*);
41-
// %s - path to source file;
42-
// %l - line in the source file;
43-
// %c - column in the source file;
44-
// %F - if function is known to be <foo>, prints "in <foo>", possibly
45-
// followed by the offset in this function, but only if source file
46-
// is unknown;
47-
// %S - prints file/line/column information;
48-
// %L - prints location information: file/line/column, if it is known, or
49-
// module+offset if it is known, or (<unknown module>) string.
50-
// %M - prints module basename and offset, if it is known, or PC.
51-
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
52-
uptr address, const AddressInfo *info, bool vs_style,
53-
const char *strip_path_prefix = "");
54-
55-
bool RenderNeedsSymbolization(const char *format);
56-
57-
void RenderSourceLocation(InternalScopedString *buffer, const char *file,
58-
int line, int column, bool vs_style,
59-
const char *strip_path_prefix);
60-
61-
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
62-
uptr offset, ModuleArch arch,
63-
const char *strip_path_prefix);
64-
65-
// Same as RenderFrame, but for data section (global variables).
66-
// Accepts %s, %l from above.
67-
// Also accepts:
68-
// %g - name of the global variable.
69-
void RenderData(InternalScopedString *buffer, const char *format,
70-
const DataInfo *DI, const char *strip_path_prefix = "");
21+
// StacktracePrinter is an interface that is implemented by
22+
// classes that can perform rendering of the different parts
23+
// of a stacktrace.
24+
class StackTracePrinter {
25+
public:
26+
static StackTracePrinter *GetOrInit();
27+
28+
virtual const char *StripFunctionName(const char *function) {
29+
UNIMPLEMENTED();
30+
}
31+
32+
virtual void RenderFrame(InternalScopedString *buffer, const char *format,
33+
int frame_no, uptr address, const AddressInfo *info,
34+
bool vs_style, const char *strip_path_prefix = "") {
35+
UNIMPLEMENTED();
36+
}
37+
38+
virtual bool RenderNeedsSymbolization(const char *format) { return false; }
39+
40+
virtual void RenderSourceLocation(InternalScopedString *buffer,
41+
const char *file, int line, int column,
42+
bool vs_style,
43+
const char *strip_path_prefix) {}
44+
45+
virtual void RenderModuleLocation(InternalScopedString *buffer,
46+
const char *module, uptr offset,
47+
ModuleArch arch,
48+
const char *strip_path_prefix) {}
49+
virtual void RenderData(InternalScopedString *buffer, const char *format,
50+
const DataInfo *DI,
51+
const char *strip_path_prefix = "") {
52+
UNIMPLEMENTED();
53+
}
54+
55+
protected:
56+
~StackTracePrinter() {}
57+
};
58+
59+
class FormattedStackTracePrinter : public StackTracePrinter {
60+
public:
61+
// Strip interceptor prefixes from function name.
62+
const char *StripFunctionName(const char *function) override;
63+
64+
// Render the contents of "info" structure, which represents the contents of
65+
// stack frame "frame_no" and appends it to the "buffer". "format" is a
66+
// string with placeholders, which is copied to the output with
67+
// placeholders substituted with the contents of "info". For example,
68+
// format string
69+
// " frame %n: function %F at %S"
70+
// will be turned into
71+
// " frame 10: function foo::bar() at my/file.cc:10"
72+
// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
73+
// source files and modules.
74+
// Here's the full list of available placeholders:
75+
// %% - represents a '%' character;
76+
// %n - frame number (copy of frame_no);
77+
// %p - PC in hex format;
78+
// %m - path to module (binary or shared object);
79+
// %o - offset in the module in hex format;
80+
// %f - function name;
81+
// %q - offset in the function in hex format (*if available*);
82+
// %s - path to source file;
83+
// %l - line in the source file;
84+
// %c - column in the source file;
85+
// %F - if function is known to be <foo>, prints "in <foo>", possibly
86+
// followed by the offset in this function, but only if source file
87+
// is unknown;
88+
// %S - prints file/line/column information;
89+
// %L - prints location information: file/line/column, if it is known, or
90+
// module+offset if it is known, or (<unknown module>) string.
91+
// %M - prints module basename and offset, if it is known, or PC.
92+
void RenderFrame(InternalScopedString *buffer, const char *format,
93+
int frame_no, uptr address, const AddressInfo *info,
94+
bool vs_style, const char *strip_path_prefix = "") override;
95+
96+
bool RenderNeedsSymbolization(const char *format) override;
97+
98+
void RenderSourceLocation(InternalScopedString *buffer, const char *file,
99+
int line, int column, bool vs_style,
100+
const char *strip_path_prefix) override;
101+
102+
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
103+
uptr offset, ModuleArch arch,
104+
const char *strip_path_prefix) override;
105+
106+
// Same as RenderFrame, but for data section (global variables).
107+
// Accepts %s, %l from above.
108+
// Also accepts:
109+
// %g - name of the global variable.
110+
void RenderData(InternalScopedString *buffer, const char *format,
111+
const DataInfo *DI,
112+
const char *strip_path_prefix = "") override;
113+
114+
protected:
115+
~FormattedStackTracePrinter() {}
116+
};
71117

72118
} // namespace __sanitizer
73119

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,24 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
8181
}
8282

8383
// We ignore the format argument to __sanitizer_symbolize_global.
84-
void RenderData(InternalScopedString *buffer, const char *format,
85-
const DataInfo *DI, const char *strip_path_prefix) {
84+
void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
85+
const char *format,
86+
const DataInfo *DI,
87+
const char *strip_path_prefix) {
8688
buffer->append(kFormatData, DI->start);
8789
}
8890

89-
bool RenderNeedsSymbolization(const char *format) { return false; }
91+
bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format) {
92+
return false;
93+
}
9094

9195
// We don't support the stack_trace_format flag at all.
92-
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
93-
uptr address, const AddressInfo *info, bool vs_style,
94-
const char *strip_path_prefix) {
96+
void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
97+
const char *format, int frame_no,
98+
uptr address,
99+
const AddressInfo *info,
100+
bool vs_style,
101+
const char *strip_path_prefix) {
95102
CHECK(!RenderNeedsSymbolization(format));
96103
buffer->append(kFormatFrame, frame_no, address);
97104
}

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,
3333
if (!common_flags()->print_summary) return;
3434
InternalScopedString buff;
3535
buff.append("%s ", error_type);
36-
RenderFrame(&buff, "%L %F", 0, info.address, &info,
37-
common_flags()->symbolize_vs_style,
38-
common_flags()->strip_path_prefix);
36+
StackTracePrinter::GetOrInit()->RenderFrame(
37+
&buff, "%L %F", 0, info.address, &info,
38+
common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix);
3939
ReportErrorSummary(buff.data(), alt_tool_name);
4040
}
4141
#endif

0 commit comments

Comments
 (0)