1*f6aab3d8Srobertimport ctypes 2*f6aab3d8Srobertimport errno 3*f6aab3d8Srobertimport io 4*f6aab3d8Srobertimport threading 5*f6aab3d8Srobertimport socket 6*f6aab3d8Srobertimport traceback 7*f6aab3d8Srobertfrom lldbsuite.support import seven 8*f6aab3d8Srobert 9*f6aab3d8Srobertdef checksum(message): 10*f6aab3d8Srobert """ 11*f6aab3d8Srobert Calculate the GDB server protocol checksum of the message. 12*f6aab3d8Srobert 13*f6aab3d8Srobert The GDB server protocol uses a simple modulo 256 sum. 14*f6aab3d8Srobert """ 15*f6aab3d8Srobert check = 0 16*f6aab3d8Srobert for c in message: 17*f6aab3d8Srobert check += ord(c) 18*f6aab3d8Srobert return check % 256 19*f6aab3d8Srobert 20*f6aab3d8Srobert 21*f6aab3d8Srobertdef frame_packet(message): 22*f6aab3d8Srobert """ 23*f6aab3d8Srobert Create a framed packet that's ready to send over the GDB connection 24*f6aab3d8Srobert channel. 25*f6aab3d8Srobert 26*f6aab3d8Srobert Framing includes surrounding the message between $ and #, and appending 27*f6aab3d8Srobert a two character hex checksum. 28*f6aab3d8Srobert """ 29*f6aab3d8Srobert return "$%s#%02x" % (message, checksum(message)) 30*f6aab3d8Srobert 31*f6aab3d8Srobert 32*f6aab3d8Srobertdef escape_binary(message): 33*f6aab3d8Srobert """ 34*f6aab3d8Srobert Escape the binary message using the process described in the GDB server 35*f6aab3d8Srobert protocol documentation. 36*f6aab3d8Srobert 37*f6aab3d8Srobert Most bytes are sent through as-is, but $, #, and { are escaped by writing 38*f6aab3d8Srobert a { followed by the original byte mod 0x20. 39*f6aab3d8Srobert """ 40*f6aab3d8Srobert out = "" 41*f6aab3d8Srobert for c in message: 42*f6aab3d8Srobert d = ord(c) 43*f6aab3d8Srobert if d in (0x23, 0x24, 0x7d): 44*f6aab3d8Srobert out += chr(0x7d) 45*f6aab3d8Srobert out += chr(d ^ 0x20) 46*f6aab3d8Srobert else: 47*f6aab3d8Srobert out += c 48*f6aab3d8Srobert return out 49*f6aab3d8Srobert 50*f6aab3d8Srobert 51*f6aab3d8Srobertdef hex_encode_bytes(message): 52*f6aab3d8Srobert """ 53*f6aab3d8Srobert Encode the binary message by converting each byte into a two-character 54*f6aab3d8Srobert hex string. 55*f6aab3d8Srobert """ 56*f6aab3d8Srobert out = "" 57*f6aab3d8Srobert for c in message: 58*f6aab3d8Srobert out += "%02x" % ord(c) 59*f6aab3d8Srobert return out 60*f6aab3d8Srobert 61*f6aab3d8Srobert 62*f6aab3d8Srobertdef hex_decode_bytes(hex_bytes): 63*f6aab3d8Srobert """ 64*f6aab3d8Srobert Decode the hex string into a binary message by converting each two-character 65*f6aab3d8Srobert hex string into a single output byte. 66*f6aab3d8Srobert """ 67*f6aab3d8Srobert out = "" 68*f6aab3d8Srobert hex_len = len(hex_bytes) 69*f6aab3d8Srobert i = 0 70*f6aab3d8Srobert while i < hex_len - 1: 71*f6aab3d8Srobert out += chr(int(hex_bytes[i:i + 2], 16)) 72*f6aab3d8Srobert i += 2 73*f6aab3d8Srobert return out 74*f6aab3d8Srobert 75*f6aab3d8Srobert 76*f6aab3d8Srobertclass MockGDBServerResponder: 77*f6aab3d8Srobert """ 78*f6aab3d8Srobert A base class for handling client packets and issuing server responses for 79*f6aab3d8Srobert GDB tests. 80*f6aab3d8Srobert 81*f6aab3d8Srobert This handles many typical situations, while still allowing subclasses to 82*f6aab3d8Srobert completely customize their responses. 83*f6aab3d8Srobert 84*f6aab3d8Srobert Most subclasses will be interested in overriding the other() method, which 85*f6aab3d8Srobert handles any packet not recognized in the common packet handling code. 86*f6aab3d8Srobert """ 87*f6aab3d8Srobert 88*f6aab3d8Srobert registerCount = 40 89*f6aab3d8Srobert packetLog = None 90*f6aab3d8Srobert class RESPONSE_DISCONNECT: pass 91*f6aab3d8Srobert 92*f6aab3d8Srobert def __init__(self): 93*f6aab3d8Srobert self.packetLog = [] 94*f6aab3d8Srobert 95*f6aab3d8Srobert def respond(self, packet): 96*f6aab3d8Srobert """ 97*f6aab3d8Srobert Return the unframed packet data that the server should issue in response 98*f6aab3d8Srobert to the given packet received from the client. 99*f6aab3d8Srobert """ 100*f6aab3d8Srobert self.packetLog.append(packet) 101*f6aab3d8Srobert if packet is MockGDBServer.PACKET_INTERRUPT: 102*f6aab3d8Srobert return self.interrupt() 103*f6aab3d8Srobert if packet == "c": 104*f6aab3d8Srobert return self.cont() 105*f6aab3d8Srobert if packet.startswith("vCont;c"): 106*f6aab3d8Srobert return self.vCont(packet) 107*f6aab3d8Srobert if packet[0] == "A": 108*f6aab3d8Srobert return self.A(packet) 109*f6aab3d8Srobert if packet[0] == "D": 110*f6aab3d8Srobert return self.D(packet) 111*f6aab3d8Srobert if packet[0] == "g": 112*f6aab3d8Srobert return self.readRegisters() 113*f6aab3d8Srobert if packet[0] == "G": 114*f6aab3d8Srobert # Gxxxxxxxxxxx 115*f6aab3d8Srobert # Gxxxxxxxxxxx;thread:1234; 116*f6aab3d8Srobert return self.writeRegisters(packet[1:].split(';')[0]) 117*f6aab3d8Srobert if packet[0] == "p": 118*f6aab3d8Srobert regnum = packet[1:].split(';')[0] 119*f6aab3d8Srobert return self.readRegister(int(regnum, 16)) 120*f6aab3d8Srobert if packet[0] == "P": 121*f6aab3d8Srobert register, value = packet[1:].split("=") 122*f6aab3d8Srobert return self.writeRegister(int(register, 16), value) 123*f6aab3d8Srobert if packet[0] == "m": 124*f6aab3d8Srobert addr, length = [int(x, 16) for x in packet[1:].split(',')] 125*f6aab3d8Srobert return self.readMemory(addr, length) 126*f6aab3d8Srobert if packet[0] == "M": 127*f6aab3d8Srobert location, encoded_data = packet[1:].split(":") 128*f6aab3d8Srobert addr, length = [int(x, 16) for x in location.split(',')] 129*f6aab3d8Srobert return self.writeMemory(addr, encoded_data) 130*f6aab3d8Srobert if packet[0:7] == "qSymbol": 131*f6aab3d8Srobert return self.qSymbol(packet[8:]) 132*f6aab3d8Srobert if packet[0:10] == "qSupported": 133*f6aab3d8Srobert return self.qSupported(packet[11:].split(";")) 134*f6aab3d8Srobert if packet == "qfThreadInfo": 135*f6aab3d8Srobert return self.qfThreadInfo() 136*f6aab3d8Srobert if packet == "qsThreadInfo": 137*f6aab3d8Srobert return self.qsThreadInfo() 138*f6aab3d8Srobert if packet == "qC": 139*f6aab3d8Srobert return self.qC() 140*f6aab3d8Srobert if packet == "QEnableErrorStrings": 141*f6aab3d8Srobert return self.QEnableErrorStrings() 142*f6aab3d8Srobert if packet == "?": 143*f6aab3d8Srobert return self.haltReason() 144*f6aab3d8Srobert if packet == "s": 145*f6aab3d8Srobert return self.haltReason() 146*f6aab3d8Srobert if packet[0] == "H": 147*f6aab3d8Srobert tid = packet[2:] 148*f6aab3d8Srobert if "." in tid: 149*f6aab3d8Srobert assert tid.startswith("p") 150*f6aab3d8Srobert # TODO: do we want to do anything with PID? 151*f6aab3d8Srobert tid = tid.split(".", 1)[1] 152*f6aab3d8Srobert return self.selectThread(packet[1], int(tid, 16)) 153*f6aab3d8Srobert if packet[0:6] == "qXfer:": 154*f6aab3d8Srobert obj, read, annex, location = packet[6:].split(":") 155*f6aab3d8Srobert offset, length = [int(x, 16) for x in location.split(',')] 156*f6aab3d8Srobert data, has_more = self.qXferRead(obj, annex, offset, length) 157*f6aab3d8Srobert if data is not None: 158*f6aab3d8Srobert return self._qXferResponse(data, has_more) 159*f6aab3d8Srobert return "" 160*f6aab3d8Srobert if packet.startswith("vAttach;"): 161*f6aab3d8Srobert pid = packet.partition(';')[2] 162*f6aab3d8Srobert return self.vAttach(int(pid, 16)) 163*f6aab3d8Srobert if packet[0] == "Z": 164*f6aab3d8Srobert return self.setBreakpoint(packet) 165*f6aab3d8Srobert if packet.startswith("qThreadStopInfo"): 166*f6aab3d8Srobert threadnum = int (packet[15:], 16) 167*f6aab3d8Srobert return self.threadStopInfo(threadnum) 168*f6aab3d8Srobert if packet == "QThreadSuffixSupported": 169*f6aab3d8Srobert return self.QThreadSuffixSupported() 170*f6aab3d8Srobert if packet == "QListThreadsInStopReply": 171*f6aab3d8Srobert return self.QListThreadsInStopReply() 172*f6aab3d8Srobert if packet.startswith("qMemoryRegionInfo:"): 173*f6aab3d8Srobert return self.qMemoryRegionInfo(int(packet.split(':')[1], 16)) 174*f6aab3d8Srobert if packet == "qQueryGDBServer": 175*f6aab3d8Srobert return self.qQueryGDBServer() 176*f6aab3d8Srobert if packet == "qHostInfo": 177*f6aab3d8Srobert return self.qHostInfo() 178*f6aab3d8Srobert if packet == "qGetWorkingDir": 179*f6aab3d8Srobert return self.qGetWorkingDir() 180*f6aab3d8Srobert if packet == "qOffsets": 181*f6aab3d8Srobert return self.qOffsets(); 182*f6aab3d8Srobert if packet == "qProcessInfo": 183*f6aab3d8Srobert return self.qProcessInfo() 184*f6aab3d8Srobert if packet == "qsProcessInfo": 185*f6aab3d8Srobert return self.qsProcessInfo() 186*f6aab3d8Srobert if packet.startswith("qfProcessInfo"): 187*f6aab3d8Srobert return self.qfProcessInfo(packet) 188*f6aab3d8Srobert if packet.startswith("jGetLoadedDynamicLibrariesInfos"): 189*f6aab3d8Srobert return self.jGetLoadedDynamicLibrariesInfos(packet) 190*f6aab3d8Srobert if packet.startswith("qPathComplete:"): 191*f6aab3d8Srobert return self.qPathComplete() 192*f6aab3d8Srobert if packet.startswith("vFile:"): 193*f6aab3d8Srobert return self.vFile(packet) 194*f6aab3d8Srobert if packet.startswith("vRun;"): 195*f6aab3d8Srobert return self.vRun(packet) 196*f6aab3d8Srobert if packet.startswith("qLaunchSuccess"): 197*f6aab3d8Srobert return self.qLaunchSuccess() 198*f6aab3d8Srobert if packet.startswith("QEnvironment:"): 199*f6aab3d8Srobert return self.QEnvironment(packet) 200*f6aab3d8Srobert if packet.startswith("QEnvironmentHexEncoded:"): 201*f6aab3d8Srobert return self.QEnvironmentHexEncoded(packet) 202*f6aab3d8Srobert if packet.startswith("qRegisterInfo"): 203*f6aab3d8Srobert regnum = int(packet[len("qRegisterInfo"):], 16) 204*f6aab3d8Srobert return self.qRegisterInfo(regnum) 205*f6aab3d8Srobert if packet == "k": 206*f6aab3d8Srobert return self.k() 207*f6aab3d8Srobert 208*f6aab3d8Srobert return self.other(packet) 209*f6aab3d8Srobert 210*f6aab3d8Srobert def qsProcessInfo(self): 211*f6aab3d8Srobert return "E04" 212*f6aab3d8Srobert 213*f6aab3d8Srobert def qfProcessInfo(self, packet): 214*f6aab3d8Srobert return "E04" 215*f6aab3d8Srobert 216*f6aab3d8Srobert def jGetLoadedDynamicLibrariesInfos(self, packet): 217*f6aab3d8Srobert return "" 218*f6aab3d8Srobert 219*f6aab3d8Srobert def qGetWorkingDir(self): 220*f6aab3d8Srobert return "2f" 221*f6aab3d8Srobert 222*f6aab3d8Srobert def qOffsets(self): 223*f6aab3d8Srobert return "" 224*f6aab3d8Srobert 225*f6aab3d8Srobert def qProcessInfo(self): 226*f6aab3d8Srobert return "" 227*f6aab3d8Srobert 228*f6aab3d8Srobert def qHostInfo(self): 229*f6aab3d8Srobert return "ptrsize:8;endian:little;" 230*f6aab3d8Srobert 231*f6aab3d8Srobert def qQueryGDBServer(self): 232*f6aab3d8Srobert return "E04" 233*f6aab3d8Srobert 234*f6aab3d8Srobert def interrupt(self): 235*f6aab3d8Srobert raise self.UnexpectedPacketException() 236*f6aab3d8Srobert 237*f6aab3d8Srobert def cont(self): 238*f6aab3d8Srobert raise self.UnexpectedPacketException() 239*f6aab3d8Srobert 240*f6aab3d8Srobert def vCont(self, packet): 241*f6aab3d8Srobert raise self.UnexpectedPacketException() 242*f6aab3d8Srobert 243*f6aab3d8Srobert def A(self, packet): 244*f6aab3d8Srobert return "" 245*f6aab3d8Srobert 246*f6aab3d8Srobert def D(self, packet): 247*f6aab3d8Srobert return "OK" 248*f6aab3d8Srobert 249*f6aab3d8Srobert def readRegisters(self): 250*f6aab3d8Srobert return "00000000" * self.registerCount 251*f6aab3d8Srobert 252*f6aab3d8Srobert def readRegister(self, register): 253*f6aab3d8Srobert return "00000000" 254*f6aab3d8Srobert 255*f6aab3d8Srobert def writeRegisters(self, registers_hex): 256*f6aab3d8Srobert return "OK" 257*f6aab3d8Srobert 258*f6aab3d8Srobert def writeRegister(self, register, value_hex): 259*f6aab3d8Srobert return "OK" 260*f6aab3d8Srobert 261*f6aab3d8Srobert def readMemory(self, addr, length): 262*f6aab3d8Srobert return "00" * length 263*f6aab3d8Srobert 264*f6aab3d8Srobert def writeMemory(self, addr, data_hex): 265*f6aab3d8Srobert return "OK" 266*f6aab3d8Srobert 267*f6aab3d8Srobert def qSymbol(self, symbol_args): 268*f6aab3d8Srobert return "OK" 269*f6aab3d8Srobert 270*f6aab3d8Srobert def qSupported(self, client_supported): 271*f6aab3d8Srobert return "qXfer:features:read+;PacketSize=3fff;QStartNoAckMode+" 272*f6aab3d8Srobert 273*f6aab3d8Srobert def qfThreadInfo(self): 274*f6aab3d8Srobert return "l" 275*f6aab3d8Srobert 276*f6aab3d8Srobert def qsThreadInfo(self): 277*f6aab3d8Srobert return "l" 278*f6aab3d8Srobert 279*f6aab3d8Srobert def qC(self): 280*f6aab3d8Srobert return "QC0" 281*f6aab3d8Srobert 282*f6aab3d8Srobert def QEnableErrorStrings(self): 283*f6aab3d8Srobert return "OK" 284*f6aab3d8Srobert 285*f6aab3d8Srobert def haltReason(self): 286*f6aab3d8Srobert # SIGINT is 2, return type is 2 digit hex string 287*f6aab3d8Srobert return "S02" 288*f6aab3d8Srobert 289*f6aab3d8Srobert def qXferRead(self, obj, annex, offset, length): 290*f6aab3d8Srobert return None, False 291*f6aab3d8Srobert 292*f6aab3d8Srobert def _qXferResponse(self, data, has_more): 293*f6aab3d8Srobert return "%s%s" % ("m" if has_more else "l", escape_binary(data)) 294*f6aab3d8Srobert 295*f6aab3d8Srobert def vAttach(self, pid): 296*f6aab3d8Srobert raise self.UnexpectedPacketException() 297*f6aab3d8Srobert 298*f6aab3d8Srobert def selectThread(self, op, thread_id): 299*f6aab3d8Srobert return "OK" 300*f6aab3d8Srobert 301*f6aab3d8Srobert def setBreakpoint(self, packet): 302*f6aab3d8Srobert raise self.UnexpectedPacketException() 303*f6aab3d8Srobert 304*f6aab3d8Srobert def threadStopInfo(self, threadnum): 305*f6aab3d8Srobert return "" 306*f6aab3d8Srobert 307*f6aab3d8Srobert def other(self, packet): 308*f6aab3d8Srobert # empty string means unsupported 309*f6aab3d8Srobert return "" 310*f6aab3d8Srobert 311*f6aab3d8Srobert def QThreadSuffixSupported(self): 312*f6aab3d8Srobert return "" 313*f6aab3d8Srobert 314*f6aab3d8Srobert def QListThreadsInStopReply(self): 315*f6aab3d8Srobert return "" 316*f6aab3d8Srobert 317*f6aab3d8Srobert def qMemoryRegionInfo(self, addr): 318*f6aab3d8Srobert return "" 319*f6aab3d8Srobert 320*f6aab3d8Srobert def qPathComplete(self): 321*f6aab3d8Srobert return "" 322*f6aab3d8Srobert 323*f6aab3d8Srobert def vFile(self, packet): 324*f6aab3d8Srobert return "" 325*f6aab3d8Srobert 326*f6aab3d8Srobert def vRun(self, packet): 327*f6aab3d8Srobert return "" 328*f6aab3d8Srobert 329*f6aab3d8Srobert def qLaunchSuccess(self): 330*f6aab3d8Srobert return "" 331*f6aab3d8Srobert 332*f6aab3d8Srobert def QEnvironment(self, packet): 333*f6aab3d8Srobert return "OK" 334*f6aab3d8Srobert 335*f6aab3d8Srobert def QEnvironmentHexEncoded(self, packet): 336*f6aab3d8Srobert return "OK" 337*f6aab3d8Srobert 338*f6aab3d8Srobert def qRegisterInfo(self, num): 339*f6aab3d8Srobert return "" 340*f6aab3d8Srobert 341*f6aab3d8Srobert def k(self): 342*f6aab3d8Srobert return ["W01", self.RESPONSE_DISCONNECT] 343*f6aab3d8Srobert 344*f6aab3d8Srobert """ 345*f6aab3d8Srobert Raised when we receive a packet for which there is no default action. 346*f6aab3d8Srobert Override the responder class to implement behavior suitable for the test at 347*f6aab3d8Srobert hand. 348*f6aab3d8Srobert """ 349*f6aab3d8Srobert class UnexpectedPacketException(Exception): 350*f6aab3d8Srobert pass 351*f6aab3d8Srobert 352*f6aab3d8Srobert 353*f6aab3d8Srobertclass ServerChannel: 354*f6aab3d8Srobert """ 355*f6aab3d8Srobert A wrapper class for TCP or pty-based server. 356*f6aab3d8Srobert """ 357*f6aab3d8Srobert 358*f6aab3d8Srobert def get_connect_address(self): 359*f6aab3d8Srobert """Get address for the client to connect to.""" 360*f6aab3d8Srobert 361*f6aab3d8Srobert def get_connect_url(self): 362*f6aab3d8Srobert """Get URL suitable for process connect command.""" 363*f6aab3d8Srobert 364*f6aab3d8Srobert def close_server(self): 365*f6aab3d8Srobert """Close all resources used by the server.""" 366*f6aab3d8Srobert 367*f6aab3d8Srobert def accept(self): 368*f6aab3d8Srobert """Accept a single client connection to the server.""" 369*f6aab3d8Srobert 370*f6aab3d8Srobert def close_connection(self): 371*f6aab3d8Srobert """Close all resources used by the accepted connection.""" 372*f6aab3d8Srobert 373*f6aab3d8Srobert def recv(self): 374*f6aab3d8Srobert """Receive a data packet from the connected client.""" 375*f6aab3d8Srobert 376*f6aab3d8Srobert def sendall(self, data): 377*f6aab3d8Srobert """Send the data to the connected client.""" 378*f6aab3d8Srobert 379*f6aab3d8Srobert 380*f6aab3d8Srobertclass ServerSocket(ServerChannel): 381*f6aab3d8Srobert def __init__(self, family, type, proto, addr): 382*f6aab3d8Srobert self._server_socket = socket.socket(family, type, proto) 383*f6aab3d8Srobert self._connection = None 384*f6aab3d8Srobert 385*f6aab3d8Srobert self._server_socket.bind(addr) 386*f6aab3d8Srobert self._server_socket.listen(1) 387*f6aab3d8Srobert 388*f6aab3d8Srobert def close_server(self): 389*f6aab3d8Srobert self._server_socket.close() 390*f6aab3d8Srobert 391*f6aab3d8Srobert def accept(self): 392*f6aab3d8Srobert assert self._connection is None 393*f6aab3d8Srobert # accept() is stubborn and won't fail even when the socket is 394*f6aab3d8Srobert # shutdown, so we'll use a timeout 395*f6aab3d8Srobert self._server_socket.settimeout(30.0) 396*f6aab3d8Srobert client, client_addr = self._server_socket.accept() 397*f6aab3d8Srobert # The connected client inherits its timeout from self._socket, 398*f6aab3d8Srobert # but we'll use a blocking socket for the client 399*f6aab3d8Srobert client.settimeout(None) 400*f6aab3d8Srobert self._connection = client 401*f6aab3d8Srobert 402*f6aab3d8Srobert def close_connection(self): 403*f6aab3d8Srobert assert self._connection is not None 404*f6aab3d8Srobert self._connection.close() 405*f6aab3d8Srobert self._connection = None 406*f6aab3d8Srobert 407*f6aab3d8Srobert def recv(self): 408*f6aab3d8Srobert assert self._connection is not None 409*f6aab3d8Srobert return self._connection.recv(4096) 410*f6aab3d8Srobert 411*f6aab3d8Srobert def sendall(self, data): 412*f6aab3d8Srobert assert self._connection is not None 413*f6aab3d8Srobert return self._connection.sendall(data) 414*f6aab3d8Srobert 415*f6aab3d8Srobert 416*f6aab3d8Srobertclass TCPServerSocket(ServerSocket): 417*f6aab3d8Srobert def __init__(self): 418*f6aab3d8Srobert family, type, proto, _, addr = socket.getaddrinfo( 419*f6aab3d8Srobert "localhost", 0, proto=socket.IPPROTO_TCP)[0] 420*f6aab3d8Srobert super().__init__(family, type, proto, addr) 421*f6aab3d8Srobert 422*f6aab3d8Srobert def get_connect_address(self): 423*f6aab3d8Srobert return "[{}]:{}".format(*self._server_socket.getsockname()) 424*f6aab3d8Srobert 425*f6aab3d8Srobert def get_connect_url(self): 426*f6aab3d8Srobert return "connect://" + self.get_connect_address() 427*f6aab3d8Srobert 428*f6aab3d8Srobert 429*f6aab3d8Srobertclass UnixServerSocket(ServerSocket): 430*f6aab3d8Srobert def __init__(self, addr): 431*f6aab3d8Srobert super().__init__(socket.AF_UNIX, socket.SOCK_STREAM, 0, addr) 432*f6aab3d8Srobert 433*f6aab3d8Srobert def get_connect_address(self): 434*f6aab3d8Srobert return self._server_socket.getsockname() 435*f6aab3d8Srobert 436*f6aab3d8Srobert def get_connect_url(self): 437*f6aab3d8Srobert return "unix-connect://" + self.get_connect_address() 438*f6aab3d8Srobert 439*f6aab3d8Srobert 440*f6aab3d8Srobertclass PtyServerSocket(ServerChannel): 441*f6aab3d8Srobert def __init__(self): 442*f6aab3d8Srobert import pty 443*f6aab3d8Srobert import tty 444*f6aab3d8Srobert primary, secondary = pty.openpty() 445*f6aab3d8Srobert tty.setraw(primary) 446*f6aab3d8Srobert self._primary = io.FileIO(primary, 'r+b') 447*f6aab3d8Srobert self._secondary = io.FileIO(secondary, 'r+b') 448*f6aab3d8Srobert 449*f6aab3d8Srobert def get_connect_address(self): 450*f6aab3d8Srobert libc = ctypes.CDLL(None) 451*f6aab3d8Srobert libc.ptsname.argtypes = (ctypes.c_int,) 452*f6aab3d8Srobert libc.ptsname.restype = ctypes.c_char_p 453*f6aab3d8Srobert return libc.ptsname(self._primary.fileno()).decode() 454*f6aab3d8Srobert 455*f6aab3d8Srobert def get_connect_url(self): 456*f6aab3d8Srobert return "serial://" + self.get_connect_address() 457*f6aab3d8Srobert 458*f6aab3d8Srobert def close_server(self): 459*f6aab3d8Srobert self._secondary.close() 460*f6aab3d8Srobert self._primary.close() 461*f6aab3d8Srobert 462*f6aab3d8Srobert def recv(self): 463*f6aab3d8Srobert try: 464*f6aab3d8Srobert return self._primary.read(4096) 465*f6aab3d8Srobert except OSError as e: 466*f6aab3d8Srobert # closing the pty results in EIO on Linux, convert it to EOF 467*f6aab3d8Srobert if e.errno == errno.EIO: 468*f6aab3d8Srobert return b'' 469*f6aab3d8Srobert raise 470*f6aab3d8Srobert 471*f6aab3d8Srobert def sendall(self, data): 472*f6aab3d8Srobert return self._primary.write(data) 473*f6aab3d8Srobert 474*f6aab3d8Srobert 475*f6aab3d8Srobertclass MockGDBServer: 476*f6aab3d8Srobert """ 477*f6aab3d8Srobert A simple TCP-based GDB server that can test client behavior by receiving 478*f6aab3d8Srobert commands and issuing custom-tailored responses. 479*f6aab3d8Srobert 480*f6aab3d8Srobert Responses are generated via the .responder property, which should be an 481*f6aab3d8Srobert instance of a class based on MockGDBServerResponder. 482*f6aab3d8Srobert """ 483*f6aab3d8Srobert 484*f6aab3d8Srobert responder = None 485*f6aab3d8Srobert _socket = None 486*f6aab3d8Srobert _thread = None 487*f6aab3d8Srobert _receivedData = None 488*f6aab3d8Srobert _receivedDataOffset = None 489*f6aab3d8Srobert _shouldSendAck = True 490*f6aab3d8Srobert 491*f6aab3d8Srobert def __init__(self, socket): 492*f6aab3d8Srobert self._socket = socket 493*f6aab3d8Srobert self.responder = MockGDBServerResponder() 494*f6aab3d8Srobert 495*f6aab3d8Srobert def start(self): 496*f6aab3d8Srobert # Start a thread that waits for a client connection. 497*f6aab3d8Srobert self._thread = threading.Thread(target=self.run) 498*f6aab3d8Srobert self._thread.start() 499*f6aab3d8Srobert 500*f6aab3d8Srobert def stop(self): 501*f6aab3d8Srobert self._thread.join() 502*f6aab3d8Srobert self._thread = None 503*f6aab3d8Srobert 504*f6aab3d8Srobert def get_connect_address(self): 505*f6aab3d8Srobert return self._socket.get_connect_address() 506*f6aab3d8Srobert 507*f6aab3d8Srobert def get_connect_url(self): 508*f6aab3d8Srobert return self._socket.get_connect_url() 509*f6aab3d8Srobert 510*f6aab3d8Srobert def run(self): 511*f6aab3d8Srobert # For testing purposes, we only need to worry about one client 512*f6aab3d8Srobert # connecting just one time. 513*f6aab3d8Srobert try: 514*f6aab3d8Srobert self._socket.accept() 515*f6aab3d8Srobert except: 516*f6aab3d8Srobert traceback.print_exc() 517*f6aab3d8Srobert return 518*f6aab3d8Srobert self._shouldSendAck = True 519*f6aab3d8Srobert self._receivedData = "" 520*f6aab3d8Srobert self._receivedDataOffset = 0 521*f6aab3d8Srobert data = None 522*f6aab3d8Srobert try: 523*f6aab3d8Srobert while True: 524*f6aab3d8Srobert data = seven.bitcast_to_string(self._socket.recv()) 525*f6aab3d8Srobert if data is None or len(data) == 0: 526*f6aab3d8Srobert break 527*f6aab3d8Srobert self._receive(data) 528*f6aab3d8Srobert except self.TerminateConnectionException: 529*f6aab3d8Srobert pass 530*f6aab3d8Srobert except Exception as e: 531*f6aab3d8Srobert print("An exception happened when receiving the response from the gdb server. Closing the client...") 532*f6aab3d8Srobert traceback.print_exc() 533*f6aab3d8Srobert finally: 534*f6aab3d8Srobert self._socket.close_connection() 535*f6aab3d8Srobert self._socket.close_server() 536*f6aab3d8Srobert 537*f6aab3d8Srobert def _receive(self, data): 538*f6aab3d8Srobert """ 539*f6aab3d8Srobert Collects data, parses and responds to as many packets as exist. 540*f6aab3d8Srobert Any leftover data is kept for parsing the next time around. 541*f6aab3d8Srobert """ 542*f6aab3d8Srobert self._receivedData += data 543*f6aab3d8Srobert packet = self._parsePacket() 544*f6aab3d8Srobert while packet is not None: 545*f6aab3d8Srobert self._handlePacket(packet) 546*f6aab3d8Srobert packet = self._parsePacket() 547*f6aab3d8Srobert 548*f6aab3d8Srobert def _parsePacket(self): 549*f6aab3d8Srobert """ 550*f6aab3d8Srobert Reads bytes from self._receivedData, returning: 551*f6aab3d8Srobert - a packet's contents if a valid packet is found 552*f6aab3d8Srobert - the PACKET_ACK unique object if we got an ack 553*f6aab3d8Srobert - None if we only have a partial packet 554*f6aab3d8Srobert 555*f6aab3d8Srobert Raises an InvalidPacketException if unexpected data is received 556*f6aab3d8Srobert or if checksums fail. 557*f6aab3d8Srobert 558*f6aab3d8Srobert Once a complete packet is found at the front of self._receivedData, 559*f6aab3d8Srobert its data is removed form self._receivedData. 560*f6aab3d8Srobert """ 561*f6aab3d8Srobert data = self._receivedData 562*f6aab3d8Srobert i = self._receivedDataOffset 563*f6aab3d8Srobert data_len = len(data) 564*f6aab3d8Srobert if data_len == 0: 565*f6aab3d8Srobert return None 566*f6aab3d8Srobert if i == 0: 567*f6aab3d8Srobert # If we're looking at the start of the received data, that means 568*f6aab3d8Srobert # we're looking for the start of a new packet, denoted by a $. 569*f6aab3d8Srobert # It's also possible we'll see an ACK here, denoted by a + 570*f6aab3d8Srobert if data[0] == '+': 571*f6aab3d8Srobert self._receivedData = data[1:] 572*f6aab3d8Srobert return self.PACKET_ACK 573*f6aab3d8Srobert if ord(data[0]) == 3: 574*f6aab3d8Srobert self._receivedData = data[1:] 575*f6aab3d8Srobert return self.PACKET_INTERRUPT 576*f6aab3d8Srobert if data[0] == '$': 577*f6aab3d8Srobert i += 1 578*f6aab3d8Srobert else: 579*f6aab3d8Srobert raise self.InvalidPacketException( 580*f6aab3d8Srobert "Unexpected leading byte: %s" % data[0]) 581*f6aab3d8Srobert 582*f6aab3d8Srobert # If we're looking beyond the start of the received data, then we're 583*f6aab3d8Srobert # looking for the end of the packet content, denoted by a #. 584*f6aab3d8Srobert # Note that we pick up searching from where we left off last time 585*f6aab3d8Srobert while i < data_len and data[i] != '#': 586*f6aab3d8Srobert i += 1 587*f6aab3d8Srobert 588*f6aab3d8Srobert # If there isn't enough data left for a checksum, just remember where 589*f6aab3d8Srobert # we left off so we can pick up there the next time around 590*f6aab3d8Srobert if i > data_len - 3: 591*f6aab3d8Srobert self._receivedDataOffset = i 592*f6aab3d8Srobert return None 593*f6aab3d8Srobert 594*f6aab3d8Srobert # If we have enough data remaining for the checksum, extract it and 595*f6aab3d8Srobert # compare to the packet contents 596*f6aab3d8Srobert packet = data[1:i] 597*f6aab3d8Srobert i += 1 598*f6aab3d8Srobert try: 599*f6aab3d8Srobert check = int(data[i:i + 2], 16) 600*f6aab3d8Srobert except ValueError: 601*f6aab3d8Srobert raise self.InvalidPacketException("Checksum is not valid hex") 602*f6aab3d8Srobert i += 2 603*f6aab3d8Srobert if check != checksum(packet): 604*f6aab3d8Srobert raise self.InvalidPacketException( 605*f6aab3d8Srobert "Checksum %02x does not match content %02x" % 606*f6aab3d8Srobert (check, checksum(packet))) 607*f6aab3d8Srobert # remove parsed bytes from _receivedData and reset offset so parsing 608*f6aab3d8Srobert # can start on the next packet the next time around 609*f6aab3d8Srobert self._receivedData = data[i:] 610*f6aab3d8Srobert self._receivedDataOffset = 0 611*f6aab3d8Srobert return packet 612*f6aab3d8Srobert 613*f6aab3d8Srobert def _sendPacket(self, packet): 614*f6aab3d8Srobert self._socket.sendall(seven.bitcast_to_bytes(frame_packet(packet))) 615*f6aab3d8Srobert 616*f6aab3d8Srobert def _handlePacket(self, packet): 617*f6aab3d8Srobert if packet is self.PACKET_ACK: 618*f6aab3d8Srobert # Ignore ACKs from the client. For the future, we can consider 619*f6aab3d8Srobert # adding validation code to make sure the client only sends ACKs 620*f6aab3d8Srobert # when it's supposed to. 621*f6aab3d8Srobert return 622*f6aab3d8Srobert response = "" 623*f6aab3d8Srobert # We'll handle the ack stuff here since it's not something any of the 624*f6aab3d8Srobert # tests will be concerned about, and it'll get turned off quickly anyway. 625*f6aab3d8Srobert if self._shouldSendAck: 626*f6aab3d8Srobert self._socket.sendall(seven.bitcast_to_bytes('+')) 627*f6aab3d8Srobert if packet == "QStartNoAckMode": 628*f6aab3d8Srobert self._shouldSendAck = False 629*f6aab3d8Srobert response = "OK" 630*f6aab3d8Srobert elif self.responder is not None: 631*f6aab3d8Srobert # Delegate everything else to our responder 632*f6aab3d8Srobert response = self.responder.respond(packet) 633*f6aab3d8Srobert if not isinstance(response, list): 634*f6aab3d8Srobert response = [response] 635*f6aab3d8Srobert for part in response: 636*f6aab3d8Srobert if part is MockGDBServerResponder.RESPONSE_DISCONNECT: 637*f6aab3d8Srobert raise self.TerminateConnectionException() 638*f6aab3d8Srobert self._sendPacket(part) 639*f6aab3d8Srobert 640*f6aab3d8Srobert PACKET_ACK = object() 641*f6aab3d8Srobert PACKET_INTERRUPT = object() 642*f6aab3d8Srobert 643*f6aab3d8Srobert class TerminateConnectionException(Exception): 644*f6aab3d8Srobert pass 645*f6aab3d8Srobert 646*f6aab3d8Srobert class InvalidPacketException(Exception): 647*f6aab3d8Srobert pass 648