Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
gdbserver.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 
4 import socket
5 import struct
6 import time
7 import logging
8 from StringIO import StringIO
9 import miasm2.analysis.debugging as debugging
10 from miasm2.jitter.jitload import ExceptionHandle
11 
12 
14 
15  "Debugguer binding for GDBServer protocol"
16 
17  general_registers_order = []
18  general_registers_size = {} # RegName : Size in octet
19  status = "S05"
20 
21  def __init__(self, dbg, port=4455):
22  server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
23  server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
24  server.bind(('localhost', port))
25  server.listen(1)
26  self.server = server
27  self.dbg = dbg
28 
29  # Communication methods
30 
31  def compute_checksum(self, data):
32  return chr(sum(map(ord, data)) % 256).encode("hex")
33 
34  def get_messages(self):
35  all_data = ""
36  data = self.sock.recv(4096)
37  all_data += data
38  while (len(data) == 4096 or data == ""):
39  if data == "":
40  # Avoid consuming CPU
41  time.sleep(0.001)
42  continue
43  data = self.sock.recv(4096)
44  all_data += data
45 
46  logging.debug("<- %r", all_data)
47  self.recv_queue += self.parse_messages(all_data)
48 
49  def parse_messages(self, data):
50  buf = StringIO(data)
51 
52  msgs = []
53 
54  while (buf.tell() < buf.len):
55  token = buf.read(1)
56  if token == "+":
57  continue
58  if token == "-":
59  raise NotImplementedError("Resend packet")
60  if token == "$":
61  packet_data = ""
62  c = buf.read(1)
63  while c != "#":
64  packet_data += c
65  c = buf.read(1)
66  checksum = buf.read(2)
67  if checksum != self.compute_checksum(packet_data):
68  raise ValueError("Incorrect checksum")
69 
70  msgs.append(packet_data)
71 
72  return msgs
73 
74  def send_string(self, s):
75  self.send_queue.append("O" + s.encode("hex"))
76 
77  def process_messages(self):
78 
79  while self.recv_queue:
80  msg = self.recv_queue.pop(0)
81  buf = StringIO(msg)
82  msg_type = buf.read(1)
83 
84  self.send_queue.append("+")
85 
86  if msg_type == "q":
87  if msg.startswith("qSupported"):
88  self.send_queue.append("PacketSize=3fff")
89  elif msg.startswith("qC"):
90  # Current thread
91  self.send_queue.append("")
92  elif msg.startswith("qAttached"):
93  # Not supported
94  self.send_queue.append("")
95  elif msg.startswith("qTStatus"):
96  # Not supported
97  self.send_queue.append("")
98  elif msg.startswith("qfThreadInfo"):
99  # Not supported
100  self.send_queue.append("")
101  else:
102  raise NotImplementedError()
103 
104  elif msg_type == "H":
105  # Set current thread
106  self.send_queue.append("OK")
107 
108  elif msg_type == "?":
109  # Report why the target halted
110  self.send_queue.append(self.status) # TRAP signal
111 
112  elif msg_type == "g":
113  # Report all general register values
114  self.send_queue.append(self.report_general_register_values())
115 
116  elif msg_type == "p":
117  # Read a specific register
118  reg_num = int(buf.read(), 16)
119  self.send_queue.append(self.read_register(reg_num))
120 
121  elif msg_type == "P":
122  # Set a specific register
123  reg_num, value = buf.read().split("=")
124  reg_num = int(reg_num, 16)
125  value = int(value.decode("hex")[::-1].encode("hex"), 16)
126  self.set_register(reg_num, value)
127  self.send_queue.append("OK")
128 
129  elif msg_type == "m":
130  # Read memory
131  addr, size = map(lambda x: int(x, 16), buf.read().split(","))
132  self.send_queue.append(self.read_memory(addr, size))
133 
134  elif msg_type == "k":
135  # Kill
136  self.sock.close()
137  self.send_queue = []
138  self.sock = None
139 
140  elif msg_type == "!":
141  # Extending debugging will be used
142  self.send_queue.append("OK")
143 
144  elif msg_type == "v":
145  if msg == "vCont?":
146  # Is vCont supported ?
147  self.send_queue.append("")
148 
149  elif msg_type == "s":
150  # Step
151  self.dbg.step()
152  self.send_queue.append("S05") # TRAP signal
153 
154  elif msg_type == "Z":
155  # Add breakpoint or watchpoint
156  bp_type = buf.read(1)
157  if bp_type == "0":
158  # Exec breakpoint
159  assert(buf.read(1) == ",")
160  addr, size = map(
161  lambda x: int(x, 16), buf.read().split(","))
162 
163  if size != 1:
164  raise NotImplementedError("Bigger size")
165  self.dbg.add_breakpoint(addr)
166  self.send_queue.append("OK")
167 
168  elif bp_type == "1":
169  # Hardware BP
170  assert(buf.read(1) == ",")
171  addr, size = map(
172  lambda x: int(x, 16), buf.read().split(","))
173 
174  self.dbg.add_memory_breakpoint(addr, size,
175  read=True,
176  write=True)
177  self.send_queue.append("OK")
178 
179  elif bp_type in ["2", "3", "4"]:
180  # Memory breakpoint
181  assert(buf.read(1) == ",")
182  read = bp_type in ["3", "4"]
183  write = bp_type in ["2", "4"]
184  addr, size = map(
185  lambda x: int(x, 16), buf.read().split(","))
186 
187  self.dbg.add_memory_breakpoint(addr, size,
188  read=read,
189  write=write)
190  self.send_queue.append("OK")
191 
192  else:
193  raise ValueError("Impossible value")
194 
195  elif msg_type == "z":
196  # Remove breakpoint or watchpoint
197  bp_type = buf.read(1)
198  if bp_type == "0":
199  # Exec breakpoint
200  assert(buf.read(1) == ",")
201  addr, size = map(
202  lambda x: int(x, 16), buf.read().split(","))
203 
204  if size != 1:
205  raise NotImplementedError("Bigger size")
206  dbgsoft = self.dbg.get_breakpoint_by_addr(addr)
207  assert(len(dbgsoft) == 1)
208  self.dbg.remove_breakpoint(dbgsoft[0])
209  self.send_queue.append("OK")
210 
211  elif bp_type == "1":
212  # Hardware BP
213  assert(buf.read(1) == ",")
214  addr, size = map(
215  lambda x: int(x, 16), buf.read().split(","))
216  self.dbg.remove_memory_breakpoint_by_addr_access(
217  addr, read=True, write=True)
218  self.send_queue.append("OK")
219 
220  elif bp_type in ["2", "3", "4"]:
221  # Memory breakpoint
222  assert(buf.read(1) == ",")
223  read = bp_type in ["3", "4"]
224  write = bp_type in ["2", "4"]
225  addr, size = map(
226  lambda x: int(x, 16), buf.read().split(","))
227 
228  self.dbg.remove_memory_breakpoint_by_addr_access(
229  addr, read=read, write=write)
230  self.send_queue.append("OK")
231 
232  else:
233  raise ValueError("Impossible value")
234 
235  elif msg_type == "c":
236  # Continue
237  self.status = ""
238  self.send_messages()
239  ret = self.dbg.run()
240  if isinstance(ret, debugging.DebugBreakpointSoft):
241  self.status = "S05"
242  self.send_queue.append("S05") # TRAP signal
243  elif isinstance(ret, ExceptionHandle):
244  if ret == ExceptionHandle.memoryBreakpoint():
245  self.status = "S05"
246  self.send_queue.append("S05")
247  else:
248  raise NotImplementedError("Unknown Except")
249  elif isinstance(ret, debugging.DebugBreakpointTerminate):
250  # Connexion should close, but keep it running as a TRAP
251  # The connexion will be close on instance destruction
252  print ret
253  self.status = "S05"
254  self.send_queue.append("S05")
255  else:
256  raise NotImplementedError()
257 
258  else:
259  raise NotImplementedError(
260  "Not implemented: message type '%s'" % msg_type)
261 
262  def send_messages(self):
263  for msg in self.send_queue:
264  if msg == "+":
265  data = "+"
266  else:
267  data = "$%s#%s" % (msg, self.compute_checksum(msg))
268  logging.debug("-> %r", data)
269  self.sock.send(data)
270  self.send_queue = []
271 
272  def main_loop(self):
273  self.recv_queue = []
274  self.send_queue = []
275 
276  self.send_string("Test\n")
277 
278  while (self.sock):
279  self.get_messages()
280  self.process_messages()
281  self.send_messages()
282 
283  def run(self):
284  self.sock, self.address = self.server.accept()
285  self.main_loop()
286 
287  # Debugguer processing methods
289  s = ""
290  for i in xrange(len(self.general_registers_order)):
291  s += self.read_register(i)
292  return s
293 
294  def read_register(self, reg_num):
295  reg_name = self.general_registers_order[reg_num]
296  reg_value = self.read_register_by_name(reg_name)
297  size = self.general_registers_size[reg_name]
298 
299  pack_token = ""
300  if size == 1:
301  pack_token = "<B"
302  elif size == 2:
303  pack_token = "<H"
304  elif size == 4:
305  pack_token = "<I"
306  elif size == 8:
307  pack_token = "<Q"
308  else:
309  raise NotImplementedError("Unknown size")
310 
311  return struct.pack(pack_token, reg_value).encode("hex")
312 
313  def set_register(self, reg_num, value):
314  reg_name = self.general_registers_order[reg_num]
315  self.dbg.set_reg_value(reg_name, value)
316 
317  def read_register_by_name(self, reg_name):
318  return self.dbg.get_reg_value(reg_name)
319 
320  def read_memory(self, addr, size):
321  except_flag_vm = self.dbg.myjit.vm.get_exception()
322  try:
323  return self.dbg.get_mem_raw(addr, size).encode("hex")
324  except RuntimeError:
325  self.dbg.myjit.vm.set_exception(except_flag_vm)
326  return "00" * size
327 
328 
330 
331  "Extend GdbServer for x86 32bits purposes"
332 
333  general_registers_order = ["EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI",
334  "EDI", "EIP", "EFLAGS", "CS", "SS", "DS", "ES",
335  "FS", "GS"]
336 
337  general_registers_size = {"EAX": 4,
338  "ECX": 4,
339  "EDX": 4,
340  "EBX": 4,
341  "ESP": 4,
342  "EBP": 4,
343  "ESI": 4,
344  "EDI": 4,
345  "EIP": 4,
346  "EFLAGS": 2,
347  "CS": 2,
348  "SS": 2,
349  "DS": 2,
350  "ES": 2,
351  "FS": 2,
352  "GS": 2}
353 
354  register_ignore = [
355  "tf", "i_f", "nt", "rf", "vm", "ac", "vif", "vip", "i_d"]
356 
357  def read_register_by_name(self, reg_name):
358  sup_func = super(GdbServer_x86_32, self).read_register_by_name
359 
360  # Assert EIP on pc jitter
361  if reg_name == "EIP":
362  return self.dbg.myjit.pc
363 
364  # EFLAGS case
365  if reg_name == "EFLAGS":
366  val = 0
367  eflags_args = [
368  "cf", 1, "pf", 0, "af", 0, "zf", "nf", "tf", "i_f", "df", "of"]
369  eflags_args += ["nt", 0, "rf", "vm", "ac", "vif", "vip", "i_d"]
370  eflags_args += [0] * 10
371 
372  for i, arg in enumerate(eflags_args):
373  if isinstance(arg, str):
374  if arg not in self.register_ignore:
375  to_add = sup_func(arg)
376  else:
377  to_add = 0
378  else:
379  to_add = arg
380 
381  val |= (to_add << i)
382  return val
383  else:
384  return sup_func(reg_name)
385 
386 
388 
389  "Extend GdbServer for msp430 purposes"
390 
391  general_registers_order = ["PC", "SP", "SR", "R3", "R4", "R5", "R6", "R7",
392  "R8", "R9", "R10", "R11", "R12", "R13", "R14",
393  "R15"]
394 
395  general_registers_size = {"PC": 2,
396  "SP": 2,
397  "SR": 2,
398  "R3": 2,
399  "R2": 2,
400  "R5": 2,
401  "R6": 2,
402  "R7": 2,
403  "R8": 2,
404  "R9": 2,
405  "R10": 2,
406  "R11": 2,
407  "R12": 2,
408  "R13": 2,
409  "R12": 2,
410  "R15": 2}
411 
412  def read_register_by_name(self, reg_name):
413  sup_func = super(GdbServer_msp430, self).read_register_by_name
414  if reg_name == "SR":
415  o = sup_func('res')
416  o <<= 1
417  o |= sup_func('of')
418  o <<= 1
419  o |= sup_func('scg1')
420  o <<= 1
421  o |= sup_func('scg0')
422  o <<= 1
423  o |= sup_func('osc')
424  o <<= 1
425  o |= sup_func('cpuoff')
426  o <<= 1
427  o |= sup_func('gie')
428  o <<= 1
429  o |= sup_func('nf')
430  o <<= 1
431  o |= sup_func('zf')
432  o <<= 1
433  o |= sup_func('cf')
434 
435  return o
436  else:
437  return sup_func(reg_name)
438