mirror of
https://frontier.innolan.net/github/amigaos-cross-toolchain6.git
synced 2024-10-19 10:29:55 +00:00
Simple interface to Exec's SAD.
This commit is contained in:
Executable
+361
@@ -0,0 +1,361 @@
|
||||
#!/usr/bin/env python2.7 -B
|
||||
|
||||
import cmd
|
||||
import socket
|
||||
import sys
|
||||
import select
|
||||
import threading
|
||||
import struct
|
||||
|
||||
|
||||
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_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()
|
||||
Reference in New Issue
Block a user