filename | src/gdbserver.c |
changeset | 1272:0b947d924029 |
prev | 1271:3edc4bdd7c0b |
next | 1298:d0eb2307b847 |
author | nkeynes |
date | Tue Mar 20 08:29:38 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | More android WIP - Implement onPause/onResume (although resume is not actually working yet) - Implement BGRA => RGBA texture conversion (BGRA doesn't seem to work on the TFP) Boot swirl is now displayed, albeit depth buffering seems to be broken. |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * GDB RDP server stub - SH4 + ARM
5 *
6 * Copyright (c) 2009 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <glib.h>
27 #include <arpa/inet.h>
28 #include "lxdream.h"
29 #include "dream.h"
30 #include "dreamcast.h"
31 #include "ioutil.h"
32 #include "cpu.h"
33 #include "gui.h"
35 #define DEFAULT_BUFFER_SIZE 1024
36 #define BUFFER_SIZE_MARGIN 32
37 #define MAX_BUFFER_SIZE 65536
39 /* These are just local interpretations - they're not interpreted by GDB
40 * in any way shape or form.
41 */
42 #define GDB_ERROR_FORMAT 1 /* Badly formatted command */
43 #define GDB_ERROR_INVAL 2 /* Invalid data */
44 #define GDB_ERROR_FAIL 3 /* Command failed */
45 struct gdb_server {
46 cpu_desc_t cpu;
47 gboolean mmu;
48 int fd;
49 const gchar *peer_name;
50 char *buf;
51 int buf_size;
52 int buf_posn;
53 };
55 static GList *gdb_server_conn_list = NULL;
57 void gdb_server_free( gpointer data )
58 {
59 struct gdb_server *server = (struct gdb_server *)data;
60 gdb_server_conn_list = g_list_remove(gdb_server_conn_list, server);
61 free((char *)server->peer_name);
62 free(server->buf);
63 free(data);
64 }
66 int gdb_checksum( char *data, int length )
67 {
68 int i;
69 int result = 0;
70 for( i=0; i<length; i++ )
71 result += data[i];
72 result &= 0xFF;
73 return result;
74 }
76 void gdb_send_frame( struct gdb_server *server, char *data, int length )
77 {
78 char out[length+5];
79 snprintf( out, length+5, "$%.*s#%02x", length, data, gdb_checksum(data,length) );
80 write( server->fd, out, length+4 );
81 }
83 /**
84 * Send bulk data (ie memory dump) as hex, with optional string prefix.
85 * Saves double copying when going through gdb_send_frame.
86 */
87 void gdb_send_hex_data( struct gdb_server *server, char *prefix, unsigned char *data, int datalen )
88 {
89 int prefixlen = 0;
90 if( prefix != NULL )
91 prefixlen = strlen(prefix);
92 int totallen = datalen*2 + prefixlen + 4;
93 char out[totallen+1];
94 char *p = &out[1];
95 int i;
97 out[0] = '$';
98 if( prefix != NULL ) {
99 p += sprintf( p, "%s", prefix );
100 }
101 for( i=0; i<datalen; i++ ) {
102 p += sprintf( p, "%02x", data[i] );
103 }
104 *p++ = '#';
105 sprintf( p, "%02x", gdb_checksum(out+1, datalen*2 + prefixlen) );
106 write( server->fd, out, totallen );
107 }
109 /**
110 * Parse bulk hex data - buffer should be at least datalen/2 bytes long
111 */
112 size_t gdb_read_hex_data( struct gdb_server *server, unsigned char *buf, char *data, int datalen )
113 {
114 char *p = data;
115 for( int i=0; i<datalen/2; i++ ) {
116 int v;
117 sscanf( p, "%02x", &v );
118 buf[i] = v;
119 p += 2;
120 }
121 return datalen/2;
122 }
124 /**
125 * Parse bulk binary-encoded data - $, #, 0x7D are encoded as 0x7d, char ^ 0x20.
126 * Buffer should be at least datalen bytes longs.
127 */
128 size_t gdb_read_binary_data( struct gdb_server *server, unsigned char *buf, char *data, int datalen )
129 {
130 unsigned char *q = buf;
131 for( int i=0, j=0; i<datalen; i++ ) {
132 if( data[i] == 0x7D ) {
133 if( i == datalen-1 ) {
134 return -1;
135 } else {
136 *q++ = data[++i] ^ 0x20;
137 }
138 } else {
139 *q++ = data[i];
140 }
141 }
142 return q - buf;
143 }
145 void gdb_printf_frame( struct gdb_server *server, char *msg, ... )
146 {
147 va_list va;
149 va_start(va,msg);
150 int len = vsnprintf( NULL, 0, msg, va );
151 char buf[len+1];
152 vsnprintf( buf, len+1, msg, va);
153 va_end(va);
154 gdb_send_frame( server, buf, len );
155 }
157 int gdb_print_registers( struct gdb_server *server, char *buf, int buflen, int firstreg, int regcount )
158 {
159 int i;
160 char *p = buf;
161 char *endp = buf + (buflen-8);
162 for( i=firstreg; i < firstreg + regcount && p < endp; i++ ) {
163 uint8_t *val = server->cpu->get_register(i);
164 if( val == NULL ) {
165 sprintf( p, "00000000" );
166 } else {
167 sprintf( p, "%02x%02x%02x%02x", val[0], val[1], val[2], val[3] );
168 }
169 p += 8;
170 }
172 return i - firstreg;
173 }
175 void gdb_set_registers( struct gdb_server *server, char *buf, int firstreg, int regcount )
176 {
177 int i;
178 char *p = buf;
179 for( i=firstreg; i < firstreg + regcount; i++ ) {
180 uint8_t *val = server->cpu->get_register(i);
181 unsigned int a,b,c,d;
182 if( val != NULL ) {
183 sscanf( p, "%02x%02x%02x%02x", &a, &b, &c, &d );
184 val[0] = (uint8_t)a;
185 val[1] = (uint8_t)b;
186 val[2] = (uint8_t)c;
187 val[3] = (uint8_t)d;
188 }
189 p += 8;
190 }
191 }
193 /**
194 * Send a 2-digit error code. There's no actual definition for any of the codes
195 * so they're more for our own amusement really.
196 */
197 void gdb_send_error( struct gdb_server *server, int error )
198 {
199 char out[4];
200 snprintf( out, 4, "E%02X", (error&0xFF) );
201 gdb_send_frame( server, out, 3 );
202 }
204 void gdb_server_handle_frame( struct gdb_server *server, int command, char *data, int length )
205 {
206 unsigned int tmp, tmp2, tmp3;
207 char buf[512];
209 switch( command ) {
210 case '!': /* Enable extended mode */
211 gdb_send_frame( server, "OK", 2 );
212 break;
213 case '?': /* Get stop reason - always return 5 (TRAP) */
214 gdb_send_frame( server, "S05", 3 );
215 break;
216 case 'c': /* Continue */
217 gui_do_later(dreamcast_run);
218 break;
219 case 'g': /* Read all general registers */
220 gdb_print_registers( server, buf, sizeof(buf), 0, server->cpu->num_gpr_regs );
221 gdb_send_frame( server, buf, strlen(buf) );
222 break;
223 case 'G': /* Write all general registers */
224 if( length != server->cpu->num_gpr_regs*8 ) {
225 gdb_send_error( server, GDB_ERROR_FORMAT );
226 } else {
227 gdb_set_registers( server, data, 0, server->cpu->num_gpr_regs );
228 gdb_send_frame( server, "OK", 2 );
229 }
230 break;
231 case 'H': /* Set thread - only thread 1 is supported here */
232 if( length < 2 ) {
233 gdb_send_error( server, GDB_ERROR_FORMAT );
234 } else {
235 int thread;
236 sscanf( data+1, "%d", &thread );
237 if( thread >= -1 && thread <= 1 ) {
238 gdb_send_frame( server, "OK", 2 );
239 } else {
240 gdb_send_error( server, GDB_ERROR_INVAL );
241 }
242 }
243 break;
244 case 'k': /* kill - do nothing */
245 gdb_send_frame( server, "", 0 );
246 break;
247 case 'm': /* Read memory */
248 if( sscanf( data, "%x,%x", &tmp, &tmp2 ) != 2 ) {
249 gdb_send_error( server, GDB_ERROR_FORMAT );
250 } else {
251 size_t datalen;
252 unsigned char mem[tmp2];
253 if( server->mmu ) {
254 datalen = server->cpu->read_mem_vma(mem, tmp, tmp2);
255 } else {
256 datalen = server->cpu->read_mem_phys(mem, tmp, tmp2);
257 }
258 if( datalen == 0 ) {
259 gdb_send_error( server, GDB_ERROR_INVAL );
260 } else {
261 gdb_send_hex_data( server, NULL, mem, datalen );
262 }
263 }
264 break;
265 case 'M': /* Write memory */
266 if( sscanf( data, "%x,%x:%n", &tmp, &tmp2, &tmp3 ) != 2 ||
267 length-tmp3 != tmp2*2 ) {
268 gdb_send_error( server, GDB_ERROR_FORMAT );
269 } else {
270 size_t len;
271 unsigned char mem[tmp2];
272 len = gdb_read_hex_data( server, mem, data+tmp3, length-tmp3 );
273 if( len != tmp2 ) {
274 gdb_send_error( server, GDB_ERROR_FORMAT );
275 } else {
276 if( server->mmu ) {
277 len = server->cpu->write_mem_vma(tmp, mem, tmp2);
278 } else {
279 len = server->cpu->write_mem_phys(tmp, mem, tmp2);
280 }
281 if( len != tmp2 ) {
282 gdb_send_error( server, GDB_ERROR_INVAL );
283 } else {
284 gdb_send_frame( server, "OK", 2 );
285 }
286 }
287 }
288 break;
289 case 'p': /* Read single register */
290 if( sscanf( data, "%x", &tmp ) != 1 ) {
291 gdb_send_error( server, GDB_ERROR_FORMAT );
292 } else if( tmp >= server->cpu->num_gdb_regs ) {
293 gdb_send_error( server, GDB_ERROR_INVAL );
294 } else {
295 gdb_print_registers( server, buf, sizeof(buf), tmp, 1 );
296 gdb_send_frame( server, buf, 8 );
297 }
298 break;
299 case 'P': /* Write single register. */
300 if( sscanf( data, "%x=%n", &tmp, &tmp2 ) != 1 ||
301 length-tmp2 != 8) {
302 gdb_send_error( server, GDB_ERROR_FORMAT );
303 } else if( tmp >= server->cpu->num_gdb_regs ) {
304 gdb_send_error( server, GDB_ERROR_INVAL );
305 } else {
306 gdb_set_registers( server, data+tmp2, tmp, 1 );
307 gdb_send_frame( server, "OK", 2 );
308 }
309 break;
310 case 'q': /* Query data */
311 if( strcmp( data, "C" ) == 0 ) {
312 gdb_send_frame( server, "QC1", 3 );
313 } else if( strcmp( data, "fThreadInfo" ) == 0 ) {
314 gdb_send_frame( server, "m1", 2 );
315 } else if( strcmp( data, "sThreadInfo" ) == 0 ) {
316 gdb_send_frame( server, "l", 1 );
317 } else if( strncmp( data, "Supported", 9 ) == 0 ) {
318 gdb_send_frame( server, "PacketSize=4000", 15 );
319 } else if( strcmp( data, "Symbol::" ) == 0 ) {
320 gdb_send_frame( server, "OK", 2 );
321 } else {
322 gdb_send_frame( server, "", 0 );
323 }
324 break;
325 case 's': /* Single-step */
326 if( length != 0 ) {
327 if( sscanf( data, "%x", &tmp ) != 1 ) {
328 gdb_send_error( server, GDB_ERROR_FORMAT );
329 } else {
330 *server->cpu->pc = tmp;
331 }
332 }
333 server->cpu->step_func();
334 gdb_send_frame( server, "S05", 3 );
335 break;
336 case 'T': /* Thread alive */
337 if( sscanf( data, "%x", &tmp ) != 1 ) {
338 gdb_send_error( server, GDB_ERROR_FORMAT );
339 } else if( tmp != 1 ) {
340 gdb_send_error( server, GDB_ERROR_INVAL );
341 } else {
342 gdb_send_frame( server, "OK", 2 );
343 }
344 break;
345 case 'v': /* Verbose */
346 /* Only current one is vCont, which we don't bother supporting
347 * at the moment, but don't warn about it either */
348 gdb_send_frame( server, "", 0 );
349 break;
350 case 'X': /* Write memory binary */
351 if( sscanf( data, "%x,%x:%n", &tmp, &tmp2, &tmp3 ) != 2 ) {
352 gdb_send_error( server, GDB_ERROR_FORMAT );
353 } else {
354 unsigned char mem[length - tmp3];
355 size_t len = gdb_read_binary_data( server, mem, data + tmp3, length-tmp3 );
356 if( len != tmp2 ) {
357 gdb_send_error( server, GDB_ERROR_FORMAT );
358 } else {
359 if( server->mmu ) {
360 len = server->cpu->write_mem_vma(tmp, mem, tmp2);
361 } else {
362 len = server->cpu->write_mem_phys(tmp, mem, tmp2);
363 }
364 if( len != tmp2 ) {
365 gdb_send_error( server, GDB_ERROR_INVAL );
366 } else {
367 gdb_send_frame( server, "OK", 2 );
368 }
369 }
370 }
371 break;
372 case 'z': /* Remove Break/watchpoint */
373 if( sscanf( data, "%d,%x,%x", &tmp, &tmp2, &tmp3 ) != 3 ) {
374 gdb_send_error( server, GDB_ERROR_FORMAT );
375 } else {
376 if( tmp == 0 || tmp == 1 ) { /* soft break or hard break */
377 server->cpu->clear_breakpoint( tmp2, BREAK_KEEP );
378 gdb_send_frame( server, "OK", 2 );
379 } else {
380 gdb_send_frame( server, "", 0 );
381 }
382 }
383 break;
384 case 'Z': /* Insert Break/watchpoint */
385 if( sscanf( data, "%d,%x,%x", &tmp, &tmp2, &tmp3 ) != 3 ) {
386 gdb_send_error( server, GDB_ERROR_FORMAT );
387 } else {
388 if( tmp == 0 || tmp == 1 ) { /* soft break or hard break */
389 server->cpu->set_breakpoint( tmp2, BREAK_KEEP );
390 gdb_send_frame( server, "OK", 2 );
391 } else {
392 gdb_send_frame( server, "", 0 );
393 }
394 }
395 break;
396 default:
397 /* Command unsupported */
398 WARN( "Received unknown GDB command '%c%s'", command, data );
399 gdb_send_frame( server, "", 0 );
400 break;
401 }
403 }
405 /**
406 * Decode out frames from the raw data stream. A frame takes the form of
407 * $<data>#<checksum>
408 * where data may not contain a '#' character, and checksum is a simple
409 * 8-bit modulo sum of all bytes in data, encoded as a 2-char hex number.
410 *
411 * The only other legal wire forms are
412 * +
413 * indicating successful reception of the last message (ignored here), and
414 * -
415 * indicating failed reception of the last message - need to resend.
416 */
417 void gdb_server_process_buffer( struct gdb_server *server )
418 {
419 int i, frame_start = -1, frame_len = -1;
420 for( i=0; i<server->buf_posn; i++ ) {
421 if( frame_start == -1 ) {
422 if( server->buf[i] == '$' ) {
423 frame_start = i;
424 } else if( server->buf[i] == '+' ) {
425 /* Success */
426 continue;
427 } else if( server->buf[i] == '-' ) {
428 /* Request retransmit */
429 } else if( server->buf[i] == '\003' ) { /* Control-C */
430 if( dreamcast_is_running() ) {
431 dreamcast_stop();
432 }
433 } /* Anything else is noise */
434 } else if( server->buf[i] == '#' ) {
435 frame_len = i - frame_start - 1;
436 if( i+2 < server->buf_posn ) {
437 int calc_checksum = gdb_checksum( &server->buf[frame_start+1], frame_len );
438 int frame_checksum = 0;
439 sscanf( &server->buf[i+1], "%02x", &frame_checksum );
441 if( calc_checksum != frame_checksum ) {
442 WARN( "GDB frame checksum failure (expected %02X but was %02X)",
443 calc_checksum, frame_checksum );
444 write( server->fd, "-", 1 );
445 } else if( frame_len == 0 ) {
446 /* Empty frame - should never occur as a request */
447 WARN( "Empty GDB frame received" );
448 write( server->fd, "-", 1 );
449 } else {
450 /* We have a good frame */
451 write( server->fd, "+", 1 );
452 server->buf[i] = '\0';
453 gdb_server_handle_frame( server, server->buf[frame_start+1], &server->buf[frame_start+2], frame_len-1 );
454 }
455 i+=2;
456 frame_start = -1;
457 }
458 }
459 }
460 if( frame_start == -1 ) {
461 server->buf_posn = 0; /* Consumed whole buffer */
462 } else if( frame_start > 0 ) {
463 memmove(&server->buf[0], &server->buf[frame_start], server->buf_posn - frame_start);
464 server->buf_posn -= frame_start;
465 }
466 }
468 gboolean gdb_server_data_callback( int fd, void *data )
469 {
470 struct gdb_server *server = (struct gdb_server *)data;
472 size_t len = read( fd, &server->buf[server->buf_posn], server->buf_size - server->buf_posn );
473 if( len > 0 ) {
474 server->buf_posn += len;
475 gdb_server_process_buffer( server );
477 /* If we have an oversized packet, extend the buffer */
478 if( server->buf_posn > server->buf_size - BUFFER_SIZE_MARGIN &&
479 server->buf_size < MAX_BUFFER_SIZE ) {
480 server->buf_size <<= 1;
481 server->buf = realloc( server->buf, server->buf_size );
482 assert( server->buf != NULL );
483 }
484 return TRUE;
485 } else {
486 INFO( "GDB disconnected" );
487 return FALSE;
488 }
489 }
491 gboolean gdb_server_connect_callback( int fd, gpointer data )
492 {
493 struct sockaddr_in sin;
494 socklen_t sinlen = sizeof(sin);
495 struct gdb_server *server = (struct gdb_server *)data;
496 int conn_fd = accept( fd, (struct sockaddr *)&sin, &sinlen);
497 if( conn_fd != -1 ) {
498 struct gdb_server *chan_serv = calloc( sizeof(struct gdb_server), 1 );
499 chan_serv->cpu = server->cpu;
500 chan_serv->mmu = server->mmu;
501 chan_serv->fd = conn_fd;
502 chan_serv->peer_name = g_strdup_printf("%s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
503 chan_serv->buf = malloc(1024);
504 chan_serv->buf_size = 1024;
505 chan_serv->buf_posn = 0;
506 io_register_tcp_listener( conn_fd, gdb_server_data_callback, chan_serv, gdb_server_free );
507 gdb_server_conn_list = g_list_append(gdb_server_conn_list, chan_serv);
508 INFO( "GDB connected from %s", chan_serv->peer_name );
509 }
510 return TRUE;
511 }
513 void gdb_server_notify_stopped( struct gdb_server *server )
514 {
515 gdb_send_frame( server, "S05", 3 );
516 }
518 /**
519 * stop handler to generate notifications to all connected clients
520 */
521 void gdb_server_on_stop()
522 {
523 GList *ptr;
524 for( ptr = gdb_server_conn_list; ptr != NULL; ptr = ptr->next ) {
525 gdb_server_notify_stopped( (struct gdb_server *)ptr->data );
526 }
527 }
529 static gboolean module_registered = FALSE;
530 static struct dreamcast_module gdb_server_module = {
531 "gdbserver", NULL, NULL, NULL, NULL, gdb_server_on_stop, NULL, NULL };
534 /**
535 * Bind a network port for a GDB remote server for the specified cpu. The
536 * port is registered for the system network callback.
537 *
538 * @param interface network interface to bind to, or null for the default (all) interface
539 * @param port
540 * @param cpu CPU to make available over the network port..
541 * @param mmu if TRUE, virtual memory is made available to GDB, otherwise GDB
542 * accesses physical memory.
543 * @return TRUE if the server was bound successfully.
544 */
545 gboolean gdb_init_server( const char *interface, int port, cpu_desc_t cpu, gboolean mmu )
546 {
547 if( !module_registered ) {
548 dreamcast_register_module( &gdb_server_module );
549 module_registered = TRUE;
550 }
552 int fd = io_create_server_socket( interface, port );
553 if( fd == -1 ) {
554 return FALSE;
555 }
557 struct gdb_server *server = calloc( sizeof(struct gdb_server), 1 );
558 server->cpu = cpu;
559 server->mmu = mmu;
560 server->fd = fd;
561 gboolean result = io_register_tcp_listener( fd, gdb_server_connect_callback, server, gdb_server_free ) != NULL;
562 INFO( "%s GDB server running on port %d", cpu->name, port );
563 return result;
564 }
.