From 17322e2be649eefaf6a02e2fcaefc444722ccfbb Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 10 Oct 2022 13:07:52 -0400 Subject: [PATCH] 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. --- src/dynapi/SDL_dynapi.c | 96 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c index d3f7f612b..13b0a5551 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) {