Files
tdkpin/original/tools/allow_ptrace.c
T
ddidderr dcc664346c feat(reverse): trace the live original physics state
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
2026-08-22 20:16:14 +02:00

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);
}
}