forked from phracker/HopperScripts
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Hopper GDB to GDB.py
executable file
·123 lines (114 loc) · 4.82 KB
/
Hopper GDB to GDB.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# Hopper gdb script. Effectively the same as the "HopperGDBServer" program that ships with Hopper, but works cross-platform
# Note that if you use this to debug a Linux process on another system, and you "override executable path", you may get an annoying error asking you select the file.
# If you just hit cancel, it will continue to work anyway.
# bradenthomas@me.com
from twisted.internet import reactor,protocol,defer
import pybonjour,struct,socket,os,sys
HOPPER_GDB_PROTOCOL_VERSION = 1
VERBOSE = (os.getenv("VERBOSE") != None)
class HopperBonjour(object):
def __init__(self, name, port):
self.rsock = pybonjour.DNSServiceRegister(name=name,
regtype="_hopper._tcp",
port=port,
callBack=self.register_callback,
domain="local.")
reactor.addReader(self)
def register_callback(self,sdRef,flags,err,name,regtype,domain):
if err==pybonjour.kDNSServiceErr_NoError:
print "Registered %s/%s/%s" % (name,regtype,domain)
def logPrefix(self): return "HopperBonjour"
def fileno(self): return self.rsock.fileno()
def doRead(self): pybonjour.DNSServiceProcessResult(self.rsock)
def connectionLost(self, reason): pass
class GDBProtocol(protocol.ProcessProtocol):
def __init__(self, hopper):
self.hopper = hopper
def connectionMade(self):
if VERBOSE: print "gdb connection made"
self.hopper.gdbConnectionMade()
def outReceived(self, data):
if VERBOSE: print "GDB OUT RECEIVED",repr(data)
self.hopper.transport.write(data)
def errReceived(self, data):
if VERBOSE: print "GDB ERR RECEIVED",repr(data)
sys.stderr.write(data)
sys.stderr.flush()
def processExited(self, status):
if VERBOSE: print "GDB EXIT",status
self.hopper.transport.loseConnection()
class HopperProtocol(protocol.Protocol):
def __init__(self, override_file, override_args):
self.state = 0
self.gdb = None
self.override_file = override_file
self.override_args = override_args
def connectionMade(self):
if VERBOSE: print "Connection made"
self.transport.write("HopperGDBServer")
def gdbConnectionMade(self):
self.state = 4
self.transport.write(chr(1))
def modifyCommand(self, data):
out = data
try:
(command_no, command_data) = data.split("-",1)
if command_data.startswith("file-exec-file") and self.override_file:
out = "%s-file-exec-file \"%s\"\n"%(command_no,self.override_file)
except:
pass
if VERBOSE and out != data: print "MODIFIED",repr(out)
return out
def dataReceived(self, data):
#if VERBOSE: print "Received",repr(data)
if self.state == 0 and data == "Hopper":
self.state = 1
data = data[6:]
self.transport.write(struct.pack("<H", HOPPER_GDB_PROTOCOL_VERSION))
if self.state == 1 and len(data) >= 2:
self.state = 2
remote_version, = struct.unpack("<H", data[:2])
data = data[2:]
if remote_version != HOPPER_GDB_PROTOCOL_VERSION:
if VERBOSE: print "Unsupported version",remote_version
self.transport.loseConnection()
return
if self.state == 2 and len(data) > 0:
self.gdb_arch = data.strip("\x00")
self.state = 3
data = ""
if self.state == 3:
if sys.platform == "darwin":
launch_args = ["gdb", "--arch=%s"%self.gdb_arch, "--quiet", "--nx", "--interpreter=mi1"]
else:
launch_args = ["gdb", "--quiet", "--nx", "--interpreter=mi1"]
if self.override_args and len(self.override_args):
launch_args.extend(["--args", self.override_file]+self.override_args)
elif self.override_file:
launch_args.append(self.override_file)
if VERBOSE: print "Launch:",str(launch_args)
self.gdb = GDBProtocol(self)
reactor.spawnProcess(self.gdb, "/usr/bin/gdb", args=launch_args)
if self.state == 4 and self.gdb != None:
if VERBOSE: print "WRITE TO GDB",repr(data)
data = self.modifyCommand(data)
self.gdb.transport.write(data)
class HopperFactory(protocol.ServerFactory):
protocol = HopperProtocol
def __init__(self, override_file, override_args):
self.override_file = override_file
self.override_args = override_args
def buildProtocol(self, addr):
return self.protocol(self.override_file, self.override_args)
argc = len(sys.argv)-1
if argc == 1 and sys.argv[1] == "-h":
print "Usage: hoppergdb_to_gdb.py [override executable path]"
sys.exit(0)
override_file = None
override_args = []
if argc > 1 and os.path.exists(sys.argv[1]):
override_file = sys.argv[1]
override_args = sys.argv[1:]
p = reactor.listenTCP(0, HopperFactory(override_file, override_args))
HopperBonjour(socket.gethostname(), p.getHost().port)
reactor.run()