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.
213 lines
7.3 KiB
C++
213 lines
7.3 KiB
C++
//===-- sanitizer_common_printer_test.cpp ---------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of sanitizer_common test suite.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "sanitizer_common/sanitizer_stacktrace_printer.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "interception/interception.h"
|
|
|
|
namespace __sanitizer {
|
|
|
|
class TestFormattedStackTracePrinter final : public FormattedStackTracePrinter {
|
|
public:
|
|
~TestFormattedStackTracePrinter() {}
|
|
};
|
|
|
|
TEST(FormattedStackTracePrinter, RenderSourceLocation) {
|
|
InternalScopedString str;
|
|
TestFormattedStackTracePrinter printer;
|
|
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "");
|
|
EXPECT_STREQ("/dir/file.cc:10:5", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 11, 0, false, "");
|
|
EXPECT_STREQ("/dir/file.cc:11", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 0, 0, false, "");
|
|
EXPECT_STREQ("/dir/file.cc", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "/dir/");
|
|
EXPECT_STREQ("file.cc:10:5", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "");
|
|
EXPECT_STREQ("/dir/file.cc(10,5)", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 11, 0, true, "");
|
|
EXPECT_STREQ("/dir/file.cc(11)", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 0, 0, true, "");
|
|
EXPECT_STREQ("/dir/file.cc", str.data());
|
|
|
|
str.clear();
|
|
printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "/dir/");
|
|
EXPECT_STREQ("file.cc(10,5)", str.data());
|
|
}
|
|
|
|
TEST(FormattedStackTracePrinter, RenderModuleLocation) {
|
|
InternalScopedString str;
|
|
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();
|
|
printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown,
|
|
"/dir/");
|
|
EXPECT_STREQ("(exe+0x123)", str.data());
|
|
|
|
// Check that we render the arch.
|
|
str.clear();
|
|
printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchX86_64H,
|
|
"/dir/");
|
|
EXPECT_STREQ("(exe:x86_64h+0x123)", str.data());
|
|
}
|
|
|
|
TEST(FormattedStackTracePrinter, RenderFrame) {
|
|
TestFormattedStackTracePrinter printer;
|
|
int frame_no = 42;
|
|
AddressInfo info;
|
|
info.address = 0x400000;
|
|
info.module = internal_strdup("/path/to/my/module");
|
|
info.module_offset = 0x200;
|
|
info.function = internal_strdup("foo");
|
|
info.function_offset = 0x100;
|
|
info.file = internal_strdup("/path/to/my/source");
|
|
info.line = 10;
|
|
info.column = 5;
|
|
InternalScopedString str;
|
|
|
|
// Dump all the AddressInfo fields.
|
|
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",
|
|
str.data());
|
|
|
|
str.clear();
|
|
// Check that RenderFrame() strips interceptor prefixes.
|
|
info.function = internal_strdup(SANITIZER_STRINGIFY(WRAP(bar)));
|
|
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",
|
|
str.data());
|
|
info.Clear();
|
|
str.clear();
|
|
|
|
// Test special format specifiers.
|
|
info.address = 0x400000;
|
|
printer.RenderFrame(&str, "%M", frame_no, info.address, &info, false);
|
|
EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
|
|
str.clear();
|
|
|
|
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;
|
|
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();
|
|
|
|
printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
|
|
EXPECT_STREQ("(/path/to/module+0x200)", str.data());
|
|
str.clear();
|
|
|
|
printer.RenderFrame(&str, "%b", frame_no, info.address, &info, false);
|
|
EXPECT_STREQ("", str.data());
|
|
str.clear();
|
|
|
|
info.uuid_size = 2;
|
|
info.uuid[0] = 0x55;
|
|
info.uuid[1] = 0x66;
|
|
|
|
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
|
|
EXPECT_EQ(nullptr, internal_strstr(str.data(), "BuildId: 5566"));
|
|
#else
|
|
EXPECT_NE(nullptr, internal_strstr(str.data(), "BuildId: 5566"));
|
|
#endif
|
|
str.clear();
|
|
|
|
printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
|
|
#if SANITIZER_APPLE
|
|
EXPECT_STREQ("(/path/to/module+0x200)", str.data());
|
|
#else
|
|
EXPECT_STREQ("(/path/to/module+0x200) (BuildId: 5566)", str.data());
|
|
#endif
|
|
str.clear();
|
|
|
|
printer.RenderFrame(&str, "%b", frame_no, info.address, &info, false);
|
|
EXPECT_STREQ("(BuildId: 5566)", str.data());
|
|
str.clear();
|
|
|
|
info.function = internal_strdup("my_function");
|
|
printer.RenderFrame(&str, "%F", frame_no, info.address, &info, false);
|
|
EXPECT_STREQ("in my_function", str.data());
|
|
str.clear();
|
|
|
|
info.function_offset = 0x100;
|
|
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");
|
|
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;
|
|
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;
|
|
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();
|
|
|
|
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;
|
|
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;
|
|
printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, true);
|
|
EXPECT_STREQ("in my_function my_file", str.data());
|
|
str.clear();
|
|
|
|
info.Clear();
|
|
}
|
|
|
|
} // namespace __sanitizer
|