'''A very crude Flash Debugger in Python, usable with BlackBerry PlayBook simulator.'''
# Copyright 2010 Peter Hansen (http://peterhansen.ca)
# Released under the Simplified BSD License: http://www.opensource.org/licenses/bsd-license.php
import sys
import struct
from socket import *
# message format details from http://osflash.org/ofd
MSG_NAME = {
0x00: 'menu state', #dd ?, dd ?
0x01: 'property', #dd addr, dw propertyIndex, sz value
0x02: 'exit', #
0x03: 'create anonymous object', #dd addr
0x04: 'remove object', #dd addr
0x05: 'trace', #sz msg
0x06: 'target error', #sz error
0x07: 'recursion depth error', #
0x08: 'with error', #
0x09: 'proto limit error', #
0x0A: 'set field', #dd addr, sz name, amf value
0x0B: 'delete field', #dd addr, sz name
0x0C: 'movie attribute', #sz name, sz value
0x0D: 'place object', #dd addr, sz name
0x0E: 'SWD file entry', #dd fileID, dd unknownIndex, sz name, sz sourceCode, dd swfIndex
0x0F: 'ask breakpoints', #
0x10: 'breakpoint hit', #dw fileID, dw line, dd addr, sz funcName
0x11: 'break', #
0x12: 'set local vars', #dd addr address of an object containing the named local variables of the current scope
0x13: 'breakpoints', #dd count, (dw fileID, dw line)[count]
0x14: 'num swd file entries', #dd num, dd swfIndex
0x15: 'remove SWD file entry', #dd fileID
0x16: 'remove breakpoint', #dd count, (dw fileID, dw line)[count]
0x17: 'not synced', #Sent if the debug ID in the .swf does not match the SWD ID in the .swd
0x18: 'URL open error', #sz error
0x19: 'process tag', #
0x1A: 'version', #dd majorVersion, db 4
0x1B: 'breakpoint hit ex', #dw fileID, dw line, dd callDepth, (dw fileID, dw line, dd thisAddr, sz callstackentry)[callDepth]
0x1C: 'set field 2', #addr, sz name, amf value
0x1D: 'squelch', #dd enabled
0x1E: 'get field', #dd addr, sz name, amf value, (sz memberName, amf memberValue)*
0x1F: 'function frame', #dd callDepth, #if(callDepth > -1) dd numRegs, reg registers[numRegs] #endif, dd addr, amf value, (sz childName, amf childValue)* contains two meta children that serve as start markers: one named "$arguments" and one named "$scopechain"
0x20: 'debugger option', #sz name, sz value
0x21: 'watch', #dw success, dw oldFlags, dw oldTag, dw flags, dw tag, dw addr, sz name
0x22: 'SWF image', #.swf file contents
0x23: 'SWD image', #.swd file contents
0x24: 'exception', #dd 0, sz exception
0x25: 'stack underflow', #dd 0
0x26: 'divide by 0', #dd 0
0x27: 'script stuck', #
0x28: 'suspend reason', #dw reason, dw swfIndex, dd offset, dd prevLineOffset, dd nextLineOffset
0x29: 'actions', #dw swfIndex, dw reserved, dd offset, dd size, db data[size] deprecated/not implemented, will be empty
0x2A: 'SWF info', #dw swfcount, (dd swfIndex, dd addr, #if(addr) db debugComing, db vmVersion, dw reserved, dd swfSize, dd swdSize, dd numSWDs, dd numLines, dd numBreakpoints, dd port, sz path, sz url, sz host, dd swdfilecount, (dd swdLocalIndex, dd swdFileID)[swdfilecount] #endif)[swfcount] addr == 0 means swf was unloaded
0x2B: 'constant pool', #dw swfIndex, dd count, (dd id, sz name, amf value)[count]
0x2C: 'console error', #sz error
0x2D: 'function info', #dd fileID, dd count, (dd offset, dd firstLine, dd lastLine, sz name)[count]
0x2E: '?', #
0x2F: '?', #
0x30: '?', #
0x31: '?', #
0x32: '?', #
0x33: '?', #
0x34: '?', #
0x35: '?', #
0x36: '?', #
0x37: 'watch 2' #dw success, dw oldFlags, dw oldTag, dw flags, dw tag, dd addr, sz name
}
s = socket(AF_INET, SOCK_STREAM)
#~ s.settimeout(500)
s.bind(('', 7935))
s.listen(5)
while 1:
print 'listening on 7935'
sock, client = s.accept()
print 'connect from', client
print
while 1:
data = sock.recv(8)
if not data:
break
length, id = struct.unpack('LL', data)
msgtype = MSG_NAME.get(id, 'unknown')
if length:
data = sock.recv(length)
else:
data = ''
if id == 0x02: # exit
print '%s: %s' % (msgtype, 'program terminated')
break
elif id == 0x05: # trace
print '%s: %s' % (msgtype, data.rstrip('\x00'))
elif id == 0x0e: # SWD file entry
fileid, unknown = struct.unpack('LL', data[:8])
name, source, rest = data[8:].split('\0', 2)
assert len(rest) == 4
assert source == ''
index, = struct.unpack('L', rest)
assert index == 0
if fileid == 1:
print '%s: %s' % (msgtype, (fileid, name, index))
print '(following SWD file entries skipped)'
else:
continue
elif id == 0x24: # exception
text, dump = data[4:].split('\0', 1)
print '%s: %s' % (msgtype, text)
print '\t(and %s extra bytes)' % len(dump)
else:
print '%s: %r' % (msgtype, data)
if 'global$init' in data:
cmd = struct.pack('LL', 0, 0x0F)
sock.send(cmd)
print 'client disconnected'
print '-' * 40