1//===-- sanitizer_common_printer_test.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 is a part of sanitizer_common test suite.
10//
11//===----------------------------------------------------------------------===//
12#include "sanitizer_common/sanitizer_stacktrace_printer.h"
13
14#include "gmock/gmock.h"
15#include "gtest/gtest.h"
16#include "interception/interception.h"
17
18using testing::MatchesRegex;
19
20namespace __sanitizer {
21
22class TestFormattedStackTracePrinter final : public FormattedStackTracePrinter {
23 public:
24 ~TestFormattedStackTracePrinter() {}
25};
26
27TEST(FormattedStackTracePrinter, RenderSourceLocation) {
28 InternalScopedString str;
29 TestFormattedStackTracePrinter printer;
30
31 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 10, column: 5, vs_style: false, strip_path_prefix: "");
32 EXPECT_STREQ("/dir/file.cc:10:5", str.data());
33
34 str.clear();
35 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 11, column: 0, vs_style: false, strip_path_prefix: "");
36 EXPECT_STREQ("/dir/file.cc:11", str.data());
37
38 str.clear();
39 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 0, column: 0, vs_style: false, strip_path_prefix: "");
40 EXPECT_STREQ("/dir/file.cc", str.data());
41
42 str.clear();
43 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 10, column: 5, vs_style: false, strip_path_prefix: "/dir/");
44 EXPECT_STREQ("file.cc:10:5", str.data());
45
46 str.clear();
47 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 10, column: 5, vs_style: true, strip_path_prefix: "");
48 EXPECT_STREQ("/dir/file.cc(10,5)", str.data());
49
50 str.clear();
51 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 11, column: 0, vs_style: true, strip_path_prefix: "");
52 EXPECT_STREQ("/dir/file.cc(11)", str.data());
53
54 str.clear();
55 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 0, column: 0, vs_style: true, strip_path_prefix: "");
56 EXPECT_STREQ("/dir/file.cc", str.data());
57
58 str.clear();
59 printer.RenderSourceLocation(buffer: &str, file: "/dir/file.cc", line: 10, column: 5, vs_style: true, strip_path_prefix: "/dir/");
60 EXPECT_STREQ("file.cc(10,5)", str.data());
61}
62
63TEST(FormattedStackTracePrinter, RenderModuleLocation) {
64 InternalScopedString str;
65 TestFormattedStackTracePrinter printer;
66 printer.RenderModuleLocation(buffer: &str, module: "/dir/exe", offset: 0x123, arch: kModuleArchUnknown, strip_path_prefix: "");
67 EXPECT_STREQ("(/dir/exe+0x123)", str.data());
68
69 // Check that we strip file prefix if necessary.
70 str.clear();
71 printer.RenderModuleLocation(buffer: &str, module: "/dir/exe", offset: 0x123, arch: kModuleArchUnknown,
72 strip_path_prefix: "/dir/");
73 EXPECT_STREQ("(exe+0x123)", str.data());
74
75 // Check that we render the arch.
76 str.clear();
77 printer.RenderModuleLocation(buffer: &str, module: "/dir/exe", offset: 0x123, arch: kModuleArchX86_64H,
78 strip_path_prefix: "/dir/");
79 EXPECT_STREQ("(exe:x86_64h+0x123)", str.data());
80}
81
82TEST(FormattedStackTracePrinter, RenderFrame) {
83 TestFormattedStackTracePrinter printer;
84 int frame_no = 42;
85 AddressInfo info;
86 info.address = 0x400000;
87 info.module = internal_strdup(s: "/path/to/my/module");
88 info.module_offset = 0x200;
89 info.function = internal_strdup(s: "foo");
90 info.function_offset = 0x100;
91 info.file = internal_strdup(s: "/path/to/my/source");
92 info.line = 10;
93 info.column = 5;
94 InternalScopedString str;
95
96 // Dump all the AddressInfo fields.
97 printer.RenderFrame(buffer: &str,
98 format: "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
99 "Function:%f FunctionOffset:%q Source:%s Line:%l "
100 "Column:%c",
101 frame_no, address: info.address, info: &info, vs_style: false, strip_path_prefix: "/path/to/");
102 EXPECT_THAT(
103 str.data(),
104 MatchesRegex(
105 "% Frame:42 PC:0x0*400000 Module:my/module ModuleOffset:0x200 "
106 "Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
107 "Column:5"));
108
109 str.clear();
110 // Check that RenderFrame() strips interceptor prefixes.
111 info.function = internal_strdup(SANITIZER_STRINGIFY(WRAP(bar)));
112 printer.RenderFrame(buffer: &str,
113 format: "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
114 "Function:%f FunctionOffset:%q Source:%s Line:%l "
115 "Column:%c",
116 frame_no, address: info.address, info: &info, vs_style: false, strip_path_prefix: "/path/to/");
117 EXPECT_THAT(
118 str.data(),
119 MatchesRegex(
120 "% Frame:42 PC:0x0*400000 Module:my/module ModuleOffset:0x200 "
121 "Function:bar FunctionOffset:0x100 Source:my/source Line:10 "
122 "Column:5"));
123 info.Clear();
124 str.clear();
125
126 // Test special format specifiers.
127 info.address = 0x400000;
128 printer.RenderFrame(buffer: &str, format: "%M", frame_no, address: info.address, info: &info, vs_style: false);
129 EXPECT_NE(nullptr, internal_strstr(haystack: str.data(), needle: "400000"));
130 str.clear();
131
132 printer.RenderFrame(buffer: &str, format: "%L", frame_no, address: info.address, info: &info, vs_style: false);
133 EXPECT_STREQ("(<unknown module>)", str.data());
134 str.clear();
135
136 info.module = internal_strdup(s: "/path/to/module");
137 info.module_offset = 0x200;
138 printer.RenderFrame(buffer: &str, format: "%M", frame_no, address: info.address, info: &info, vs_style: false);
139 EXPECT_NE(nullptr, internal_strstr(haystack: str.data(), needle: "(module+0x"));
140 EXPECT_NE(nullptr, internal_strstr(haystack: str.data(), needle: "200"));
141 str.clear();
142
143 printer.RenderFrame(buffer: &str, format: "%L", frame_no, address: info.address, info: &info, vs_style: false);
144 EXPECT_STREQ("(/path/to/module+0x200)", str.data());
145 str.clear();
146
147 printer.RenderFrame(buffer: &str, format: "%b", frame_no, address: info.address, info: &info, vs_style: false);
148 EXPECT_STREQ("", str.data());
149 str.clear();
150
151 info.uuid_size = 2;
152 info.uuid[0] = 0x55;
153 info.uuid[1] = 0x66;
154
155 printer.RenderFrame(buffer: &str, format: "%M", frame_no, address: info.address, info: &info, vs_style: false);
156 EXPECT_NE(nullptr, internal_strstr(haystack: str.data(), needle: "(module+0x"));
157 EXPECT_NE(nullptr, internal_strstr(haystack: str.data(), needle: "200"));
158#if SANITIZER_APPLE
159 EXPECT_EQ(nullptr, internal_strstr(str.data(), "BuildId: 5566"));
160#else
161 EXPECT_NE(nullptr, internal_strstr(haystack: str.data(), needle: "BuildId: 5566"));
162#endif
163 str.clear();
164
165 printer.RenderFrame(buffer: &str, format: "%L", frame_no, address: info.address, info: &info, vs_style: false);
166#if SANITIZER_APPLE
167 EXPECT_STREQ("(/path/to/module+0x200)", str.data());
168#else
169 EXPECT_STREQ("(/path/to/module+0x200) (BuildId: 5566)", str.data());
170#endif
171 str.clear();
172
173 printer.RenderFrame(buffer: &str, format: "%b", frame_no, address: info.address, info: &info, vs_style: false);
174 EXPECT_STREQ("(BuildId: 5566)", str.data());
175 str.clear();
176
177 info.function = internal_strdup(s: "my_function");
178 printer.RenderFrame(buffer: &str, format: "%F", frame_no, address: info.address, info: &info, vs_style: false);
179 EXPECT_STREQ("in my_function", str.data());
180 str.clear();
181
182 info.function_offset = 0x100;
183 printer.RenderFrame(buffer: &str, format: "%F %S", frame_no, address: info.address, info: &info, vs_style: false);
184 EXPECT_STREQ("in my_function+0x100 <null>", str.data());
185 str.clear();
186
187 info.file = internal_strdup(s: "my_file");
188 printer.RenderFrame(buffer: &str, format: "%F %S", frame_no, address: info.address, info: &info, vs_style: false);
189 EXPECT_STREQ("in my_function my_file", str.data());
190 str.clear();
191
192 info.line = 10;
193 printer.RenderFrame(buffer: &str, format: "%F %S", frame_no, address: info.address, info: &info, vs_style: false);
194 EXPECT_STREQ("in my_function my_file:10", str.data());
195 str.clear();
196
197 info.column = 5;
198 printer.RenderFrame(buffer: &str, format: "%S %L", frame_no, address: info.address, info: &info, vs_style: false);
199 EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
200 str.clear();
201
202 printer.RenderFrame(buffer: &str, format: "%S %L", frame_no, address: info.address, info: &info, vs_style: true);
203 EXPECT_STREQ("my_file(10,5) my_file(10,5)", str.data());
204 str.clear();
205
206 info.column = 0;
207 printer.RenderFrame(buffer: &str, format: "%F %S", frame_no, address: info.address, info: &info, vs_style: true);
208 EXPECT_STREQ("in my_function my_file(10)", str.data());
209 str.clear();
210
211 info.line = 0;
212 printer.RenderFrame(buffer: &str, format: "%F %S", frame_no, address: info.address, info: &info, vs_style: true);
213 EXPECT_STREQ("in my_function my_file", str.data());
214 str.clear();
215
216 info.Clear();
217}
218
219} // namespace __sanitizer
220

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cpp