aboutsummaryrefslogtreecommitdiffstats
path: root/fw/decomp/auc.summary.json (follow)
Commit message (Collapse)AuthorAge
* name all five GP entry-point slots from the image header: TMZ reaches 100%user2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | ta_entry_points read the trampoline's +0xA0 (Create) and +0xB0 (Invoke) slots and threw away the three between them. Those are TA_DestroyEntryPoint, TA_OpenSessionEntryPoint and TA_CloseSessionEntryPoint. That is the whole reason TMZ sat at 50% named: it has six functions and three of the unnamed ones were entry stubs the header identifies exactly. The slot order is read off GCP rather than assumed from the GP spec. GCP has all five named independently and its table reads Create, nullsub(destroy), OpenSession, CloseSession, Invoke, with WSPE and HDCP agreeing and the types agreeing too -- slots 0, 2, 4 return a status, slots 1 and 3 are void. Running the new derivation against GCP reproduces GCP's own names exactly, which is the check that makes this evidence rather than convention. Applied to every module, only where porting left the address unnamed. Per-module: tmz 50 -> 100, rap 76 -> 98, csu 70 -> 92, oc 90 -> 97, dtm 75 -> 89. Corpus 19,038 -> 19,126 meaningful names (65.8% -> 66.1%), field share 75.5% -> 75.8%. RAS disagrees and is deliberately left alone. Its libdump names TA_CreateEntryPoint and TA_DestroyEntryPoint at addresses the header assigns to OpenSession and CloseSession, a systematic two-slot shift across all 18 builds. My first run wrote the header names anyway, which left RAS asserting two different Create entry points -- a contradiction I introduced and then caught by checking for duplicated roles. A guard now refuses to add a second holder of a role, so the conflict is reported on every build and nothing is written. No build has a duplicated entry-point role. Which source is right for RAS stays open: the obvious tiebreaker, argument count, is not decisive on functions IDA never prototyped.
* find the real cause of the 138-name regression: an inconsistent seed, not a ↵user2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | rename bug Two passes were spent guessing at this and both guesses were wrong -- a defect in the rename path, then a collision with an existing symbol. Tracing `assigned` through the fix block and the emit for the build that actually failed settled it in one run. The seed reference list is built from fw/libdumps, which still carried the PLACEHOLDER names, while the processed reference build contributed the SEMANTIC names for the same body hash. build_index then saw one hash mapping to two distinct names, marked those bodies ambiguous and refused to name them in any build. The tell was in the per-build line all along: ambiguity in 22.0.0.53 read amb=36 against amb=8 at HEAD, and I had been reading the named count without looking at the column next to it. Applying LIB_RENAME to the seed names as well makes the pool consistent. 22.0.0.53 returns to amb=8 and 96 named, and the six held-back names can now be applied: isdigit, vsnprintf_getc, vsnprintf_emit_char, vsnprintf_emit_char_bounded, vsnprintf_narrow_signed and vsnprintf_narrow_unsigned. Net across the corpus, both metrics move the right way at once, which is what the earlier attempts could not achieve: named 19,304 -> 19,352 (66.7% -> 66.9%), placeholder names 397 -> 235, field share 67.4% -> 67.5%. GCP alone gains 20 names and drops from 143 placeholders to 77. The temporary tracing is removed and LIB_RENAME_PENDING is gone, replaced by a note recording that the cause was an inconsistent seed and that it was found by instrumenting rather than reasoning.
* key the shared-runtime typing on body hash, which removes the rename ↵user2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | trade-off entirely Last pass rejected the placeholder-name upgrade because it cost about 1175 typed field accesses: the shared-runtime typing matched NAME fragments, so renaming lib_e53fbaaa_32 to vsnprintf_setup moved the function out from under the rule that typed its argument. The fix identified there is implemented here. TEE_FMT_HASHES holds the 71 body hashes of that cluster, derived from every function the fragment rule used to match across all 99 builds so the switch cannot narrow coverage. Content identity is what established the cluster in the first place, and it is immune to any renaming. With that in place the trade disappears and both metrics improve together, which is the point: gcp share 82.5% -> 83.6% placeholders 389 -> 143 wspe share 91.3% -> 92.6% placeholders 252 -> 133 powerplay share 65.3% -> 70.7% placeholders 186 -> 60 xgmi share 69.1% -> 71.0% placeholders 100 -> 55 LIB_RENAME is therefore enabled, with the measured before/after recorded at the gate rather than a bare "fixed". Also corrected from last pass: I reported that the rename "does not work" and ruled out ordering, mapping contents and key matching. The mechanism was fine. Standalone it returned True on the very functions I claimed it failed on, and the actual cause of the zero-diff was my own shell -- "| grep -m1" closed the pipe, SIGPIPE killed the run before it wrote, and I read that as the code having no effect. Two passes were spent on a bug that was in my measurement, not the pipeline.
* correct an overclaim: the artifacts are not byte-reproducible, and persist ↵user2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DISPATCH names An earlier pass reported that all 99 artifacts regenerate byte-identically. That was true of that one run and does not hold in general. A full clean regeneration of all sixteen modules changes 220 files, and the cause is IDA's auto-analysis not being identical across fresh databases: AUC's function count comes back 39 instead of 40, and decompiled text varies cosmetically ("(int)nullsub_3" against "nullsub_3"). The claim is corrected here rather than left standing. Semantically the drift is small -- 4 names of 19,353 -- but all four were tier DISPATCH, which exposed a wrong decision. fw/ta_snapshot_names.py excluded DISPATCH on the grounds that fw/ta_re.py re-derives it every run. It does, but not deterministically: dispatcher recovery depends on which function Hex-Rays decompiles cleanly on a given analysis, so xgmi_cmd00, xgmi_cmd04, xgmi_cmd0B and fp_cmd04 simply did not come back. DISPATCH is now persisted, and the exclusion reasoning in that file is rewritten to say why. Persisting it still cannot mask a regression: the dispatcher step runs regardless, so where recovery works the DISPATCH tier wins and where it fails the restored name appears as tier IDA. The tier difference is itself the signal that recovery failed on that build. 7817 names were recovered from the committed artifacts into fw/cgnames so nothing derived is left depending on a database that may not reproduce. XGMI came back whole. The one name that did NOT come back turned out to be a defect being fixed rather than lost. HEAD had TWO functions called fp_cmd04 -- 0x401334 from the dispatcher and 0x402b4c from byte porting -- and the current dispatcher map routes command 4 to 0x402b4c, agreeing with the ported name. So HEAD carried a duplicate, this run does not, and the allow_overwrite=False guard on the re-apply is what refused to restore the bad one. Worth keeping: a name count going DOWN was the correct outcome, and reading it as a regression would have reintroduced the duplicate. Verified state after the clean regeneration: 16/16 gates PASS, 99 builds, 19,349 of 28,945 named (66.8%), field share 66.4%, 21 decompile failures.
* fix phantom commands in the dispatcher map, found by auditing names against ituser2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Rather than chase another percentage, this pass audited whether the names already applied are CORRECT, using the only authority available: the dispatcher. For every build, each handler whose name claims a command id was checked against the command the dispatcher actually routes to it. 257 handlers checked, 246 agreed, and 11 conflicted -- all in GCP, all of the form gcp_cmdFE0A_QueryAccessibilityAttributes__hN being routed from commands 0x8, 0x9, 0xA and 0xF. Those are not GCP commands at all. They are arms of 0xFE0A's own sub-command switch, absorbed as top-level commands because dispatch_map merged EVERY switch-bearing callee at the shallowest depth. The handler names were right; my command map was wrong, which is the opposite of what the conflict report implied. The merge is replaced by taking only the richest switch at the shallowest depth. The union was introduced to allow a TA that splits low ids and 0xFExx ids across sibling switches, but GCP serves both from one function, so nothing is lost: the reference still recovers 14 commands, all 14 still match fw/cmdmaps/gcp_ea.json address for address, and the phantom 0x8/0x9/0xA/0xF are gone. The three still missing (0x3, 0xFE08, 0xFE0E) remain the inlined arms with no callee, as before. Re-running the audit afterwards: 332 handlers checked, 332 agree, zero conflicts. The FE07 case that had been reported since the cross-check was built is also clear, because the pipeline now relabels that handler from gcp_cmdFE03_* to gcp_cmdFE07_* rather than leaving the inherited misnomer in place. Two more corrupted databases were found and rebuilt (hdcp_23.0.8.49, merit_24.0.4.42), with the same "worker exited with status 1" symptom as the gcp one last pass. Rebuilding loses the call-graph names on those builds, so ta_cgname was re-run for both; naming lands at 66.5% rather than 66.9% because of that churn. Also measured and rejected this pass, so they are not retried: cross-module naming by exact body hash yields 77 names, and by mnemonic sequence 170 (against 1496 that match an ambiguous cluster and cannot be resolved). Together under 2% of what remains unnamed, which is not worth the regeneration cost.
* type the host request for the remaining components: every module now has oneuser2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Seven more request structures derived the same way as the earlier four, which takes the count from 8 to 15 of 16. The sixteenth is TMZ, and it needs nothing: its invoke entry is literally 'return 0', which confirms from the entry itself the "TMZ is a stub" note in AUDIT-NEW-TAS.md. Four of the seven close against a size the firmware itself enforces, which is the standard the earlier xgmi/oc/wspe/hdcp structures set: csu floor 0x24 cmd at +0, ack at +4, status at +8, body to 0x24 dtm floor 0x50 args at +0x10, 0x10 + 0x40 = 0x50 exactly merit floor 0x2024 handlers receive the whole buffer opm floor 0x3D54 independently reproduces the "params_size >= 0x3D54" already recorded in AUDIT-NEW-TAS-RE.md, from the entry rather than from that note Three do not enforce a size and say so in their declarations, as asd_req and powerplay_req already do: auc (ctx bounded exactly at +0x10..+0x298, params extent only observed), fp (the _DWORD * interior pointers scale, so v4 + 3 is +0x0C and v4 + 68 is +0x110), and rap -- which is nonetheless the best bounded of the three because its entry zero-fills exactly 24 bytes at +0x18 and then stores at +0x30, closing the layout at 0x34 without guesswork. RAP also REFINES the negative recorded against powerplay_req. That commit said POWERPLAY is the only entry writing a 'command | 0x80000000' ack word; the test looked for it at +4. RAP writes the same ack at +0x08 and CSU at +0x04. So the ack convention is NOT unique to POWERPLAY -- it simply sits at a component-specific offset, which remains a reason not to hoist one shared header, but not the reason first given. Two more cases of the inherited-prototype defect, both recorded rather than silently applied: CSU's handlers are called as csu_cmdNN(ctx: *a4, params: v5) where v5 is a4[1], the declared SIZE and an integer, so the 'struct ta_params *' prototype from fw/pseudo misdescribes it -- the same defect already noted for OC. Metric correction worth stating: the field-access measure now also counts struct-by-value accesses, because XGMI applies its struct to a stack buffer and reads v12.cmd_id rather than v12->cmd_id, which the arrow-only count had been scoring as zero. On the comparable named-only basis: typed field accesses 0 at session start -> 3742, against 8254 raw pointer-arithmetic dereferences, a 31.2% field share. Struct-typed signatures 309/10070 (3.1%) -> 487/10088 (4.8%). Only MERIT and the TMZ stub still show no typed field accesses, MERIT because IDA keeps an explicit cast at its one dispatch read even though the pointer is typed.
* anchor prototypes to command ids, and derive the OC and WSPE request structuresuser2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Matching prototypes to functions by NAME reached only 8 of GCP's 24, and the reason turned out to be a correctness problem rather than a matching one: this tree carries two naming generations that disagree about which command a handler serves. fw/pseudo calls the handler at 0x402f90 gcp_cmdFE0C_CreateCryptoSession; fw/libdumps calls the same function gcp_cmdFE0C_CreateAuthenticatedSession. The hardware findings settle it -- FINDING-GCP-ACQUIRE-GATE-BYPASS records 0xFE0C as CreateCryptoSession and FINDING-GCP-FE0D-REFCOUNT-DESYNC agrees -- so the libdump name is wrong and had propagated into every artifact generated so far. Keying on the command id and resolving the address through the dispatcher avoids the disagreement entirely, because the dispatcher is the only authority on which function serves which command. GCP goes from 5-9 applied prototypes per build to 14-17 and from 28 struct-typed signatures to 172, and the handler at 0x402e94 is relabelled from gcp_cmdFE03_* to gcp_cmdFE07_* on every build -- the single conflict the cross-check had been reporting since it was built. Two more request structures are derived and verified the same way as xgmi_req. OC and WSPE both dispatch with if/else chains rather than a switch, so the switch-based dispatcher recovery finds nothing for them and their invoke entry has to be used directly; both work on the host buffer in place rather than staging a copy, so their offsets are host offsets by construction. oc_req closes at 0x1C (handler blocks at +0x0C and +0x16, the latter running 6 bytes to the end of the validated size) and wspe_req at 0x14 (handler block at +0x10). Both sizes are the ones the dispatchers' own size floors enforce. Applied, OC's entry reads 'v5->cmd_id == 2' and the type propagates outward to 'struct oc_req **a4'. Recorded against this work rather than hidden: applying a pseudo-file prototype by name can introduce a WRONG signature. OC's dispatcher calls oc_cmd01(ctx: v5 + 3, params: (struct ta_params *)7) -- the second argument is the literal 7, so the inherited 'struct ta_params *' misdescribes it, and the cast in the output is the tell. Prototypes should be checked against what their call sites actually pass before being applied. Measured from the artifacts rather than from effort: struct-typed signatures 309/10070 (3.1%) -> 456/10070 (4.5%), modules with a derived request struct 0 -> 3, modules with zero struct-typed signatures 6 -> 4. The rate stays low for a structural reason worth stating plainly: ASD is 6763 of the 10070 functions and has no recorded type information at all, so work on the small components cannot move the global figure. ASD is where the remaining value is.
* apply the prototypes, types and comments the pass had been droppinguser2026-10-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The decompiled artifacts were missing almost all type information. Three things were available in the tree and only one was being used: * declare_type was never called, so no type definitions were parsed at all; * set_type ran only for the four handover types, because fw/libdumps records just {ea,hash,name,size} and the twelve Windows TA types therefore had no signatures to port; * the recorded comments were read into a variable and discarded without ever being applied. All three are now applied, in dependency order, and counted per build so the result is measurable instead of something you have to notice by reading the output. Across 99 builds: 7727 prototypes (was 1232, all of them ASD), 6068 comments (was zero), 309 struct-typed signatures (was zero). The reason prototypes were failing was NOT the missing types, which is what I assumed when I reported "202 of 1434 rejected" without diagnosing it. Declaring the types first changed the rejection count by nothing. 205 of the 239 failures were prototypes recorded in the bare shape 'int()', with no __fastcall for the name-insertion to latch onto, so they were emitted as the unparsable 'int();'. The name now goes before the first parenthesis whatever the shape, and prototypes land 100%: 1434/1434 on the ASD reference, 99/99 HDCP, 9/9 DTM. Worth recording so nobody repeats the detour: the 43 'local_types' in each handover symbol set are ARM NEON and SVE vector typedefs plus va_list and BOOL -- compiler boilerplate with no domain structs in it. Declaring them is harmless and buys nothing. The only real PSP structs in this tree are the seven hand-written ones in fw/ta_ida.py (gcp_ctx, ta_params, gcp_drm_session, gcp_auth_session, gcp_crypto_session, merit_slot, merit_table), which were sitting unused and are now applied: GCP command handlers finally read as '(struct gcp_ctx *ctx, struct ta_params *params)' rather than '(int, int)'. So the remaining type gap is a data gap, not a pipeline one. Thirteen of the sixteen components have no struct definitions anywhere in the repo to apply, and ASD's 6800 prototypes are almost entirely primitive-typed, which is why it shows only 30 struct-typed signatures against 1439 named functions. Closing that needs structs to be defined by hand, component by component.
* name TA command handlers from the dispatcher, and extend the run to all ↵user2026-10-01
twelve types Byte and mnemonic similarity cannot name a handler whose code diverged, and that failure landed exactly where it hurts: gcp_cmdFE0C, the function carrying the acquire-gate refcount bypass, was unnamed on six of eleven GCP builds. The dispatch table does not care about similarity -- whatever sits in the 0xFE0C arm is the 0xFE0C handler by construction. So the handler names now come from the image itself: the header's trampoline gives TA_InvokeCommandEntryPoint, Hex-Rays recovers the switch, and each case arm is attributed to the function it calls. Parsing the decompiler's switch output beats hand-rolling Thumb jump-table decoding, and callee tokens resolve through the live function list rather than by assuming they look like sub_<addr>, so it works whether or not names were applied first. Validated against the one authoritative map that already existed: all 14 commands this recovers for GCP 22.0.4.50 match fw/cmdmaps/gcp_ea.json address for address, with none spurious. The three it misses (0x3, 0xFE08, 0xFE0E) are precisely the arms with no callee -- inlined into the dispatcher, and recorded in the old map as loc_ labels that were never function starts. FE0C is now named on all eleven builds. Two bugs the first attempt had, both caught by its own conflict reporting. Walking three levels deep from the invoke entry swept up nested sub-command switches inside individual handlers and invented a GCP command 0x0F that does not exist; the walk is now limited to the invoke entry and its direct callees, with a depth-2 fallback only when depth 1 finds no switch at all. And one handler commonly serves several commands -- GCP routes 0xFE03-0xFE07 to one function -- so commands are grouped by handler address before naming or judging agreement. The self-port gate was measuring the wrong quantity. Dividing EXACT matches by every recorded symbol conflated a broken matcher with IDA simply not defining a function at a recorded address, and failed five sound types on that basis -- TMZ scored 17%. The denominator is now the reference symbols that are function starts in the reference build; all twelve types then gate at 100%. That fix made the gate blind to a different error, so it gained a second check. MERIT ships two distinct 24.0.4.42 builds, the reference was being chosen by version alone, and the libdump had been recorded from 444eceee while bc1706f8 was loaded: 24 of 31 symbols landed on nothing and every MERIT build sat near 30% named. The reference is now pinned by hash from fw/syms/<ta>.meta.json, and an orphan-symbol rate above 10% is reported as a suspected build/symbol mismatch. MERIT went to 58-83% named. 62 builds across twelve types, zero decompile failures. The remaining conflicts are real and worth reading rather than suppressing: GCP's 0xFE07 handler carries the inherited name gcp_cmdFE03_CreateAuthenticatedSession, because the older name-keyed cmdmap collapsed 0xFE03-0xFE07 onto one label while the dispatcher shows only 0xFE07 reaching that function.