1// RUN: %clangxx %s -o %t -g && %run %t 2>&1 | FileCheck %s
2
3// REQUIRES: internal_symbolizer
4
5#include <assert.h>
6#include <dlfcn.h>
7#include <link.h>
8#include <sanitizer/hwasan_interface.h>
9#include <sanitizer/msan_interface.h>
10#include <string.h>
11
12#include <string>
13#include <vector>
14
15extern "C" {
16bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset,
17 char *Buffer, int MaxLength,
18 bool SymbolizeInlineFrames);
19bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset,
20 char *Buffer, int MaxLength);
21bool __sanitizer_symbolize_frame(const char *ModuleName, uint64_t ModuleOffset,
22 char *Buffer, int MaxLength);
23void __sanitizer_print_stack_trace();
24bool __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
25 int MaxLength);
26}
27
28struct ScopedInSymbolizer {
29#if defined(__has_feature)
30# if __has_feature(memory_sanitizer)
31 ScopedInSymbolizer() { __msan_scoped_disable_interceptor_checks(); }
32 ~ScopedInSymbolizer() { __msan_scoped_enable_interceptor_checks(); }
33# endif
34#endif
35};
36
37struct FrameInfo {
38 int line;
39 std::string file;
40 std::string function;
41 void *address;
42};
43
44__attribute__((noinline)) void *GetPC() { return __builtin_return_address(0); }
45
46__attribute__((always_inline)) FrameInfo InlineFunction() {
47 void *address = GetPC();
48 return {.line: 0, .file: "", .function: "",
49 .address: reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)};
50}
51
52__attribute__((noinline)) FrameInfo NoInlineFunction() {
53 void *address = GetPC();
54 return {.line: 0, .file: "", .function: "",
55 .address: reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)};
56}
57
58template <int N> struct A {
59 template <class T> FrameInfo RecursiveTemplateFunction(const T &t);
60};
61
62template <int N>
63template <class T>
64__attribute__((noinline)) FrameInfo A<N>::RecursiveTemplateFunction(const T &) {
65 std::vector<T> t;
66 return A<N - 1>().RecursiveTemplateFunction(t);
67}
68
69template <>
70template <class T>
71__attribute__((noinline)) FrameInfo A<0>::RecursiveTemplateFunction(const T &) {
72 return NoInlineFunction();
73}
74
75__attribute__((no_sanitize_memory)) std::pair<const char *, uint64_t>
76GetModuleAndOffset(const void *address) {
77 Dl_info di;
78 link_map *lm = nullptr;
79#if __has_feature(hwaddress_sanitizer)
80 address = __hwasan_tag_pointer(address, 0);
81#endif
82 assert(
83 dladdr1(address, &di, reinterpret_cast<void **>(&lm), RTLD_DL_LINKMAP));
84 return {di.dli_fname, reinterpret_cast<uint64_t>(address) - lm->l_addr};
85}
86
87std::string Symbolize(FrameInfo frame) {
88 auto modul_offset = GetModuleAndOffset(address: frame.address);
89 char buffer[1024] = {};
90 ScopedInSymbolizer in_symbolizer;
91 assert(__sanitizer_symbolize_code(modul_offset.first, modul_offset.second,
92 buffer, std::size(buffer), true));
93 return buffer;
94}
95
96std::string GetRegex(const FrameInfo &frame) {
97 return frame.function + "[^\\n]*\\n[^\\n]*" + frame.file + ":" +
98 std::to_string(val: frame.line);
99}
100
101void TestInline() {
102 auto frame = InlineFunction();
103 fprintf(stderr, format: "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str());
104 // CHECK-LABEL: TestInline: InlineFunction()
105 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 58]]
106 // CHECK-NEXT: TestInline()
107 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 5]]
108}
109
110void TestNoInline() {
111 auto frame = NoInlineFunction();
112 fprintf(stderr, format: "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str());
113 // CHECK-LABEL: TestNoInline: NoInlineFunction()
114 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 61]]
115}
116
117void TestLongFunctionNames() {
118 auto frame = A<10>().RecursiveTemplateFunction(0);
119 fprintf(stderr, format: "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str());
120 // CHECK-LABEL: TestLongFunctionNames: NoInlineFunction()
121 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 68]]
122}
123
124std::string SymbolizeStaticVar() {
125 static int var = 1;
126 auto modul_offset = GetModuleAndOffset(address: &var);
127 char buffer[1024] = {};
128 ScopedInSymbolizer in_symbolizer;
129 assert(__sanitizer_symbolize_data(modul_offset.first, modul_offset.second,
130 buffer, std::size(buffer)));
131 return buffer;
132}
133
134void TestData() {
135 fprintf(stderr, format: "%s: %s\n", __FUNCTION__, SymbolizeStaticVar().c_str());
136 // CHECK-LABEL: TestData: SymbolizeStaticVar[abi:cxx11]()::var
137 // CHECK-NEXT: {{[0-9]+ +[0-9]+}}
138 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 13]]
139}
140
141__attribute__((noinline)) std::string SymbolizeLocalVars(const void *pc) {
142 auto modul_offset = GetModuleAndOffset(address: pc);
143 char buffer[1024] = {};
144 ScopedInSymbolizer in_symbolizer;
145 __sanitizer_symbolize_frame(ModuleName: modul_offset.first, ModuleOffset: modul_offset.second, Buffer: buffer,
146 MaxLength: std::size(buffer));
147 return buffer;
148}
149
150__attribute__((
151 noinline,
152 no_sanitize_address /* Asan merges allocas destroying variable DI */)) void
153TestFrame() {
154 volatile int var = 1;
155 void *address = GetPC();
156 fprintf(stderr, format: "%s: %s\n", __FUNCTION__,
157 SymbolizeLocalVars(pc: address).c_str());
158 // CHECK-LABEL: TestFrame: TestFrame
159 // CHECK-NEXT: var
160 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 6]]
161 // CHECK-NEXT: {{-?[0-9]+ +[0-9]+}}
162 // CHECK-NEXT: TestFrame
163 // CHECK-NEXT: address
164 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 9]]
165 // CHECK-NEXT: {{-?[0-9]+ +[0-9]+}}
166}
167
168void TestDemangle() {
169 char out[128];
170 assert(!__sanitizer_symbolize_demangle("1A", out, sizeof(out)));
171
172 const char name[] = "_Z3fooi";
173 for (int i = 1; i < sizeof(out); ++i) {
174 memset(s: out, c: 1, n: sizeof(out));
175 assert(__sanitizer_symbolize_demangle(name, out, i) == (i > 8));
176 assert(i < 9 || 0 == strncmp(out, "foo(int)", i - 1));
177 }
178}
179
180int main() {
181 TestInline();
182 TestNoInline();
183 TestLongFunctionNames();
184 TestData();
185 TestFrame();
186 TestDemangle();
187}
188

source code of compiler-rt/test/sanitizer_common/TestCases/Linux/internal_symbolizer.cpp