trace FIFA17 provider lifecycle

This commit is contained in:
funman300
2026-08-25 23:18:08 +00:00
parent 5eed124b85
commit 43c460741b
4 changed files with 608 additions and 16 deletions
+11 -16
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
"""Trace FIFA17 ACTION_ADVANCE dispatch after MATCH_CREATED delivery.
"""Trace FIFA17 provider dispatch and ACTION_ADVANCE delivery boundaries.
Stage one (`match_transition_trace.py`) proves the HTTP response, deserializer,
and FUT_CREATE_MATCH_DP delivery. This stage uses that provider callback to
capture the screen key, then records every nested global UI dispatch for that
same screen until the positive-control FUT_GET_MATCH_KITS_DP arrives. It also
captures the low-level create event and final native-to-UI provider bridge.
This probe correlates the global UI dispatch of FUT_CREATE_MATCH_DP and
FUT_GET_MATCH_KITS_DP, the subscribed CardsDLL provider, the internal 0x7546
create-response callback that can replay FUT_CREATE_MATCH_DP, and the final
native-to-UI bridge. At global dispatch, r8d is the provider ID and rdx is the
payload; neither register is a screen key.
The generated GDB program uses hardware-assisted execution breakpoints only.
It never writes client memory and never drives game input.
@@ -84,28 +84,22 @@ handle SIGUSR1 nostop noprint pass
handle SIGUSR2 nostop noprint pass
attach {pid}
set $screen_key = 0
set $target_seen = 0
hbreak *0x{address['provider']:x}
condition 1 $edx == 0x{transition.FUT_CREATE_MATCH_DP:x} || $edx == 0x{transition.FUT_GET_MATCH_KITS_DP:x}
commands
silent
if $edx == 0x{transition.FUT_CREATE_MATCH_DP:x}
set $screen_key = $r8
set $target_seen = 1
end
python import time; print("ADVTRACE epoch_ns=%d mono_ns=%d PROVIDER" % (time.time_ns(), time.monotonic_ns()), end=" ")
printf "thread=%d provider=%#x screen_key=%p controller=%p caller=%p\\n", $_thread, $edx, $r8, $rcx, *(void**)$rsp
printf "thread=%d provider=%#x payload=%p controller=%p caller=%p\\n", $_thread, $edx, $r8, $rcx, *(void**)$rsp
continue
end
hbreak *0x{address['global_dispatch']:x}
condition 2 $target_seen != 0 && $r8 == $screen_key
condition 2 $r8d == 0x{transition.FUT_CREATE_MATCH_DP:x} || $r8d == 0x{transition.FUT_GET_MATCH_KITS_DP:x}
commands
silent
python import time; print("ADVTRACE epoch_ns=%d mono_ns=%d GLOBAL_DISPATCH" % (time.time_ns(), time.monotonic_ns()), end=" ")
printf "thread=%d id=%#x screen_key=%p registry=%p caller=%p\\n", $_thread, $rdx, $r8, $rcx, *(void**)$rsp
printf "thread=%d provider=%#x payload=%p manager=%p caller=%p\\n", $_thread, $r8d, $rdx, $rcx, *(void**)$rsp
continue
end
@@ -144,7 +138,8 @@ def selftest() -> None:
assert script.count("hbreak *") == 4
assert f"$edx == 0x{transition.FUT_CREATE_MATCH_DP:x}" in script
assert f"$edx == 0x{transition.FUT_GET_MATCH_KITS_DP:x}" in script
assert "$r8 == $screen_key" in script
assert f"$r8d == 0x{transition.FUT_CREATE_MATCH_DP:x}" in script
assert f"$r8d == 0x{transition.FUT_GET_MATCH_KITS_DP:x}" in script
assert "CREATE_MATCH_CONTROLLER" in script
assert "PROVIDER_BRIDGE" in script
assert "set *(" not in script