filename | src/gdbserver.c |
changeset | 1025:f32183d273fb |
prev | 1020:04e622ab1635 |
next | 1071:182cfe43c09e |
author | nkeynes |
date | Sun Jul 05 13:54:48 2009 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | No-op merge lxdream-mem to tip to remove head (Long since merged in actuality) |
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 "dreamcast.h"
30 #include "netutil.h"
31 #include "cpu.h"
33 #define DEFAULT_BUFFER_SIZE 1024
34 #define BUFFER_SIZE_MARGIN 32
35 #define MAX_BUFFER_SIZE 65536
37 /* These are just local interpretations - they're not interpreted by GDB
38 * in any way shape or form.
39 */
40 #define GDB_ERROR_FORMAT 1 /* Badly formatted command */
41 #define GDB_ERROR_INVAL 2 /* Invalid data */
42 #define GDB_ERROR_FAIL 3 /* Command failed */
43 struct gdb_server {
44 cpu_desc_t cpu;
45 gboolean mmu;
46 int fd;
47 const gchar *peer_name;
48 char *buf;
49 int buf_size;
50 int buf_posn;
51 };
53 void gdb_server_free( gpointer data )
54 {
55 struct gdb_server *server = (struct gdb_server *)data;
56 free((char *)server->peer_name);
57 free(server->buf);
58 free(data);
59 }
61 int gdb_checksum( char *data, int length )
62 {
63 int i;
64 int result = 0;
65 for( i=0; i<length; i++ )
66 result += data[i];
67 result &= 0xFF;
68 return result;
69 }
71 void gdb_send_frame( struct gdb_server *server, char *data, int length )
72 {
73 char out[length+5];
74 snprintf( out, length+5, "$%.*s#%02x", length, data, gdb_checksum(data,length) );
75 write( server->fd, out, length+4 );
76 }
78 /**
79 * Send bulk data (ie memory dump) as hex, with optional string prefix.
80 * Saves double copying when going through gdb_send_frame.
81 */
82 void gdb_send_hex_data( struct gdb_server *server, char *prefix, unsigned char *data, int datalen )
83 {
84 int prefixlen = 0;
85 if( prefix != NULL )
86 prefixlen = strlen(prefix);
87 int totallen = datalen*2 + prefixlen + 4;
88 char out[totallen+1];
89 char *p = &out[1];
90 int i;
92 out[0] = '$';
93 if( prefix != NULL ) {
94 p += sprintf( p, "%s", prefix );
95 }
96 for( i=0; i<datalen; i++ ) {
97 p += sprintf( p, "%02x", data[i] );
98 }
99 *p++ = '#';
100 sprintf( p, "%02x", gdb_checksum(out+1, datalen*2 + prefixlen) );
101 write( server->fd, out, totallen );
102 }
104 /**
105 * Parse bulk hex data - buffer should be at least datalen/2 bytes long
106 */
107 size_t gdb_read_hex_data( struct gdb_server *server, unsigned char *buf, char *data, int datalen )
108 {
109 char *p = data;
110 for( int i=0; i<datalen/2; i++ ) {
111 int v;
112 sscanf( p, "%02x", &v );
113 buf[i] = v;
114 p += 2;
115 }
116 return datalen/2;
117 }
119 /**
120 * Parse bulk binary-encoded data - $, #, 0x7D are encoded as 0x7d, char ^ 0x20.
121 * Buffer should be at least datalen bytes longs.
122 */
123 size_t gdb_read_binary_data( struct gdb_server *server, unsigned char *buf, char *data, int datalen )
124 {
125 unsigned char *q = buf;
126 for( int i=0, j=0; i<datalen; i++ ) {
127 if( data[i] == 0x7D ) {
128 if( i == datalen-1 ) {
129 return -1;
130 } else {
131 *q++ = data[++i] ^ 0x20;
132 }
133 } else {
134 *q++ = data[i];
135 }
136 }
137 return q - buf;
138 }
140 void gdb_printf_frame( struct gdb_server *server, char *msg, ... )
141 {
142 va_list va;
144 va_start(va,msg);
145 int len = vsnprintf( NULL, 0, msg, va );
146 char buf[len+1];
147 vsnprintf( buf, len+1, msg, va);
148 va_end(va);
149 gdb_send_frame( server, buf, len );
150 }
152 int gdb_print_registers( struct gdb_server *server, char *buf, int buflen, int firstreg, int regcount )
153 {
154 int i;
155 char *p = buf;
156 char *endp = buf + (buflen-8);
157 for( i=firstreg; i < firstreg + regcount && p < endp; i++ ) {
158 uint8_t *val = server->cpu->get_register(i);
159 if( val == NULL ) {
160 sprintf( p, "00000000" );
161 } else {
162 sprintf( p, "%02x%02x%02x%02x", val[0], val[1], val[2], val[3] );
163 }
164 p += 8;
165 }
167 return i - firstreg;
168 }
170 void gdb_set_registers( struct gdb_server *server, char *buf, int firstreg, int regcount )
171 {
172 int i;
173 char *p = buf;
174 for( i=firstreg; i < firstreg + regcount; i++ ) {
175 uint8_t *val = server->cpu->get_register(i);
176 unsigned int a,b,c,d;
177 if( val != NULL ) {
178 sscanf( p, "%02x%02x%02x%02x", &a, &b, &c, &d );
179 val[0] = (uint8_t)a;
180 val[1] = (uint8_t)b;
181 val[2] = (uint8_t)c;
182 val[3] = (uint8_t)d;
183 }
184 p += 8;
185 }
186 }
188 /**
189 * Send a 2-digit error code. There's no actual definition for any of the codes
190 * so they're more for our own amusement really.
191 */
192 void gdb_send_error( struct gdb_server *server, int error )
193 {
194 char out[4];
195 snprintf( out, 4, "E%02X", (error&0xFF) );
196 gdb_send_frame( server, out, 3 );
197 }
199 void gdb_server_handle_frame( struct gdb_server *server, int command, char *data, int length )
200 {
201 unsigned int tmp, tmp2, tmp3;
202 char buf[512];
204 switch( command ) {
205 case '!': /* Enable extended mode */
206 gdb_send_frame( server, "OK", 2 );
207 break;
208 case '?': /* Get stop reason - always return 5 (TRAP) */
209 gdb_send_frame( server, "S05", 3 );
210 break;
211 case 'c': /* Continue */
212 dreamcast_run();
213 gdb_send_frame( server, "S05", 3 );
214 break;
215 case 'g': /* Read all general registers */
216 gdb_print_registers( server, buf, sizeof(buf), 0, server->cpu->num_gpr_regs );
217 gdb_send_frame( server, buf, strlen(buf) );
218 break;
219 case 'G': /* Write all general registers */
220 if( length != server->cpu->num_gpr_regs*8 ) {
221 gdb_send_error( server, GDB_ERROR_FORMAT );
222 } else {
223 gdb_set_registers( server, data, 0, server->cpu->num_gpr_regs );
224 gdb_send_frame( server, "OK", 2 );
225 }
226 break;
227 case 'H': /* Set thread - only thread 1 is supported here */
228 if( length < 2 ) {
229 gdb_send_error( server, GDB_ERROR_FORMAT );
230 } else {
231 int thread;
232 sscanf( data+1, "%d", &thread );
233 if( thread >= -1 && thread <= 1 ) {
234 gdb_send_frame( server, "OK", 2 );
235 } else {
236 gdb_send_error( server, GDB_ERROR_INVAL );
237 }
238 }
239 break;
240 case 'k': /* kill - do nothing */
241 gdb_send_frame( server, "", 0 );
242 break;
243 case 'm': /* Read memory */
244 if( sscanf( data, "%x,%x", &tmp, &tmp2 ) != 2 ) {
245 gdb_send_error( server, GDB_ERROR_FORMAT );
246 } else {
247 size_t datalen;
248 unsigned char mem[tmp2];
249 if( server->mmu ) {
250 datalen = server->cpu->read_mem_vma(mem, tmp, tmp2);
251 } else {
252 datalen = server->cpu->read_mem_phys(mem, tmp, tmp2);
253 }
254 if( datalen == 0 ) {
255 gdb_send_error( server, GDB_ERROR_INVAL );
256 } else {
257 gdb_send_hex_data( server, NULL, mem, datalen );
258 }
259 }
260 break;
261 case 'M': /* Write memory */
262 if( sscanf( data, "%x,%x:%n", &tmp, &tmp2, &tmp3 ) != 2 ||
263 length-tmp3 != tmp2*2 ) {
264 gdb_send_error( server, GDB_ERROR_FORMAT );
265 } else {
266 size_t len;
267 unsigned char mem[tmp2];
268 len = gdb_read_hex_data( server, mem, data+tmp3, length-tmp3 );
269 if( len != tmp2 ) {
270 gdb_send_error( server, GDB_ERROR_FORMAT );
271 } else {
272 if( server->mmu ) {
273 len = server->cpu->write_mem_vma(tmp, mem, tmp2);
274 } else {
275 len = server->cpu->write_mem_phys(tmp, mem, tmp2);
276 }
277 if( len != tmp2 ) {
278 gdb_send_error( server, GDB_ERROR_INVAL );
279 } else {
280 gdb_send_frame( server, "OK", 2 );
281 }
282 }
283 }
284 break;
285 case 'p': /* Read single register */
286 if( sscanf( data, "%x", &tmp ) != 1 ) {
287 gdb_send_error( server, GDB_ERROR_FORMAT );
288 } else if( tmp >= server->cpu->num_gdb_regs ) {
289 gdb_send_error( server, GDB_ERROR_INVAL );
290 } else {
291 gdb_print_registers( server, buf, sizeof(buf), tmp, 1 );
292 gdb_send_frame( server, buf, 8 );
293 }
294 break;
295 case 'P': /* Write single register. */
296 if( sscanf( data, "%x=%n", &tmp, &tmp2 ) != 1 ||
297 length-tmp2 != 8) {
298 gdb_send_error( server, GDB_ERROR_FORMAT );
299 } else if( tmp >= server->cpu->num_gdb_regs ) {
300 gdb_send_error( server, GDB_ERROR_INVAL );
301 } else {
302 gdb_set_registers( server, data+tmp2, tmp, 1 );
303 gdb_send_frame( server, "OK", 2 );
304 }
305 break;
306 case 'q': /* Query data */
307 if( strcmp( data, "C" ) == 0 ) {
308 gdb_send_frame( server, "QC1", 3 );
309 } else if( strcmp( data, "fThreadInfo" ) == 0 ) {
310 gdb_send_frame( server, "m1", 2 );
311 } else if( strcmp( data, "sThreadInfo" ) == 0 ) {
312 gdb_send_frame( server, "l", 1 );
313 } else if( strncmp( data, "Supported", 9 ) == 0 ) {
314 gdb_send_frame( server, "PacketSize=4000", 15 );
315 } else if( strcmp( data, "Symbol::" ) == 0 ) {
316 gdb_send_frame( server, "OK", 2 );
317 } else {
318 gdb_send_frame( server, "", 0 );
319 }
320 break;
321 case 's': /* Single-step */
322 if( length != 0 ) {
323 if( sscanf( data, "%x", &tmp ) != 1 ) {
324 gdb_send_error( server, GDB_ERROR_FORMAT );
325 } else {
326 *server->cpu->pc = tmp;
327 }
328 }
329 server->cpu->step_func();
330 gdb_send_frame( server, "S05", 3 );
331 break;
332 case 'T': /* Thread alive */
333 if( sscanf( data, "%x", &tmp ) != 1 ) {
334 gdb_send_error( server, GDB_ERROR_FORMAT );
335 } else if( tmp != 1 ) {
336 gdb_send_error( server, GDB_ERROR_INVAL );
337 } else {
338 gdb_send_frame( server, "OK", 2 );
339 }
340 break;
341 case 'v': /* Verbose */
342 /* Only current one is vCont, which we don't bother supporting
343 * at the moment, but don't warn about it either */
344 gdb_send_frame( server, "", 0 );
345 break;
346 case 'X': /* Write memory binary */
347 if( sscanf( data, "%x,%x:%n", &tmp, &tmp2, &tmp3 ) != 2 ) {
348 gdb_send_error( server, GDB_ERROR_FORMAT );
349 } else {
350 unsigned char mem[length - tmp3];
351 size_t len = gdb_read_binary_data( server, mem, data + tmp3, length-tmp3 );
352 if( len != tmp2 ) {
353 gdb_send_error( server, GDB_ERROR_FORMAT );
354 } else {
355 if( server->mmu ) {
356 len = server->cpu->write_mem_vma(tmp, mem, tmp2);
357 } else {
358 len = server->cpu->write_mem_phys(tmp, mem, tmp2);
359 }
360 if( len != tmp2 ) {
361 gdb_send_error( server, GDB_ERROR_INVAL );
362 } else {
363 gdb_send_frame( server, "OK", 2 );
364 }
365 }
366 }
367 break;
368 case 'z': /* Remove Break/watchpoint */
369 if( sscanf( data, "%d,%x,%x", &tmp, &tmp2, &tmp3 ) != 3 ) {
370 gdb_send_error( server, GDB_ERROR_FORMAT );
371 } else {
372 if( tmp == 0 || tmp == 1 ) { /* soft break or hard break */
373 server->cpu->clear_breakpoint( tmp2, BREAK_KEEP );
374 gdb_send_frame( server, "OK", 2 );
375 } else {
376 gdb_send_frame( server, "", 0 );
377 }
378 }
379 break;
380 case 'Z': /* Insert Break/watchpoint */
381 if( sscanf( data, "%d,%x,%x", &tmp, &tmp2, &tmp3 ) != 3 ) {
382 gdb_send_error( server, GDB_ERROR_FORMAT );
383 } else {
384 if( tmp == 0 || tmp == 1 ) { /* soft break or hard break */
385 server->cpu->set_breakpoint( tmp2, BREAK_KEEP );
386 gdb_send_frame( server, "OK", 2 );
387 } else {
388 gdb_send_frame( server, "", 0 );
389 }
390 }
391 break;
392 default:
393 /* Command unsupported */
394 WARN( "Received unknown GDB command '%c%s'", command, data );
395 gdb_send_frame( server, "", 0 );
396 break;
397 }
399 }
401 /**
402 * Decode out frames from the raw data stream. A frame takes the form of
403 * $<data>#<checksum>
404 * where data may not contain a '#' character, and checksum is a simple
405 * 8-bit modulo sum of all bytes in data, encoded as a 2-char hex number.
406 *
407 * The only other legal wire forms are
408 * +
409 * indicating successful reception of the last message (ignored here), and
410 * -
411 * indicating failed reception of the last message - need to resend.
412 */
413 void gdb_server_process_buffer( struct gdb_server *server )
414 {
415 int i, frame_start = -1, frame_len = -1;
416 for( i=0; i<server->buf_posn; i++ ) {
417 if( frame_start == -1 ) {
418 if( server->buf[i] == '$' ) {
419 frame_start = i;
420 } else if( server->buf[i] == '+' ) {
421 /* Success */
422 continue;
423 } else if( server->buf[i] == '-' ) {
424 /* Request retransmit */
425 } /* Anything else is noise */
426 } else if( server->buf[i] == '#' ) {
427 frame_len = i - frame_start - 1;
428 if( i+2 < server->buf_posn ) {
429 int calc_checksum = gdb_checksum( &server->buf[frame_start+1], frame_len );
430 int frame_checksum = 0;
431 sscanf( &server->buf[i+1], "%02x", &frame_checksum );
433 if( calc_checksum != frame_checksum ) {
434 WARN( "GDB frame checksum failure (expected %02X but was %02X)",
435 calc_checksum, frame_checksum );
436 write( server->fd, "-", 1 );
437 } else if( frame_len == 0 ) {
438 /* Empty frame - should never occur as a request */
439 WARN( "Empty GDB frame received" );
440 write( server->fd, "-", 1 );
441 } else {
442 /* We have a good frame */
443 write( server->fd, "+", 1 );
444 server->buf[i] = '\0';
445 gdb_server_handle_frame( server, server->buf[frame_start+1], &server->buf[frame_start+2], frame_len-1 );
446 }
447 i+=2;
448 frame_start = -1;
449 }
450 }
451 }
452 if( frame_start == -1 ) {
453 server->buf_posn = 0; /* Consumed whole buffer */
454 } else if( frame_start > 0 ) {
455 memmove(&server->buf[0], &server->buf[frame_start], server->buf_posn - frame_start);
456 server->buf_posn -= frame_start;
457 }
458 }
460 gboolean gdb_server_data_callback( int fd, void *data )
461 {
462 struct gdb_server *server = (struct gdb_server *)data;
464 size_t len = read( fd, &server->buf[server->buf_posn], server->buf_size - server->buf_posn );
465 if( len > 0 ) {
466 server->buf_posn += len;
467 gdb_server_process_buffer( server );
469 /* If we have an oversized packet, extend the buffer */
470 if( server->buf_posn > server->buf_size - BUFFER_SIZE_MARGIN &&
471 server->buf_size < MAX_BUFFER_SIZE ) {
472 server->buf_size <<= 1;
473 server->buf = realloc( server->buf, server->buf_size );
474 assert( server->buf != NULL );
475 }
476 return TRUE;
477 } else {
478 INFO( "GDB disconnected" );
479 return FALSE;
480 }
481 }
483 gboolean gdb_server_connect_callback( int fd, gpointer data )
484 {
485 struct sockaddr_in sin;
486 socklen_t sinlen;
487 struct gdb_server *server = (struct gdb_server *)data;
488 int conn_fd = accept( fd, (struct sockaddr *)&sin, &sinlen);
489 if( conn_fd != -1 ) {
490 struct gdb_server *chan_serv = calloc( sizeof(struct gdb_server), 1 );
491 chan_serv->cpu = server->cpu;
492 chan_serv->mmu = server->mmu;
493 chan_serv->fd = conn_fd;
494 chan_serv->peer_name = g_strdup_printf("%s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
495 chan_serv->buf = malloc(1024);
496 chan_serv->buf_size = 1024;
497 chan_serv->buf_posn = 0;
498 net_register_tcp_listener( conn_fd, gdb_server_data_callback, chan_serv, gdb_server_free );
499 INFO( "GDB connected from %s", chan_serv->peer_name );
500 }
501 return TRUE;
502 }
504 /**
505 * Bind a network port for a GDB remote server for the specified cpu. The
506 * port is registered for the system network callback.
507 *
508 * @param interface network interface to bind to, or null for the default (all) interface
509 * @param port
510 * @param cpu CPU to make available over the network port..
511 * @param mmu if TRUE, virtual memory is made available to GDB, otherwise GDB
512 * accesses physical memory.
513 * @return TRUE if the server was bound successfully.
514 */
515 gboolean gdb_init_server( const char *interface, int port, cpu_desc_t cpu, gboolean mmu )
516 {
517 int fd = net_create_server_socket( interface, port );
518 if( fd == -1 ) {
519 return FALSE;
520 }
522 struct gdb_server *server = calloc( sizeof(struct gdb_server), 1 );
523 server->cpu = cpu;
524 server->mmu = mmu;
525 server->fd = fd;
526 net_register_tcp_listener( fd, gdb_server_connect_callback, server, gdb_server_free );
527 INFO( "%s GDB server running on port %d", cpu->name, port );
528 }
.