lifter: add MERGEN_INSTR_TRACE_FILE per-instruction breadcrumb (#193)

Companion to MERGEN_BLOCK_TRACE_FILE. Writes one line per instruction
lifted to the target file, with per-instruction flush. Pins exactly
which instruction VA precedes a crash when debuggers are unavailable.

Format:
  0x<instruction-VA>

Used to localise the chain+T=32 crash from 'block 755' down to the
exact PC 0x14017fae1 - the 'push [rsp]' immediately after 'pop rsp'
in the VM's stack-switch gadget at 0x14017facc..0x14017fae3. That
pair is the concrete crash trigger: pop rsp loads a new RSP value,
then push [rsp] attempts to read from that new RSP and the lifter's
memory path crashes when the address is out-of-range.

No behaviour change when the env var is unset. Verified:
- python test.py baseline green
- default themida lift unchanged (359 blocks, 1/4 imports)

Co-authored-by: Claude <claude@anthropic.com>
This commit is contained in:
naci
2026-04-24 19:59:12 +03:00
committed by GitHub
parent e7b0babec8
commit 08709710da
+11
View File
@@ -480,6 +480,17 @@ public:
{
auto decodeSample = profiler.sample("lift_decode");
this->current_address = addr;
// Per-instruction VA breadcrumb: complements MERGEN_BLOCK_TRACE_FILE
// by pinning the exact instruction PC when a crash occurs within a
// block. Set MERGEN_INSTR_TRACE_FILE to enable.
if (const char* trace = std::getenv("MERGEN_INSTR_TRACE_FILE")) {
FILE* f = std::fopen(trace, "a");
if (f) {
std::fprintf(f, "0x%llx\n", (unsigned long long)addr);
std::fflush(f);
std::fclose(f);
}
}
auto offset = file.address_to_mapped_address(addr);
if (offset == 0) {
this->run = 0;