dynapi: Optionally log every call into the SDL API. This will only log things going through dynapi, which means it won't do anything if dynapi is disabled for a given build, but also things that call the `*_REAL` version of an API won't log either (which is to say, if an internal piece of SDL calls a public API, it won't log it, but if an application calls that same entry point, it will). Since this just inserts a different function pointer, unless you explicitly request this at runtime, it won't add any overhead, and, of course, the entire thing can be turned off with a single #define so it doesn't even add extra unused code to the shared library if the kill switch is flipped.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c
index d3f7f61..13b0a55 100644
--- a/src/dynapi/SDL_dynapi.c
+++ b/src/dynapi/SDL_dynapi.c
@@ -50,7 +50,6 @@
static void SDL_InitDynamicAPI(void);
-
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
Even self-contained stuff might call SDL_Error and break everything. */
@@ -191,6 +190,79 @@ SDL_DYNAPI_VARARGS(,,)
#error Write me.
#endif
+#define ENABLE_SDL_CALL_LOGGING 1
+#if ENABLE_SDL_CALL_LOGGING
+static int SDLCALL SDL_SetError_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) {
+ char buf[512]; /* !!! FIXME: dynamic allocation */ \
+ va_list ap;
+ SDL_Log_REAL("SDL2CALL SDL_SetError");
+ va_start(ap, fmt);
+ SDL_vsnprintf_REAL(buf, sizeof (buf), fmt, ap);
+ va_end(ap);
+ return SDL_SetError_REAL("%s", buf);
+}
+static int SDLCALL SDL_sscanf_LOGSDLCALLS(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) {
+ int retval;
+ va_list ap;
+ SDL_Log_REAL("SDL2CALL SDL_sscanf");
+ va_start(ap, fmt);
+ retval = SDL_vsscanf_REAL(buf, fmt, ap);
+ va_end(ap);
+ return retval;
+}
+static int SDLCALL SDL_snprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) {
+ int retval;
+ va_list ap;
+ SDL_Log_REAL("SDL2CALL SDL_snprintf");
+ va_start(ap, fmt);
+ retval = SDL_vsnprintf_REAL(buf, maxlen, fmt, ap);
+ va_end(ap);
+ return retval;
+}
+static int SDLCALL SDL_asprintf_LOGSDLCALLS(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) {
+ int retval;
+ va_list ap;
+ SDL_Log_REAL("SDL2CALL SDL_asprintf");
+ va_start(ap, fmt);
+ retval = SDL_vasprintf_REAL(strp, fmt, ap);
+ va_end(ap);
+ return retval;
+}
+static void SDLCALL SDL_Log_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) {
+ va_list ap;
+ SDL_Log_REAL("SDL2CALL SDL_Log");
+ va_start(ap, fmt);
+ SDL_LogMessageV_REAL(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \
+ va_end(ap);
+}
+static void SDLCALL SDL_LogMessage_LOGSDLCALLS(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) {
+ va_list ap;
+ SDL_Log_REAL("SDL2CALL SDL_LogMessage");
+ va_start(ap, fmt);
+ SDL_LogMessageV_REAL(category, priority, fmt, ap);
+ va_end(ap);
+}
+#define SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(logname, prio) \
+ static void SDLCALL SDL_Log##logname##_LOGSDLCALLS(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
+ va_list ap; va_start(ap, fmt); \
+ SDL_Log_REAL("SDL2CALL SDL_Log%s", #logname); \
+ SDL_LogMessageV_REAL(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
+ va_end(ap); \
+ }
+SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Verbose, VERBOSE)
+SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Debug, DEBUG)
+SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Info, INFO)
+SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Warn, WARN)
+SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Error, ERROR)
+SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Critical, CRITICAL)
+#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
+ rc SDLCALL fn##_LOGSDLCALLS params { SDL_Log_REAL("SDL2CALL %s", #fn); ret fn##_REAL args; }
+#define SDL_DYNAPI_PROC_NO_VARARGS 1
+#include "SDL_dynapi_procs.h"
+#undef SDL_DYNAPI_PROC
+#undef SDL_DYNAPI_PROC_NO_VARARGS
+#endif
+
/* we make this a static function so we can call the correct one without the
system's dynamic linker resolving to the wrong version of this. */
static Sint32
@@ -206,9 +278,25 @@ initialize_jumptable(Uint32 apiver, void *table, Uint32 tablesize)
}
/* Init our jump table first. */
- #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
- #include "SDL_dynapi_procs.h"
- #undef SDL_DYNAPI_PROC
+ #if ENABLE_SDL_CALL_LOGGING
+ {
+ const char *env = SDL_getenv_REAL("SDL_DYNAPI_LOG_CALLS");
+ const SDL_bool log_calls = (env && SDL_atoi_REAL(env));
+ if (log_calls) {
+ #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_LOGSDLCALLS;
+ #include "SDL_dynapi_procs.h"
+ #undef SDL_DYNAPI_PROC
+ } else {
+ #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
+ #include "SDL_dynapi_procs.h"
+ #undef SDL_DYNAPI_PROC
+ }
+ }
+ #else
+ #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
+ #include "SDL_dynapi_procs.h"
+ #undef SDL_DYNAPI_PROC
+ #endif
/* Then the external table... */
if (output_jump_table != &jump_table) {