WineDbg changes the Win16 exception path and cannot capture continuous game state reliably. Add a Linux-only launcher that opts the normally running Wine process into same-user tracing without modifying TDKPIN.EXE, plus a sampler that locates the loaded DGROUP and game object from recovered signatures. The CSV trace exposes original millipixel positions, predicted positions, velocities, flipper state, and claw state whenever they change. This provides an external oracle for reconstructing and differentially testing the fixed- point mechanics instead of tuning the Rust approximation against screenshots. Test Plan: - `shellcheck original/tools/run_traceable_original.sh` -- passed - `ruff check original/tools/trace_original_state.py` -- passed - strict shared-library compile with `cc` warnings as errors -- passed - live Wine smoke trace and four-second charged launch capture -- passed - `git diff --cached --check` -- passed
42 lines
1.2 KiB
C
42 lines
1.2 KiB
C
#define _GNU_SOURCE
|
|
|
|
#include <linux/prctl.h>
|
|
#include <pthread.h>
|
|
#include <sys/prctl.h>
|
|
#include <time.h>
|
|
|
|
/*
|
|
* Wine's Win16 process is re-parented during startup, so Linux's default Yama
|
|
* policy rejects a later same-user debugger attach. This preload helper only
|
|
* relaxes that relationship check for the process into which it is loaded.
|
|
* Normal uid-based ptrace permission checks still apply.
|
|
*/
|
|
static void apply_ptrace_policy(void)
|
|
{
|
|
(void)prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
|
(void)prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
|
|
}
|
|
|
|
static void *reapply_ptrace_policy(void *unused)
|
|
{
|
|
const struct timespec interval = {.tv_sec = 0, .tv_nsec = 250000000};
|
|
(void)unused;
|
|
|
|
/* Wine adjusts process policy during bootstrap; outlast those updates. */
|
|
for (unsigned int attempt = 0; attempt < 20; attempt++) {
|
|
(void)nanosleep(&interval, NULL);
|
|
apply_ptrace_policy();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
__attribute__((constructor)) static void allow_same_user_debugger(void)
|
|
{
|
|
pthread_t worker;
|
|
|
|
apply_ptrace_policy();
|
|
if (pthread_create(&worker, NULL, reapply_ptrace_policy, NULL) == 0) {
|
|
(void)pthread_detach(worker);
|
|
}
|
|
}
|