aboutsummaryrefslogtreecommitdiffstats
path: root/experiments/fibonacci.c
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-27 21:32:24 +0200
committerblasty <blasty@local>2026-07-27 21:32:24 +0200
commit713bed2864b755c4e83ab55c6e5726216cc812bf (patch)
treeadbbad78cc33c1becd3914cb287ba99bae5cd368 /experiments/fibonacci.c
parenttests: run the scenario suite on a scratch copy, not the tracked target (diff)
downloadida-tui-713bed2864b755c4e83ab55c6e5726216cc812bf.tar.gz
ida-tui-713bed2864b755c4e83ab55c6e5726216cc812bf.tar.xz
ida-tui-713bed2864b755c4e83ab55c6e5726216cc812bf.zip
trace: read Tenet execution traces (model layer)
First slice of the execution-trace viewer: parse, index and query a Tenet trace. No UI yet — this is the layer everything else stands on, and its shape decides whether decompiler painting is cheap later. A Tenet trace is a line-per-instruction delta log: registers that changed, the PC every line, and each memory access WITH its bytes. That's enough to reconstruct any register or address at any point in time, in either direction. Our own reader, not a port. The reference (tenet-original) packs traces into segments with compressed address/mask tables, which earns its keep for its Qt timeline; we need different queries and would rather own ~400 lines than inherit 3700. Indexed around the query the UI actually asks, which the reference answers one address at a time: WHICH TIMESTAMPS EXECUTED THIS SET OF ADDRESSES. A listing row is one address, but a pseudocode line covers many (we already have decomp_map for that), so by_ip maps address -> timestamps and hits() takes a set. Painting a pseudocode line will be one call, not one per instruction. Registers are stored as per-register change points, so a value at time t is a bisect, and "which instruction set this register?" (last_write) is the same lookup — that being the question a trace explorer exists to answer. Rebasing is not optional: our echo trace runs at 0x7ffff6faa000 while the database has that code at 0x2490. Page offsets survive relocation, so the low 12 bits of an instruction address are invariant; bucket the database's addresses by those bits and take the slide the most trace addresses agree on. Verified against a real IDB: slide -0x7ffff6fa8000, and it picks out the 12 functions the trace actually entered (main, start, ...) from 128. Performance: 176k instructions parse in 350ms (~500k lines/s), so a 10M-line trace is ~20s and wants a progress callback, which load() takes. FOUND A BUG IN THE REFERENCE while building the differential test. A register written on the LAST line of a 65535-line segment is missing from the next segment's base state, so Tenet returns a stale value until that register is written again — measured: wrong for all 179 timestamps of one such window. It survives in the reference because it only shows when the register isn't rewritten immediately. That changed how the test works. Rather than "must agree with the reference", it ARBITRATES with the raw text when they differ: if the text backs us it's reported and allowed, if the text backs them it fails. Blanket agreement would have made us copy their bug to stay green. tests: test_trace.py (27, pure stdlib) covers reconstruction, the set queries, rebasing (including that a lone agreeing address is not enough, and that matching is on page offsets rather than addresses looking plausible) and malformed input; test_trace_vs_tenet.py (10) diffs against the reference on real traces.
Diffstat (limited to 'experiments/fibonacci.c')
0 files changed, 0 insertions, 0 deletions