re: the base-solver's confidence axis was inverted
The remaining named false-positive mode - "107 rows solve to a 64K-boundary
base, a bare addis with no addi of its own, so any scatter of displacements
votes for it" - is refuted by its own measurement.
New positive test in the tool: simulate lis/addis rD,r0,HI + addi rD,rA,N +
or rD,rA,rA forward through each row's function and ask whether the solved
base lands in the solved register.
64K-boundary bases ("low confidence") : 107 / 107 confirmed
non-zero low half ("trustworthy") : 8 / 154 confirmed
A round base is the case where the compiler needed no second instruction, so
`addis r11, r0, 0x820B` stands in the code in full. A miss on the other class
is silence (base built in the caller or loaded from memory), not refutation.
Control: every row the corpus independently validated against the disc has a
64K-boundary base - debriefing, career, save, leaderboard, the 205-name PG*
HUD roster, material slots, the S16 boss collision/frames/motions and its
loader. 13 rows over 10 functions. The dense-short-string false positives the
corpus did name (r31 = 0x8202xxxx) all sit in the "trustworthy" class.
The 0x820B0000 cluster is DUPLICATION, not error: 60 of its 82 rows are one
function emitted 60 times, exactly 491 instructions each, two instructions
differing (both global data pointers), identical 41-address string sequences.
40 resource names written into a per-copy global via sub_8217FA08 at 24-byte
strides. 38 of the 40 are disc GameResourceID values (480 distinct); rot_n001
and rou_e202 are not, and no disc GameResourceID uses the rot_ prefix.
Artefact diff 13/4, confined to the replaced section; the 261-row table and
the 64K histogram untouched; byte-identical on a second run. Fourteen other
artefacts byte-identical.
This commit is contained in:
@@ -90,20 +90,81 @@ def main():
|
||||
for name, reg, B, tot, n in rows:
|
||||
print(" %-18s %-5s 0x%08X %d / %d" % (name, reg, B, tot, n))
|
||||
|
||||
# Confidence. A base whose low half is 0x0000 is a bare `addis` with no
|
||||
# `addi` of its own -- any scatter of displacements votes for it, so those
|
||||
# rows are the tool's false-positive mode and must be read with the
|
||||
# resolution ratio, not on their own.
|
||||
# Does the function itself build the solved base into the solved register?
|
||||
# Simulate `lis/addis rD, r0, HI`, `addi rD, rA, N` and `or rD, rA, rA`
|
||||
# forward through the body; a hit is POSITIVE confirmation of the base.
|
||||
# (A miss is not a refutation: a callee-saved base is often materialised in
|
||||
# the caller or loaded from memory, which is why the solver exists at all.)
|
||||
want = collections.defaultdict(set)
|
||||
for name, reg, B, tot, n in rows:
|
||||
want[name].add((reg, B))
|
||||
sim = con.execute(
|
||||
"SELECT address,mnemonic,operands FROM instructions "
|
||||
"WHERE mnemonic IN ('addi','addis','lis','or') ORDER BY address").fetchall()
|
||||
body = collections.defaultdict(list)
|
||||
for a, m, o in sim:
|
||||
i = bisect.bisect_right(starts, a) - 1
|
||||
if i < 0 or funcs[i][1] <= a:
|
||||
continue
|
||||
if funcs[i][2] in want:
|
||||
body[funcs[i][2]].append((m, o))
|
||||
confirmed = set()
|
||||
for name, pairs in sorted(body.items()):
|
||||
targets = want[name]
|
||||
val = {}
|
||||
for m, o in pairs:
|
||||
q = [x.strip() for x in o.split(',')]
|
||||
if len(q) != 3:
|
||||
continue
|
||||
if m in ('addis', 'lis') and q[1] == 'r0':
|
||||
try:
|
||||
val[q[0]] = (int(q[2], 0) << 16) & 0xFFFFFFFF
|
||||
except ValueError:
|
||||
val.pop(q[0], None)
|
||||
elif m == 'addi':
|
||||
try:
|
||||
d = int(q[2], 0)
|
||||
except ValueError:
|
||||
val.pop(q[0], None)
|
||||
continue
|
||||
if q[1] == 'r0':
|
||||
val[q[0]] = d & 0xFFFFFFFF
|
||||
elif q[1] in val:
|
||||
val[q[0]] = (val[q[1]] + d) & 0xFFFFFFFF
|
||||
else:
|
||||
val.pop(q[0], None)
|
||||
elif m == 'or' and q[1] == q[2]:
|
||||
if q[1] in val:
|
||||
val[q[0]] = val[q[1]]
|
||||
else:
|
||||
val.pop(q[0], None)
|
||||
for reg, B in sorted(targets):
|
||||
if val.get(reg) == B:
|
||||
confirmed.add((name, reg, B))
|
||||
|
||||
round_rows = [r for r in rows if (r[2] & 0xFFFF) == 0]
|
||||
solved_rows = [r for r in rows if (r[2] & 0xFFFF) != 0]
|
||||
print("\n## Confidence split")
|
||||
print(" bases with a non-zero low half (a real `addis`+`addi` pair): %d" % len(solved_rows))
|
||||
print(" bases on a 64K boundary (LOW CONFIDENCE, see below) : %d" % len(round_rows))
|
||||
ok = lambda rs: sum(1 for r in rs if (r[0], r[1], r[2]) in confirmed)
|
||||
print("\n## Is the base built by the function itself? (positive test only)")
|
||||
print(" rows whose function materialises the solved base into the solved"
|
||||
" register: %d / %d" % (ok(rows), len(rows)))
|
||||
print(" bases on a 64K boundary : %d / %d"
|
||||
% (ok(round_rows), len(round_rows)))
|
||||
print(" bases with a non-zero low half : %d / %d"
|
||||
% (ok(solved_rows), len(solved_rows)))
|
||||
print(" A 64K-boundary base is `addis rX, r0, 0xHHHH` written out in full, so it"
|
||||
" confirms\n directly; it is NOT the low-confidence class it was first"
|
||||
" called. A non-zero low\n half usually means the base was built in the"
|
||||
" caller or loaded from memory, which\n the simulation cannot see -- a miss"
|
||||
" there is silence, not a refutation.")
|
||||
rb = collections.Counter(r[2] for r in round_rows)
|
||||
print("\n 64K-boundary bases by value:")
|
||||
for B, c in sorted(rb.items(), key=lambda kv: (-kv[1], kv[0])):
|
||||
print(" 0x%08X x%d rows" % (B, c))
|
||||
print(" ⚠ the 0x820B0000 cluster is ~60 near-identical functions in"
|
||||
" 0x8281xxxx-0x8284xxxx that all name the same `rou_e0NN` list.")
|
||||
print(" \u26a0 60 of the 0x820B0000 rows are one function emitted 60 times:"
|
||||
" exactly 491\n instructions each, an identical sequence of 41 string"
|
||||
" addresses, differing only\n in two global data pointers. That is"
|
||||
" DUPLICATION, not error.")
|
||||
|
||||
# Is a row a DATA-TABLE schema or engine/XDK vocabulary? The objective test
|
||||
# is whether its names are IDXD record/field names on the disc.
|
||||
|
||||
Reference in New Issue
Block a user