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