|
| 1 | +// RUN: %clangxx %s -o %t && %run %t |
| 2 | + |
| 3 | +// REQUIRES: internal_symbolizer |
| 4 | + |
| 5 | +#include <assert.h> |
| 6 | +#include <dlfcn.h> |
| 7 | +#include <link.h> |
| 8 | +#include <sanitizer/msan_interface.h> |
| 9 | +#include <string.h> |
| 10 | + |
| 11 | +#include <string> |
| 12 | +#include <vector> |
| 13 | + |
| 14 | +extern "C" { |
| 15 | +bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset, |
| 16 | + char *Buffer, int MaxLength, |
| 17 | + bool SymbolizeInlineFrames); |
| 18 | +bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset, |
| 19 | + char *Buffer, int MaxLength); |
| 20 | +void __sanitizer_print_stack_trace(); |
| 21 | +bool __sanitizer_symbolize_demangle(const char *Name, char *Buffer, |
| 22 | + int MaxLength); |
| 23 | +} |
| 24 | + |
| 25 | +struct ScopedInSymbolizer { |
| 26 | +#if defined(__has_feature) |
| 27 | +# if __has_feature(memory_sanitizer) |
| 28 | + ScopedInSymbolizer() { __msan_scoped_disable_interceptor_checks(); } |
| 29 | + ~ScopedInSymbolizer() { __msan_scoped_enable_interceptor_checks(); } |
| 30 | +# endif |
| 31 | +#endif |
| 32 | +}; |
| 33 | + |
| 34 | +struct FrameInfo { |
| 35 | + int line; |
| 36 | + std::string file; |
| 37 | + std::string function; |
| 38 | + void *address; |
| 39 | +}; |
| 40 | + |
| 41 | +__attribute__((noinline)) void *GetPC() { return __builtin_return_address(0); } |
| 42 | + |
| 43 | +__attribute__((always_inline)) FrameInfo InlineFunction() { |
| 44 | + void *address = GetPC(); |
| 45 | + return {__LINE__ - 1, __FILE__, __FUNCTION__, |
| 46 | + reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)}; |
| 47 | +} |
| 48 | + |
| 49 | +__attribute__((noinline)) FrameInfo NoInlineFunction() { |
| 50 | + void *address = GetPC(); |
| 51 | + return {__LINE__ - 1, __FILE__, __FUNCTION__, |
| 52 | + reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(address) - 1)}; |
| 53 | +} |
| 54 | + |
| 55 | +template <int N> struct A { |
| 56 | + template <class T> FrameInfo RecursiveTemplateFunction(const T &t); |
| 57 | +}; |
| 58 | + |
| 59 | +template <int N> |
| 60 | +template <class T> |
| 61 | +__attribute__((noinline)) FrameInfo A<N>::RecursiveTemplateFunction(const T &) { |
| 62 | + std::vector<T> t; |
| 63 | + return A<N - 1>().RecursiveTemplateFunction(t); |
| 64 | +} |
| 65 | + |
| 66 | +template <> |
| 67 | +template <class T> |
| 68 | +__attribute__((noinline)) FrameInfo A<0>::RecursiveTemplateFunction(const T &) { |
| 69 | + return NoInlineFunction(); |
| 70 | +} |
| 71 | + |
| 72 | +__attribute__((no_sanitize_memory)) std::pair<const char *, uint64_t> |
| 73 | +GetModuleAndOffset(void *address) { |
| 74 | + Dl_info di; |
| 75 | + link_map *lm = nullptr; |
| 76 | + assert( |
| 77 | + dladdr1(address, &di, reinterpret_cast<void **>(&lm), RTLD_DL_LINKMAP)); |
| 78 | + return {di.dli_fname, reinterpret_cast<uint64_t>(address) - lm->l_addr}; |
| 79 | +} |
| 80 | + |
| 81 | +std::string Symbolize(FrameInfo frame) { |
| 82 | + auto modul_offset = GetModuleAndOffset(frame.address); |
| 83 | + char buffer[1024] = {}; |
| 84 | + ScopedInSymbolizer in_symbolizer; |
| 85 | + __sanitizer_symbolize_code(modul_offset.first, modul_offset.second, buffer, |
| 86 | + std::size(buffer), true); |
| 87 | + return buffer; |
| 88 | +} |
| 89 | + |
| 90 | +std::string GetRegex(const FrameInfo &frame) { |
| 91 | + return frame.function + "[^\\n]*\\n[^\\n]*" + frame.file + ":" + |
| 92 | + std::to_string(frame.line); |
| 93 | +} |
| 94 | + |
| 95 | +void TestInline() { |
| 96 | + auto frame = InlineFunction(); |
| 97 | + fprintf(stderr, "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str()); |
| 98 | +} |
| 99 | + |
| 100 | +void TestNoInline() { |
| 101 | + auto frame = NoInlineFunction(); |
| 102 | + fprintf(stderr, "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str()); |
| 103 | +} |
| 104 | + |
| 105 | +void TestLongFunctionNames() { |
| 106 | + auto frame = A<10>().RecursiveTemplateFunction(0); |
| 107 | + fprintf(stderr, "%s: %s\n", __FUNCTION__, Symbolize(frame).c_str()); |
| 108 | +} |
| 109 | + |
| 110 | +std::string SymbolizeStaticVar() { |
| 111 | + static int var = 1; |
| 112 | + auto modul_offset = GetModuleAndOffset(&var); |
| 113 | + char buffer[1024] = {}; |
| 114 | + ScopedInSymbolizer in_symbolizer; |
| 115 | + __sanitizer_symbolize_data(modul_offset.first, modul_offset.second, buffer, |
| 116 | + std::size(buffer)); |
| 117 | + return buffer; |
| 118 | +} |
| 119 | + |
| 120 | +void TestData() { |
| 121 | + fprintf(stderr, "%s: %s\n", __FUNCTION__, SymbolizeStaticVar().c_str()); |
| 122 | +} |
| 123 | + |
| 124 | +void TestDemangle() { |
| 125 | + char out[128]; |
| 126 | + assert(!__sanitizer_symbolize_demangle("1A", out, sizeof(out))); |
| 127 | + |
| 128 | + const char name[] = "_Z3fooi"; |
| 129 | + for (int i = 1; i < sizeof(out); ++i) { |
| 130 | + memset(out, 1, sizeof(out)); |
| 131 | + assert(__sanitizer_symbolize_demangle(name, out, i) == (i > 8)); |
| 132 | + assert(i < 9 || 0 == strncmp(out, "foo(int)", i - 1)); |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +int main() { |
| 137 | + TestInline(); |
| 138 | + TestNoInline(); |
| 139 | + TestLongFunctionNames(); |
| 140 | + TestData(); |
| 141 | + TestDemangle(); |
| 142 | +} |
0 commit comments