duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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