error.cpp (6739B)
1 #include "c4/error.hpp" 2 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <stdarg.h> 6 7 #define C4_LOGF_ERR(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) 8 #define C4_LOGF_WARN(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) 9 #define C4_LOGP(msg, ...) printf(msg) 10 11 #if defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC)) 12 # include "c4/windows.hpp" 13 #elif defined(C4_PS4) 14 # include <libdbg.h> 15 #elif defined(C4_UNIX) || defined(C4_LINUX) 16 # include <sys/stat.h> 17 # include <cstring> 18 # include <fcntl.h> 19 #elif defined(C4_MACOS) || defined(C4_IOS) 20 # include <assert.h> 21 # include <stdbool.h> 22 # include <sys/types.h> 23 # include <sys/sysctl.h> 24 #endif 25 // the amalgamation tool is dumb and was omitting this include under MACOS. 26 // So do it only once: 27 #if defined(C4_UNIX) || defined(C4_LINUX) || defined(C4_MACOS) || defined(C4_IOS) 28 # include <unistd.h> 29 #endif 30 31 #if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION) 32 # include <exception> 33 #endif 34 35 #ifdef __clang__ 36 # pragma clang diagnostic push 37 # pragma clang diagnostic ignored "-Wformat-nonliteral" 38 # pragma clang diagnostic ignored "-Wold-style-cast" 39 #elif defined(__GNUC__) 40 # pragma GCC diagnostic push 41 # pragma GCC diagnostic ignored "-Wformat-nonliteral" 42 # pragma GCC diagnostic ignored "-Wold-style-cast" 43 #endif 44 45 46 //----------------------------------------------------------------------------- 47 namespace c4 { 48 49 static error_flags s_error_flags = ON_ERROR_DEFAULTS; 50 static error_callback_type s_error_callback = nullptr; 51 52 //----------------------------------------------------------------------------- 53 54 error_flags get_error_flags() 55 { 56 return s_error_flags; 57 } 58 void set_error_flags(error_flags flags) 59 { 60 s_error_flags = flags; 61 } 62 63 error_callback_type get_error_callback() 64 { 65 return s_error_callback; 66 } 67 /** Set the function which is called when an error occurs. */ 68 void set_error_callback(error_callback_type cb) 69 { 70 s_error_callback = cb; 71 } 72 73 //----------------------------------------------------------------------------- 74 75 void handle_error(srcloc where, const char *fmt, ...) 76 { 77 char buf[1024]; 78 size_t msglen = 0; 79 if(s_error_flags & (ON_ERROR_LOG|ON_ERROR_CALLBACK)) 80 { 81 va_list args; 82 va_start(args, fmt); 83 int ilen = vsnprintf(buf, sizeof(buf), fmt, args); // ss.vprintf(fmt, args); 84 va_end(args); 85 msglen = ilen >= 0 && ilen < (int)sizeof(buf) ? static_cast<size_t>(ilen) : sizeof(buf)-1; 86 } 87 88 if(s_error_flags & ON_ERROR_LOG) 89 { 90 C4_LOGF_ERR("\n"); 91 #if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC) 92 C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf); 93 C4_LOGF_ERR("%s:%d: ERROR here: %s\n", where.file, where.line, where.func); 94 #elif defined(C4_ERROR_SHOWS_FILELINE) 95 C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf); 96 #elif ! defined(C4_ERROR_SHOWS_FUNC) 97 C4_LOGF_ERR("ERROR: %s\n", buf); 98 #endif 99 } 100 101 if(s_error_flags & ON_ERROR_CALLBACK) 102 { 103 if(s_error_callback) 104 { 105 s_error_callback(buf, msglen/*ss.c_strp(), ss.tellp()*/); 106 } 107 } 108 109 if(s_error_flags & ON_ERROR_ABORT) 110 { 111 abort(); 112 } 113 114 if(s_error_flags & ON_ERROR_THROW) 115 { 116 #if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION) 117 throw Exception(buf); 118 #else 119 abort(); 120 #endif 121 } 122 } 123 124 //----------------------------------------------------------------------------- 125 126 void handle_warning(srcloc where, const char *fmt, ...) 127 { 128 va_list args; 129 char buf[1024]; //sstream<c4::string> ss; 130 va_start(args, fmt); 131 vsnprintf(buf, sizeof(buf), fmt, args); 132 va_end(args); 133 C4_LOGF_WARN("\n"); 134 #if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC) 135 C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf/*ss.c_strp()*/); 136 C4_LOGF_WARN("%s:%d: WARNING: here: %s\n", where.file, where.line, where.func); 137 #elif defined(C4_ERROR_SHOWS_FILELINE) 138 C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf/*ss.c_strp()*/); 139 #elif ! defined(C4_ERROR_SHOWS_FUNC) 140 C4_LOGF_WARN("WARNING: %s\n", buf/*ss.c_strp()*/); 141 #endif 142 //c4::log.flush(); 143 } 144 145 //----------------------------------------------------------------------------- 146 bool is_debugger_attached() 147 { 148 #if defined(C4_UNIX) || defined(C4_LINUX) 149 static bool first_call = true; 150 static bool first_call_result = false; 151 if(first_call) 152 { 153 first_call = false; 154 //! @see http://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb 155 //! (this answer: http://stackoverflow.com/a/24969863/3968589 ) 156 char buf[1024] = ""; 157 158 int status_fd = open("/proc/self/status", O_RDONLY); 159 if (status_fd == -1) 160 { 161 return 0; 162 } 163 164 ssize_t num_read = ::read(status_fd, buf, sizeof(buf)); 165 166 if (num_read > 0) 167 { 168 static const char TracerPid[] = "TracerPid:"; 169 char *tracer_pid; 170 171 if(num_read < 1024) 172 { 173 buf[num_read] = 0; 174 } 175 tracer_pid = strstr(buf, TracerPid); 176 if (tracer_pid) 177 { 178 first_call_result = !!::atoi(tracer_pid + sizeof(TracerPid) - 1); 179 } 180 } 181 } 182 return first_call_result; 183 #elif defined(C4_PS4) 184 return (sceDbgIsDebuggerAttached() != 0); 185 #elif defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC)) 186 return IsDebuggerPresent() != 0; 187 #elif defined(C4_MACOS) || defined(C4_IOS) 188 // https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x 189 // Returns true if the current process is being debugged (either 190 // running under the debugger or has a debugger attached post facto). 191 int junk; 192 int mib[4]; 193 struct kinfo_proc info; 194 size_t size; 195 196 // Initialize the flags so that, if sysctl fails for some bizarre 197 // reason, we get a predictable result. 198 199 info.kp_proc.p_flag = 0; 200 201 // Initialize mib, which tells sysctl the info we want, in this case 202 // we're looking for information about a specific process ID. 203 204 mib[0] = CTL_KERN; 205 mib[1] = KERN_PROC; 206 mib[2] = KERN_PROC_PID; 207 mib[3] = getpid(); 208 209 // Call sysctl. 210 211 size = sizeof(info); 212 junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); 213 assert(junk == 0); 214 215 // We're being debugged if the P_TRACED flag is set. 216 return ((info.kp_proc.p_flag & P_TRACED) != 0); 217 #else 218 return false; 219 #endif 220 } // is_debugger_attached() 221 222 } // namespace c4 223 224 225 #ifdef __clang__ 226 # pragma clang diagnostic pop 227 #elif defined(__GNUC__) 228 # pragma GCC diagnostic pop 229 #endif