1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_test_common_utils_report_H 18 #define __TBB_test_common_utils_report_H 19 20 #include "config.h" 21 22 #include <mutex> 23 #include <cstdarg> 24 25 #if __SUNPRO_CC 26 #include <stdio.h> 27 #else 28 #include <cstdio> 29 #endif 30 31 #if defined(MAX_TRACE_SIZE) && MAX_TRACE_SIZE < 1024 32 #undef MAX_TRACE_SIZE 33 #endif 34 #ifndef MAX_TRACE_SIZE 35 #define MAX_TRACE_SIZE 1024 36 #endif 37 38 39 #if __GLIBC__>2 || ( __GLIBC__==2 && __GLIBC_MINOR__ >= 1) || __APPLE__ 40 #include <execinfo.h> /*backtrace*/ 41 #define BACKTRACE_FUNCTION_AVAILABLE 1 42 #endif 43 44 #if defined(_MSC_VER) && _MSC_VER >= 1300 || defined(__GNUC__) || defined(__GNUG__) 45 #define TRACE_ORIG_INFO __FILE__, __LINE__, __FUNCTION__ 46 #else 47 #define TRACE_ORIG_INFO __FILE__, __LINE__, "" 48 #define __FUNCTION__ "" 49 #endif 50 51 #if defined(_WIN32) || defined(_WIN64) 52 #if (_WIN32_WINNT > 0x0501 && defined(_MSC_VER) && !defined(_M_ARM)) 53 // Suppress "typedef ignored ... when no variable is declared" warning by vc14 54 #pragma warning (push) 55 #pragma warning (disable: 4091) 56 #include <dbghelp.h> 57 #pragma warning (pop) 58 #pragma comment (lib, "dbghelp.lib") 59 #endif 60 #endif 61 62 //! printf style tracing macro without automatic new line character adding 63 #define TRACENL utils::internal::tracer.set_trace_info(0, TRACE_ORIG_INFO)->trace 64 65 //! printf style reporting macro 66 /** On heterogeneous platforms redirects its output to the host side. **/ 67 #define REPORT TRACENL 68 69 namespace utils { 70 namespace internal { 71 72 #ifndef TBBReporter 73 struct TBBReporter { 74 void Report ( const char* msg ) { 75 printf( "%s", msg ); 76 fflush(stdout); 77 #ifdef _WINDOWS_ 78 OutputDebugStringA(msg); 79 #endif 80 } 81 }; 82 #endif 83 84 class Tracer { 85 int m_flags; 86 const char *m_file; 87 const char *m_func; 88 std::size_t m_line; 89 90 TBBReporter m_reporter; 91 92 public: 93 enum { 94 prefix = 1, 95 need_lf = 2 96 }; 97 98 Tracer(): m_flags(0), m_file(nullptr), m_func(nullptr), m_line(0) {} 99 100 Tracer* set_trace_info( int flags, const char *file, std::size_t line, const char *func ) { 101 m_flags = flags; 102 m_line = line; 103 m_file = file; 104 m_func = func; 105 return this; 106 } 107 108 void trace( const char* fmt, ... ) { 109 char msg[MAX_TRACE_SIZE]; 110 char msg_fmt_buf[MAX_TRACE_SIZE]; 111 const char *msg_fmt = fmt; 112 if (m_flags & prefix) { 113 snprintf (msg_fmt_buf, MAX_TRACE_SIZE, "[%s] %s", m_func, fmt); 114 msg_fmt = msg_fmt_buf; 115 } 116 std::va_list argptr; 117 va_start(argptr, fmt); 118 int len = vsnprintf(msg, MAX_TRACE_SIZE, msg_fmt, argptr); 119 va_end(argptr); 120 if (m_flags & need_lf && len < MAX_TRACE_SIZE - 1 && msg_fmt[len-1] != '\n') { 121 msg[len] = '\n'; 122 msg[len + 1] = 0; 123 } 124 m_reporter.Report(msg); 125 } 126 }; // class Tracer 127 128 static Tracer tracer; 129 130 template<int> 131 bool not_the_first_call () { 132 static bool first_call = false; 133 bool res = first_call; 134 first_call = true; 135 return res; 136 } 137 138 } // internal 139 140 inline void print_call_stack() { 141 static std::mutex mutex; 142 std::lock_guard<std::mutex> lock(mutex); 143 144 fflush(stdout); fflush(stderr); 145 #if BACKTRACE_FUNCTION_AVAILABLE 146 const int sz = 100; // max number of frames to capture 147 void *buff[sz]; 148 int n = backtrace(buff, sz); 149 REPORT("Call stack info (%d):\n", n); 150 backtrace_symbols_fd(buff, n, fileno(stdout)); 151 #elif __SUNPRO_CC 152 REPORT("Call stack info:\n"); 153 printstack(fileno(stdout)); 154 #elif _WIN32_WINNT > 0x0501 && _MSC_VER>=1500 && !__TBB_WIN8UI_SUPPORT && !defined(WINAPI_FAMILY) 155 const int sz = 62; // XP limitation for number of frames 156 void *buff[sz]; 157 int n = CaptureStackBackTrace(0, sz, buff, NULL); 158 REPORT("Call stack info (%d):\n", n); 159 static LONG once = 0; 160 if( !InterlockedExchange(&once, 1) ) 161 SymInitialize(GetCurrentProcess(), NULL, TRUE); 162 const int len = 255; // just some reasonable string buffer size 163 union { SYMBOL_INFO sym; char pad[sizeof(SYMBOL_INFO)+len]; }; 164 sym.MaxNameLen = len; 165 sym.SizeOfStruct = sizeof( SYMBOL_INFO ); 166 DWORD64 offset; 167 for(int i = 1; i < n; i++) { // skip current frame 168 if(!SymFromAddr( GetCurrentProcess(), DWORD64(buff[i]), &offset, &sym )) { 169 sym.Address = ULONG64(buff[i]); offset = 0; sym.Name[0] = 0; 170 } 171 REPORT("[%d] %016I64X+%04I64X: %s\n", i, sym.Address, offset, sym.Name); 172 } 173 #endif 174 } 175 176 } // util 177 178 #endif // __TBB_test_common_utils_report_H 179