Search
lxdream.org :: lxdream/src/gdbserver.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdbserver.c
changeset 998:1754a8c6a9cf
next1020:04e622ab1635
author nkeynes
date Tue Apr 07 10:39:02 2009 +0000 (15 years ago)
branchxlat-refactor
permissions -rw-r--r--
last change Create an xlat-refactor branch
view annotate diff log raw
     1 /**
     2  * $Id: gdbserver.c 1018 2009-03-19 12:29:06Z nkeynes $
     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, unsigned 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, unsigned 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         if( val != NULL ) {
   177             sscanf( p, "%02x%02x%02x%02x", val, val+1, val+2, val+3 );
   178         }
   179         p += 8;
   180     }
   181 }
   183 /**
   184  * Send a 2-digit error code. There's no actual definition for any of the codes
   185  * so they're more for our own amusement really.
   186  */
   187 void gdb_send_error( struct gdb_server *server, int error )
   188 {
   189     char out[4];
   190     snprintf( out, 4, "E%02X", (error&0xFF) );
   191     gdb_send_frame( server, out, 3 );
   192 }
   194 void gdb_server_handle_frame( struct gdb_server *server, int command, char *data, int length )
   195 {
   196     unsigned int tmp, tmp2, tmp3;
   197     char buf[512];
   199     switch( command ) {
   200     case '!': /* Enable extended mode */
   201         gdb_send_frame( server, "OK", 2 );
   202         break;
   203     case '?': /* Get stop reason - always return 5 (TRAP) */
   204         gdb_send_frame( server, "S05", 3 );
   205         break;
   206     case 'c': /* Continue */
   207         dreamcast_run();
   208         gdb_send_frame( server, "S05", 3 );
   209         break;
   210     case 'g': /* Read all general registers */
   211         gdb_print_registers( server, buf, sizeof(buf), 0, server->cpu->num_gpr_regs );
   212         gdb_send_frame( server, buf, strlen(buf) );
   213         break;
   214     case 'G': /* Write all general registers */
   215         if( length != server->cpu->num_gpr_regs*8 ) {
   216             gdb_send_error( server, GDB_ERROR_FORMAT );
   217         } else {
   218             gdb_set_registers( server, data, 0, server->cpu->num_gpr_regs );
   219             gdb_send_frame( server, "OK", 2 );
   220         }
   221         break;
   222     case 'H': /* Set thread - only thread 1 is supported here */
   223         if( length < 2 ) {
   224             gdb_send_error( server, GDB_ERROR_FORMAT );
   225         } else {
   226             int thread;
   227             sscanf( data+1, "%d", &thread );
   228             if( thread >= -1 && thread <= 1 ) {
   229                 gdb_send_frame( server, "OK", 2 );
   230             } else {
   231                 gdb_send_error( server, GDB_ERROR_INVAL );
   232             }
   233         }
   234         break;
   235     case 'k': /* kill - do nothing */
   236         gdb_send_frame( server, "", 0 );
   237         break;
   238     case 'm': /* Read memory */
   239         if( sscanf( data, "%x,%x", &tmp, &tmp2 ) != 2 ) {
   240             gdb_send_error( server, GDB_ERROR_FORMAT );
   241         } else {
   242             size_t datalen;
   243             char mem[tmp2];
   244             if( server->mmu ) {
   245                 datalen = server->cpu->read_mem_vma(mem, tmp, tmp2);
   246             } else {
   247                 datalen = server->cpu->read_mem_phys(mem, tmp, tmp2);
   248             }
   249             if( datalen == 0 ) {
   250                 gdb_send_error( server, GDB_ERROR_INVAL );
   251             } else {
   252                 gdb_send_hex_data( server, NULL, mem, datalen );
   253             }
   254         }   
   255         break;
   256     case 'M': /* Write memory */
   257         if( sscanf( data, "%x,%x:%n", &tmp, &tmp2, &tmp3 ) != 2 ||
   258                 length-tmp3 != tmp2*2 ) {
   259             gdb_send_error( server, GDB_ERROR_FORMAT );
   260         } else {
   261             size_t len;
   262             char mem[tmp2];
   263             len = gdb_read_hex_data( server, mem, data+tmp3, length-tmp3 );
   264             if( len != tmp2 ) {
   265                 gdb_send_error( server, GDB_ERROR_FORMAT );
   266             } else {
   267                 if( server->mmu ) {
   268                     len = server->cpu->write_mem_vma(tmp, mem, tmp2);
   269                 } else {
   270                     len = server->cpu->write_mem_phys(tmp, mem, tmp2);
   271                 }
   272                 if( len != tmp2 ) {
   273                     gdb_send_error( server, GDB_ERROR_INVAL );
   274                 } else {
   275                     gdb_send_frame( server, "OK", 2 );
   276                 }
   277             }
   278         }
   279         break;   
   280     case 'p': /* Read single register */
   281         if( sscanf( data, "%x", &tmp ) != 1 ) {
   282             gdb_send_error( server, GDB_ERROR_FORMAT );
   283         } else if( tmp >= server->cpu->num_gdb_regs ) {
   284             gdb_send_error( server, GDB_ERROR_INVAL );
   285         } else {
   286             gdb_print_registers( server, buf, sizeof(buf), tmp, 1 );
   287             gdb_send_frame( server, buf, 8 );
   288         }
   289         break;
   290     case 'P': /* Write single register. */
   291         if( sscanf( data, "%x=%n", &tmp, &tmp2 ) != 1 || 
   292                 length-tmp2 != 8) {
   293             gdb_send_error( server, GDB_ERROR_FORMAT );
   294         } else if( tmp >= server->cpu->num_gdb_regs ) {
   295             gdb_send_error( server, GDB_ERROR_INVAL );
   296         } else {
   297             gdb_set_registers( server, data+tmp2, tmp, 1 ); 
   298             gdb_send_frame( server, "OK", 2 );
   299         }
   300         break;
   301     case 'q': /* Query data */
   302         if( strcmp( data, "C" ) == 0 ) {
   303             gdb_send_frame( server, "QC1", 3 );
   304         } else if( strcmp( data, "fThreadInfo" ) == 0 ) {
   305             gdb_send_frame( server, "m1", 2 );
   306         } else if( strcmp( data, "sThreadInfo" ) == 0 ) {
   307             gdb_send_frame( server, "l", 1 );
   308         } else if( strncmp( data, "Supported", 9 ) == 0 ) {
   309             gdb_send_frame( server, "PacketSize=4000", 15 );
   310         } else if( strcmp( data, "Symbol::" ) == 0 ) {
   311             gdb_send_frame( server, "OK", 2 );
   312         } else {
   313             gdb_send_frame( server, "", 0 );
   314         }
   315         break;
   316     case 's': /* Single-step */
   317         if( length != 0 ) {
   318             if( sscanf( data, "%x", &tmp ) != 1 ) {
   319                 gdb_send_error( server, GDB_ERROR_FORMAT );
   320             } else {
   321                 *server->cpu->pc = tmp;
   322             }
   323         }
   324         server->cpu->step_func();
   325         gdb_send_frame( server, "S05", 3 );
   326         break;
   327     case 'T': /* Thread alive */
   328         if( sscanf( data, "%x", &tmp ) != 1 ) {
   329             gdb_send_error( server, GDB_ERROR_FORMAT );
   330         } else if( tmp != 1 ) {
   331             gdb_send_error( server, GDB_ERROR_INVAL );
   332         } else {
   333             gdb_send_frame( server, "OK", 2 );
   334         }
   335         break;
   336     case 'v': /* Verbose */
   337         /* Only current one is vCont, which we don't bother supporting
   338          * at the moment, but don't warn about it either */
   339         gdb_send_frame( server, "", 0 );
   340         break;
   341     case 'X': /* Write memory binary */
   342         if( sscanf( data, "%x,%x:%n", &tmp, &tmp2, &tmp3 ) != 2 ) {
   343             gdb_send_error( server, GDB_ERROR_FORMAT );
   344         } else {
   345             char mem[length - tmp3];
   346             size_t len = gdb_read_binary_data( server, mem, data + tmp3, length-tmp3 );
   347             if( len != tmp2 ) {
   348                 gdb_send_error( server, GDB_ERROR_FORMAT );
   349             } else {
   350                 if( server->mmu ) {
   351                     len = server->cpu->write_mem_vma(tmp, mem, tmp2);
   352                 } else {
   353                     len = server->cpu->write_mem_phys(tmp, mem, tmp2);
   354                 }
   355                 if( len != tmp2 ) {
   356                     gdb_send_error( server, GDB_ERROR_INVAL );
   357                 } else {
   358                     gdb_send_frame( server, "OK", 2 );
   359                 }
   360             }
   361         }
   362         break;
   363     case 'z': /* Remove Break/watchpoint */
   364         if( sscanf( data, "%d,%x,%x", &tmp, &tmp2, &tmp3 ) != 3 ) {
   365             gdb_send_error( server, GDB_ERROR_FORMAT );
   366         } else {
   367             if( tmp == 0 || tmp == 1 ) { /* soft break or hard break */
   368                 server->cpu->clear_breakpoint( tmp2, BREAK_KEEP );
   369                 gdb_send_frame( server, "OK", 2 );
   370             } else {
   371                 gdb_send_frame( server, "", 0 );
   372             }
   373         }
   374         break;
   375     case 'Z': /* Insert Break/watchpoint */
   376         if( sscanf( data, "%d,%x,%x", &tmp, &tmp2, &tmp3 ) != 3 ) {
   377             gdb_send_error( server, GDB_ERROR_FORMAT );
   378         } else {
   379             if( tmp == 0 || tmp == 1 ) { /* soft break or hard break */
   380                 server->cpu->set_breakpoint( tmp2, BREAK_KEEP );
   381                 gdb_send_frame( server, "OK", 2 );
   382             } else {
   383                 gdb_send_frame( server, "", 0 );
   384             }
   385         }
   386         break;
   387     default:
   388         /* Command unsupported */
   389         WARN( "Received unknown GDB command '%c%s'", command, data ); 
   390         gdb_send_frame( server, "", 0 );
   391         break;
   392     }
   394 }
   396 /**
   397  * Decode out frames from the raw data stream. A frame takes the form of
   398  *   $<data>#<checksum>
   399  * where data may not contain a '#' character, and checksum is a simple 
   400  * 8-bit modulo sum of all bytes in data, encoded as a 2-char hex number.
   401  * 
   402  * The only other legal wire forms are 
   403  *   + 
   404  * indicating successful reception of the last message (ignored here), and
   405  *   -
   406  * indicating failed reception of the last message - need to resend.
   407  */
   408 void gdb_server_process_buffer( struct gdb_server *server )
   409 {
   410     int i, frame_start = -1, frame_len = -1;
   411     for( i=0; i<server->buf_posn; i++ ) {
   412         if( frame_start == -1 ) {
   413             if( server->buf[i] == '$' ) {
   414                 frame_start = i;
   415             } else if( server->buf[i] == '+' ) {
   416                 /* Success */
   417                 continue;
   418             } else if( server->buf[i] == '-' ) {
   419                 /* Request retransmit */
   420             } /* Anything else is noise */
   421         } else if( server->buf[i] == '#' ) {
   422             frame_len = i - frame_start - 1;
   423             if( i+2 < server->buf_posn ) {
   424                 int calc_checksum = gdb_checksum( &server->buf[frame_start+1], frame_len );
   425                 int frame_checksum = 0;
   426                 sscanf( &server->buf[i+1], "%02x", &frame_checksum );    
   428                 if( calc_checksum != frame_checksum ) {
   429                     WARN( "GDB frame checksum failure (expected %02X but was %02X)", 
   430                             calc_checksum, frame_checksum ); 
   431                     write( server->fd, "-", 1 );
   432                 } else if( frame_len == 0 ) {
   433                     /* Empty frame - should never occur as a request */
   434                     WARN( "Empty GDB frame received" );
   435                     write( server->fd, "-", 1 );
   436                 } else {
   437                     /* We have a good frame */
   438                     write( server->fd, "+", 1 );
   439                     server->buf[i] = '\0';
   440                     gdb_server_handle_frame( server, server->buf[frame_start+1], &server->buf[frame_start+2], frame_len-1 );
   441                 }
   442                 i+=2;
   443                 frame_start = -1;
   444             }
   445         }
   446     }
   447     if( frame_start == -1 ) {
   448         server->buf_posn = 0; /* Consumed whole buffer */
   449     } else if( frame_start > 0 ) {
   450         memmove(&server->buf[0], &server->buf[frame_start], server->buf_posn - frame_start);
   451         server->buf_posn -= frame_start;
   452     }
   453 }
   455 gboolean gdb_server_data_callback( int fd, void *data )
   456 {
   457     struct gdb_server *server = (struct gdb_server *)data;
   459     size_t len = read( fd, &server->buf[server->buf_posn], server->buf_size - server->buf_posn );
   460     if( len > 0 ) {
   461         server->buf_posn += len;
   462         gdb_server_process_buffer( server );
   464         /* If we have an oversized packet, extend the buffer */
   465         if( server->buf_posn > server->buf_size - BUFFER_SIZE_MARGIN &&
   466                 server->buf_size < MAX_BUFFER_SIZE ) {
   467             server->buf_size <<= 1;
   468             server->buf = realloc( server->buf, server->buf_size );
   469             assert( server->buf != NULL );
   470         }
   471         return TRUE;
   472     } else {
   473         INFO( "GDB disconnected" );
   474         return FALSE;
   475     }
   476 }
   478 gboolean gdb_server_connect_callback( int fd, gpointer data )
   479 {
   480     struct sockaddr_in sin;
   481     socklen_t sinlen;
   482     struct gdb_server *server = (struct gdb_server *)data;
   483     int conn_fd = accept( fd, (struct sockaddr *)&sin, &sinlen);
   484     if( conn_fd != -1 ) {
   485         struct gdb_server *chan_serv = calloc( sizeof(struct gdb_server), 1 );
   486         chan_serv->cpu = server->cpu;
   487         chan_serv->mmu = server->mmu;
   488         chan_serv->fd = conn_fd;
   489         chan_serv->peer_name = g_strdup_printf("%s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); 
   490         chan_serv->buf = malloc(1024);
   491         chan_serv->buf_size = 1024;
   492         chan_serv->buf_posn = 0;
   493         net_register_tcp_listener( conn_fd, gdb_server_data_callback, chan_serv, gdb_server_free );
   494         INFO( "GDB connected from %s", chan_serv->peer_name );
   495     }
   496     return TRUE;
   497 }
   499 /**
   500  * Bind a network port for a GDB remote server for the specified cpu. The
   501  * port is registered for the system network callback.
   502  * 
   503  * @param interface network interface to bind to, or null for the default (all) interface  
   504  * @param port 
   505  * @param cpu CPU to make available over the network port.. 
   506  * @param mmu if TRUE, virtual memory is made available to GDB, otherwise GDB
   507  *     accesses physical memory.
   508  * @return TRUE if the server was bound successfully.
   509  */
   510 gboolean gdb_init_server( const char *interface, int port, cpu_desc_t cpu, gboolean mmu )
   511 {
   512     int fd = net_create_server_socket( interface, port );
   513     if( fd == -1 ) {
   514         return FALSE;
   515     }
   517     struct gdb_server *server = calloc( sizeof(struct gdb_server), 1 );
   518     server->cpu = cpu;
   519     server->mmu = mmu;
   520     server->fd = fd;
   521     net_register_tcp_listener( fd, gdb_server_connect_callback, server, gdb_server_free );
   522     INFO( "%s GDB server running on port %d", cpu->name, port ); 
   523 }
.