[Scummvm-cvs-logs] SF.net SVN: scummvm: [28607] tools/branches/gsoc2007-decompiler
brixxie at users.sourceforge.net
brixxie at users.sourceforge.net
Tue Aug 14 05:56:28 CEST 2007
Revision: 28607
http://scummvm.svn.sourceforge.net/scummvm/?rev=28607&view=rev
Author: brixxie
Date: 2007-08-13 20:56:28 -0700 (Mon, 13 Aug 2007)
Log Message:
-----------
added various bugfixes to scumm frontend, added cfg.py
Modified Paths:
--------------
tools/branches/gsoc2007-decompiler/finalD/decompiler.py
tools/branches/gsoc2007-decompiler/finalD/disasm.py
tools/branches/gsoc2007-decompiler/finalD/iformat.py
tools/branches/gsoc2007-decompiler/finalD/scumm.py
Added Paths:
-----------
tools/branches/gsoc2007-decompiler/finalD/cfg.py
Property Changed:
----------------
tools/branches/gsoc2007-decompiler/
Property changes on: tools/branches/gsoc2007-decompiler
___________________________________________________________________
Name: svk:merge
- 489ca303-0d3d-4dc1-a57d-017c7912a06a:/local/gsoc2007-decompiler:71
+ 489ca303-0d3d-4dc1-a57d-017c7912a06a:/local/gsoc2007-decompiler:73
Added: tools/branches/gsoc2007-decompiler/finalD/cfg.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/cfg.py (rev 0)
+++ tools/branches/gsoc2007-decompiler/finalD/cfg.py 2007-08-14 03:56:28 UTC (rev 28607)
@@ -0,0 +1,95 @@
+"""Control flow graph module."""
+
+from iformat import *
+from altgraph import Graph
+
+
+class BT:
+ """Block type enumeration."""
+
+ fall = 0
+ """fall-through block"""
+ one_way = 1
+ """one way block"""
+ two_way = 2
+ """two way block"""
+
+
+class BasicBlock:
+ """BasicBlock class."""
+
+ def __init__(self, instrs, btype):
+ """
+ Initialize BasicBlock object.
+
+ Arguments:
+ instrs -- a list of instructions
+ btype -- basic block type (see BT)
+ """
+ self.instrs = instrs
+ self.btype = btype
+
+ def __str__(self):
+ """BasicBlock string representation."""
+ return str(self.instrs)
+
+ def get_first(self):
+ """Return first instruction offset in block."""
+ return self.instrs[0]
+
+ def get_last(self):
+ """Return last instruction offset in block."""
+ return self.instrs[-1]
+
+
+def get_bt(last_instr):
+ """Return block type of block with last instruction last_instr."""
+ return {CondJump : BT.two_way,
+ Jump : BT.one_way}.get(last_instr.__class__, BT.fall)
+
+def gen_basic_blocks(decoded):
+ """Generate basic block from a decoded instruction dictionary."""
+ blocks = []
+ block_instrs = []
+ jump_targets = set(map(lambda jmp: jmp.get_to(),
+ filter(is_jump, decoded.values())))
+ decoded_tuples = decoded.items()
+ decoded_tuples.sort(key=(lambda t: t[0]))
+ for off, instr in decoded_tuples:
+ if off in jump_targets:
+ if block_instrs:
+ blocks.append(BasicBlock(block_instrs, BT.fall))
+ block_instrs = []
+ block_instrs.append(off)
+ if is_jump(instr):
+ blocks.append(BasicBlock(block_instrs, get_bt(instr)))
+ block_instrs = []
+ if block_instrs:
+ blocks.append(BasicBlock(block_instrs, BT.fall))
+ return blocks
+
+def gen_control_flow_graph(blocks, decoded):
+ """
+ Generate a control flow graph.
+
+ Arguments:
+ blocks -- a list of BasicBlock objects
+ decoded -- a dict of offset : Instr
+ """
+ edges = []
+ def index_key(lst, val, key):
+ for i, e in enumerate(lst):
+ if key(e) == val:
+ return i
+ for i, block in enumerate(blocks):
+ if block.btype == BT.one_way or block.btype == BT.two_way:
+ # we know the last Instr is some kind of Jump instance
+ jump_target = decoded[block.get_last()].get_to()
+ target_index = index_key(blocks, jump_target, BasicBlock.get_first)
+ assert(target_index != None) # this should be non None
+ edges.append((i, target_index))
+ # a two-way has a fall-through too!
+ if block.btype == BT.fall or block.btype == BT.two_way:
+ if i+1 != len(blocks):
+ edges.append((i, i+1))
+ return Graph.Graph(edges)
Property changes on: tools/branches/gsoc2007-decompiler/finalD/cfg.py
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:eol-style
+ native
Modified: tools/branches/gsoc2007-decompiler/finalD/decompiler.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/decompiler.py 2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/decompiler.py 2007-08-14 03:56:28 UTC (rev 28607)
@@ -3,6 +3,7 @@
import disasm
import scumm
import bytecode
+import cfg
import array
from optparse import OptionParser
@@ -14,16 +15,28 @@
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename")
+ parser.add_option("-d", "--disassemble", dest="disonly", action="store_true", default=False)
(options, args) = parser.parse_args()
f = open(options.filename, 'r')
sc = scumm.SCUMM345(array.array('B', f.read()),
3,
indy_flag = True,
halt_on_error = False)
- sc.parse_header()
try:
- while 1:
- print sc.decode_next()
- except bytecode.IncompleteFetchError:
- pass
+ sc.parse_header()
+ dis = disasm.Disasm(sc)
+ decoded = dis.decode()
+ if not options.disonly:
+ blocks = cfg.gen_basic_blocks(decoded)
+ graph = cfg.gen_control_flow_graph(blocks, decoded)
+ print "%s" % graph
+ else:
+ decoded_tuples = decoded.items()
+ decoded_tuples.sort(key=lambda t: t[0])
+ for off, instr in decoded_tuples:
+ print "[%.4X] %s;" % (off, instr)
+ except:
+ print "ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOORRRRRRRRRRRRRRR"
+ print options.filename
+ raise
print "END"
Modified: tools/branches/gsoc2007-decompiler/finalD/disasm.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/disasm.py 2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/disasm.py 2007-08-14 03:56:28 UTC (rev 28607)
@@ -22,8 +22,8 @@
Arguments:
bc -- instance of bytecode.ByteCode class
"""
- self.decoded = []
- """Hold decoded instructions."""
+ self.decoded = {}
+ """Hold decoded instructions indexed by script offset."""
self._bc = bc
"""Hold bytecode.ByteCode instance."""
@@ -33,7 +33,8 @@
# Append results of self.decode_next() to self.decoded until
# an exception is raised.
while 1:
- self.decoded.append(self._bc.decode_next())
+ pos = self._bc.get_pos()
+ self.decoded[pos] = self._bc.decode_next()
except bytecode.IncompleteFetchError:
# If an bytecode.IncompleteFetchError was raised, we are done.
return self.decoded
Modified: tools/branches/gsoc2007-decompiler/finalD/iformat.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/iformat.py 2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/iformat.py 2007-08-14 03:56:28 UTC (rev 28607)
@@ -26,7 +26,7 @@
class AssgnInstr(Instr):
"""Assignment Instruction in intermediate format."""
- def __init__(self, op, dst, val):
+ def __init__(self, op, dst, val):
Instr.__init__(self, op, (dst, val))
def __str__(self):
@@ -39,6 +39,9 @@
def __init__(self, to):
Instr.__init__(self, "goto", (to,))
+ def get_to(self):
+ return self.args[0]
+
def __str__(self):
return "goto %.4X" % self.args[0]
@@ -51,3 +54,8 @@
def __str__(self):
return "unless(%s) goto %.4X" % (self.condition, self.args[0])
+
+
+def is_jump(instr):
+ """Return true if instr is a Jump."""
+ return instr.__class__ == Jump or instr.__class__ == CondJump
Modified: tools/branches/gsoc2007-decompiler/finalD/scumm.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/scumm.py 2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/scumm.py 2007-08-14 03:56:28 UTC (rev 28607)
@@ -395,6 +395,10 @@
bytecode.ByteCode.__init__(self, init, SCUMM.get_byte)
+ def get_pos(self):
+ """Return self._pos - self.script_start."""
+ return self._pos - self.script_start
+
def skip_verb_header(self, off, ofetch, cfetch=0):
min_offset = 255
offset = off
@@ -709,7 +713,7 @@
self.register_opcodes(opcodes, handler)
def calc_abs_jump(self, relative):
- return 0x7fff & (relative + (self.get_pos() - self.script_start))
+ return 0x7fff & (relative + self.get_pos())
def make_jump(self, condition=0):
offset = self.get_word()
@@ -1112,8 +1116,8 @@
def mak_state_handler(name):
def handler(opcode):
if opcode & 0x40:
- return Instr(name, 0)
- return Instr(name, self.get_byte())
+ return Instr(name, [])
+ return Instr(name, [self.get_byte()])
return handler
self.register_opcodes([0x0f, 0x4f], mak_state_handler("clearState02"))
self.register_opcodes([0x37, 0x77], mak_state_handler("clearState04"))
@@ -1201,6 +1205,7 @@
if self.version == 5:
self.register_complex_set("getObjectState", 0x0f, self.vow)
self.register_complex("panCameraTo", 0x12, self.vow)
+ self.register_opcodes([0x14, 0x94, 0xd8], self.do_print_ego)
self.register_opcodes([0x13, 0x53, 0x93, 0xd3], self.do_actor_ops)
self.register_complex_set("actorFromPos", 0x15, self.vow, self.vow)
self.register_opcodes([0x17, 0x97,
@@ -1349,9 +1354,9 @@
d = self.get_byte()
if (d & 0x1f) == 3:
return Instr("oldRoomEffect-set",
- self.get_var_or_word(opcode, pmasks[0]))
+ [self.get_var_or_word(opcode, pmasks[0])])
return Instr("oldRoomEffect-fadein",
- self.get_var_or_word(opcode, pmasks[0]))
+ [self.get_var_or_word(opcode, pmasks[0])])
def do_begin_override(self, _):
d = self.get_byte()
@@ -1679,7 +1684,7 @@
instr = self.produce_instr("LoadCharset", opc,
self.vob, self.vob)
else:
- instr = self.produce_instr("CursorCommand", self.lst)
+ instr = self.produce_instr("CursorCommand", opc, self.lst)
else:
raise UnknownSubOpError, \
"SCUMM345.do_cursor_command: unknown subop %d" % opcm
@@ -1744,27 +1749,28 @@
break
opcm = opc & 0x1f
if opcm == 0x0:
- args.append(self.produce_instr("Pos", self.vow, self.vow))
+ args.append(self.produce_instr("Pos", opc, self.vow, self.vow))
elif opcm == 0x1:
- args.append(self.produce_instr("Color", self.vob))
+ args.append(self.produce_instr("Color", opc, self.vob))
elif opcm == 0x2:
- args.append(self.produce_instr("Clipped", self.vow))
+ args.append(self.produce_instr("Clipped", opc, self.vow))
elif opcm == 0x3:
- args.append(self.produce_instr("RestoreBG", self.vow, self.vow))
+ args.append(self.produce_instr("RestoreBG", opc, self.vow, self.vow))
elif opcm == 0x4:
args.append(Instr("Center", []))
elif opcm == 0x6:
if self.unblocked:
- args.append(self.produce_instr("Height", self.vow))
+ args.append(self.produce_instr("Height", opc, self.vow))
else:
args.append(Instr("Left", []))
elif opcm == 0x7:
args.append(Instr("Overhead", []))
elif opcm == 0x8:
args.append(self.produce_instr("PlayCDTrack",
+ opc,
self.vow, self.vow))
elif opcm == 0xf:
- args.append(self.produce_instr("Text", self.asc))
+ args.append(self.produce_instr("Text", opc, self.asc))
break
else:
raise UnknownSubOpError, \
@@ -1775,11 +1781,11 @@
opc = self.get_byte()
opcm = opc & 0x1f
if opcm == 0x1:
- instr = self.produce_instr("setBoxFlags", self.vob, self.vob)
+ instr = self.produce_instr("setBoxFlags", opc, self.vob, self.vob)
elif opcm == 0x2:
- instr = self.produce_instr("setBoxScale", self.vob, self.vob)
+ instr = self.produce_instr("setBoxScale", opc, self.vob, self.vob)
elif opcm == 0x3:
- instr = self.produce_instr("setBoxSlot", self.vob, self.vob)
+ instr = self.produce_instr("setBoxSlot", opc, self.vob, self.vob)
elif opcm == 0x4:
instr = Instr("createBoxMatrix", [])
else:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list