1 /* 2 Copyright (c) 2005-2022 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 #ifndef NOMINMAX 57 #define NOMINMAX 58 #endif 59 #include <windows.h> 60 #include <dbghelp.h> 61 #pragma warning (pop) 62 #pragma comment (lib, "dbghelp.lib") 63 #endif 64 #endif 65 66 //! printf style tracing macro without automatic new line character adding 67 #define TRACENL utils::internal::tracer.set_trace_info(0, TRACE_ORIG_INFO)->trace 68 69 //! printf style reporting macro 70 /** On heterogeneous platforms redirects its output to the host side. **/ 71 #define REPORT TRACENL 72 73 namespace utils { 74 namespace internal { 75 76 #ifndef TBBReporter 77 struct TBBReporter { 78 void Report ( const char* msg ) { 79 printf( "%s", msg ); 80 fflush(stdout); 81 #ifdef _WINDOWS_ 82 OutputDebugStringA(msg); 83 #endif 84 } 85 }; 86 #endif 87 88 class Tracer { 89 int m_flags; 90 const char *m_file; 91 const char *m_func; 92 std::size_t m_line; 93 94 TBBReporter m_reporter; 95 96 public: 97 enum { 98 prefix = 1, 99 need_lf = 2 100 }; 101 102 Tracer(): m_flags(0), m_file(nullptr), m_func(nullptr), m_line(0) {} 103 104 Tracer* set_trace_info( int flags, const char *file, std::size_t line, const char *func ) { 105 m_flags = flags; 106 m_line = line; 107 m_file = file; 108 m_func = func; 109 return this; 110 } 111 112 void trace( const char* fmt, ... ) { 113 char msg[MAX_TRACE_SIZE]; 114 char msg_fmt_buf[MAX_TRACE_SIZE]; 115 const char *msg_fmt = fmt; 116 if (m_flags & prefix) { 117 snprintf (msg_fmt_buf, MAX_TRACE_SIZE, "[%s] %s", m_func, fmt); 118 msg_fmt = msg_fmt_buf; 119 } 120 std::va_list argptr; 121 va_start(argptr, fmt); 122 int len = vsnprintf(msg, MAX_TRACE_SIZE, msg_fmt, argptr); 123 va_end(argptr); 124 if (m_flags & need_lf && len < MAX_TRACE_SIZE - 1 && msg_fmt[len-1] != '\n') { 125 msg[len] = '\n'; 126 msg[len + 1] = 0; 127 } 128 m_reporter.Report(msg); 129 } 130 }; // class Tracer 131 132 static Tracer tracer; 133 134 template<int> 135 bool not_the_first_call () { 136 static bool first_call = false; 137 bool res = first_call; 138 first_call = true; 139 return res; 140 } 141 142 } // internal 143 144 inline void print_call_stack() { 145 static std::mutex mutex; 146 std::lock_guard<std::mutex> lock(mutex); 147 148 fflush(stdout); fflush(stderr); 149 #if BACKTRACE_FUNCTION_AVAILABLE 150 const int sz = 100; // max number of frames to capture 151 void *buff[sz]; 152 int n = backtrace(buff, sz); 153 REPORT("Call stack info (%d):\n", n); 154 backtrace_symbols_fd(buff, n, fileno(stdout)); 155 #elif __SUNPRO_CC 156 REPORT("Call stack info:\n"); 157 printstack(fileno(stdout)); 158 #elif _WIN32_WINNT > 0x0501 && _MSC_VER>=1500 && !__TBB_WIN8UI_SUPPORT && !defined(WINAPI_FAMILY) 159 const int sz = 62; // XP limitation for number of frames 160 void *buff[sz]; 161 int n = CaptureStackBackTrace(0, sz, buff, nullptr); 162 REPORT("Call stack info (%d):\n", n); 163 static LONG once = 0; 164 if( !InterlockedExchange(&once, 1) ) 165 SymInitialize(GetCurrentProcess(), nullptr, TRUE); 166 const int len = 255; // just some reasonable string buffer size 167 union { SYMBOL_INFO sym; char pad[sizeof(SYMBOL_INFO)+len]; }; 168 sym.MaxNameLen = len; 169 sym.SizeOfStruct = sizeof( SYMBOL_INFO ); 170 DWORD64 offset; 171 for(int i = 1; i < n; i++) { // skip current frame 172 if(!SymFromAddr( GetCurrentProcess(), DWORD64(buff[i]), &offset, &sym )) { 173 sym.Address = ULONG64(buff[i]); offset = 0; sym.Name[0] = 0; 174 } 175 REPORT("[%d] %016I64X+%04I64X: %s\n", i, sym.Address, offset, sym.Name); 176 } 177 #endif 178 } 179 180 } // util 181 182 #endif // __TBB_test_common_utils_report_H 183