188 lines · cpp
1// RUN: %clangxx %s -o %t -g && %run %t 2>&1 | FileCheck %s2 3// REQUIRES: internal_symbolizer4 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# endif34#endif35};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 {0, "", "",49 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)};50}51 52__attribute__((noinline)) FrameInfo NoInlineFunction() {53 void *address = GetPC();54 return {0, "", "",55 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#endif82 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(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(frame.line);99}100 101void 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 110void 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 117void 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 124std::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 134void TestData() {135 fprintf(stderr, "%s: %s\n", __FUNCTION__, SymbolizeStaticVar().c_str());136 // CHECK-LABEL: TestData: SymbolizeStaticVar[abi:cxx11]()::var137 // 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(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 */)) void153TestFrame() {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: TestFrame159 // CHECK-NEXT: var160 // CHECK-NEXT: internal_symbolizer.cpp:[[# @LINE - 6]]161 // CHECK-NEXT: {{-?[0-9]+ +[0-9]+}}162 // CHECK-NEXT: TestFrame163 // CHECK-NEXT: address164 // 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(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 180int main() {181 TestInline();182 TestNoInline();183 TestLongFunctionNames();184 TestData();185 TestFrame();186 TestDemangle();187}188