diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 93c4f97..0299518 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -336,6 +336,34 @@ unknown, what evidence exists, and what the first step would be. Move an item in unread, as is what B reaching zero does, and whether all 170 `timer_stop` sites are phase teardown. +* 🔎🔴 **(2026-08-27) THE TIMER MESSAGE'S CONSUMER: LOCATED, NOT READ — and the + argument I was about to make is REFUTED BY ITS OWN CONTROL. + [structures/isl-mission-timer](structures/isl-mission-timer.md).** + The tempting move was "`0xAB03E5BA` is built at exactly one site, so nothing + consumes the timer message". **The control kills it: 25 of the 40 distinct + `0xAB03xxxx` tags in the image are built exactly once (62.5 %)** — single-site + construction is the *majority*, not an anomaly. And the tag appears **nowhere + in the image as a 4-byte word** — in fact **no 4-aligned word anywhere begins + `0xAB03`** — so there is no static table of subscribed tags to find either. + ✅ **Two structural reads that do stand.** (1) The post is a **queue push, not a + dispatch**: `sub_82175C20(bus+4, &msg)` is a ring-buffer append (capacity `+8`, + head `+12`, count `+16`, array `+4`, grown via `sub_8228E208`) and never looks + at the message. (2) The message class has a **one-method vtable**: + `0x820A8D18`–`0x820A8DA0` is a run of 2-word records + `{ sub_82301C20, 0x8210Exxx }`; the timer message's vptr `0x820A8D68` gives + `vtable[0] = sub_82301C20` (a scalar deleting destructor — stores `0x820A7014` + over the vptr, conditionally frees) and `vtable[-1] = 0x8210E288`, an **MSVC + RTTI locator** (`0,0,0, &typeDesc 0x8289D094, &classHierarchy 0x8210E29C`, + `numBaseClasses = 3`) — data, not code, and below `sylpheed.db`'s `0x82150000` + floor. **So the message carries no handler of its own**, and dispatch is neither + a literal compare nor virtual on the message. + 🟡 **Located:** the bus at `[0x828F35DC]` carries a **map at `+8216`**, looked + up through `sub_82254A08` from **`sub_823001E8`**, whose only caller is + `sub_8230C398` — the per-frame message pump, called from the frame loop + (`0x821A6544`) with the frame `dt`. So the question reduces to **what inserts + into `bus+8216` and with which key**. That path is unread, so **the item is NOT + settled**: whether running out of time ends the mission is still unknown. + ## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26) `XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the diff --git a/docs/re/structures/isl-mission-timer.md b/docs/re/structures/isl-mission-timer.md index fc63500..fa72a9a 100644 --- a/docs/re/structures/isl-mission-timer.md +++ b/docs/re/structures/isl-mission-timer.md @@ -110,13 +110,52 @@ the same coroutine one instruction apart, which is why they read almost the same value and the conflation was invisible. **The 1200-second limit belongs to the mission timer; it is not stopwatch 0's limit.** +## 🔴 The message bus: what the "one occurrence" of the tag is worth — nothing + +The obvious next move was to search for a second site building `0xAB03E5BA` and +conclude from its absence that nothing consumes the timer message. **That +reasoning is dead**, and the control kills it: + +| | | +|---|---| +| instructions building `0xAB03E5BA` (`addis 0xAB03` + `ori 0xE5BA`) | 1 — the producer | +| `0xAB03E5BA` as a 4-byte word **anywhere** in the image | **0** | +| *any* 4-aligned word beginning `0xAB03` anywhere in the image | **0** | +| distinct `0xAB03xxxx` tags built by an `addis`/`ori` pair | 40 | +| **of those, built exactly once** | **25 (62.5 %)** | + +Single-site construction is the **majority** case, so it says nothing about this +tag in particular. And because no tag is ever stored as a static word, there is +no table of subscribed tags to find either. + +### ✅ Two structural reasons it cannot be a compare or a virtual call + +* **The post is a QUEUE PUSH, not a dispatch.** `sub_82175C20(bus+4, &msg)` is a + ring-buffer append — capacity at `+8`, head at `+12`, count at `+16`, element + array at `+4`, growing through `sub_8228E208`. It never looks at the message. +* **The message class has a ONE-METHOD vtable.** `0x820A8D18`–`0x820A8DA0` is a + run of 2-word records `{ sub_82301C20, 0x8210Exxx }`. The timer message's vptr + is `0x820A8D68`, so `vtable[0] = sub_82301C20` — a scalar deleting destructor + (it stores `0x820A7014` over the vptr and conditionally frees) — and + `vtable[-1] = 0x8210E288`, an MSVC RTTI locator (`0,0,0, &typeDescriptor + 0x8289D094, &classHierarchy 0x8210E29C`, `numBaseClasses = 3`). Not code: that + address is data, and the disassembly does not even reach it (`sylpheed.db` + starts at `0x82150000`). **The message carries no handler of its own.** + +### 🟡 Where the subscriber actually lives — located, not read + +The bus object at `[0x828F35DC]` carries a **map at `+8216`**, looked up through +`sub_82254A08` from **`sub_823001E8`** — whose only caller is `sub_8230C398`, the +per-frame message pump (itself called from the frame loop `sub_821A6544` with the +frame `dt`). So dispatch is a **runtime registry keyed by the tag**, and the +question "does running out of time end the mission" reduces to: *what inserts into +`bus+8216`, and with which key.* That insert path is not read here. + ## 🟡 Not settled -* **Who subscribes to `0xAB03E5BA`.** The literal appears at exactly one site — - the producer — but `0xAB03` is the high half of *many* message tags in this - image and dispatch is not by literal compare, so a single occurrence is **not** - evidence that nothing consumes it. Whether running out of time ends the mission - is therefore unread. +* **Who subscribes to `0xAB03E5BA`** — see above. Located to the registry at + `bus+8216`; the registration path is unread, so whether running out of time + ends the mission is still unknown. * What B counting to zero does. Nothing observed acts on it. * Whether `timer_stop`'s 170 sites are all phase teardown, or some are a real mid-mission stop.