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