Search
lxdream.org :: lxdream/src/gdbserver.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdbserver.c
changeset 1081:ef31ae97bb8b
prev1077:136fc24d17ef
next1271:3edc4bdd7c0b
author nkeynes
date Fri Mar 02 23:49:10 2012 +1000 (8 years ago)
permissions -rw-r--r--
last change Android WIP:
* Rename gui_jni.c to gui_android.c - now quite android specific.
* Implement generic EGL driver with very minimal Java wrapper
* Run emulation in separate thread, and implement simple queue for
inter-thread communication.
* Add menu/action-bar items for start + reset
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 "ioutil.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         io_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 = io_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     gboolean result = io_register_tcp_listener( fd, gdb_server_connect_callback, server, gdb_server_free ) != NULL;
   527     INFO( "%s GDB server running on port %d", cpu->name, port );
   528     return result;
   529 }
.