#!/usr/bin/env python3
"""Probe 9: inventory the VM state table at the dump point."""
STAGE2 = '/root/luad/samples/boulder/stage2.lua'
PAYLOAD = '/root/luad/samples/boulder/payload.bin'
OUT = '/tmp/opencode/dump_run9.luau'

SHIM = r'''
local __realprint = print
tick = function() return 0 end
time = function() return 0 end
warn = function() end
typeof = function(v) return type(v) end
local __HOST = getfenv()
__ENV = setmetatable({}, {
	__index = function(t, k) return __HOST[k] end,
	__newindex = function(t, k, v) __HOST[k] = v end,
})
__GDUMP = function(G)
	local keys = {}
	for k in pairs(G) do if type(k) == "number" then keys[#keys + 1] = k end end
	table.sort(keys)
	for i = 1, #keys do
		local k = keys[i]
		local v = rawget(G, k)
		local t = type(v)
		local repr
		if t == "number" then repr = string.format("%.10g", v)
		elseif t == "string" then repr = string.format("%q", v:sub(1, 40))
		elseif t == "table" then
			local n = 0
			for _ in pairs(v) do n = n + 1 end
			repr = "tbl#" .. n
		elseif t == "function" then repr = "fn"
		else repr = t end
		__realprint("GS", k, t, repr)
	end
end
'''

def main():
    stage2 = open(STAGE2, 'rb').read().decode('latin-1')
    payload = open(PAYLOAD, 'rb').read()
    rlit = '"' + ''.join('\\x%02x' % b for b in payload) + '"'
    stage2 = stage2.replace('local R=...;', 'local R=buffer.fromstring(' + rlit + ');', 1)
    needle = 'y,A,m,P,e=W:KS(e,P,A,G,y);'
    assert stage2.count(needle) == 1
    stage2 = stage2.replace(needle, needle + '__GDUMP(G);', 1)
    out = SHIM + 'local __ok,__err=pcall(function()\nlocal __fn=function()\n' + stage2 + '\nend\nsetfenv(__fn,__ENV)\nreturn __fn()\nend)\n'
    out += '__realprint("EXEC", __ok, tostring(__err))\n'
    open(OUT, 'w').write(out)
    print("wrote", OUT, len(out))

if __name__ == '__main__':
    main()
