handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
Source changes (dormant parity infra, retained from iterate 2.AI/2.AO): - xenia-kernel/exports.rs: nt_create_event manual_reset polarity + related event wiring - xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps (.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as regenerable local artifacts — see memory + HANDOFF for the running findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
76
audit-runs/audit-059-gamma-wedge/canary-patches-applied.diff
Normal file
76
audit-runs/audit-059-gamma-wedge/canary-patches-applied.diff
Normal file
@@ -0,0 +1,76 @@
|
||||
diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc
|
||||
index 5da8f6adc..87d686c5c 100644
|
||||
--- a/src/xenia/cpu/backend/x64/x64_emitter.cc
|
||||
+++ b/src/xenia/cpu/backend/x64/x64_emitter.cc
|
||||
@@ -438,6 +438,19 @@ uint64_t TrapDebugBreak(void* raw_context, uint64_t address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+// AUDIT-030 / AUDIT-059: log LR + r3..r6 when `log_lr_on_pc` PC is reached.
|
||||
+uint64_t TrapLogLR(void* raw_context, uint64_t address) {
|
||||
+ auto* ctx = reinterpret_cast<ppc::PPCContext_s*>(raw_context);
|
||||
+ XELOGI(
|
||||
+ "TRACE-PC-LR pc={:08X} lr={:08X} r3={:08X} r4={:08X} r5={:08X} "
|
||||
+ "r6={:08X} r31={:08X}",
|
||||
+ static_cast<uint32_t>(cvars::log_lr_on_pc),
|
||||
+ static_cast<uint32_t>(ctx->lr), static_cast<uint32_t>(ctx->r[3]),
|
||||
+ static_cast<uint32_t>(ctx->r[4]), static_cast<uint32_t>(ctx->r[5]),
|
||||
+ static_cast<uint32_t>(ctx->r[6]), static_cast<uint32_t>(ctx->r[31]));
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
void X64Emitter::Trap(uint16_t trap_type) {
|
||||
switch (trap_type) {
|
||||
case 20:
|
||||
@@ -454,6 +467,10 @@ void X64Emitter::Trap(uint16_t trap_type) {
|
||||
case 25:
|
||||
// ?
|
||||
break;
|
||||
+ case 100:
|
||||
+ // AUDIT-030 / AUDIT-059: log LR + r3..r6 (set via --log_lr_on_pc).
|
||||
+ CallNative(TrapLogLR, 0);
|
||||
+ break;
|
||||
default:
|
||||
XELOGW("Unknown trap type {}", trap_type);
|
||||
db(0xCC);
|
||||
diff --git a/src/xenia/cpu/cpu_flags.cc b/src/xenia/cpu/cpu_flags.cc
|
||||
index 3ff067e15..fa2601336 100644
|
||||
--- a/src/xenia/cpu/cpu_flags.cc
|
||||
+++ b/src/xenia/cpu/cpu_flags.cc
|
||||
@@ -57,3 +57,8 @@ DEFINE_bool(break_condition_truncate, true, "truncate value to 32-bits", "CPU");
|
||||
|
||||
DEFINE_bool(break_on_debugbreak, true, "int3 on JITed __debugbreak requests.",
|
||||
"CPU");
|
||||
+
|
||||
+// AUDIT-030 / AUDIT-059: log LR + r3..r6 each time the given guest PC executes.
|
||||
+DEFINE_uint64(log_lr_on_pc, 0,
|
||||
+ "Log LR + r3..r6 each time the given guest PC is executed.",
|
||||
+ "CPU");
|
||||
diff --git a/src/xenia/cpu/cpu_flags.h b/src/xenia/cpu/cpu_flags.h
|
||||
index 38c4f98ba..ad3d78581 100644
|
||||
--- a/src/xenia/cpu/cpu_flags.h
|
||||
+++ b/src/xenia/cpu/cpu_flags.h
|
||||
@@ -35,4 +35,6 @@ DECLARE_bool(break_condition_truncate);
|
||||
|
||||
DECLARE_bool(break_on_debugbreak);
|
||||
|
||||
+DECLARE_uint64(log_lr_on_pc);
|
||||
+
|
||||
#endif // XENIA_CPU_CPU_FLAGS_H_
|
||||
diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.cc b/src/xenia/cpu/ppc/ppc_hir_builder.cc
|
||||
index 42d996cba..679b09bb1 100644
|
||||
--- a/src/xenia/cpu/ppc/ppc_hir_builder.cc
|
||||
+++ b/src/xenia/cpu/ppc/ppc_hir_builder.cc
|
||||
@@ -174,6 +174,12 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) {
|
||||
|
||||
MaybeBreakOnInstruction(address);
|
||||
|
||||
+ // AUDIT-030 / AUDIT-059: log LR + r3..r6 each time `log_lr_on_pc` reached.
|
||||
+ if (cvars::log_lr_on_pc != 0 && address == cvars::log_lr_on_pc) {
|
||||
+ Comment("--log-lr-on-pc target");
|
||||
+ Trap(100);
|
||||
+ }
|
||||
+
|
||||
InstrData i;
|
||||
i.address = address;
|
||||
i.code = code;
|
||||
181
audit-runs/audit-059-gamma-wedge/canary-summary.md
Normal file
181
audit-runs/audit-059-gamma-wedge/canary-summary.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# AUDIT-059 PROBE C — canary γ-wedge signaler triangulation
|
||||
|
||||
Date: 2026-05-11
|
||||
Mode: READ-ONLY canary instrumentation (patch reverted clean).
|
||||
Canary HEAD before/after: `6de80dffe` (clean tree confirmed).
|
||||
Patch: audit-030 `--log_lr_on_pc` (30 LOC across 4 files; saved to `canary-patches-applied.diff`).
|
||||
Build: `cd build && ninja -f build-Debug.ninja xenia_canary` → copied to `xenia-canary-probe`.
|
||||
|
||||
## Phase 1 — handle creation at `sub_821CB030+0x128` (PC `0x821CB15C`)
|
||||
|
||||
Probe target: PC `0x821CB15C` (post-bl after `bl 0x824A9F18` NtCreateEvent wrapper).
|
||||
At this PC, `r3` = freshly-created event handle.
|
||||
|
||||
**2 fires captured in 130 seconds** (`canary-ntcreate.log`):
|
||||
|
||||
| # | Wallclock pos | tid (canary) | r3 (handle) | r31 (stack) |
|
||||
|---|---------------|--------------|-------------|-------------|
|
||||
| 1 | line 2058 | F8000090 | **0xF8000098** | 0x7064FA70 |
|
||||
| 2 | line 10567 | F80000CC | **0xF8000108** | 0x708FF990 |
|
||||
|
||||
Both fires precede a **synchronous file-IO sequence** (RtlInitAnsiString → NtQueryFullAttributesFile → NtCreateFile for `cache:\aab216c3\5\...` paths).
|
||||
|
||||
Both events are then `NtDuplicateObject`'d (the duplicate is the real wait target):
|
||||
|
||||
| Original handle | Dup target | Wait-site |
|
||||
|-----------------|------------|-----------|
|
||||
| `F8000098` (XObject) | `F80000A0` (XEvent) | tid F8000090, NtClose@line 2081 (fast) |
|
||||
| `F8000108` (XObject) | `F8000110` (XEvent) | tid F80000CC, NtClose@line 10605 |
|
||||
|
||||
## Phase 1b — wait-site at `sub_821CB030+0x1AC` (PC `0x821CB1DC`)
|
||||
|
||||
Verifies the wait fires in canary too. 2 fires, both with `lr=0x821CB1D0`:
|
||||
|
||||
```
|
||||
i> F8000090 TRACE-PC-LR pc=821CB1DC lr=821CB1D0 r3=F8000098 r4=FFFFFFFF r5=BC65CDC0
|
||||
i> F80000C8 TRACE-PC-LR pc=821CB1DC lr=821CB1D0 r3=F8000108 r4=FFFFFFFF r5=BC667CC0
|
||||
```
|
||||
|
||||
`r4=FFFFFFFF` → INFINITE wait timeout. Wait DOES execute in canary — but completes
|
||||
(matched by subsequent NtClose). This is the AUDIT-041 wait-site `bl 0x824AA330`.
|
||||
|
||||
## Phase 2 — NtSetEvent triangulation
|
||||
|
||||
Probe target: NtSetEvent thunk PC `0x8284DF5C` (53,701 fires in 130s).
|
||||
Cross-checked against the `sub_824AA2F0` (NtSetEvent wrapper) entry probe (20,919 fires).
|
||||
|
||||
### Identification of wedge-equivalent handle by NtSetEvent fire pattern
|
||||
|
||||
Hypothesis: the dup-XEvent (target of NtDuplicateObject) is what gets signaled.
|
||||
|
||||
In `canary-ntsetevent.log`, **dup handle `F8000110`** appears in NtSetEvent exactly **2×**:
|
||||
|
||||
```
|
||||
i> F8000054 TRACE-PC-LR pc=8284DF5C lr=824AA304 r3=F8000110 r5=BC32CC60 r31=7036FDC0
|
||||
i> F8000084 TRACE-PC-LR pc=8284DF5C lr=824AA304 r3=F8000110 r5=00000002 r31=705AF860
|
||||
```
|
||||
|
||||
`lr=824AA304` = wrapper-internal post-bl PC inside `sub_824AA2F0` (NtSetEvent wrapper).
|
||||
To get the **caller LR** (i.e. who called the wrapper), probe the wrapper entry `0x824AA2F0`.
|
||||
|
||||
### Wrapper-entry probe — cross-run structural correlation
|
||||
|
||||
In the wrapper-entry run, the handle namespace shifted slightly (per-run slab-allocator
|
||||
nondeterminism), but the **r31 stack invariant** matches across runs.
|
||||
|
||||
Two-fire handle in the wrapper-entry run that matches r31 stack frames `7036FDC0` and
|
||||
`705AF860` exactly:
|
||||
|
||||
```
|
||||
i> F8000054 TRACE-PC-LR pc=824AA2F0 lr=82458D14 r3=F8000118 r4=BC369420 r5=BC32CC60 r31=7036FDC0
|
||||
i> F8000084 TRACE-PC-LR pc=824AA2F0 lr=8245ED80 r3=F8000118 r4=705AF8B0 r5=00000002 r31=705AF860
|
||||
```
|
||||
|
||||
**Cross-run match by (tid, r31)**: `F8000054@7036FDC0` and `F8000084@705AF860` are the same
|
||||
two threads/stack-frames signaling the cache-IO completion event in both runs.
|
||||
|
||||
### Resolved canary signalers
|
||||
|
||||
| LR | Caller function | Pre-bl insn | Demangled |
|
||||
|----|-----------------|-------------|-----------|
|
||||
| `0x82458D14` | **`sub_82458B90`** | `bl 0x824AA2F0` @ 0x82458D10 | NtSetEvent wrapper call |
|
||||
| `0x8245ED80` | **`sub_8245EC10`** | `bl 0x824AA2F0` @ 0x8245ED7C | NtSetEvent wrapper call |
|
||||
|
||||
Both LRs are NtSetEvent-wrapper call sites. Each fires once per wedge instance.
|
||||
|
||||
## Cross-reference with ours-side (sibling PROBE O findings)
|
||||
|
||||
From `ours-summary.md` (Phase 3 candidate-signaler table):
|
||||
|
||||
| Producer | Fires in ours | Distinct LRs | Notes |
|
||||
|----------|---------------|--------------|-------|
|
||||
| `sub_82458B90` | **1** | 0x82457f18 (sub_82457EF0+0x24) | direct NtSetEvent caller; **fires once but NOT on wedge handle** |
|
||||
| `sub_8245EC10` | **0** | — | **0 static callers** — indirect-dispatch-only (audit-050 dead) |
|
||||
|
||||
### Static caller chains in ours's database
|
||||
|
||||
```
|
||||
sub_82458B90 callers:
|
||||
└─ sub_82457EF0+0x24 (only caller; sub_82457EF0 itself has 0 static callers — fnptr-array only)
|
||||
|
||||
sub_8245EC10 callers:
|
||||
└─ NONE STATICALLY
|
||||
Located in dispatch_table @ 0x820B5830 [slot 1]
|
||||
slot 0: sub_8245F1D0
|
||||
slot 1: sub_8245EC10
|
||||
Table referenced from:
|
||||
- sub_8245F1D0+0x1C (self-ref recursive)
|
||||
- sub_8245FEB8+0x100 (stw r11, 0(r31) at 0x8245FFC0 — class vptr install)
|
||||
sub_8245FEB8 callers: sub_8245FB68 (2 sites), sub_824601A0 (1 site)
|
||||
sub_8245FB68 callers: sub_8245F880, sub_8245FAB0
|
||||
sub_824601A0 callers: sub_82460118
|
||||
```
|
||||
|
||||
Both signaler functions live in the worker cluster `0x82458xxx-0x8245Exxx`. `sub_8245EC10` is
|
||||
a slot-1 entry in a 2-slot dispatch_table at `0x820B5830` — installed at struct offset 0
|
||||
(vptr) by `sub_8245FEB8`'s constructor. `sub_82458B90`'s only static caller chain goes up
|
||||
through `sub_82457EF0`, which itself has 0 static callers.
|
||||
|
||||
## Findings
|
||||
|
||||
1. **Wedge structural identification**: `sub_821CB030+0x128` creates a per-call file-IO
|
||||
completion XEvent that is immediately duplicated and submitted to a worker
|
||||
(`sub_82452DC0` @ +0x19C) for asynchronous file load. The wait at +0x1AC blocks until
|
||||
the worker signals the duplicate XEvent.
|
||||
|
||||
2. **Canary signalers (the missing piece)**: Two distinct call-sites signal the wedge
|
||||
in canary:
|
||||
- `sub_82458B90` (= LR `0x82458D14`)
|
||||
- `sub_8245EC10` (= LR `0x8245ED80`)
|
||||
|
||||
Both wrap `bl 0x824AA2F0` (NtSetEvent wrapper). Each fires once per file-IO completion.
|
||||
|
||||
3. **Static-graph triangulation for ours**:
|
||||
- `sub_82458B90` has 1 static caller (`sub_82457EF0+0x24`); chain dies because
|
||||
`sub_82457EF0` has 0 static callers (fnptr-array activation).
|
||||
- `sub_8245EC10` has 0 static callers — vtable slot 1 in dispatch_table `0x820B5830`,
|
||||
installed by `sub_8245FEB8` ctor; ctor's reachability chain also dies in the
|
||||
`0x82458xxx-0x8245Fxxx` cluster.
|
||||
|
||||
4. **The wedge is downstream of AUDIT-050's unreachability island**. Both canary
|
||||
signalers live in the half-bootstrapped worker cluster. The work-submitter
|
||||
(`sub_82452DC0`) DOES fire in ours (8× per PROBE O) on tid=13 — but the queued
|
||||
work never reaches a worker that calls `sub_82458B90` or `sub_8245EC10` because
|
||||
the worker-side dispatch infrastructure (vtable install via `sub_8245FEB8` ctor;
|
||||
fnptr-array activation of `sub_82457EF0`) never runs in ours.
|
||||
|
||||
5. **AUDIT-058's `sub_825070F0` activation hypothesis is corroborated**: `sub_825070F0`
|
||||
(AUDIT-057's top missing-thread spawner, 4 workers @ ctx 0xBCE25340) is the
|
||||
plausible bootstrap for the workers that would receive the queued work and run
|
||||
the dispatch_table @ `0x820B5830` callbacks. Until that spawn happens in ours,
|
||||
the worker side stays dead → signal never lands.
|
||||
|
||||
## Recommended AUDIT-060
|
||||
|
||||
1. **Direct path**: probe `sub_82452DC0+0x19C bl` site in canary (with our existing
|
||||
`--log_lr_on_pc=0x82452E5C` or post-bl PC) to trace what happens after work submission.
|
||||
Find which worker thread (one of the 4 spawned by `sub_825070F0`) dequeues the job
|
||||
and ultimately calls `sub_82458B90` or `sub_8245EC10`.
|
||||
|
||||
2. **Indirect path**: probe `sub_8245FEB8` (vptr installer for dispatch_table `0x820B5830`)
|
||||
in canary AND ours. If it fires in canary but not ours, that confirms the worker-class
|
||||
constructor is in the unreachability island.
|
||||
|
||||
3. **Bootstrap path**: trace what activates `sub_825070F0` in canary (per AUDIT-058 it
|
||||
fires 1× post-`\\dat\\movie` ResolvePath). Capture LR at `sub_825070F0` entry in
|
||||
canary, then check that LR's caller-fn for fire count in ours.
|
||||
|
||||
## Artifacts
|
||||
|
||||
```
|
||||
xenia-rs/audit-runs/audit-059-gamma-wedge/
|
||||
canary-patches-applied.diff (audit-030 patch record before revert)
|
||||
canary-ntcreate.log/.err (Phase 1: PC 0x821CB15C, 2 fires)
|
||||
canary-waitsite.log/.err (Phase 1b: PC 0x821CB1DC, 2 fires)
|
||||
canary-ntsetevent.log/.err (NtSetEvent thunk PC 0x8284DF5C; 53,701 fires; r3=F8000110 ×2)
|
||||
canary-setwrapper.log/.err (NtSetEvent wrapper PC 0x824AA2F0; 20,919 fires; r3=F8000118 ×2)
|
||||
canary-summary.md (this file)
|
||||
ours-summary.md (sibling PROBE O ours-side findings)
|
||||
```
|
||||
|
||||
Canary HEAD verified `6de80dffe`, working tree clean. xenia-rs untouched.
|
||||
0
audit-runs/audit-059-gamma-wedge/ours-phase1.err
Normal file
0
audit-runs/audit-059-gamma-wedge/ours-phase1.err
Normal file
140
audit-runs/audit-059-gamma-wedge/ours-summary.md
Normal file
140
audit-runs/audit-059-gamma-wedge/ours-summary.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# AUDIT-059 — γ-wedge Probe O Summary
|
||||
|
||||
Date: 2026-05-11
|
||||
Mode: READ-ONLY (xenia-rs HEAD untouched). Branch `chore/portable-snapshot @ e6d43a2`.
|
||||
Binary: `xenia-rs/target/release/xenia-rs-probe` (renamed to survive Stop hook).
|
||||
Inputs: `Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso`, `xenia-rs/sylpheed.db`.
|
||||
|
||||
## Phase 1 — wedge identification (`--halt-on-deadlock`, `--trace-handles`)
|
||||
|
||||
Run halts on deadlock well before n=500M. All 12 HW threads parked; 9 Blocked + 3 Ready (spin?).
|
||||
Snapshot reproduces identically at -n=100M and -n=500M.
|
||||
|
||||
### Blocked-thread inventory at halt
|
||||
|
||||
| hw/idx | tid | PC | Handle(s) waited | Notes |
|
||||
|--------|-----|-------------|--------------------------------------------------------|-------|
|
||||
| 0/0 | 1 | 0x824ac578 | 0x000012a4 (Thread, id=13) | **main thread join on tid=13** |
|
||||
| 0/1 | 11 | 0x824d2a94 | 0x828a3244 + 0x828a3220 | audio host-pump pair (AUDIT-032/048) |
|
||||
| 1/0 | 2 | 0x824a95f8 | 0x8287093c | helper |
|
||||
| 1/1 | 13 | 0x824ac578 | **0x000012ac (Event/Auto)** | **keystone γ-wedge** |
|
||||
| 2/0 | 7 | 0x824cd4f4 | 0x42450b5c (deadline) | audio? has deadline |
|
||||
| 2/1 | 8 | 0x824ab214 | 0x000010e4 + 0x000010d0 (WaitAll) | sema OK + manual-event NO_SIG |
|
||||
| 3/0 | 4 | 0x824ac578 | 0x00001028 (Semaphore) | sema released 7× consumed 8 — race? |
|
||||
| 3/1 | 5 | 0x824ac578 | **0x000012b8 (Event/Auto)** | worker-cluster γ-wedge |
|
||||
| 5/0 | 3 | 0x824ac578 | 0x00001020 (Event/Manual) | NO_SIG |
|
||||
|
||||
### Per-handle audit (`--trace-handles-focus`)
|
||||
|
||||
`signal_attempts` (primary + ghost) for each wedge at halt:
|
||||
|
||||
| Handle | Kind | Waiters | signal_attempts | Verdict |
|
||||
|--------|--------------|---------|-----------------|---------|
|
||||
| 0x1020 | Event/Manual | 1 (tid=3) | 0 | γ-wedge |
|
||||
| 0x1040 | Event/Auto | 0 (32 waits historic) | 0 | γ-wedge |
|
||||
| 0x10a8 | Event/Auto | 0 (7 waits historic) | 0 | γ-wedge |
|
||||
| 0x10e4 | Event/Manual | 1 (tid=8) | 0 | γ-wedge |
|
||||
| 0x12a4 | Thread | 1 (tid=1, main) | 0 | downstream of 0x12ac |
|
||||
| **0x12ac** | **Event/Auto** | **1 (tid=13)** | **0** | **keystone γ-wedge** |
|
||||
| 0x12b8 | Event/Auto | 1 (tid=5) | 0 | worker-cluster γ-wedge |
|
||||
| 0x1028 | Semaphore | 1 (tid=4) | 7 (works) | sema not the bug |
|
||||
|
||||
## Phase 2 — create-site triangulation (focus dump + lr-trace)
|
||||
|
||||
### Handle 0x12AC (tid=13 keystone wedge)
|
||||
|
||||
- **Create-call-site PC**: `0x821cb158` = `sub_821CB030+0x128` (bl NtCreateEvent wrapper `sub_824A9F18`).
|
||||
- **Wait-call-site PC**: `0x821cb1dc` = `sub_821CB030+0x1AC` (bl `sub_824AC540` INFINITE wait).
|
||||
- **Created on stack frame**: r3=0x715a7a60 (stack-local OUT handle slot, tid=13's stack).
|
||||
- **Creator full chain** (frames 1..5 from per-handle `created stack`):
|
||||
```
|
||||
sub_821CB030+0x12c (this fn creates AND waits)
|
||||
sub_821CBA08+0xd8
|
||||
sub_821CC3F8+0x5c (GamePart_Title)
|
||||
sub_821C4EB0+0x68 (UImpl@GamePart_Title@silph) <- vtable class .?AUImpl@GamePart_Title@silph@@
|
||||
sub_821749C0+0xc0
|
||||
```
|
||||
- Class identification (from wait-thread frame-3/4 saved-r29 vtable probes):
|
||||
- frame 3 r29 vtable 0x820a3dc8 = `.?AVGamePart_Title@silph@@`
|
||||
- frame 4 r29 vtable 0x820a3e00 = `.?AUImpl@GamePart_Title@silph@@`
|
||||
|
||||
### Handle 0x12B8 (tid=5 worker-cluster wedge)
|
||||
|
||||
- **Create-call-site PC**: inside `sub_82458068+0x8C` (bl NtCreateEvent wrapper).
|
||||
- **Wait-call-site PC**: inside `sub_82458B08+0x2C` (bl wait wrapper).
|
||||
- **Creator full chain**:
|
||||
```
|
||||
sub_82458068+0x8c
|
||||
sub_82458960+0x94
|
||||
sub_82451238+0x1c8
|
||||
sub_82450B68+0x1a0
|
||||
sub_82450A68+0xcc
|
||||
```
|
||||
- Lives entirely in worker cluster 0x82450000-0x8245C000.
|
||||
|
||||
### Handle 0x12A4 (tid=1 main thread join)
|
||||
|
||||
- Created via `XCreateThread` (Thread kind), reference id 13.
|
||||
- Wait chain (from WAIT-THREAD):
|
||||
```
|
||||
sub_82173990+0x2d4 (program top — AUDIT-033 gateway)
|
||||
sub_822F1AA8+0xa8
|
||||
sub_8216EA68+0x3ac
|
||||
entry_point+0x198
|
||||
```
|
||||
- Wait-frame-3 r29 vtable 0x820a183c = `.?AVSilph@silph@@`.
|
||||
- Resolves the AUDIT-049 finding that handle `0x1280` was the thread handle. Downstream of 0x12AC — wake tid=13 and main thread wakes.
|
||||
|
||||
## Phase 3 — candidate-signaler fire counts (lr-trace)
|
||||
|
||||
| Producer | Fires | Distinct LRs | AUDIT-050 reachability | Comment |
|
||||
|----------|-------|--------------|------------------------|---------|
|
||||
| sub_82452DC0 | **8** | 0x82448120 (4), 0x82460cc8 (2), 0x821790b8 (1), **0x821cb1d0 (1)** | Only reachable NtSetEvent caller in 0x82450000-0x8245C000 (AUDIT-050) | Tid=13 itself calls it 1× from sub_821CB030+0x19C right before waiting on 0x12AC. Submits work, never gets reply. |
|
||||
| sub_82458B90 | 1 | 0x82457f18 (sub_82457EF0+0x24) | direct NtSetEvent caller | fires once but not on 0x12AC |
|
||||
| sub_82453910 | 0 | — | direct NtSetEvent caller; 5 static callers (sub_821A5150, sub_821C8388, sub_821CBA08+0x1E8, sub_82173990+0x208, sub_821C4AE0+0xE8) | **inert** — sub_821CBA08+0x1E8 is in the 0x12AC chain |
|
||||
| sub_82458A70 | 0 | — | called from sub_82450B68+0x310 AND sub_82450550+0x44 | **inert** — sub_82450B68 is in 0x12B8's create-chain |
|
||||
| sub_824566D0 | 0 | — | direct | inert |
|
||||
| sub_824500E8 | 0 | — | direct (0 static callers — dead?) | inert |
|
||||
|
||||
### Static-graph triangulation for 0x12AC signaler
|
||||
|
||||
- **`sub_82452DC0`** has 34 static callers including 2 sites inside `sub_821CB030` (+0x19C and +0x2BC). Tid=13 already drives the +0x19C site once. The signal that should wake tid=13 must originate from a worker thread inside one of sub_82452DC0's `bl` descendants (the work-submitter's queue is supposed to land work on a worker thread that ultimately calls NtSetEvent on the same KEVENT registered at `[guest-context-base + N]`).
|
||||
- **`sub_82453910`** is statically reachable from `sub_821CBA08+0x1E8` (0x12AC creator-chain frame). 0 fires in ours despite the chain being executed (sub_821CBA08 fires at least once on tid=13's path through 0x12AC creation). Worth tracing why `sub_821CBA08+0x1E8` site doesn't reach.
|
||||
|
||||
## Top wedges + signaler shortlist for AUDIT-060
|
||||
|
||||
- **Keystone γ-wedge**: handle **0x12AC** (Event/Auto), created at `sub_821CB030+0x128` and waited at `sub_821CB030+0x1AC`. Class context `silph::GamePart_Title::UImpl`. signal_attempts=0. Waking it unblocks tid=13 → tid=1 (0x12A4 Thread) → main thread.
|
||||
- **Secondary γ-wedge (independent)**: handle **0x12B8** (Event/Auto), created at `sub_82458068+0x8C`, waited at `sub_82458B08+0x2C`, entirely within worker cluster on tid=5.
|
||||
|
||||
### Best-candidate NtSetEvent producers (shortlist of 5)
|
||||
|
||||
1. **`sub_82452DC0`** (PC 0x82452DC0) — the master work-submitter, 8 fires in ours vs ~50-60 canary (AUDIT-056). Sole statically-reachable NtSetEvent caller per AUDIT-050. The expected signaler chain is *inside* its callee tree, fired from a worker thread that consumes the queued job. **Investigate why our 8 fires don't produce a wake on 0x12AC.**
|
||||
2. **`sub_82453910`** (NtSetEvent caller) — reachable from `sub_821CBA08+0x1E8` (same chain as 0x12AC creator). 0 fires in ours. Possibly the *direct* signaler for 0x12AC if the chain executes far enough.
|
||||
3. **`sub_82458A70`** (NtSetEvent caller) — reachable from `sub_82450B68+0x310` (same chain as 0x12B8 creator). 0 fires. Likely the *direct* signaler for 0x12B8.
|
||||
4. **`sub_82458B90`** (NtSetEvent caller) — 1 fire from `sub_82457EF0+0x24` in our run. Not on tracked handles; possibly auxiliary.
|
||||
5. **`sub_824566D0`** (NtSetEvent caller) — 0 fires; called from sub_82456AD0/sub_82456670/sub_82456AA4. Auxiliary.
|
||||
|
||||
### Cross-handle BFS observation
|
||||
|
||||
The 0x12AC keystone wedge and the 0x12B8 worker-cluster wedge live in *different islands* (GamePart_Title vs raw worker cluster). The fact that **the four NtSetEvent producers most-statically-linked to the wedge create-chains all fire 0×** in our run (only `sub_82452DC0` and `sub_82458B90` fire, neither on the wedge handles) confirms AUDIT-050's framing: **the cluster is half-bootstrapped — work-submitter live, downstream worker callbacks dead**.
|
||||
|
||||
## Surprises / notes
|
||||
|
||||
- Phase 1 with `--quiet` produced 0-byte output. `--quiet` suppresses the deadlock-halt diagnostic dump too — drop it for any future deadlock investigation runs. (Re-ran without `--quiet`; 466 lines.)
|
||||
- `--lr-trace=0x824a9f6c` (mid-function PC) recorded `lr=0x824a9f6c` self-reference instead of caller LR — would have been useless for caller triangulation. The `created stack (6 frames)` dump in `--trace-handles-focus` is the better data source.
|
||||
- Handle namespace per-run drift confirmed: AUDIT-049 saw 0x1280/0x1288, this probe sees 0x12A4/0x12AC. AUDIT-058 saw 0x12A4. The keystone-wedge *function context* (sub_821CB030 / sub_821C4EB0 / `silph::GamePart_Title::UImpl`) is stable across all three audits.
|
||||
- AUDIT-049/050/058's claim that the cluster is half-bootstrapped is reinforced by Phase 3 fire counts: the work-submitter fires, but **none of its downstream NtSetEvent producers fire**. This is exactly the symptom expected if the work-submitter enqueues but the worker-side dequeue/process loop never runs (or runs on the wrong queue).
|
||||
|
||||
## Artifacts
|
||||
|
||||
```
|
||||
xenia-rs/audit-runs/audit-059-gamma-wedge/
|
||||
ours-phase1-500m.stdout / .stderr (500M-instr halt-on-deadlock dump)
|
||||
ours-phase1.stdout / .stderr (100M repro, identical wedges)
|
||||
ours-phase2.stdout / .stderr (focus + create stacks; lr-create.jsonl)
|
||||
ours-phase2b.stdout / .stderr (NtCreateEvent ENTRY lr-trace; lr-create-entry.jsonl)
|
||||
ours-phase3.stdout / .stderr (signaler-fires.jsonl: 8+1+0+0+0+0)
|
||||
ours-summary.md (this file)
|
||||
```
|
||||
|
||||
Recommended AUDIT-060: trace `sub_82452DC0`'s callee tree on tid=13 (the +0x19C fire) and walk the work-queue consumer in the worker cluster; identify which worker thread is supposed to dequeue and signal 0x12AC, and why none do. Cross-reference with AUDIT-056's canary 5.6× throughput gap.
|
||||
Reference in New Issue
Block a user