]>
Commit | Line | Data |
---|---|---|
39037602 A |
1 | import logging |
2 | from interface import Interface | |
3 | import rsprotocol | |
4 | import random | |
5 | ||
6 | ||
7 | class GDBServer(object): | |
8 | """instance of gdbserver""" | |
9 | def __init__(self, backing_instance): | |
10 | super(GDBServer, self).__init__() | |
11 | self.process = backing_instance | |
12 | self.portnum = random.randint(2000, 8000) | |
13 | logging.info("Starting gdb server for localhost:%d" % self.portnum) | |
14 | self.conn = Interface('localhost', self.portnum) | |
15 | self.version_string = 'name:kdbserver;version:0.1' | |
16 | ||
17 | def run(self): | |
18 | if not self.conn.connect(): | |
19 | logging.critical("No client connected. Bailing.") | |
20 | return False | |
21 | ||
22 | logging.debug('Starting gdb server.') | |
23 | ||
24 | while True: | |
25 | #loop for running the server. | |
26 | #read command | |
27 | readBytes = "" | |
28 | ||
29 | while True: | |
30 | try: | |
31 | p_bytes = self.conn.read() | |
32 | except Exception, e: | |
33 | logging.warn("found exception in read %s" % (str(e))) | |
34 | logging.debug("currentbytes: %s" % readBytes) | |
35 | readBytes = '' | |
36 | break | |
37 | readBytes += p_bytes | |
38 | p_begin = readBytes.find('$') | |
39 | p_end = readBytes.find('#') | |
40 | if p_begin >= 0 and p_end >= 0 and p_end > p_begin: | |
41 | break | |
5ba3f43e | 42 | # ignore if empty or ack messages |
39037602 A |
43 | if readBytes in ('', '+'): |
44 | logging.debug('ignoring message: %s' % readBytes) | |
45 | continue | |
46 | req_msg = rsprotocol.Message.fromRSPByteData(readBytes) | |
47 | resp = self.handleMessage(req_msg) | |
48 | #in case resp is to detach | |
49 | if resp is None: | |
50 | return True | |
51 | for r_msg in resp: | |
52 | logging.debug("response: %s" % r_msg.getRSPByteData()) | |
53 | self.conn.write(r_msg.getRSPByteData()) | |
54 | return True | |
55 | ||
56 | def handleMessage(self, msg): | |
57 | """ return array of messages that needs to responded. """ | |
58 | query = msg.getData() | |
59 | replymsgs = [] | |
60 | sendAck = None | |
61 | logging.debug('RCV:' + query) | |
62 | ||
63 | if query == "?": | |
64 | h_msg = rsprotocol.Message(self.process.getSignalInfo()) | |
65 | replymsgs.append(h_msg) | |
66 | ||
67 | elif query[0] == 'm': | |
68 | replymsgs.append(self.getMemory(query)) | |
69 | ||
70 | elif query in ('qVAttachOrWaitSupported'): | |
71 | logging.debug('Ignoring query %s' % query) | |
72 | replymsgs.append(rsprotocol.UnSupportedMessage) | |
73 | ||
74 | elif query == "qC": | |
75 | replymsgs.append(self.getCurrentThreadID(query)) | |
76 | ||
77 | elif query[0] in ('z', 'Z'): | |
78 | logging.debug('Ignoring breakpoint query %s' % query) | |
79 | replymsgs.append(rsprotocol.UnSupportedMessage) | |
80 | ||
81 | elif query[0] in ('g', 'p'): | |
82 | replymsgs.append(self.getRegisterData(query)) | |
83 | ||
84 | elif query[0] in ('P', 'G'): | |
85 | # we do not support writing into registers | |
86 | replymsgs.append(rsprotocol.Message('E05')) | |
87 | ||
88 | elif query in ('QStartNoAckMode'): | |
89 | replymsgs.append(rsprotocol.OKMessage) | |
90 | sendAck = True | |
91 | ||
92 | elif query in ('QListThreadsInStopReply', 'QThreadSuffixSupported'): | |
93 | replymsgs.append(rsprotocol.OKMessage) | |
94 | ||
95 | elif query == 'qGDBServerVersion': | |
96 | replymsgs.append(rsprotocol.Message(self.version_string)) | |
97 | ||
98 | elif query == 'qShlibInfoAddr': | |
99 | #return shared library info address if any | |
100 | replymsgs.append(self.getSharedLibInfoAddress(query)) | |
101 | ||
102 | elif query == 'qProcessInfo': | |
103 | replymsgs.append(self.getProcessInfo(query)) | |
104 | ||
105 | elif query == 'qHostInfo': | |
106 | h_msg = rsprotocol.Message(self.process.getHostInfo()) | |
107 | replymsgs.append(h_msg) | |
108 | ||
109 | elif query == 'vCont?': | |
110 | replymsgs.append(rsprotocol.Message('vCont;')) | |
111 | ||
112 | elif query == 'D': | |
113 | logging.info('Client requested to detach.') | |
114 | return None | |
115 | ||
116 | elif query.find('qRegisterInfo') >= 0: | |
117 | replymsgs.append(self.getRegisterInfo(query)) | |
118 | ||
119 | elif query.find('qMemoryRegionInfo') >= 0: | |
120 | replymsgs.append(self.getMemoryRegionInfo(query)) | |
121 | ||
122 | elif query.find('qThreadStopInfo') >= 0 or query in ('qfThreadInfo', 'qsThreadInfo'): | |
123 | replymsgs.append(self.getThreadRegistersInfo(query)) | |
124 | ||
125 | else: | |
126 | replymsgs.append(rsprotocol.UnSupportedMessage) | |
127 | ||
128 | if sendAck is not None: | |
129 | if sendAck: | |
130 | replymsgs.insert(0, rsprotocol.AckMessage) | |
131 | else: | |
132 | replymsgs.insert(0, rsprotocol.NAckMessage) | |
133 | ||
134 | return replymsgs | |
135 | ||
136 | def getThreadRegistersInfo(self, query): | |
137 | bytes = '' | |
138 | if query == 'qfThreadInfo': | |
139 | bytes = self.process.getFirstThreadInfo() | |
140 | elif query == 'qsThreadInfo': | |
141 | bytes = self.process.getSubsequestThreadInfo() | |
142 | else: | |
143 | try: | |
144 | query = query.replace('qThreadStopInfo', '') | |
145 | tid = int(query, 16) | |
146 | bytes = self.process.getThreadStopInfo(tid) | |
147 | except Exception, e: | |
148 | logging.error("Failed to get register information query: %s error: %s" % (query, e.message)) | |
149 | return rsprotocol.Message(bytes) | |
150 | ||
151 | def getRegisterData(self, query): | |
152 | if query[0] == 'g': | |
153 | #TODO should implement thissometime. Considering getThreadRegistersInfo is there | |
154 | #we wont need this one. | |
155 | return rsprotocol.UnSupportedMessage | |
156 | ||
157 | #the query is of type p<regnum>;thread:<id>; | |
158 | bytes = '' | |
159 | try: | |
160 | args = query[1:].split(';') | |
161 | if len(args) > 0: | |
162 | regnum = int(args[0], 16) | |
163 | if args[1].find('thread') >= 0: | |
164 | threadid = int(args[1].split(':')[-1], 16) | |
165 | bytes = self.process.getRegisterDataForThread(threadid, regnum) | |
166 | logging.debug('REGISTER INFO bytes = ' + bytes) | |
167 | except Exception, e: | |
168 | logging.error("Failed to get register information query: %s error: %s" % (query, e.message)) | |
169 | return rsprotocol.Message(bytes) | |
170 | ||
171 | def getRegisterInfo(self, query): | |
172 | bytes = '' | |
173 | try: | |
174 | query = query.replace('qRegisterInfo', '') | |
175 | regnum = int(query, 16) | |
176 | bytes = self.process.getRegisterInfo(regnum) | |
177 | except Exception, e: | |
178 | logging.error("Failed to get register information error: %s" % e.message) | |
179 | return rsprotocol.Message(bytes) | |
180 | ||
181 | def getMemory(self, query): | |
182 | query = query[1:] | |
183 | addr, size = query.split(',') | |
184 | mem_address = int(addr, 16) | |
185 | mem_size = int(size, 16) | |
186 | bytes = '' | |
187 | try: | |
188 | bytes = self.process.readMemory(mem_address, mem_size) | |
189 | except Exception, e: | |
190 | logging.warn('Failed to read data %s' % str(e)) | |
191 | return rsprotocol.Message('E03') | |
192 | return rsprotocol.Message(bytes) | |
193 | ||
194 | def getMemoryRegionInfo(self, query): | |
195 | return rsprotocol.UnSupportedMessage | |
196 | ||
197 | def setMemory(self, query): | |
198 | logging.info('Not supporting writing to memory. %s' % query) | |
199 | return rsprotocol.Message('E09') | |
200 | ||
201 | def getProcessInfo(self, query): | |
202 | data = '' | |
203 | try: | |
204 | data = self.process.getProcessInfo() | |
205 | except Exception, e: | |
206 | logging.error("Failed to get process information") | |
207 | return rsprotocol.Message(data) | |
208 | ||
209 | def getSharedLibInfoAddress(self, query): | |
210 | data = 'E44' | |
211 | try: | |
212 | data = self.process.getSharedLibInfoAddress() | |
213 | data = self.process.encodeThreadID(data) | |
214 | except Exception, e: | |
215 | logging.error("Failed to get Shared Library information") | |
216 | return rsprotocol.Message(data) | |
217 | ||
218 | def getCurrentThreadID(self, query): | |
219 | tid = '0' | |
220 | try: | |
221 | tid = '%x' % (self.process.getCurrentThreadID()) | |
222 | except Exception, e: | |
223 | logging.error("Failed to get QC info") | |
224 | ||
225 | return rsprotocol.Message('QC'+tid) | |
226 | ||
227 | def kill(self): | |
228 | pass |