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.
main
Ryan C. Gordon 2022-10-10 13:07:52 -04:00
parent 4507083503
commit 17322e2be6
No known key found for this signature in database
GPG Key ID: FA148B892AB48044
1 changed files with 92 additions and 4 deletions

View File

@ -50,7 +50,6 @@
static void SDL_InitDynamicAPI(void); static void SDL_InitDynamicAPI(void);
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP. /* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
Even self-contained stuff might call SDL_Error and break everything. */ Even self-contained stuff might call SDL_Error and break everything. */
@ -191,6 +190,79 @@ SDL_DYNAPI_VARARGS(,,)
#error Write me. #error Write me.
#endif #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 /* 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. */ system's dynamic linker resolving to the wrong version of this. */
static Sint32 static Sint32
@ -206,9 +278,25 @@ initialize_jumptable(Uint32 apiver, void *table, Uint32 tablesize)
} }
/* Init our jump table first. */ /* Init our jump table first. */
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL; #if ENABLE_SDL_CALL_LOGGING
#include "SDL_dynapi_procs.h" {
#undef SDL_DYNAPI_PROC 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... */ /* Then the external table... */
if (output_jump_table != &jump_table) { if (output_jump_table != &jump_table) {