Skip to content

Commit

Permalink
[NFC][sanitizer_symbolizer]Add StackTracePrinter class (#66530)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
avillega committed Sep 15, 2023
1 parent 1f15e39 commit d4152c5
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 135 deletions.
7 changes: 4 additions & 3 deletions compiler-rt/lib/hwasan/hwasan_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,10 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
frame_desc.append(" record_addr:0x%zx record:0x%zx",
reinterpret_cast<uptr>(record_addr), record);
if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
RenderFrame(&frame_desc, " %F %L", 0, frame->info.address, &frame->info,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderFrame(
&frame_desc, " %F %L", 0, frame->info.address, &frame->info,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
frame->ClearAll();
}
Printf("%s\n", frame_desc.data());
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/msan/msan_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ void DescribeMemoryRange(const void *x, uptr size) {

void ReportUMRInsideAddressRange(const char *function, const void *start,
uptr size, uptr offset) {
function = StripFunctionName(function);
function = StackTracePrinter::GetOrInit()->StripFunctionName(function);
Decorator d;
Printf("%s", d.Warning());
Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class StackTraceTextPrinter {
frame_delimiter_(frame_delimiter),
output_(output),
dedup_token_(dedup_token),
symbolize_(RenderNeedsSymbolization(stack_trace_fmt)) {}
symbolize_(StackTracePrinter::GetOrInit()->RenderNeedsSymbolization(
stack_trace_fmt)) {}

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

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

if (prev_len != output_->length())
output_->append("%c", frame_delimiter_);
Expand Down Expand Up @@ -210,7 +211,8 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
DataInfo DI;
if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
InternalScopedString data_desc;
RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderData(&data_desc, fmt, &DI,
common_flags()->strip_path_prefix);
internal_strncpy(out_buf, data_desc.data(), out_buf_size);
out_buf[out_buf_size - 1] = 0;
}
Expand Down
48 changes: 35 additions & 13 deletions compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,30 @@

#include "sanitizer_stacktrace_printer.h"

#include "sanitizer_common.h"
#include "sanitizer_file.h"
#include "sanitizer_flags.h"
#include "sanitizer_fuchsia.h"

namespace __sanitizer {

const char *StripFunctionName(const char *function) {

StackTracePrinter *StackTracePrinter::GetOrInit() {
static StackTracePrinter *stacktrace_printer;
static StaticSpinMutex init_mu;
SpinMutexLock l(&init_mu);
if (stacktrace_printer)
return stacktrace_printer;

stacktrace_printer =
new (GetGlobalLowLevelAllocator()) FormattedStackTracePrinter();

CHECK(stacktrace_printer);
return stacktrace_printer;
}

const char *FormattedStackTracePrinter::StripFunctionName(
const char *function) {
if (!common_flags()->demangle)
return function;
if (!function)
Expand Down Expand Up @@ -141,9 +158,12 @@ static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,

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

void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
uptr address, const AddressInfo *info, bool vs_style,
const char *strip_path_prefix) {
void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
const char *format, int frame_no,
uptr address,
const AddressInfo *info,
bool vs_style,
const char *strip_path_prefix) {
// info will be null in the case where symbolization is not needed for the
// given format. This ensures that the code below will get a hard failure
// rather than print incorrect information in case RenderNeedsSymbolization
Expand Down Expand Up @@ -250,7 +270,7 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
}
}

bool RenderNeedsSymbolization(const char *format) {
bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format) {
if (0 == internal_strcmp(format, "DEFAULT"))
format = kDefaultFormat;
for (const char *p = format; *p != '\0'; p++) {
Expand All @@ -273,8 +293,10 @@ bool RenderNeedsSymbolization(const char *format) {
return false;
}

void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI, const char *strip_path_prefix) {
void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
const char *format,
const DataInfo *DI,
const char *strip_path_prefix) {
for (const char *p = format; *p != '\0'; p++) {
if (*p != '%') {
buffer->append("%c", *p);
Expand Down Expand Up @@ -304,9 +326,9 @@ void RenderData(InternalScopedString *buffer, const char *format,

#endif // !SANITIZER_SYMBOLIZER_MARKUP

void RenderSourceLocation(InternalScopedString *buffer, const char *file,
int line, int column, bool vs_style,
const char *strip_path_prefix) {
void FormattedStackTracePrinter::RenderSourceLocation(
InternalScopedString *buffer, const char *file, int line, int column,
bool vs_style, const char *strip_path_prefix) {
if (vs_style && line > 0) {
buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
if (column > 0)
Expand All @@ -323,9 +345,9 @@ void RenderSourceLocation(InternalScopedString *buffer, const char *file,
}
}

void RenderModuleLocation(InternalScopedString *buffer, const char *module,
uptr offset, ModuleArch arch,
const char *strip_path_prefix) {
void FormattedStackTracePrinter::RenderModuleLocation(
InternalScopedString *buffer, const char *module, uptr offset,
ModuleArch arch, const char *strip_path_prefix) {
buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
if (arch != kModuleArchUnknown) {
buffer->append(":%s", ModuleArchToString(arch));
Expand Down
148 changes: 97 additions & 51 deletions compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,61 +13,107 @@
#define SANITIZER_STACKTRACE_PRINTER_H

#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer.h"

namespace __sanitizer {

// Strip interceptor prefixes from function name.
const char *StripFunctionName(const char *function);

// Render the contents of "info" structure, which represents the contents of
// stack frame "frame_no" and appends it to the "buffer". "format" is a
// string with placeholders, which is copied to the output with
// placeholders substituted with the contents of "info". For example,
// format string
// " frame %n: function %F at %S"
// will be turned into
// " frame 10: function foo::bar() at my/file.cc:10"
// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
// source files and modules.
// Here's the full list of available placeholders:
// %% - represents a '%' character;
// %n - frame number (copy of frame_no);
// %p - PC in hex format;
// %m - path to module (binary or shared object);
// %o - offset in the module in hex format;
// %f - function name;
// %q - offset in the function in hex format (*if available*);
// %s - path to source file;
// %l - line in the source file;
// %c - column in the source file;
// %F - if function is known to be <foo>, prints "in <foo>", possibly
// followed by the offset in this function, but only if source file
// is unknown;
// %S - prints file/line/column information;
// %L - prints location information: file/line/column, if it is known, or
// module+offset if it is known, or (<unknown module>) string.
// %M - prints module basename and offset, if it is known, or PC.
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
uptr address, const AddressInfo *info, bool vs_style,
const char *strip_path_prefix = "");

bool RenderNeedsSymbolization(const char *format);

void RenderSourceLocation(InternalScopedString *buffer, const char *file,
int line, int column, bool vs_style,
const char *strip_path_prefix);

void RenderModuleLocation(InternalScopedString *buffer, const char *module,
uptr offset, ModuleArch arch,
const char *strip_path_prefix);

// Same as RenderFrame, but for data section (global variables).
// Accepts %s, %l from above.
// Also accepts:
// %g - name of the global variable.
void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI, const char *strip_path_prefix = "");
// StacktracePrinter is an interface that is implemented by
// classes that can perform rendering of the different parts
// of a stacktrace.
class StackTracePrinter {
public:
static StackTracePrinter *GetOrInit();

virtual const char *StripFunctionName(const char *function) {
UNIMPLEMENTED();
}

virtual void RenderFrame(InternalScopedString *buffer, const char *format,
int frame_no, uptr address, const AddressInfo *info,
bool vs_style, const char *strip_path_prefix = "") {
UNIMPLEMENTED();
}

virtual bool RenderNeedsSymbolization(const char *format) { return false; }

virtual void RenderSourceLocation(InternalScopedString *buffer,
const char *file, int line, int column,
bool vs_style,
const char *strip_path_prefix) {}

virtual void RenderModuleLocation(InternalScopedString *buffer,
const char *module, uptr offset,
ModuleArch arch,
const char *strip_path_prefix) {}
virtual void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI,
const char *strip_path_prefix = "") {
UNIMPLEMENTED();
}

protected:
~StackTracePrinter() {}
};

class FormattedStackTracePrinter : public StackTracePrinter {
public:
// Strip interceptor prefixes from function name.
const char *StripFunctionName(const char *function) override;

// Render the contents of "info" structure, which represents the contents of
// stack frame "frame_no" and appends it to the "buffer". "format" is a
// string with placeholders, which is copied to the output with
// placeholders substituted with the contents of "info". For example,
// format string
// " frame %n: function %F at %S"
// will be turned into
// " frame 10: function foo::bar() at my/file.cc:10"
// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
// source files and modules.
// Here's the full list of available placeholders:
// %% - represents a '%' character;
// %n - frame number (copy of frame_no);
// %p - PC in hex format;
// %m - path to module (binary or shared object);
// %o - offset in the module in hex format;
// %f - function name;
// %q - offset in the function in hex format (*if available*);
// %s - path to source file;
// %l - line in the source file;
// %c - column in the source file;
// %F - if function is known to be <foo>, prints "in <foo>", possibly
// followed by the offset in this function, but only if source file
// is unknown;
// %S - prints file/line/column information;
// %L - prints location information: file/line/column, if it is known, or
// module+offset if it is known, or (<unknown module>) string.
// %M - prints module basename and offset, if it is known, or PC.
void RenderFrame(InternalScopedString *buffer, const char *format,
int frame_no, uptr address, const AddressInfo *info,
bool vs_style, const char *strip_path_prefix = "") override;

bool RenderNeedsSymbolization(const char *format) override;

void RenderSourceLocation(InternalScopedString *buffer, const char *file,
int line, int column, bool vs_style,
const char *strip_path_prefix) override;

void RenderModuleLocation(InternalScopedString *buffer, const char *module,
uptr offset, ModuleArch arch,
const char *strip_path_prefix) override;

// Same as RenderFrame, but for data section (global variables).
// Accepts %s, %l from above.
// Also accepts:
// %g - name of the global variable.
void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI,
const char *strip_path_prefix = "") override;

protected:
~FormattedStackTracePrinter() {}
};

} // namespace __sanitizer

Expand Down
19 changes: 13 additions & 6 deletions compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,24 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
}

// We ignore the format argument to __sanitizer_symbolize_global.
void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI, const char *strip_path_prefix) {
void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
const char *format,
const DataInfo *DI,
const char *strip_path_prefix) {
buffer->append(kFormatData, DI->start);
}

bool RenderNeedsSymbolization(const char *format) { return false; }
bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format) {
return false;
}

// We don't support the stack_trace_format flag at all.
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
uptr address, const AddressInfo *info, bool vs_style,
const char *strip_path_prefix) {
void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
const char *format, int frame_no,
uptr address,
const AddressInfo *info,
bool vs_style,
const char *strip_path_prefix) {
CHECK(!RenderNeedsSymbolization(format));
buffer->append(kFormatFrame, frame_no, address);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,
if (!common_flags()->print_summary) return;
InternalScopedString buff;
buff.append("%s ", error_type);
RenderFrame(&buff, "%L %F", 0, info.address, &info,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderFrame(
&buff, "%L %F", 0, info.address, &info,
common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix);
ReportErrorSummary(buff.data(), alt_tool_name);
}
#endif
Expand Down

0 comments on commit d4152c5

Please sign in to comment.