33
44#include "debugger.h"
55#include "gdbserver.h"
6+ #include "gdbserver_remote_commands.h"
67#include "packets.h"
78#include "arch.h"
89#include "gdbserver_utils.h"
3637#include <sys/types.h>
3738#include <semaphore.h>
3839
39- typedef uint8_t (* trapped_action_t )(const void * data , void * response );
40-
4140static int gdbserver_socket ;
4241int gdbserver_client_socket = -1 ; // Made non-static so packets.c can access it
4342uint8_t tmpbuf [0x20000 ]; // Made non-static so vfile_ext.c can access it
4443static volatile char gdbserver_trapped = 0 ;
45- static volatile char gdbserver_do_not_report_trap = 0 ;
4644static int gdbserver_port = 0 ;
45+ static int gdbserver_last_trap_reason = DEBUG_TRAP_REASON_SIGNAL_RECEIVED ;
4746
4847static pthread_t network_thread_id ;
4948static trapped_action_t scheduled_action = NULL ;
@@ -54,7 +53,9 @@ static uint8_t scheduled_action_response_delivered = 0;
5453static pthread_cond_t trapped_cond ;
5554static pthread_cond_t response_cond ;
5655static pthread_mutex_t trap_process_mutex ;
57- static pthread_mutex_t network_mutex ;
56+ static pthread_mutex_t network_read_mutex ;
57+ static pthread_mutex_t network_write_mutex ;
58+ static int gdbserver_reset_event = -1 ;
5859
5960/** vSpectranext autoboot: if true at machine_reset, apply ram mount + autoboot once, then clear. */
6061static bool spectranext_autoboot = false;
@@ -77,7 +78,38 @@ static libspectrum_word* registers[] = {
7778};
7879
7980static uint8_t gdbserver_detrap ();
80- static uint8_t gdbserver_execute_on_main_thread (trapped_action_t call , const void * data , void * response );
81+ static void gdbserver_send_stop_reply (int trap_reason );
82+
83+ void gdbserver_lock_network_write (void )
84+ {
85+ pthread_mutex_lock (& network_write_mutex );
86+ }
87+
88+ void gdbserver_unlock_network_write (void )
89+ {
90+ pthread_mutex_unlock (& network_write_mutex );
91+ }
92+
93+ static void gdbserver_send_stop_reply (int trap_reason )
94+ {
95+ char tbuf [64 ];
96+ int signal ;
97+
98+ switch (trap_reason )
99+ {
100+ case DEBUG_TRAP_REASON_BREAKPOINT :
101+ signal = 5 ; /* SIGTRAP */
102+ break ;
103+ case DEBUG_TRAP_REASON_SIGNAL_RECEIVED :
104+ case DEBUG_TRAP_REASON_OTHER :
105+ default :
106+ signal = 2 ; /* SIGINT */
107+ break ;
108+ }
109+
110+ sprintf (tbuf , "T%02xthread:p%02x.%02x;" , signal , 1 , 1 );
111+ packet_send_message ((const uint8_t * )tbuf , strlen (tbuf ));
112+ }
81113
82114static uint8_t action_get_registers (const void * arg , void * response );
83115static uint8_t action_set_registers (const void * arg , void * response );
@@ -88,7 +120,6 @@ static uint8_t action_set_register(const void* arg, void* response);
88120static uint8_t action_set_breakpoint (const void * arg , void * response );
89121static uint8_t action_remove_breakpoint (const void * arg , void * response );
90122static uint8_t action_step_instruction (const void * arg , void * response );
91- static uint8_t action_reset (const void * arg , void * response );
92123static uint8_t action_autoboot (const void * arg , void * response );
93124
94125struct action_mem_args_t {
@@ -113,6 +144,75 @@ struct action_breakpoint_args_t {
113144 size_t maddr , mlen ;
114145};
115146
147+ void gdbserver_send_remote_console_output (const char * text )
148+ {
149+ size_t len = strlen (text );
150+
151+ if (gdbserver_client_socket == -1 || !gdbserver_debugging_enabled )
152+ return ;
153+
154+ if (1 + len * 2 >= sizeof (tmpbuf ))
155+ len = (sizeof (tmpbuf ) - 1 ) / 2 ;
156+
157+ tmpbuf [0 ] = 'O' ;
158+ mem2hex ((const uint8_t * )text , (char * )& tmpbuf [1 ], (int )len );
159+ packet_send_message (tmpbuf , 1 + len * 2 );
160+ }
161+
162+ static int decode_remote_command (const char * hex_command , char * command , size_t command_size )
163+ {
164+ size_t hex_len = strlen (hex_command );
165+
166+ if ((hex_len & 1 ) != 0 )
167+ return 0 ;
168+
169+ if (hex_len / 2 >= command_size )
170+ return 0 ;
171+
172+ hex2mem (hex_command , (uint8_t * )command , (int )(hex_len / 2 ));
173+ command [hex_len / 2 ] = '\0' ;
174+ return 1 ;
175+ }
176+
177+ static void process_remote_command (const char * hex_command )
178+ {
179+ const struct remote_command_entry_t * entry ;
180+ char command [256 ];
181+
182+ if (!decode_remote_command (hex_command , command , sizeof (command ))) {
183+ packet_send_message ((const uint8_t * )"E01" , 3 );
184+ return ;
185+ }
186+
187+ for (entry = remote_commands ; entry -> name ; entry ++ ) {
188+ if (!strcmp (command , entry -> name )) {
189+ if (entry -> handler ())
190+ packet_send_message ((const uint8_t * )"E01" , 3 );
191+ else
192+ packet_send_message ((const uint8_t * )"OK" , 2 );
193+ return ;
194+ }
195+ }
196+
197+ packet_send_message ((const uint8_t * )"E04" , 3 );
198+ }
199+
200+ static void gdbserver_reset_event_fn (libspectrum_dword event_time , int type ,
201+ void * user_data )
202+ {
203+ (void )event_time ;
204+ (void )type ;
205+ (void )user_data ;
206+
207+ machine_reset (0 );
208+ }
209+
210+ uint8_t gdbserver_reset_via_remote_command (void )
211+ {
212+ gdbserver_schedule_reset ();
213+ return 0 ;
214+ }
215+
116216static void process_xfer (const char * name , char * args )
117217{
118218 const char * mode = args ;
@@ -132,6 +232,11 @@ static void process_query(char *payload)
132232 const char * name ;
133233 char * args ;
134234
235+ if (payload == strstr (payload , "Rcmd," )) {
236+ process_remote_command (payload + 5 );
237+ return ;
238+ }
239+
135240 args = strchr (payload , ':' );
136241 if (args )
137242 * args ++ = '\0' ;
@@ -464,13 +569,11 @@ uint8_t process_packet()
464569 {
465570 if (gdbserver_trapped )
466571 {
467- char tbuf [64 ];
468- sprintf (tbuf , "T%02xthread:p%02x.%02x;" , 5 , 1 , 1 );
469- packet_send_message ((const uint8_t * )tbuf , strlen (tbuf ));
572+ gdbserver_send_stop_reply (gdbserver_last_trap_reason );
470573 }
471574 else
472575 {
473- packet_send_message (( const uint8_t * ) "OK" , 2 ) ;
576+ debugger_mode = DEBUGGER_MODE_HALTED ;
474577 }
475578 break ;
476579 }
@@ -486,18 +589,18 @@ uint8_t process_packet()
486589
487590static int process_network (int socket )
488591{
489- pthread_mutex_lock (& network_mutex );
592+ pthread_mutex_lock (& network_read_mutex );
490593
491594 // Read raw bytes from socket
492595 int bytes_read = packets_read_socket (socket );
493596 if (bytes_read < 0 )
494597 {
495- pthread_mutex_unlock (& network_mutex );
598+ pthread_mutex_unlock (& network_read_mutex );
496599 return -1 ; // Error or EOF
497600 }
498601 if (bytes_read == 0 )
499602 {
500- pthread_mutex_unlock (& network_mutex );
603+ pthread_mutex_unlock (& network_read_mutex );
501604 return 0 ; // No data available
502605 }
503606
@@ -519,7 +622,7 @@ static int process_network(int socket)
519622
520623 // Clear consumed bytes
521624 packets_clear_incoming_raw ();
522- pthread_mutex_unlock (& network_mutex );
625+ pthread_mutex_unlock (& network_read_mutex );
523626 return 0 ;
524627 }
525628 else if (result == PACKETS_FEED_INTERRUPT )
@@ -535,7 +638,7 @@ static int process_network(int socket)
535638
536639 // All bytes consumed but no complete packet yet
537640 packets_clear_incoming_raw ();
538- pthread_mutex_unlock (& network_mutex );
641+ pthread_mutex_unlock (& network_read_mutex );
539642
540643 return 0 ;
541644}
@@ -549,11 +652,11 @@ static void* network_thread(void* arg)
549652 timeout .tv_sec = 0 ;
550653 timeout .tv_usec = 500000 ;
551654
552- pthread_mutex_lock (& network_mutex );
655+ pthread_mutex_lock (& network_read_mutex );
553656
554657 if (gdbserver_socket < 0 )
555658 {
556- pthread_mutex_unlock (& network_mutex );
659+ pthread_mutex_unlock (& network_read_mutex );
557660 break ;
558661 }
559662
@@ -563,10 +666,10 @@ static void* network_thread(void* arg)
563666
564667 if (select (gdbserver_socket + 1 , & set , NULL , NULL , & timeout ) <= 0 )
565668 {
566- pthread_mutex_unlock (& network_mutex );
669+ pthread_mutex_unlock (& network_read_mutex );
567670 continue ;
568671 }
569- pthread_mutex_unlock (& network_mutex );
672+ pthread_mutex_unlock (& network_read_mutex );
570673 }
571674
572675 socklen_t socklen ;
@@ -592,17 +695,6 @@ static void* network_thread(void* arg)
592695 // Reset packets subsystem for new connection
593696 packets_reset ();
594697 packets_clear_incoming_raw ();
595- gdbserver_do_not_report_trap = 1 ;
596- debugger_mode = DEBUGGER_MODE_HALTED ;
597-
598- // property wait for it to trap
599- pthread_mutex_lock (& trap_process_mutex );
600- while (!gdbserver_trapped )
601- {
602- pthread_cond_wait (& trapped_cond , & trap_process_mutex );
603- }
604- pthread_mutex_unlock (& trap_process_mutex );
605-
606698
607699 int ret ;
608700 while ((ret = process_network (gdbserver_client_socket )) == 0 ) ;
@@ -624,10 +716,13 @@ void gdbserver_init()
624716 pthread_cond_init (& trapped_cond , NULL );
625717 pthread_cond_init (& response_cond , NULL );
626718 pthread_mutex_init (& trap_process_mutex , NULL );
627- pthread_mutex_init (& network_mutex , NULL );
719+ pthread_mutex_init (& network_read_mutex , NULL );
720+ pthread_mutex_init (& network_write_mutex , NULL );
628721
629722 // Initialize packets subsystem
630723 packets_init ();
724+ gdbserver_reset_event =
725+ event_register (gdbserver_reset_event_fn , "GDB server reset" );
631726
632727 gdbserver_refresh_status ();
633728}
@@ -737,14 +832,14 @@ void gdbserver_stop()
737832 return ;
738833 }
739834
740- pthread_mutex_lock (& network_mutex );
835+ pthread_mutex_lock (& network_read_mutex );
741836 if (gdbserver_socket != -1 )
742837 {
743838 compat_socket_close (gdbserver_socket );
744839 gdbserver_socket = -1 ;
745840 }
746841
747- pthread_mutex_unlock (& network_mutex );
842+ pthread_mutex_unlock (& network_read_mutex );
748843
749844 gdbserver_debugging_enabled = 0 ;
750845 pthread_join (network_thread_id , NULL );
@@ -753,7 +848,8 @@ void gdbserver_stop()
753848
754849void gdbserver_schedule_reset (void )
755850{
756- gdbserver_execute_on_main_thread (action_reset , NULL , NULL );
851+ if (gdbserver_reset_event >= 0 )
852+ event_add (tstates + 1 , gdbserver_reset_event );
757853}
758854
759855void gdbserver_schedule_autoboot (void )
@@ -821,7 +917,7 @@ static uint8_t gdbserver_detrap()
821917// schedule a simple job (call) on the main thread, while it's trapped
822918// data and response are supposed to be located on the stack of the caller (network) thread,
823919// as it's going to be stopped until the response is there
824- static uint8_t gdbserver_execute_on_main_thread (trapped_action_t call , const void * data , void * response )
920+ uint8_t gdbserver_execute_on_main_thread (trapped_action_t call , const void * data , void * response )
825921{
826922 pthread_mutex_lock (& trap_process_mutex );
827923
@@ -1013,14 +1109,6 @@ static uint8_t action_remove_breakpoint(const void* arg, void* response)
10131109 return 0 ;
10141110}
10151111
1016- static uint8_t action_reset (const void * arg , void * response )
1017- {
1018- (void )arg ;
1019- (void )response ;
1020- machine_reset (0 );
1021- return 0 ;
1022- }
1023-
10241112void gdbserver_on_machine_reset (void )
10251113{
10261114#ifdef BUILD_SPECTRANET
@@ -1080,31 +1168,11 @@ int gdbserver_activate()
10801168
10811169int gdbserver_activate_with_reason (int trap_reason )
10821170{
1083- // printf("Execution stopped: trapped.\n");
1084-
1085- if (gdbserver_do_not_report_trap == 0 )
1086- {
1087- // notify the gdb client that we have trapped
1088- char tbuf [64 ];
1089- int signal ;
1090- switch (trap_reason )
1091- {
1092- case DEBUG_TRAP_REASON_BREAKPOINT :
1093- signal = 5 ; // SIGTRAP
1094- break ;
1095- case DEBUG_TRAP_REASON_SIGNAL_RECEIVED :
1096- case DEBUG_TRAP_REASON_OTHER :
1097- default :
1098- signal = 2 ; // SIGINT
1099- break ;
1100- }
1101- sprintf (tbuf , "T%02xthread:p%02x.%02x;" , signal , 1 , 1 );
1102- packet_send_message ((const uint8_t * )tbuf , strlen (tbuf ));
1103- }
1171+ if (gdbserver_client_socket != -1 && gdbserver_debugging_enabled )
1172+ gdbserver_send_stop_reply (trap_reason );
11041173
11051174 pthread_mutex_lock (& trap_process_mutex );
1106-
1107- gdbserver_do_not_report_trap = 0 ;
1175+ gdbserver_last_trap_reason = trap_reason ;
11081176 gdbserver_trapped = 1 ;
11091177 pthread_cond_signal (& trapped_cond );
11101178
0 commit comments