xref: /llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/internal_symbolizer.cpp (revision 7eb253111333d0d85ca95eaf3ff42b8b40559bce)
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 
15 extern "C" {
16 bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset,
17                                 char *Buffer, int MaxLength,
18                                 bool SymbolizeInlineFrames);
19 bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset,
20                                 char *Buffer, int MaxLength);
21 bool __sanitizer_symbolize_frame(const char *ModuleName, uint64_t ModuleOffset,
22                                  char *Buffer, int MaxLength);
23 void __sanitizer_print_stack_trace();
24 bool __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
25                                     int MaxLength);
26 }
27 
28 struct ScopedInSymbolizer {
29 #if defined(__has_feature)
30 #  if __has_feature(memory_sanitizer)
ScopedInSymbolizerScopedInSymbolizer31   ScopedInSymbolizer() { __msan_scoped_disable_interceptor_checks(); }
~ScopedInSymbolizerScopedInSymbolizer32   ~ScopedInSymbolizer() { __msan_scoped_enable_interceptor_checks(); }
33 #  endif
34 #endif
35 };
36 
37 struct FrameInfo {
38   int line;
39   std::string file;
40   std::string function;
41   void *address;
42 };
43 
GetPC()44 __attribute__((noinline)) void *GetPC() { return __builtin_return_address(0); }
45 
InlineFunction()46 __attribute__((always_inline)) FrameInfo InlineFunction() {
47   void *address = GetPC();
48   return {0, "", "",
49           reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)};
50 }
51 
NoInlineFunction()52 __attribute__((noinline)) FrameInfo NoInlineFunction() {
53   void *address = GetPC();
54   return {0, "", "",
55           reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)};
56 }
57 
58 template <int N> struct A {
59   template <class T> FrameInfo RecursiveTemplateFunction(const T &t);
60 };
61 
62 template <int N>
63 template <class T>
RecursiveTemplateFunction(const T &)64 __attribute__((noinline)) FrameInfo A<N>::RecursiveTemplateFunction(const T &) {
65   std::vector<T> t;
66   return A<N - 1>().RecursiveTemplateFunction(t);
67 }
68 
69 template <>
70 template <class T>
RecursiveTemplateFunction(const 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>
GetModuleAndOffset(const void * address)76 GetModuleAndOffset(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 
Symbolize(FrameInfo frame)87 std::string Symbolize(FrameInfo frame) {
88   auto modul_offset = GetModuleAndOffset(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 
GetRegex(const FrameInfo & frame)96 std::string GetRegex(const FrameInfo &frame) {
97   return frame.function + "[^\\n]*\\n[^\\n]*" + frame.file + ":" +
98          std::to_string(frame.line);
99 }
100 
TestInline()101 void TestInline() {
102   auto frame = InlineFunction();
103   fprintf(stderr, "%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 
TestNoInline()110 void TestNoInline() {
111   auto frame = NoInlineFunction();
112   fprintf(stderr, "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str());
113   // CHECK-LABEL: TestNoInline: NoInlineFunction()
114   // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 61]]
115 }
116 
TestLongFunctionNames()117 void TestLongFunctionNames() {
118   auto frame = A<10>().RecursiveTemplateFunction(0);
119   fprintf(stderr, "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str());
120   // CHECK-LABEL: TestLongFunctionNames: NoInlineFunction()
121   // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 68]]
122 }
123 
SymbolizeStaticVar()124 std::string SymbolizeStaticVar() {
125   static int var = 1;
126   auto modul_offset = GetModuleAndOffset(&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 
TestData()134 void TestData() {
135   fprintf(stderr, "%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 
SymbolizeLocalVars(const void * pc)141 __attribute__((noinline)) std::string SymbolizeLocalVars(const void *pc) {
142   auto modul_offset = GetModuleAndOffset(pc);
143   char buffer[1024] = {};
144   ScopedInSymbolizer in_symbolizer;
145   __sanitizer_symbolize_frame(modul_offset.first, modul_offset.second, buffer,
146                               std::size(buffer));
147   return buffer;
148 }
149 
150 __attribute__((
151     noinline,
152     no_sanitize_address /* Asan merges allocas destroying variable DI */)) void
TestFrame()153 TestFrame() {
154   volatile int var = 1;
155   void *address = GetPC();
156   fprintf(stderr, "%s: %s\n", __FUNCTION__,
157           SymbolizeLocalVars(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 
TestDemangle()168 void 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(out, 1, 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 
main()180 int main() {
181   TestInline();
182   TestNoInline();
183   TestLongFunctionNames();
184   TestData();
185   TestFrame();
186   TestDemangle();
187 }
188