Reland: [sanitizer_symbolizer] Add StackTracePrinter virtual class (#66689)

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.

Reason for revert: A missing header file for the
sanitizer_symbolizer_markup.cpp files.
This was not caught in local builds or pre-merge checks given that to
trigger the error, the code
has to be compiled for Fuchsia.
For this reland I've build for the fuchsia targets as well as linux.
This commit is contained in:
Andres Villegas 2023-09-21 11:28:20 -07:00 committed by GitHub
parent e0388e0e06
commit f8ae2e4277
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 216 additions and 130 deletions

View File

@ -260,9 +260,10 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
frame_desc.AppendF(" 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());

View File

@ -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",

View File

@ -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_
@ -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_->AppendF("%c", frame_delimiter_);
@ -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;
}

View File

@ -18,7 +18,22 @@
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)
@ -141,9 +156,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
@ -250,7 +268,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++) {
@ -273,8 +291,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->AppendF("%c", *p);
@ -304,9 +324,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->AppendF("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
if (column > 0)
@ -323,9 +343,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->AppendF("(%s", StripPathPrefix(module, strip_path_prefix));
if (arch != kModuleArchUnknown) {
buffer->AppendF(":%s", ModuleArchToString(arch));

View File

@ -13,61 +13,102 @@
#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);
// 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();
// 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 = "");
virtual const char *StripFunctionName(const char *function) = 0;
bool RenderNeedsSymbolization(const char *format);
virtual void RenderFrame(InternalScopedString *buffer, const char *format,
int frame_no, uptr address, const AddressInfo *info,
bool vs_style,
const char *strip_path_prefix = "") = 0;
void RenderSourceLocation(InternalScopedString *buffer, const char *file,
int line, int column, bool vs_style,
const char *strip_path_prefix);
virtual bool RenderNeedsSymbolization(const char *format) = 0;
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
uptr offset, ModuleArch arch,
const char *strip_path_prefix);
virtual void RenderSourceLocation(InternalScopedString *buffer,
const char *file, int line, int column,
bool vs_style,
const char *strip_path_prefix) = 0;
// 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 = "");
virtual void RenderModuleLocation(InternalScopedString *buffer,
const char *module, uptr offset,
ModuleArch arch,
const char *strip_path_prefix) = 0;
virtual void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI,
const char *strip_path_prefix = "") = 0;
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

View File

@ -22,6 +22,7 @@
# include <unwind.h>
# include "sanitizer_stacktrace.h"
# include "sanitizer_stacktrace_printer.h"
# include "sanitizer_symbolizer.h"
namespace __sanitizer {
@ -81,17 +82,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->AppendF(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->AppendF(kFormatFrame, frame_no, address);
}

View File

@ -33,9 +33,9 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,
if (!common_flags()->print_summary) return;
InternalScopedString buff;
buff.AppendF("%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

View File

@ -16,57 +16,68 @@
namespace __sanitizer {
TEST(SanitizerStacktracePrinter, RenderSourceLocation) {
class TestFormattedStackTracePrinter final : public FormattedStackTracePrinter {
public:
~TestFormattedStackTracePrinter() {}
};
TEST(FormattedStackTracePrinter, RenderSourceLocation) {
InternalScopedString str;
RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "");
TestFormattedStackTracePrinter printer;
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "");
EXPECT_STREQ("/dir/file.cc:10:5", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 11, 0, false, "");
printer.RenderSourceLocation(&str, "/dir/file.cc", 11, 0, false, "");
EXPECT_STREQ("/dir/file.cc:11", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 0, 0, false, "");
printer.RenderSourceLocation(&str, "/dir/file.cc", 0, 0, false, "");
EXPECT_STREQ("/dir/file.cc", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "/dir/");
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "/dir/");
EXPECT_STREQ("file.cc:10:5", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "");
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "");
EXPECT_STREQ("/dir/file.cc(10,5)", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 11, 0, true, "");
printer.RenderSourceLocation(&str, "/dir/file.cc", 11, 0, true, "");
EXPECT_STREQ("/dir/file.cc(11)", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 0, 0, true, "");
printer.RenderSourceLocation(&str, "/dir/file.cc", 0, 0, true, "");
EXPECT_STREQ("/dir/file.cc", str.data());
str.clear();
RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "/dir/");
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "/dir/");
EXPECT_STREQ("file.cc(10,5)", str.data());
}
TEST(SanitizerStacktracePrinter, RenderModuleLocation) {
TEST(FormattedStackTracePrinter, RenderModuleLocation) {
InternalScopedString str;
RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown, "");
TestFormattedStackTracePrinter printer;
printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown, "");
EXPECT_STREQ("(/dir/exe+0x123)", str.data());
// Check that we strip file prefix if necessary.
str.clear();
RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown, "/dir/");
printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown,
"/dir/");
EXPECT_STREQ("(exe+0x123)", str.data());
// Check that we render the arch.
str.clear();
RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchX86_64H, "/dir/");
printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchX86_64H,
"/dir/");
EXPECT_STREQ("(exe:x86_64h+0x123)", str.data());
}
TEST(SanitizerStacktracePrinter, RenderFrame) {
TEST(FormattedStackTracePrinter, RenderFrame) {
TestFormattedStackTracePrinter printer;
int frame_no = 42;
AddressInfo info;
info.address = 0x400000;
@ -80,11 +91,11 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
InternalScopedString str;
// Dump all the AddressInfo fields.
RenderFrame(&str,
"%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
"Function:%f FunctionOffset:%q Source:%s Line:%l "
"Column:%c",
frame_no, info.address, &info, false, "/path/to/");
printer.RenderFrame(&str,
"%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
"Function:%f FunctionOffset:%q Source:%s Line:%l "
"Column:%c",
frame_no, info.address, &info, false, "/path/to/");
EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
"Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
"Column:5",
@ -93,11 +104,11 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
str.clear();
// Check that RenderFrame() strips interceptor prefixes.
info.function = internal_strdup(SANITIZER_STRINGIFY(WRAP(bar)));
RenderFrame(&str,
"%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
"Function:%f FunctionOffset:%q Source:%s Line:%l "
"Column:%c",
frame_no, info.address, &info, false, "/path/to/");
printer.RenderFrame(&str,
"%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
"Function:%f FunctionOffset:%q Source:%s Line:%l "
"Column:%c",
frame_no, info.address, &info, false, "/path/to/");
EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
"Function:bar FunctionOffset:0x100 Source:my/source Line:10 "
"Column:5",
@ -107,26 +118,26 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
// Test special format specifiers.
info.address = 0x400000;
RenderFrame(&str, "%M", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%M", frame_no, info.address, &info, false);
EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
str.clear();
RenderFrame(&str, "%L", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
EXPECT_STREQ("(<unknown module>)", str.data());
str.clear();
info.module = internal_strdup("/path/to/module");
info.module_offset = 0x200;
RenderFrame(&str, "%M", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%M", frame_no, info.address, &info, false);
EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
str.clear();
RenderFrame(&str, "%L", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
EXPECT_STREQ("(/path/to/module+0x200)", str.data());
str.clear();
RenderFrame(&str, "%b", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%b", frame_no, info.address, &info, false);
EXPECT_STREQ("", str.data());
str.clear();
@ -134,7 +145,7 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
info.uuid[0] = 0x55;
info.uuid[1] = 0x66;
RenderFrame(&str, "%M", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%M", frame_no, info.address, &info, false);
EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
#if SANITIZER_APPLE
@ -144,7 +155,7 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
#endif
str.clear();
RenderFrame(&str, "%L", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
#if SANITIZER_APPLE
EXPECT_STREQ("(/path/to/module+0x200)", str.data());
#else
@ -152,46 +163,46 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
#endif
str.clear();
RenderFrame(&str, "%b", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%b", frame_no, info.address, &info, false);
EXPECT_STREQ("(BuildId: 5566)", str.data());
str.clear();
info.function = internal_strdup("my_function");
RenderFrame(&str, "%F", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%F", frame_no, info.address, &info, false);
EXPECT_STREQ("in my_function", str.data());
str.clear();
info.function_offset = 0x100;
RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
EXPECT_STREQ("in my_function+0x100 <null>", str.data());
str.clear();
info.file = internal_strdup("my_file");
RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
EXPECT_STREQ("in my_function my_file", str.data());
str.clear();
info.line = 10;
RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
EXPECT_STREQ("in my_function my_file:10", str.data());
str.clear();
info.column = 5;
RenderFrame(&str, "%S %L", frame_no, info.address, &info, false);
printer.RenderFrame(&str, "%S %L", frame_no, info.address, &info, false);
EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
str.clear();
RenderFrame(&str, "%S %L", frame_no, info.address, &info, true);
printer.RenderFrame(&str, "%S %L", frame_no, info.address, &info, true);
EXPECT_STREQ("my_file(10,5) my_file(10,5)", str.data());
str.clear();
info.column = 0;
RenderFrame(&str, "%F %S", frame_no, info.address, &info, true);
printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, true);
EXPECT_STREQ("in my_function my_file(10)", str.data());
str.clear();
info.line = 0;
RenderFrame(&str, "%F %S", frame_no, info.address, &info, true);
printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, true);
EXPECT_STREQ("in my_function my_file", str.data());
str.clear();

View File

@ -106,10 +106,10 @@ void PrintStack(const ReportStack *ent) {
SymbolizedStack *frame = ent->frames;
for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
InternalScopedString res;
RenderFrame(&res, common_flags()->stack_trace_format, i,
frame->info.address, &frame->info,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderFrame(
&res, common_flags()->stack_trace_format, i, frame->info.address,
&frame->info, common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
Printf("%s\n", res.data());
}
Printf("\n");

View File

@ -149,9 +149,10 @@ static void RenderLocation(InternalScopedString *Buffer, Location Loc) {
if (SLoc.isInvalid())
Buffer->AppendF("<unknown>");
else
RenderSourceLocation(Buffer, SLoc.getFilename(), SLoc.getLine(),
SLoc.getColumn(), common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderSourceLocation(
Buffer, SLoc.getFilename(), SLoc.getLine(), SLoc.getColumn(),
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
return;
}
case Location::LK_Memory:
@ -160,12 +161,14 @@ static void RenderLocation(InternalScopedString *Buffer, Location Loc) {
case Location::LK_Symbolized: {
const AddressInfo &Info = Loc.getSymbolizedStack()->info;
if (Info.file)
RenderSourceLocation(Buffer, Info.file, Info.line, Info.column,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderSourceLocation(
Buffer, Info.file, Info.line, Info.column,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
else if (Info.module)
RenderModuleLocation(Buffer, Info.module, Info.module_offset,
Info.module_arch, common_flags()->strip_path_prefix);
StackTracePrinter::GetOrInit()->RenderModuleLocation(
Buffer, Info.module, Info.module_offset, Info.module_arch,
common_flags()->strip_path_prefix);
else
Buffer->AppendF("%p", reinterpret_cast<void *>(Info.address));
return;