Search
lxdream.org :: lxdream/src/gdbserver.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdbserver.c
changeset 1298:d0eb2307b847
prev1272:0b947d924029
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
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; 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 }
.