X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/7e41aa883dd258f888d0470250eead40a53ef1f5..3903760236c30e3b5ace7a4eefac3a269d68957c:/tools/lldbmacros/usertaskdebugging/gdbserver.py diff --git a/tools/lldbmacros/usertaskdebugging/gdbserver.py b/tools/lldbmacros/usertaskdebugging/gdbserver.py new file mode 100644 index 000000000..19b871adb --- /dev/null +++ b/tools/lldbmacros/usertaskdebugging/gdbserver.py @@ -0,0 +1,228 @@ +import logging +from interface import Interface +import rsprotocol +import random + + +class GDBServer(object): + """instance of gdbserver""" + def __init__(self, backing_instance): + super(GDBServer, self).__init__() + self.process = backing_instance + self.portnum = random.randint(2000, 8000) + logging.info("Starting gdb server for localhost:%d" % self.portnum) + self.conn = Interface('localhost', self.portnum) + self.version_string = 'name:kdbserver;version:0.1' + + def run(self): + if not self.conn.connect(): + logging.critical("No client connected. Bailing.") + return False + + logging.debug('Starting gdb server.') + + while True: + #loop for running the server. + #read command + readBytes = "" + + while True: + try: + p_bytes = self.conn.read() + except Exception, e: + logging.warn("found exception in read %s" % (str(e))) + logging.debug("currentbytes: %s" % readBytes) + readBytes = '' + break + readBytes += p_bytes + p_begin = readBytes.find('$') + p_end = readBytes.find('#') + if p_begin >= 0 and p_end >= 0 and p_end > p_begin: + break + #if empty message or acks just ignore + if readBytes in ('', '+'): + logging.debug('ignoring message: %s' % readBytes) + continue + req_msg = rsprotocol.Message.fromRSPByteData(readBytes) + resp = self.handleMessage(req_msg) + #in case resp is to detach + if resp is None: + return True + for r_msg in resp: + logging.debug("response: %s" % r_msg.getRSPByteData()) + self.conn.write(r_msg.getRSPByteData()) + return True + + def handleMessage(self, msg): + """ return array of messages that needs to responded. """ + query = msg.getData() + replymsgs = [] + sendAck = None + logging.debug('RCV:' + query) + + if query == "?": + h_msg = rsprotocol.Message(self.process.getSignalInfo()) + replymsgs.append(h_msg) + + elif query[0] == 'm': + replymsgs.append(self.getMemory(query)) + + elif query in ('qVAttachOrWaitSupported'): + logging.debug('Ignoring query %s' % query) + replymsgs.append(rsprotocol.UnSupportedMessage) + + elif query == "qC": + replymsgs.append(self.getCurrentThreadID(query)) + + elif query[0] in ('z', 'Z'): + logging.debug('Ignoring breakpoint query %s' % query) + replymsgs.append(rsprotocol.UnSupportedMessage) + + elif query[0] in ('g', 'p'): + replymsgs.append(self.getRegisterData(query)) + + elif query[0] in ('P', 'G'): + # we do not support writing into registers + replymsgs.append(rsprotocol.Message('E05')) + + elif query in ('QStartNoAckMode'): + replymsgs.append(rsprotocol.OKMessage) + sendAck = True + + elif query in ('QListThreadsInStopReply', 'QThreadSuffixSupported'): + replymsgs.append(rsprotocol.OKMessage) + + elif query == 'qGDBServerVersion': + replymsgs.append(rsprotocol.Message(self.version_string)) + + elif query == 'qShlibInfoAddr': + #return shared library info address if any + replymsgs.append(self.getSharedLibInfoAddress(query)) + + elif query == 'qProcessInfo': + replymsgs.append(self.getProcessInfo(query)) + + elif query == 'qHostInfo': + h_msg = rsprotocol.Message(self.process.getHostInfo()) + replymsgs.append(h_msg) + + elif query == 'vCont?': + replymsgs.append(rsprotocol.Message('vCont;')) + + elif query == 'D': + logging.info('Client requested to detach.') + return None + + elif query.find('qRegisterInfo') >= 0: + replymsgs.append(self.getRegisterInfo(query)) + + elif query.find('qMemoryRegionInfo') >= 0: + replymsgs.append(self.getMemoryRegionInfo(query)) + + elif query.find('qThreadStopInfo') >= 0 or query in ('qfThreadInfo', 'qsThreadInfo'): + replymsgs.append(self.getThreadRegistersInfo(query)) + + else: + replymsgs.append(rsprotocol.UnSupportedMessage) + + if sendAck is not None: + if sendAck: + replymsgs.insert(0, rsprotocol.AckMessage) + else: + replymsgs.insert(0, rsprotocol.NAckMessage) + + return replymsgs + + def getThreadRegistersInfo(self, query): + bytes = '' + if query == 'qfThreadInfo': + bytes = self.process.getFirstThreadInfo() + elif query == 'qsThreadInfo': + bytes = self.process.getSubsequestThreadInfo() + else: + try: + query = query.replace('qThreadStopInfo', '') + tid = int(query, 16) + bytes = self.process.getThreadStopInfo(tid) + except Exception, e: + logging.error("Failed to get register information query: %s error: %s" % (query, e.message)) + return rsprotocol.Message(bytes) + + def getRegisterData(self, query): + if query[0] == 'g': + #TODO should implement thissometime. Considering getThreadRegistersInfo is there + #we wont need this one. + return rsprotocol.UnSupportedMessage + + #the query is of type p;thread:; + bytes = '' + try: + args = query[1:].split(';') + if len(args) > 0: + regnum = int(args[0], 16) + if args[1].find('thread') >= 0: + threadid = int(args[1].split(':')[-1], 16) + bytes = self.process.getRegisterDataForThread(threadid, regnum) + logging.debug('REGISTER INFO bytes = ' + bytes) + except Exception, e: + logging.error("Failed to get register information query: %s error: %s" % (query, e.message)) + return rsprotocol.Message(bytes) + + def getRegisterInfo(self, query): + bytes = '' + try: + query = query.replace('qRegisterInfo', '') + regnum = int(query, 16) + bytes = self.process.getRegisterInfo(regnum) + except Exception, e: + logging.error("Failed to get register information error: %s" % e.message) + return rsprotocol.Message(bytes) + + def getMemory(self, query): + query = query[1:] + addr, size = query.split(',') + mem_address = int(addr, 16) + mem_size = int(size, 16) + bytes = '' + try: + bytes = self.process.readMemory(mem_address, mem_size) + except Exception, e: + logging.warn('Failed to read data %s' % str(e)) + return rsprotocol.Message('E03') + return rsprotocol.Message(bytes) + + def getMemoryRegionInfo(self, query): + return rsprotocol.UnSupportedMessage + + def setMemory(self, query): + logging.info('Not supporting writing to memory. %s' % query) + return rsprotocol.Message('E09') + + def getProcessInfo(self, query): + data = '' + try: + data = self.process.getProcessInfo() + except Exception, e: + logging.error("Failed to get process information") + return rsprotocol.Message(data) + + def getSharedLibInfoAddress(self, query): + data = 'E44' + try: + data = self.process.getSharedLibInfoAddress() + data = self.process.encodeThreadID(data) + except Exception, e: + logging.error("Failed to get Shared Library information") + return rsprotocol.Message(data) + + def getCurrentThreadID(self, query): + tid = '0' + try: + tid = '%x' % (self.process.getCurrentThreadID()) + except Exception, e: + logging.error("Failed to get QC info") + + return rsprotocol.Message('QC'+tid) + + def kill(self): + pass