You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

133 lines
4.2 KiB

#!/usr/bin/env python2
#
# Utility to dump bytecode into a human readable form.
#
import os
import sys
import struct
import optparse
def decode_string(buf, off):
strlen, = struct.unpack('>L', buf[off:off+4])
off += 4
strdata = buf[off:off+strlen]
off += strlen
return off, strdata
def sanitize_string(val):
# Don't try to UTF-8 decode, just escape non-printable ASCII.
def f(c):
if ord(c) < 0x20 or ord(c) > 0x7e or c in '\'"':
return '\\x%02x' % ord(c)
else:
return c
return "'" + ''.join(map(f, val)) + "'"
def decode_sanitize_string(buf, off):
off, val = decode_string(buf, off)
return off, sanitize_string(val)
def dump_function(buf, off, ind):
count_inst, count_const, count_funcs = struct.unpack('>LLL', buf[off:off+12])
off += 12
print('%sInstructions: %d' % (ind, count_inst))
print('%sConstants: %d' % (ind, count_const))
print('%sInner functions: %d' % (ind, count_funcs))
# Line numbers present, assuming debugger support; otherwise 0.
nregs, nargs, start_line, end_line = struct.unpack('>HHLL', buf[off:off+12])
off += 12
print('%sNregs: %d' % (ind, nregs))
print('%sNargs: %d' % (ind, nargs))
print('%sStart line number: %d' % (ind, start_line))
print('%sEnd line number: %d' % (ind, end_line))
compfunc_flags, = struct.unpack('>L', buf[off:off+4])
off += 4
print('%sduk_hcompiledfunction flags: 0x%08x' % (ind, compfunc_flags))
for i in xrange(count_inst):
ins, = struct.unpack('>L', buf[off:off+4])
off += 4
print('%s %06d: %08lx' % (ind, i, ins))
print('%sConstants:' % ind)
for i in xrange(count_const):
const_type, = struct.unpack('B', buf[off:off+1])
off += 1
if const_type == 0x00:
off, strdata = decode_sanitize_string(buf, off)
print('%s %06d: %s' % (ind, i, strdata))
elif const_type == 0x01:
num, = struct.unpack('>d', buf[off:off+8])
off += 8
print('%s %06d: %f' % (ind, i, num))
else:
raise Exception('invalid constant type: %d' % const_type)
for i in xrange(count_funcs):
print('%sInner function %d:' % (ind, i))
off = dump_function(buf, off, ind + ' ')
val, = struct.unpack('>L', buf[off:off+4])
off += 4
print('%s.length: %d' % (ind, val))
off, val = decode_sanitize_string(buf, off)
print('%s.name: %s' % (ind, val))
off, val = decode_sanitize_string(buf, off)
print('%s.fileName: %s' % (ind, val))
off, val = decode_string(buf, off) # actually a buffer
print('%s._Pc2line: %s' % (ind, val.encode('hex')))
while True:
off, name = decode_string(buf, off)
if name == '':
break
name = sanitize_string(name)
val, = struct.unpack('>L', buf[off:off+4])
off += 4
print('%s_Varmap[%s] = %d' % (ind, name, val))
num_formals, = struct.unpack('>L', buf[off:off+4])
off += 4
if num_formals != 0xffffffff:
print('%s_Formals: %d formal arguments' % (ind, num_formals))
for idx in xrange(num_formals):
off, name = decode_string(buf, off)
name = sanitize_string(name)
print('%s_Formals[%d] = %s' % (ind, idx, name))
else:
print('%s_Formals: absent' % ind)
return off
def dump_bytecode(buf, off, ind):
sig, = struct.unpack('B', buf[off:off+1])
print('%sSignature byte: 0x%02x' % (ind, sig))
off += 1
if sig == 0xff:
raise Exception('pre-Duktape 2.2 0xFF signature byte (signature byte is 0xBF since Duktape 2.2)')
if sig != 0xbf:
raise Exception('invalid signature byte: %d' % sig)
off = dump_function(buf, off, ind + ' ')
return off
def main():
parser = optparse.OptionParser()
parser.add_option('--hex-decode', dest='hex_decode', default=False, action='store_true', help='Input file is ASCII hex encoded, decode before dump')
(opts, args) = parser.parse_args()
with open(args[0], 'rb') as f:
d = f.read()
if opts.hex_decode:
d = d.strip()
d = d.decode('hex')
dump_bytecode(d, 0, '')
if __name__ == '__main__':
main()