1 // RUN: %clangxx %s -o %t -g && %run %t 2>&1 | FileCheck %s
3 // REQUIRES: internal_symbolizer
8 #include <sanitizer/hwasan_interface.h>
9 #include <sanitizer/msan_interface.h>
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
,
28 struct 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(); }
44 __attribute__((noinline
)) void *GetPC() { return __builtin_return_address(0); }
46 __attribute__((always_inline
)) FrameInfo
InlineFunction() {
47 void *address
= GetPC();
49 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address
) - 1)};
52 __attribute__((noinline
)) FrameInfo
NoInlineFunction() {
53 void *address
= GetPC();
55 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address
) - 1)};
58 template <int N
> struct A
{
59 template <class T
> FrameInfo
RecursiveTemplateFunction(const T
&t
);
64 __attribute__((noinline
)) FrameInfo A
<N
>::RecursiveTemplateFunction(const T
&) {
66 return A
<N
- 1>().RecursiveTemplateFunction(t
);
71 __attribute__((noinline
)) FrameInfo A
<0>::RecursiveTemplateFunction(const T
&) {
72 return NoInlineFunction();
75 __attribute__((no_sanitize_memory
)) std::pair
<const char *, uint64_t>
76 GetModuleAndOffset(const void *address
) {
78 link_map
*lm
= nullptr;
79 #if __has_feature(hwaddress_sanitizer)
80 address
= __hwasan_tag_pointer(address
, 0);
83 dladdr1(address
, &di
, reinterpret_cast<void **>(&lm
), RTLD_DL_LINKMAP
));
84 return {di
.dli_fname
, reinterpret_cast<uint64_t>(address
) - lm
->l_addr
};
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));
96 std::string
GetRegex(const FrameInfo
&frame
) {
97 return frame
.function
+ "[^\\n]*\\n[^\\n]*" + frame
.file
+ ":" +
98 std::to_string(frame
.line
);
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]]
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]]
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]]
124 std::string
SymbolizeStaticVar() {
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
)));
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]]
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
,
152 no_sanitize_address
/* Asan merges allocas destroying variable DI */)) void
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
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]+}}
168 void TestDemangle() {
170 assert(!__sanitizer_symbolize_demangle("1A", out
, sizeof(out
)));
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));
183 TestLongFunctionNames();