amigaos-cross-toolchain6/tools/sadfe.py

390 lines
9.1 KiB
Python
Executable File

#!/usr/bin/env python2.7 -B
import cmd
import socket
import sys
import select
import threading
import tempfile
import subprocess
import struct
def make_srec(addr, code):
header = 'S00600004844521B'
terminate = 'S9030000FC'
addr = '%.8x' % addr
code = code.encode('hex').upper()
length = '%.2x' % (len(code.decode('hex')) + 5)
srec = length + addr + code
bytesum = sum(ord(i) for i in srec.decode('hex'))
cksum = "%.2X" % (~bytesum & 0xFF)
return '\n'.join([header, 'S3' + srec + cksum, terminate])
class SimpleAmigaDebuggerConnection(object):
def __init__(self, server):
self.server = server
def recv(self, size=None):
recv = lambda: self.server.recv(8192)
if not size:
return recv()
buf = ""
while len(buf) < size:
data = recv()
if not len(data):
break
buf += data
if len(buf) != size:
raise ValueError(buf)
return buf
def send(self, data):
self.server.send(data)
def send_cmd(self, cmd, payload=None):
self.send(struct.pack('>BB', 0xAF, cmd))
if payload is not None:
return self.send(payload)
def close(self):
self.server.close()
def expect(self, data):
recv_data = self.recv(len(data))
assert recv_data == data
def expect_ack(self, cmd):
self.expect(struct.pack('>BB', 0x00, cmd))
def expect_done(self, cmd, datalen=0):
self.expect(struct.pack('>BB', 0x1F, cmd))
if datalen:
data = self.recv(datalen)
else:
data = None
self.expect("SAD?")
return data
def nop(self):
self.send_cmd(0)
def write_byte(self, ptr, val):
self.send_cmd(1, struct.pack('>IB', ptr, val))
self.expect_ack(1)
self.expect_done(1)
def write_word(self, ptr, val):
self.send_cmd(2, struct.pack('>IH', ptr, val))
self.expect_ack(2)
self.expect_done(2)
def write_long(self, ptr, val):
self.send_cmd(3, struct.pack('>II', ptr, val))
self.expect_ack(3)
self.expect_done(3)
def read_byte(self, ptr):
self.send_cmd(4, struct.pack('>I', ptr))
self.expect_ack(4)
data = self.expect_done(4, 1)
return struct.unpack('>B', data)[0]
def read_word(self, ptr):
self.send_cmd(5, struct.pack('>I', ptr))
self.expect_ack(5)
data = self.expect_done(5, 2)
return struct.unpack('>H', data)[0]
def read_long(self, ptr):
self.send_cmd(6, struct.pack('>I', ptr))
self.expect_ack(6)
data = self.expect_done(6, 4)
return struct.unpack('>I', data)[0]
def call_address(self, ptr):
self.send_cmd(7, struct.pack('>I', ptr))
self.expect_ack(7)
self.expect_done(7)
def return_to_system(self):
self.send_cmd(8, struct.pack('>I', 0))
self.expect_ack(8)
def get_context_frame(self):
self.send_cmd(9)
self.expect_ack(9)
data = self.expect_done(9, 4)
return struct.unpack('>I', data)[0]
def allocate_memory(self, size, memtype):
self.send_cmd(10, struct.pack('>II', size, memtype))
self.expect_ack(10)
data = self.expect_done(10, 4)
return struct.unpack('>I', data)[0]
def free_memory(self, ptr):
self.send_cmd(11, struct.pack('>I', ptr))
self.expect_ack(11)
self.expect_done(11)
def turn_on_single(self):
self.send_cmd(12)
self.expect_ack(12)
data = self.expect_done(12, 4)
return struct.unpack('>I', data)[0]
def turn_off_single(self, ptr):
self.send_cmd(13, struct.pack('>I', ptr))
self.expect_ack(13)
self.expect_done(13)
def write_array(self, ptr, data):
self.send_cmd(14, struct.pack('>IIs', ptr, len(data), data))
self.expect_ack(14)
self.expect_done(14)
def read_array(self, ptr, size):
self.send_cmd(15, struct.pack('>II', ptr, size))
self.expect_ack(15)
return self.expect_done(15, size)
def reset(self):
self.send_cmd(16)
self.expect_ack(16)
class SimpleAmigaDebuggerFrontEnd(cmd.Cmd):
def __init__(self, sad):
cmd.Cmd.__init__(self)
self.prompt = '>>> '
self.sad = sad
def parse_args(self, args, *types):
args = args.split(' ')
if len(args) != len(types):
print 'Wrong number of arguments!'
return None
values = []
for v, t in zip(args, types):
if t == 'ptr':
v = int(v, 16)
assert (v >= 0 or v < 2 ** 32)
elif t == 'byte':
v = int(v, 10)
assert (v >= 0 or v < 2 ** 8)
elif t == 'word':
v = int(v, 10)
assert (v >= 0 or v < 2 ** 16)
elif t == 'long':
v = int(v, 10)
assert (v >= 0 or v < 2 ** 32)
elif t == 'data':
v = v.decode('hex')
else:
raise ValueError
values.append(v)
return values
def do_quit(self, args):
return True
def do_wb(self, args):
""" write byte """
ptr, byte = self.parse_args(args, 'ptr', 'byte')
self.sad.write_byte(ptr, byte)
def do_ww(self, args):
""" write word """
ptr, word = self.parse_args(args, 'ptr', 'word')
self.sad.write_word(ptr, word)
def do_wl(self, args):
""" write long """
ptr, long_ = self.parse_args(args, 'ptr', 'long')
self.sad.write_long(ptr, long_)
def do_rb(self, args):
""" read byte """
ptr = self.parse_args(args, 'ptr')[0]
byte = self.sad.read_byte(ptr)
print "%.2x" % byte
def do_rw(self, args):
""" read word """
ptr = self.parse_args(args, 'ptr')[0]
word = self.sad.read_word(ptr)
print "%.4x" % word
def do_rl(self, args):
""" read long """
ptr = self.parse_args(args, 'ptr')[0]
long_ = self.sad.read_long(ptr)
print "%.8x" % long_
def do_call(self, args):
""" call address """
ptr = self.parse_args(args, 'ptr')[0]
self.sad.call_address(ptr)
def do_return(self, _):
""" return to system """
self.sad.return_to_system()
return True
def do_frame(self, _):
""" get context frame """
ptr = self.sad.get_context_frame()
data = self.sad.read_array(ptr, 21 * 4 + 2)
data = struct.unpack('>IIIIIIIIIIIIIIIIIIIIHI', data)
desc = ['VBR', 'AttnFlags', 'ExecBase', 'USP', 'D0', 'D1', 'D2', 'D3',
'D4', 'D5', 'D6', 'D7', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6',
'Prompt', 'SR', 'PC']
for k, v in zip(desc, data):
print k.ljust(max(len(d) for d in desc)), "%.8x" % v
def do_alloc(self, args):
""" allocate memory """
size = self.parse_args(args, 'long')[0]
ptr = self.sad.allocate_memory(size, 0)
print "%.8x" % ptr
def do_free(self, args):
""" free memory """
ptr = self.parse_args(args, 'ptr')[0]
self.sad.free_memory(ptr)
def do_trace(self, _):
""" turn on single """
ptr = self.sad.turn_on_single()
print "%.8x" % ptr
def do_notrace(self, args):
""" turn off single """
ptr = self.parse_args(args, 'ptr')[0]
self.sad.turn_off_single(ptr)
def do_wr(self, args):
""" write array """
ptr, data = self.parse_args(args, 'ptr', 'data')
self.sad.write_array(ptr, data)
def do_rr(self, args):
""" read array """
ptr, size = self.parse_args(args, 'ptr', 'long')
data = self.sad.read_array(ptr, size)
print data.encode('hex')
def do_dis(self, args):
""" disassemble """
ptr, size = self.parse_args(args, 'ptr', 'long')
data = self.sad.read_array(ptr, size)
with tempfile.NamedTemporaryFile() as srec:
srec.write(make_srec(ptr, data))
srec.flush()
output = subprocess.check_output(
['m68k-amigaos-objdump', '-b', 'srec', '-m', '68020', '-D', srec.name])
print '\n'.join(output.split('\n')[7:-1])
def do_reset(self, _):
""" reset """
self.sad.reset()
class SimpleAmigaDebuggerThread(threading.Thread):
def __init__(self, server):
threading.Thread.__init__(self)
self.sad = SimpleAmigaDebuggerConnection(server)
def run(self):
sadfe = SimpleAmigaDebuggerFrontEnd(self.sad)
sadfe.cmdloop()
self.sad.close()
class SimpleAmigaDebuggerClient(object):
def __init__(self):
self.socket = None
self.sad_mode = False
def sad_keep_alive(self):
ready = select.select([self.socket, self.client], [], [], 0.5)[0]
if not ready:
self.socket.send(struct.pack('>BB', 0xAF, 0))
if self.socket in ready:
data = self.socket.recv(8192)
# print "=> client", data.encode('hex')
self.client.send(data)
if self.client in ready:
data = self.client.recv(8192)
if not len(data):
self.client.close()
self.sad_mode = False
return
# print "=> server", data.encode('hex')
self.socket.send(data)
def run(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(("localhost", 1234))
try:
recvbuf = ""
while True:
if self.sad_mode:
self.sad_keep_alive()
continue
data = self.socket.recv(8192)
recvbuf += data
if recvbuf.endswith("SAD?"):
print ""
client, server = socket.socketpair()
recvbuf = ""
self.sad_mode = True
self.client = client
SimpleAmigaDebuggerThread(server).start()
sys.stdout.write(data)
sys.stdout.flush()
recvbuf = recvbuf[-4:]
except KeyboardInterrupt:
pass
self.socket.close()
if __name__ == '__main__':
client = SimpleAmigaDebuggerClient()
client.run()