xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cpp (revision bf4347b3da31625ce1ae2dd4ffb5c557072e03c0)
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 
18 using testing::MatchesRegex;
19 
20 namespace __sanitizer {
21 
22 class TestFormattedStackTracePrinter final : public FormattedStackTracePrinter {
23  public:
24   ~TestFormattedStackTracePrinter() {}
25 };
26 
27 TEST(FormattedStackTracePrinter, RenderSourceLocation) {
28   InternalScopedString str;
29   TestFormattedStackTracePrinter printer;
30 
31   printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "");
32   EXPECT_STREQ("/dir/file.cc:10:5", str.data());
33 
34   str.clear();
35   printer.RenderSourceLocation(&str, "/dir/file.cc", 11, 0, false, "");
36   EXPECT_STREQ("/dir/file.cc:11", str.data());
37 
38   str.clear();
39   printer.RenderSourceLocation(&str, "/dir/file.cc", 0, 0, false, "");
40   EXPECT_STREQ("/dir/file.cc", str.data());
41 
42   str.clear();
43   printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "/dir/");
44   EXPECT_STREQ("file.cc:10:5", str.data());
45 
46   str.clear();
47   printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "");
48   EXPECT_STREQ("/dir/file.cc(10,5)", str.data());
49 
50   str.clear();
51   printer.RenderSourceLocation(&str, "/dir/file.cc", 11, 0, true, "");
52   EXPECT_STREQ("/dir/file.cc(11)", str.data());
53 
54   str.clear();
55   printer.RenderSourceLocation(&str, "/dir/file.cc", 0, 0, true, "");
56   EXPECT_STREQ("/dir/file.cc", str.data());
57 
58   str.clear();
59   printer.RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "/dir/");
60   EXPECT_STREQ("file.cc(10,5)", str.data());
61 }
62 
63 TEST(FormattedStackTracePrinter, RenderModuleLocation) {
64   InternalScopedString str;
65   TestFormattedStackTracePrinter printer;
66   printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown, "");
67   EXPECT_STREQ("(/dir/exe+0x123)", str.data());
68 
69   // Check that we strip file prefix if necessary.
70   str.clear();
71   printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchUnknown,
72                                "/dir/");
73   EXPECT_STREQ("(exe+0x123)", str.data());
74 
75   // Check that we render the arch.
76   str.clear();
77   printer.RenderModuleLocation(&str, "/dir/exe", 0x123, kModuleArchX86_64H,
78                                "/dir/");
79   EXPECT_STREQ("(exe:x86_64h+0x123)", str.data());
80 }
81 
82 TEST(FormattedStackTracePrinter, RenderFrame) {
83   TestFormattedStackTracePrinter printer;
84   int frame_no = 42;
85   AddressInfo info;
86   info.address = 0x400000;
87   info.module = internal_strdup("/path/to/my/module");
88   info.module_offset = 0x200;
89   info.function = internal_strdup("foo");
90   info.function_offset = 0x100;
91   info.file = internal_strdup("/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(&str,
98                       "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
99                       "Function:%f FunctionOffset:%q Source:%s Line:%l "
100                       "Column:%c",
101                       frame_no, info.address, &info, false, "/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(&str,
113                       "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
114                       "Function:%f FunctionOffset:%q Source:%s Line:%l "
115                       "Column:%c",
116                       frame_no, info.address, &info, false, "/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(&str, "%M", frame_no, info.address, &info, false);
129   EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
130   str.clear();
131 
132   printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
133   EXPECT_STREQ("(<unknown module>)", str.data());
134   str.clear();
135 
136   info.module = internal_strdup("/path/to/module");
137   info.module_offset = 0x200;
138   printer.RenderFrame(&str, "%M", frame_no, info.address, &info, false);
139   EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
140   EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
141   str.clear();
142 
143   printer.RenderFrame(&str, "%L", frame_no, info.address, &info, false);
144   EXPECT_STREQ("(/path/to/module+0x200)", str.data());
145   str.clear();
146 
147   printer.RenderFrame(&str, "%b", frame_no, info.address, &info, 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(&str, "%M", frame_no, info.address, &info, false);
156   EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
157   EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
158 #if SANITIZER_APPLE
159   EXPECT_EQ(nullptr, internal_strstr(str.data(), "BuildId: 5566"));
160 #else
161   EXPECT_NE(nullptr, internal_strstr(str.data(), "BuildId: 5566"));
162 #endif
163   str.clear();
164 
165   printer.RenderFrame(&str, "%L", frame_no, info.address, &info, 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(&str, "%b", frame_no, info.address, &info, false);
174   EXPECT_STREQ("(BuildId: 5566)", str.data());
175   str.clear();
176 
177   info.function = internal_strdup("my_function");
178   printer.RenderFrame(&str, "%F", frame_no, info.address, &info, false);
179   EXPECT_STREQ("in my_function", str.data());
180   str.clear();
181 
182   info.function_offset = 0x100;
183   printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
184   EXPECT_STREQ("in my_function+0x100 <null>", str.data());
185   str.clear();
186 
187   info.file = internal_strdup("my_file");
188   printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
189   EXPECT_STREQ("in my_function my_file", str.data());
190   str.clear();
191 
192   info.line = 10;
193   printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, false);
194   EXPECT_STREQ("in my_function my_file:10", str.data());
195   str.clear();
196 
197   info.column = 5;
198   printer.RenderFrame(&str, "%S %L", frame_no, info.address, &info, false);
199   EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
200   str.clear();
201 
202   printer.RenderFrame(&str, "%S %L", frame_no, info.address, &info, 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(&str, "%F %S", frame_no, info.address, &info, true);
208   EXPECT_STREQ("in my_function my_file(10)", str.data());
209   str.clear();
210 
211   info.line = 0;
212   printer.RenderFrame(&str, "%F %S", frame_no, info.address, &info, true);
213   EXPECT_STREQ("in my_function my_file", str.data());
214   str.clear();
215 
216   info.Clear();
217 }
218 
219 }  // namespace __sanitizer
220