gdbstub.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2020 Intel Corporation
  4. #
  5. # SPDX-License-Identifier: Apache-2.0
  6. import abc
  7. import binascii
  8. import logging
  9. logger = logging.getLogger("gdbstub")
  10. class GdbStub(abc.ABC):
  11. def __init__(self, logfile, elffile):
  12. self.logfile = logfile
  13. self.elffile = elffile
  14. self.socket = None
  15. self.gdb_signal = None
  16. mem_regions = list()
  17. for r in logfile.get_memory_regions():
  18. mem_regions.append(r)
  19. for r in elffile.get_memory_regions():
  20. mem_regions.append(r)
  21. self.mem_regions = mem_regions
  22. def get_gdb_packet(self):
  23. socket = self.socket
  24. if socket is None:
  25. return None
  26. data = b''
  27. checksum = 0
  28. # Wait for '$'
  29. while True:
  30. ch = socket.recv(1)
  31. if ch == b'$':
  32. break
  33. # Get a full packet
  34. while True:
  35. ch = socket.recv(1)
  36. if ch == b'#':
  37. # End of packet
  38. break
  39. checksum += ord(ch)
  40. data += ch
  41. # Get checksum (2-bytes)
  42. ch = socket.recv(2)
  43. in_chksum = ord(binascii.unhexlify(ch))
  44. logger.debug(f"Received GDB packet: {data}")
  45. if (checksum % 256) == in_chksum:
  46. # ACK
  47. logger.debug("ACK")
  48. socket.send(b'+')
  49. return data
  50. else:
  51. # NACK
  52. logger.debug(f"NACK (checksum {in_chksum} != {checksum}")
  53. socket.send(b'-')
  54. return None
  55. def put_gdb_packet(self, data):
  56. socket = self.socket
  57. if socket is None:
  58. return
  59. checksum = 0
  60. for d in data:
  61. checksum += d
  62. pkt = b'$' + data + b'#'
  63. checksum = checksum % 256
  64. pkt += format(checksum, "02X").encode()
  65. logger.debug(f"Sending GDB packet: {pkt}")
  66. socket.send(pkt)
  67. def handle_signal_query_packet(self):
  68. # the '?' packet
  69. pkt = b'S'
  70. pkt += format(self.gdb_signal, "02X").encode()
  71. self.put_gdb_packet(pkt)
  72. @abc.abstractmethod
  73. def handle_register_group_read_packet(self):
  74. # the 'g' packet for reading a group of registers
  75. pass
  76. def handle_register_group_write_packet(self):
  77. # the 'G' packet for writing to a group of registers
  78. #
  79. # We don't support writing so return error
  80. self.put_gdb_packet(b"E01")
  81. def handle_register_single_read_packet(self, pkt):
  82. # the 'p' packet for reading a single register
  83. self.put_gdb_packet(b"E01")
  84. def handle_register_single_write_packet(self, pkt):
  85. # the 'P' packet for writing to registers
  86. #
  87. # We don't support writing so return error
  88. self.put_gdb_packet(b"E01")
  89. def handle_memory_read_packet(self, pkt):
  90. # the 'm' packet for reading memory: m<addr>,<len>
  91. def get_mem_region(addr):
  92. for r in self.mem_regions:
  93. if r['start'] <= addr <= r['end']:
  94. return r
  95. return None
  96. # extract address and length from packet
  97. # and convert them into usable integer values
  98. str_addr, str_length = pkt[1:].split(b',')
  99. s_addr = int(b'0x' + str_addr, 16)
  100. length = int(b'0x' + str_length, 16)
  101. # FIXME: Need more efficient way of extracting memory content
  102. remaining = length
  103. addr = s_addr
  104. barray = b''
  105. r = get_mem_region(addr)
  106. while remaining > 0:
  107. if r is None:
  108. barray = None
  109. break
  110. if addr > r['end']:
  111. r = get_mem_region(addr)
  112. continue
  113. offset = addr - r['start']
  114. barray += r['data'][offset:offset+1]
  115. addr += 1
  116. remaining -= 1
  117. if barray is not None:
  118. pkt = binascii.hexlify(barray)
  119. self.put_gdb_packet(pkt)
  120. else:
  121. self.put_gdb_packet(b"E01")
  122. def handle_memory_write_packet(self, pkt):
  123. # the 'M' packet for writing to memory
  124. #
  125. # We don't support writing so return error
  126. self.put_gdb_packet(b"E02")
  127. def handle_general_query_packet(self, pkt):
  128. self.put_gdb_packet(b'')
  129. def run(self, socket):
  130. self.socket = socket
  131. while True:
  132. pkt = self.get_gdb_packet()
  133. if pkt is None:
  134. continue
  135. pkt_type = pkt[0:1]
  136. logger.debug(f"Got packet type: {pkt_type}")
  137. if pkt_type == b'?':
  138. self.handle_signal_query_packet()
  139. elif pkt_type in (b'C', b'S'):
  140. # Continue/stepping execution, which is not supported.
  141. # So signal exception again
  142. self.handle_signal_query_packet()
  143. elif pkt_type == b'g':
  144. self.handle_register_group_read_packet()
  145. elif pkt_type == b'G':
  146. self.handle_register_group_write_packet()
  147. elif pkt_type == b'p':
  148. self.handle_register_single_read_packet(pkt)
  149. elif pkt_type == b'P':
  150. self.handle_register_single_write_packet(pkt)
  151. elif pkt_type == b'm':
  152. self.handle_memory_read_packet(pkt)
  153. elif pkt_type == b'M':
  154. self.handle_memory_write_packet(pkt)
  155. elif pkt_type == b'q':
  156. self.handle_general_query_packet(pkt)
  157. elif pkt_type == b'k':
  158. # GDB quits
  159. break
  160. else:
  161. self.put_gdb_packet(b'')