1import logging 2from .interface import Interface 3from . import rsprotocol 4import random 5 6 7class GDBServer(object): 8 """instance of gdbserver""" 9 def __init__(self, backing_instance): 10 super().__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 as 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.decode() 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 42 # ignore if empty or ack messages 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 as e: 148 logging.error("Failed to get register information query: %s error: %s" % (query, e)) 149 return rsprotocol.Message(bytes) 150 151 def getRegisterData(self, query): 152 if query[0] == 'g': 153 #TODO should implement this sometime. 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 as e: 168 logging.error("Failed to get register information query: %s error: %s" % (query, e)) 169 return rsprotocol.Message(bytes) 170 171 def getRegisterInfo(self, query): 172 bytes = '' 173 try: 174 query_index = query.replace('qRegisterInfo', '') 175 regnum = int(query_index, 16) 176 bytes = self.process.getRegisterInfo(regnum) 177 except Exception as e: 178 logging.error("Non-fatal: Failed to get register information: query: %s error: %s" % (query, e)) 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 as 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 as 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 as 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 as e: 223 logging.error("Failed to get QC info") 224 225 return rsprotocol.Message('QC'+tid) 226 227 def kill(self): 228 pass 229