1
+ from abc import ABC , abstractmethod
1
2
import ctypes
2
3
import errno
3
4
import io
4
5
import threading
5
6
import socket
6
7
import traceback
7
8
from lldbsuite .support import seven
9
+ from typing import Optional
8
10
9
11
10
12
def checksum (message ):
@@ -86,8 +88,8 @@ class MockGDBServerResponder:
86
88
handles any packet not recognized in the common packet handling code.
87
89
"""
88
90
89
- registerCount = 40
90
- packetLog = None
91
+ registerCount : int = 40
92
+ packetLog : Optional [ list [ str ]] = None
91
93
92
94
class RESPONSE_DISCONNECT :
93
95
pass
@@ -103,6 +105,7 @@ def respond(self, packet):
103
105
Return the unframed packet data that the server should issue in response
104
106
to the given packet received from the client.
105
107
"""
108
+ assert self .packetLog is not None
106
109
self .packetLog .append (packet )
107
110
if packet is MockGDBServer .PACKET_INTERRUPT :
108
111
return self .interrupt ()
@@ -242,7 +245,7 @@ def qProcessInfo(self):
242
245
def qHostInfo (self ):
243
246
return "ptrsize:8;endian:little;"
244
247
245
- def qEcho (self ):
248
+ def qEcho (self , _ : int ):
246
249
return "E04"
247
250
248
251
def qQueryGDBServer (self ):
@@ -263,10 +266,10 @@ def A(self, packet):
263
266
def D (self , packet ):
264
267
return "OK"
265
268
266
- def readRegisters (self ):
269
+ def readRegisters (self ) -> str :
267
270
return "00000000" * self .registerCount
268
271
269
- def readRegister (self , register ) :
272
+ def readRegister (self , register : int ) -> str :
270
273
return "00000000"
271
274
272
275
def writeRegisters (self , registers_hex ):
@@ -306,7 +309,8 @@ def haltReason(self):
306
309
# SIGINT is 2, return type is 2 digit hex string
307
310
return "S02"
308
311
309
- def qXferRead (self , obj , annex , offset , length ):
312
+ def qXferRead (self , obj : str , annex : str , offset : int ,
313
+ length : int ) -> tuple [str | None , bool ]:
310
314
return None , False
311
315
312
316
def _qXferResponse (self , data , has_more ):
@@ -374,15 +378,17 @@ class UnexpectedPacketException(Exception):
374
378
pass
375
379
376
380
377
- class ServerChannel :
381
+ class ServerChannel ( ABC ) :
378
382
"""
379
383
A wrapper class for TCP or pty-based server.
380
384
"""
381
385
382
- def get_connect_address (self ):
386
+ @abstractmethod
387
+ def get_connect_address (self ) -> str :
383
388
"""Get address for the client to connect to."""
384
389
385
- def get_connect_url (self ):
390
+ @abstractmethod
391
+ def get_connect_url (self ) -> str :
386
392
"""Get URL suitable for process connect command."""
387
393
388
394
def close_server (self ):
@@ -394,10 +400,12 @@ def accept(self):
394
400
def close_connection (self ):
395
401
"""Close all resources used by the accepted connection."""
396
402
397
- def recv (self ):
403
+ @abstractmethod
404
+ def recv (self ) -> bytes :
398
405
"""Receive a data packet from the connected client."""
399
406
400
- def sendall (self , data ):
407
+ @abstractmethod
408
+ def sendall (self , data : bytes ) -> None :
401
409
"""Send the data to the connected client."""
402
410
403
411
@@ -428,11 +436,11 @@ def close_connection(self):
428
436
self ._connection .close ()
429
437
self ._connection = None
430
438
431
- def recv (self ):
439
+ def recv (self ) -> bytes :
432
440
assert self ._connection is not None
433
441
return self ._connection .recv (4096 )
434
442
435
- def sendall (self , data ) :
443
+ def sendall (self , data : bytes ) -> None :
436
444
assert self ._connection is not None
437
445
return self ._connection .sendall (data )
438
446
@@ -444,21 +452,21 @@ def __init__(self):
444
452
)[0 ]
445
453
super ().__init__ (family , type , proto , addr )
446
454
447
- def get_connect_address (self ):
455
+ def get_connect_address (self ) -> str :
448
456
return "[{}]:{}" .format (* self ._server_socket .getsockname ())
449
457
450
- def get_connect_url (self ):
458
+ def get_connect_url (self ) -> str :
451
459
return "connect://" + self .get_connect_address ()
452
460
453
461
454
462
class UnixServerSocket (ServerSocket ):
455
463
def __init__ (self , addr ):
456
464
super ().__init__ (socket .AF_UNIX , socket .SOCK_STREAM , 0 , addr )
457
465
458
- def get_connect_address (self ):
466
+ def get_connect_address (self ) -> str :
459
467
return self ._server_socket .getsockname ()
460
468
461
- def get_connect_url (self ):
469
+ def get_connect_url (self ) -> str :
462
470
return "unix-connect://" + self .get_connect_address ()
463
471
464
472
@@ -472,7 +480,7 @@ def __init__(self):
472
480
self ._primary = io .FileIO (primary , "r+b" )
473
481
self ._secondary = io .FileIO (secondary , "r+b" )
474
482
475
- def get_connect_address (self ):
483
+ def get_connect_address (self ) -> str :
476
484
libc = ctypes .CDLL (None )
477
485
libc .ptsname .argtypes = (ctypes .c_int ,)
478
486
libc .ptsname .restype = ctypes .c_char_p
@@ -485,7 +493,7 @@ def close_server(self):
485
493
self ._secondary .close ()
486
494
self ._primary .close ()
487
495
488
- def recv (self ):
496
+ def recv (self ) -> bytes :
489
497
try :
490
498
return self ._primary .read (4096 )
491
499
except OSError as e :
@@ -494,8 +502,8 @@ def recv(self):
494
502
return b""
495
503
raise
496
504
497
- def sendall (self , data ) :
498
- return self ._primary .write (data )
505
+ def sendall (self , data : bytes ) -> None :
506
+ self ._primary .write (data )
499
507
500
508
501
509
class MockGDBServer :
@@ -528,18 +536,21 @@ def stop(self):
528
536
self ._thread .join ()
529
537
self ._thread = None
530
538
531
- def get_connect_address (self ):
539
+ def get_connect_address (self ) -> str :
540
+ assert self ._socket is not None
532
541
return self ._socket .get_connect_address ()
533
542
534
- def get_connect_url (self ):
543
+ def get_connect_url (self ) -> str :
544
+ assert self ._socket is not None
535
545
return self ._socket .get_connect_url ()
536
546
537
547
def run (self ):
548
+ assert self ._socket is not None
538
549
# For testing purposes, we only need to worry about one client
539
550
# connecting just one time.
540
551
try :
541
552
self ._socket .accept ()
542
- except :
553
+ except Exception :
543
554
traceback .print_exc ()
544
555
return
545
556
self ._shouldSendAck = True
@@ -554,7 +565,7 @@ def run(self):
554
565
self ._receive (data )
555
566
except self .TerminateConnectionException :
556
567
pass
557
- except Exception as e :
568
+ except Exception :
558
569
print (
559
570
"An exception happened when receiving the response from the gdb server. Closing the client..."
560
571
)
@@ -587,7 +598,9 @@ def _parsePacket(self):
587
598
Once a complete packet is found at the front of self._receivedData,
588
599
its data is removed form self._receivedData.
589
600
"""
601
+ assert self ._receivedData is not None
590
602
data = self ._receivedData
603
+ assert self ._receivedDataOffset is not None
591
604
i = self ._receivedDataOffset
592
605
data_len = len (data )
593
606
if data_len == 0 :
@@ -640,10 +653,13 @@ def _parsePacket(self):
640
653
self ._receivedDataOffset = 0
641
654
return packet
642
655
643
- def _sendPacket (self , packet ):
644
- self ._socket .sendall (seven .bitcast_to_bytes (frame_packet (packet )))
656
+ def _sendPacket (self , packet : str ):
657
+ assert self ._socket is not None
658
+ framed_packet = seven .bitcast_to_bytes (frame_packet (packet ))
659
+ self ._socket .sendall (framed_packet )
645
660
646
661
def _handlePacket (self , packet ):
662
+ assert self ._socket is not None
647
663
if packet is self .PACKET_ACK :
648
664
# Ignore ACKs from the client. For the future, we can consider
649
665
# adding validation code to make sure the client only sends ACKs
0 commit comments