2008-02-25 11:48:04 -06:00
/***************************************************************************
* Copyright ( C ) 2005 by Dominic Rath *
* Dominic . Rath @ gmx . de *
* *
2010-03-16 08:45:07 -05:00
* Copyright ( C ) 2007 - 2010 Ø yvind Harboe *
2008-07-25 01:54:17 -05:00
* oyvind . harboe @ zylin . com *
* *
2008-09-20 05:50:53 -05:00
* Copyright ( C ) 2008 by Spencer Oliver *
* spen @ spen - soft . co . uk *
* *
2011-04-14 03:25:01 -05:00
* Copyright ( C ) 2011 by Broadcom Corporation *
* Evan Hunter - ehunter @ broadcom . com *
* *
2011-04-19 01:43:33 -05:00
* Copyright ( C ) ST - Ericsson SA 2011 *
* michel . jaouen @ stericsson . com : smp minimum support *
* *
2008-02-25 11:48:04 -06:00
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the *
* Free Software Foundation , Inc . , *
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2009-12-03 06:14:44 -06:00
# include <target/breakpoints.h>
2009-12-03 06:14:51 -06:00
# include <target/target_request.h>
2009-12-03 06:14:50 -06:00
# include <target/register.h>
2008-02-25 11:48:04 -06:00
# include "server.h"
2009-12-04 18:40:19 -06:00
# include <flash/nor/core.h>
2009-11-16 02:35:24 -06:00
# include "gdb_server.h"
2009-12-03 06:14:47 -06:00
# include <target/image.h>
2009-12-03 06:14:31 -06:00
# include <jtag/jtag.h>
2011-04-14 03:25:01 -05:00
# include "rtos/rtos.h"
2011-04-19 01:43:33 -05:00
# include "target/smp.h"
2008-02-25 11:48:04 -06:00
2010-01-11 02:14:01 -06:00
/**
* @ file
* GDB server implementation .
*
* This implements the GDB Remote Serial Protocol , over TCP connections ,
* giving GDB access to the JTAG or other hardware debugging facilities
* found in most modern embedded processors .
*/
2009-12-10 12:11:03 -06:00
/* private connection data for GDB */
struct gdb_connection
{
char buffer [ GDB_BUFFER_SIZE ] ;
char * buf_p ;
int buf_cnt ;
int ctrl_c ;
enum target_state frontend_state ;
struct image * vflash_image ;
int closed ;
int busy ;
int noack_mode ;
2011-04-19 01:43:33 -05:00
bool sync ; /* set flag to true if you want the next stepi to return immediately.
2009-12-10 12:11:03 -06:00
allowing GDB to pick up a fresh set of register values from the target
without modifying the target state . */
2010-03-16 08:45:07 -05:00
/* We delay reporting memory write errors until next step/continue or memory
* write . This improves performance of gdb load significantly as the GDB packet
* can be replied immediately and a new GDB packet will be ready without delay
* ( ca . 10 % or so . . . ) .
*/
bool mem_write_error ;
2009-12-10 12:11:03 -06:00
} ;
2008-02-25 11:48:04 -06:00
#if 0
# define _DEBUG_GDB_IO_
# endif
2009-11-13 10:06:49 -06:00
static struct gdb_connection * current_gdb_connection ;
2009-09-24 01:34:23 -05:00
2008-08-13 15:42:07 -05:00
static int gdb_breakpoint_override ;
static enum breakpoint_type gdb_breakpoint_override_type ;
2010-01-20 01:30:36 -06:00
static int gdb_error ( struct connection * connection , int retval ) ;
2010-09-27 01:48:31 -05:00
static const char * gdb_port ;
static const char * gdb_port_next ;
2010-01-11 02:14:01 -06:00
static const char DIGITS [ 16 ] = " 0123456789abcdef " ;
2008-02-25 11:48:04 -06:00
2009-11-09 08:12:02 -06:00
static void gdb_log_callback ( void * priv , const char * file , unsigned line ,
2008-02-29 05:16:38 -06:00
const char * function , const char * string ) ;
2008-02-25 11:48:04 -06:00
2009-11-24 13:01:15 -06:00
/* number of gdb connections, mainly to suppress gdb related debugging spam
2009-05-27 15:30:17 -05:00
* in helper / log . c when no gdb connections are actually active */
int gdb_actual_connections ;
2008-02-25 11:48:04 -06:00
/* set if we are sending a memory map to gdb
* via qXfer : memory - map : read packet */
2008-04-18 02:33:03 -05:00
/* enabled by default*/
2010-01-20 01:30:36 -06:00
static int gdb_use_memory_map = 1 ;
2008-04-18 02:33:03 -05:00
/* enabled by default*/
2010-01-20 01:30:36 -06:00
static int gdb_flash_program = 1 ;
2008-02-25 11:48:04 -06:00
/* if set, data aborts cause an error to be reported in memory read packets
2010-01-20 01:30:36 -06:00
* see the code in gdb_read_memory_packet ( ) for further explanations .
* Disabled by default .
*/
static int gdb_report_data_abort ;
2008-02-25 11:48:04 -06:00
2010-01-20 01:30:36 -06:00
static int gdb_last_signal ( struct target * target )
2008-02-25 11:48:04 -06:00
{
switch ( target - > debug_reason )
{
case DBG_REASON_DBGRQ :
return 0x2 ; /* SIGINT */
case DBG_REASON_BREAKPOINT :
case DBG_REASON_WATCHPOINT :
case DBG_REASON_WPTANDBKPT :
return 0x05 ; /* SIGTRAP */
case DBG_REASON_SINGLESTEP :
return 0x05 ; /* SIGTRAP */
case DBG_REASON_NOTHALTED :
return 0x0 ; /* no signal... shouldn't happen */
default :
2008-03-25 10:45:17 -05:00
LOG_USER ( " undefined debug reason %d - target needs reset " , target - > debug_reason ) ;
2008-03-05 04:28:32 -06:00
return 0x0 ;
}
}
2010-01-20 01:30:36 -06:00
static int check_pending ( struct connection * connection ,
int timeout_s , int * got_data )
2008-03-05 04:28:32 -06:00
{
/* a non-blocking socket will block if there is 0 bytes available on the socket,
* but return with as many bytes as are available immediately
*/
struct timeval tv ;
fd_set read_fds ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-03-05 04:28:32 -06:00
int t ;
2009-06-23 17:42:03 -05:00
if ( got_data = = NULL )
2008-03-05 04:28:32 -06:00
got_data = & t ;
2009-06-23 17:42:54 -05:00
* got_data = 0 ;
2008-03-05 04:28:32 -06:00
2009-06-23 17:45:47 -05:00
if ( gdb_con - > buf_cnt > 0 )
2008-03-05 04:28:32 -06:00
{
* got_data = 1 ;
return ERROR_OK ;
}
2008-09-24 03:42:13 -05:00
2008-03-05 04:28:32 -06:00
FD_ZERO ( & read_fds ) ;
FD_SET ( connection - > fd , & read_fds ) ;
2008-09-24 03:42:13 -05:00
2008-03-05 04:28:32 -06:00
tv . tv_sec = timeout_s ;
tv . tv_usec = 0 ;
2009-01-01 10:06:46 -06:00
if ( socket_select ( connection - > fd + 1 , & read_fds , NULL , NULL , & tv ) = = 0 )
2008-03-05 04:28:32 -06:00
{
/* This can typically be because a "monitor" command took too long
* before printing any progress messages
*/
2009-06-23 17:45:47 -05:00
if ( timeout_s > 0 )
2008-03-05 04:28:32 -06:00
{
return ERROR_GDB_TIMEOUT ;
} else
{
return ERROR_OK ;
}
2008-02-25 11:48:04 -06:00
}
2009-06-23 17:42:54 -05:00
* got_data = FD_ISSET ( connection - > fd , & read_fds ) ! = 0 ;
2008-03-05 04:28:32 -06:00
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
2009-12-10 12:14:45 -06:00
static int gdb_get_char_inner ( struct connection * connection , int * next_char )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2009-06-23 17:42:54 -05:00
int retval = ERROR_OK ;
2008-02-25 11:48:04 -06:00
2010-05-14 08:04:14 -05:00
# ifdef _DEBUG_GDB_IO_
char * debug_buffer ;
# endif
2008-02-25 11:48:04 -06:00
for ( ; ; )
{
2010-09-27 01:26:31 -05:00
if ( connection - > service - > type ! = CONNECTION_TCP )
2008-12-15 03:43:26 -06:00
{
gdb_con - > buf_cnt = read ( connection - > fd , gdb_con - > buffer , GDB_BUFFER_SIZE ) ;
}
else
{
retval = check_pending ( connection , 1 , NULL ) ;
if ( retval ! = ERROR_OK )
return retval ;
gdb_con - > buf_cnt = read_socket ( connection - > fd , gdb_con - > buffer , GDB_BUFFER_SIZE ) ;
}
2008-12-16 04:55:08 -06:00
2008-02-25 11:48:04 -06:00
if ( gdb_con - > buf_cnt > 0 )
{
break ;
}
if ( gdb_con - > buf_cnt = = 0 )
{
gdb_con - > closed = 1 ;
return ERROR_SERVER_REMOTE_CLOSED ;
}
# ifdef _WIN32
errno = WSAGetLastError ( ) ;
2009-06-23 17:36:56 -05:00
switch ( errno )
2008-02-25 11:48:04 -06:00
{
case WSAEWOULDBLOCK :
usleep ( 1000 ) ;
break ;
case WSAECONNABORTED :
2008-03-05 04:28:32 -06:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
case WSAECONNRESET :
2008-03-05 04:28:32 -06:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
default :
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " read: %d " , errno ) ;
2008-02-25 11:48:04 -06:00
exit ( - 1 ) ;
}
# else
2009-06-23 17:36:56 -05:00
switch ( errno )
2008-02-25 11:48:04 -06:00
{
case EAGAIN :
usleep ( 1000 ) ;
break ;
case ECONNABORTED :
2008-03-05 04:28:32 -06:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
case ECONNRESET :
2008-03-05 04:28:32 -06:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
default :
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " read: %s " , strerror ( errno ) ) ;
2008-03-05 04:28:32 -06:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
# endif
}
# ifdef _DEBUG_GDB_IO_
debug_buffer = malloc ( gdb_con - > buf_cnt + 1 ) ;
memcpy ( debug_buffer , gdb_con - > buffer , gdb_con - > buf_cnt ) ;
debug_buffer [ gdb_con - > buf_cnt ] = 0 ;
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " received '%s' " , debug_buffer ) ;
2008-02-25 11:48:04 -06:00
free ( debug_buffer ) ;
# endif
gdb_con - > buf_p = gdb_con - > buffer ;
gdb_con - > buf_cnt - - ;
* next_char = * ( gdb_con - > buf_p + + ) ;
if ( gdb_con - > buf_cnt > 0 )
connection - > input_pending = 1 ;
else
2008-02-28 04:07:54 -06:00
connection - > input_pending = 0 ;
2008-02-25 11:48:04 -06:00
# ifdef _DEBUG_GDB_IO_
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " returned char '%c' (0x%2.2x) " , * next_char , * next_char ) ;
2008-02-25 11:48:04 -06:00
# endif
2008-03-05 04:28:32 -06:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2009-12-10 12:14:45 -06:00
/**
* The cool thing about this fn is that it allows buf_p and buf_cnt to be
* held in registers in the inner loop .
*
* For small caches and embedded systems this is important !
*/
static inline int gdb_get_char_fast ( struct connection * connection , int * next_char , char * * buf_p , int * buf_cnt )
{
int retval = ERROR_OK ;
if ( ( * buf_cnt ) - - > 0 )
{
* next_char = * * buf_p ;
( * buf_p ) + + ;
if ( * buf_cnt > 0 )
connection - > input_pending = 1 ;
else
connection - > input_pending = 0 ;
# ifdef _DEBUG_GDB_IO_
LOG_DEBUG ( " returned char '%c' (0x%2.2x) " , * next_char , * next_char ) ;
# endif
return ERROR_OK ;
}
struct gdb_connection * gdb_con = connection - > priv ;
gdb_con - > buf_p = * buf_p ;
gdb_con - > buf_cnt = * buf_cnt ;
retval = gdb_get_char_inner ( connection , next_char ) ;
* buf_p = gdb_con - > buf_p ;
* buf_cnt = gdb_con - > buf_cnt ;
return retval ;
}
2010-01-20 01:30:36 -06:00
static int gdb_get_char ( struct connection * connection , int * next_char )
2009-12-10 12:14:45 -06:00
{
struct gdb_connection * gdb_con = connection - > priv ;
return gdb_get_char_fast ( connection , next_char , & gdb_con - > buf_p , & gdb_con - > buf_cnt ) ;
}
2010-01-20 01:30:36 -06:00
static int gdb_putback_char ( struct connection * connection , int last_char )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
if ( gdb_con - > buf_p > gdb_con - > buffer )
{
* ( - - gdb_con - > buf_p ) = last_char ;
gdb_con - > buf_cnt + + ;
}
else
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: couldn't put character back " ) ;
2008-02-25 11:48:04 -06:00
}
return ERROR_OK ;
}
/* The only way we can detect that the socket is closed is the first time
* we write to it , we will fail . Subsequent write operations will
* succeed . Shudder ! */
2010-01-20 01:30:36 -06:00
static int gdb_write ( struct connection * connection , void * data , int len )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
if ( gdb_con - > closed )
return ERROR_SERVER_REMOTE_CLOSED ;
2008-12-16 04:55:08 -06:00
2010-09-27 02:24:51 -05:00
if ( connection_write ( connection , data , len ) = = len )
2008-02-25 11:48:04 -06:00
{
2010-09-27 01:26:31 -05:00
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
gdb_con - > closed = 1 ;
return ERROR_SERVER_REMOTE_CLOSED ;
}
2010-01-20 01:30:36 -06:00
static int gdb_put_packet_inner ( struct connection * connection ,
char * buffer , int len )
2008-02-25 11:48:04 -06:00
{
int i ;
unsigned char my_checksum = 0 ;
# ifdef _DEBUG_GDB_IO_
char * debug_buffer ;
# endif
int reply ;
int retval ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
for ( i = 0 ; i < len ; i + + )
my_checksum + = buffer [ i ] ;
2008-03-05 04:28:32 -06:00
# ifdef _DEBUG_GDB_IO_
2008-09-24 03:42:13 -05:00
/*
2008-03-05 04:28:32 -06:00
* At this point we should have nothing in the input queue from GDB ,
* however sometimes ' - ' is sent even though we ' ve already received
* an ACK ( + ) for everything we ' ve sent off .
*/
int gotdata ;
for ( ; ; )
{
2010-01-20 01:30:36 -06:00
retval = check_pending ( connection , 0 , & gotdata ) ;
if ( retval ! = ERROR_OK )
2008-03-05 04:28:32 -06:00
return retval ;
if ( ! gotdata )
break ;
if ( ( retval = gdb_get_char ( connection , & reply ) ) ! = ERROR_OK )
return retval ;
2009-06-23 17:49:06 -05:00
if ( reply = = ' $ ' ) {
2008-12-13 06:44:39 -06:00
/* fix a problem with some IAR tools */
2009-06-23 17:47:42 -05:00
gdb_putback_char ( connection , reply ) ;
2008-10-11 01:13:21 -05:00
LOG_DEBUG ( " Unexpected start of new packet " ) ;
break ;
}
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " Discard unexpected char %c " , reply ) ;
2008-03-05 04:28:32 -06:00
}
# endif
2008-02-25 11:48:04 -06:00
while ( 1 )
{
# ifdef _DEBUG_GDB_IO_
debug_buffer = malloc ( len + 1 ) ;
memcpy ( debug_buffer , buffer , len ) ;
debug_buffer [ len ] = 0 ;
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " sending packet '$%s#%2.2x' " , debug_buffer , my_checksum ) ;
2008-02-25 11:48:04 -06:00
free ( debug_buffer ) ;
# endif
2008-02-28 04:07:54 -06:00
2008-03-06 06:04:27 -06:00
char local_buffer [ 1024 ] ;
local_buffer [ 0 ] = ' $ ' ;
2009-04-19 15:51:16 -05:00
if ( ( size_t ) len + 4 < = sizeof ( local_buffer ) )
2008-02-25 11:48:04 -06:00
{
2008-03-06 06:04:27 -06:00
/* performance gain on smaller packets by only a single call to gdb_write() */
2009-06-23 17:44:17 -05:00
memcpy ( local_buffer + 1 , buffer , len + + ) ;
2008-03-06 06:04:27 -06:00
local_buffer [ len + + ] = ' # ' ;
local_buffer [ len + + ] = DIGITS [ ( my_checksum > > 4 ) & 0xf ] ;
local_buffer [ len + + ] = DIGITS [ my_checksum & 0xf ] ;
2009-06-23 17:35:09 -05:00
if ( ( retval = gdb_write ( connection , local_buffer , len ) ) ! = ERROR_OK )
2008-10-14 08:14:52 -05:00
{
return retval ;
}
2008-02-25 11:48:04 -06:00
}
2008-03-06 06:04:27 -06:00
else
2008-02-25 11:48:04 -06:00
{
2008-03-06 06:04:27 -06:00
/* larger packets are transmitted directly from caller supplied buffer
by several calls to gdb_write ( ) to avoid dynamic allocation */
local_buffer [ 1 ] = ' # ' ;
local_buffer [ 2 ] = DIGITS [ ( my_checksum > > 4 ) & 0xf ] ;
local_buffer [ 3 ] = DIGITS [ my_checksum & 0xf ] ;
2009-06-23 17:35:09 -05:00
if ( ( retval = gdb_write ( connection , local_buffer , 1 ) ) ! = ERROR_OK )
2008-10-14 08:14:52 -05:00
{
return retval ;
}
2009-06-23 17:35:09 -05:00
if ( ( retval = gdb_write ( connection , buffer , len ) ) ! = ERROR_OK )
2008-10-14 08:14:52 -05:00
{
return retval ;
}
2009-06-23 17:44:17 -05:00
if ( ( retval = gdb_write ( connection , local_buffer + 1 , 3 ) ) ! = ERROR_OK )
2008-10-14 08:14:52 -05:00
{
return retval ;
}
2008-02-25 11:48:04 -06:00
}
2008-09-24 03:42:13 -05:00
2008-08-22 14:58:19 -05:00
if ( gdb_con - > noack_mode )
break ;
2008-09-24 03:42:13 -05:00
2008-02-25 11:48:04 -06:00
if ( ( retval = gdb_get_char ( connection , & reply ) ) ! = ERROR_OK )
return retval ;
if ( reply = = ' + ' )
break ;
else if ( reply = = ' - ' )
{
/* Stop sending output packets for now */
log_remove_callback ( gdb_log_callback , connection ) ;
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " negative reply, retrying " ) ;
2008-02-25 11:48:04 -06:00
}
else if ( reply = = 0x3 )
{
gdb_con - > ctrl_c = 1 ;
if ( ( retval = gdb_get_char ( connection , & reply ) ) ! = ERROR_OK )
return retval ;
if ( reply = = ' + ' )
break ;
else if ( reply = = ' - ' )
{
/* Stop sending output packets for now */
log_remove_callback ( gdb_log_callback , connection ) ;
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " negative reply, retrying " ) ;
2008-02-25 11:48:04 -06:00
}
2009-06-23 17:49:06 -05:00
else if ( reply = = ' $ ' ) {
2008-10-11 01:13:21 -05:00
LOG_ERROR ( " GDB missing ack(1) - assumed good " ) ;
2009-06-23 17:47:42 -05:00
gdb_putback_char ( connection , reply ) ;
2008-10-11 01:13:21 -05:00
return ERROR_OK ;
} else {
2008-10-22 04:30:33 -05:00
2008-10-11 01:13:21 -05:00
LOG_ERROR ( " unknown character(1) 0x%2.2x in reply, dropping connection " , reply ) ;
2009-06-23 17:42:54 -05:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2008-10-22 04:30:33 -05:00
}
2009-06-23 17:49:06 -05:00
else if ( reply = = ' $ ' ) {
2008-10-11 01:13:21 -05:00
LOG_ERROR ( " GDB missing ack(2) - assumed good " ) ;
2009-06-23 17:47:42 -05:00
gdb_putback_char ( connection , reply ) ;
2008-10-11 01:13:21 -05:00
return ERROR_OK ;
2008-10-22 04:30:33 -05:00
}
2008-02-25 11:48:04 -06:00
else
{
2008-10-11 01:13:21 -05:00
LOG_ERROR ( " unknown character(2) 0x%2.2x in reply, dropping connection " , reply ) ;
2009-06-23 17:42:54 -05:00
gdb_con - > closed = 1 ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
}
if ( gdb_con - > closed )
return ERROR_SERVER_REMOTE_CLOSED ;
return ERROR_OK ;
}
2011-04-14 03:25:01 -05:00
int gdb_put_packet ( struct connection * connection , char * buffer , int len )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
gdb_con - > busy = 1 ;
int retval = gdb_put_packet_inner ( connection , buffer , len ) ;
gdb_con - > busy = 0 ;
2008-09-24 03:42:13 -05:00
/* we sent some data, reset timer for keep alive messages */
kept_alive ( ) ;
2008-02-25 11:48:04 -06:00
return retval ;
}
2009-11-13 10:10:43 -06:00
static __inline__ int fetch_packet ( struct connection * connection , int * checksum_ok , int noack , int * len , char * buffer )
2008-02-25 11:48:04 -06:00
{
2008-08-26 06:29:59 -05:00
unsigned char my_checksum = 0 ;
char checksum [ 3 ] ;
2008-02-25 11:48:04 -06:00
int character ;
2009-12-10 12:14:45 -06:00
int retval = ERROR_OK ;
2008-09-24 03:42:13 -05:00
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-08-26 06:29:59 -05:00
my_checksum = 0 ;
2008-02-25 11:48:04 -06:00
int count = 0 ;
2008-08-26 06:29:59 -05:00
count = 0 ;
2009-12-10 12:14:45 -06:00
/* move this over into local variables to use registers and give the
* more freedom to optimize */
char * buf_p = gdb_con - > buf_p ;
int buf_cnt = gdb_con - > buf_cnt ;
2008-08-26 06:29:59 -05:00
for ( ; ; )
{
/* The common case is that we have an entire packet with no escape chars.
* We need to leave at least 2 bytes in the buffer to have
* gdb_get_char ( ) update various bits and bobs correctly .
*/
2009-12-10 12:14:45 -06:00
if ( ( buf_cnt > 2 ) & & ( ( buf_cnt + count ) < * len ) )
2008-08-26 06:29:59 -05:00
{
/* The compiler will struggle a bit with constant propagation and
* aliasing , so we help it by showing that these values do not
* change inside the loop
*/
int i ;
2009-12-10 12:14:45 -06:00
char * buf = buf_p ;
int run = buf_cnt - 2 ;
2008-08-26 06:29:59 -05:00
i = 0 ;
int done = 0 ;
while ( i < run )
{
character = * buf + + ;
i + + ;
if ( character = = ' # ' )
{
/* Danger! character can be '#' when esc is
* used so we need an explicit boolean for done here .
*/
done = 1 ;
break ;
}
if ( character = = ' } ' )
{
/* data transmitted in binary mode (X packet)
* uses 0x7d as escape character */
my_checksum + = character & 0xff ;
character = * buf + + ;
i + + ;
my_checksum + = character & 0xff ;
buffer [ count + + ] = ( character ^ 0x20 ) & 0xff ;
}
else
{
my_checksum + = character & 0xff ;
buffer [ count + + ] = character & 0xff ;
}
}
2009-12-10 12:14:45 -06:00
buf_p + = i ;
buf_cnt - = i ;
2008-08-26 06:29:59 -05:00
if ( done )
break ;
}
if ( count > * len )
{
LOG_ERROR ( " packet buffer too small " ) ;
2009-12-10 12:14:45 -06:00
retval = ERROR_GDB_BUFFER_TOO_SMALL ;
break ;
2008-08-26 06:29:59 -05:00
}
2009-12-10 12:14:45 -06:00
retval = gdb_get_char_fast ( connection , & character , & buf_p , & buf_cnt ) ;
if ( retval ! = ERROR_OK )
break ;
2008-08-26 06:29:59 -05:00
if ( character = = ' # ' )
break ;
if ( character = = ' } ' )
{
/* data transmitted in binary mode (X packet)
* uses 0x7d as escape character */
my_checksum + = character & 0xff ;
2009-12-10 12:14:45 -06:00
retval = gdb_get_char_fast ( connection , & character , & buf_p , & buf_cnt ) ;
if ( retval ! = ERROR_OK )
break ;
2008-08-26 06:29:59 -05:00
my_checksum + = character & 0xff ;
buffer [ count + + ] = ( character ^ 0x20 ) & 0xff ;
}
else
{
my_checksum + = character & 0xff ;
buffer [ count + + ] = character & 0xff ;
}
}
2009-12-10 12:14:45 -06:00
gdb_con - > buf_p = buf_p ;
gdb_con - > buf_cnt = buf_cnt ;
if ( retval ! = ERROR_OK )
return retval ;
2008-08-26 06:29:59 -05:00
* len = count ;
if ( ( retval = gdb_get_char ( connection , & character ) ) ! = ERROR_OK )
return retval ;
checksum [ 0 ] = character ;
if ( ( retval = gdb_get_char ( connection , & character ) ) ! = ERROR_OK )
return retval ;
checksum [ 1 ] = character ;
checksum [ 2 ] = 0 ;
2008-09-24 03:42:13 -05:00
2008-08-26 06:29:59 -05:00
if ( ! noack )
{
2009-06-23 17:42:54 -05:00
* checksum_ok = ( my_checksum = = strtoul ( checksum , NULL , 16 ) ) ;
2008-08-26 06:29:59 -05:00
}
2008-09-24 03:42:13 -05:00
2008-08-26 06:29:59 -05:00
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_get_packet_inner ( struct connection * connection ,
char * buffer , int * len )
2008-08-26 06:29:59 -05:00
{
int character ;
2008-02-25 11:48:04 -06:00
int retval ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
while ( 1 )
{
do
{
if ( ( retval = gdb_get_char ( connection , & character ) ) ! = ERROR_OK )
return retval ;
# ifdef _DEBUG_GDB_IO_
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " character: '%c' " , character ) ;
2008-02-25 11:48:04 -06:00
# endif
switch ( character )
{
case ' $ ' :
break ;
case ' + ' :
2008-07-23 17:24:02 -05:00
/* gdb sends a dummy ack '+' at every remote connect - see remote_start_remote (remote.c)
2009-11-24 13:01:15 -06:00
* in case anyone tries to debug why they receive this warning every time */
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " acknowledgment received, but no packet pending " ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' - ' :
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " negative acknowledgment, but no packet pending " ) ;
2008-02-25 11:48:04 -06:00
break ;
case 0x3 :
gdb_con - > ctrl_c = 1 ;
* len = 0 ;
return ERROR_OK ;
default :
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " ignoring character 0x%x " , character ) ;
2008-02-25 11:48:04 -06:00
break ;
}
} while ( character ! = ' $ ' ) ;
2008-02-28 04:07:54 -06:00
2009-02-18 01:39:20 -06:00
int checksum_ok = 0 ;
2008-08-26 06:29:59 -05:00
/* explicit code expansion here to get faster inlined code in -O3 by not
* calculating checksum
*/
if ( gdb_con - > noack_mode )
{
2009-06-23 17:42:54 -05:00
if ( ( retval = fetch_packet ( connection , & checksum_ok , 1 , len , buffer ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
return retval ;
2008-08-26 06:29:59 -05:00
} else
2008-02-25 11:48:04 -06:00
{
2009-06-23 17:42:54 -05:00
if ( ( retval = fetch_packet ( connection , & checksum_ok , 0 , len , buffer ) ) ! = ERROR_OK )
2008-08-26 06:29:59 -05:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2008-08-26 06:29:59 -05:00
if ( gdb_con - > noack_mode )
2008-08-22 14:58:19 -05:00
{
2008-08-26 06:29:59 -05:00
/* checksum is not checked in noack mode */
break ;
2008-08-22 14:58:19 -05:00
}
2008-08-26 06:29:59 -05:00
if ( checksum_ok )
2008-08-22 14:58:19 -05:00
{
2008-10-14 08:14:52 -05:00
if ( ( retval = gdb_write ( connection , " + " , 1 ) ) ! = ERROR_OK )
{
return retval ;
}
2008-08-22 14:58:19 -05:00
break ;
}
2008-02-25 11:48:04 -06:00
}
if ( gdb_con - > closed )
return ERROR_SERVER_REMOTE_CLOSED ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_get_packet ( struct connection * connection , char * buffer , int * len )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
gdb_con - > busy = 1 ;
int retval = gdb_get_packet_inner ( connection , buffer , len ) ;
gdb_con - > busy = 0 ;
return retval ;
}
2008-02-28 04:07:54 -06:00
2010-01-20 01:30:36 -06:00
static int gdb_output_con ( struct connection * connection , const char * line )
2008-02-25 11:48:04 -06:00
{
char * hex_buffer ;
int i , bin_size ;
bin_size = strlen ( line ) ;
2008-02-28 02:11:18 -06:00
hex_buffer = malloc ( bin_size * 2 + 2 ) ;
2008-02-29 05:16:38 -06:00
if ( hex_buffer = = NULL )
return ERROR_GDB_BUFFER_TOO_SMALL ;
2008-02-25 11:48:04 -06:00
hex_buffer [ 0 ] = ' O ' ;
2009-06-23 17:45:47 -05:00
for ( i = 0 ; i < bin_size ; i + + )
2008-02-25 11:48:04 -06:00
snprintf ( hex_buffer + 1 + i * 2 , 3 , " %2.2x " , line [ i ] ) ;
2009-06-23 17:44:17 -05:00
hex_buffer [ bin_size * 2 + 1 ] = 0 ;
2008-02-25 11:48:04 -06:00
2008-10-14 08:14:52 -05:00
int retval = gdb_put_packet ( connection , hex_buffer , bin_size * 2 + 1 ) ;
2008-02-25 11:48:04 -06:00
free ( hex_buffer ) ;
2008-10-14 08:14:52 -05:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2010-01-20 01:30:36 -06:00
static int gdb_output ( struct command_context * context , const char * line )
2008-02-25 11:48:04 -06:00
{
/* this will be dumped to the log and also sent as an O packet if possible */
2008-03-25 10:45:17 -05:00
LOG_USER_N ( " %s " , line ) ;
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
2009-11-13 12:11:13 -06:00
static void gdb_frontend_halted ( struct target * target , struct connection * connection )
2008-08-13 07:21:57 -05:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_connection = connection - > priv ;
2008-09-24 03:42:13 -05:00
2009-07-08 05:25:23 -05:00
/* In the GDB protocol when we are stepping or continuing execution,
2008-08-13 07:21:57 -05:00
* we have a lingering reply . Upon receiving a halted event
* when we have that lingering packet , we reply to the original
* step or continue packet .
*
* Executing monitor commands can bring the target in and
* out of the running state so we ' ll see lots of TARGET_EVENT_XXX
* that are to be ignored .
*/
if ( gdb_connection - > frontend_state = = TARGET_RUNNING )
{
char sig_reply [ 4 ] ;
2010-06-17 08:30:25 -05:00
int signal_var ;
2008-11-05 02:48:50 -06:00
2008-08-13 07:21:57 -05:00
/* stop forwarding log packets! */
log_remove_callback ( gdb_log_callback , connection ) ;
if ( gdb_connection - > ctrl_c )
{
2010-06-17 08:30:25 -05:00
signal_var = 0x2 ;
2008-08-13 07:21:57 -05:00
gdb_connection - > ctrl_c = 0 ;
}
else
{
2010-06-17 08:30:25 -05:00
signal_var = gdb_last_signal ( target ) ;
2008-08-13 07:21:57 -05:00
}
2010-06-17 08:30:25 -05:00
snprintf ( sig_reply , 4 , " T%2.2x " , signal_var ) ;
2008-08-13 07:21:57 -05:00
gdb_put_packet ( connection , sig_reply , 3 ) ;
gdb_connection - > frontend_state = TARGET_HALTED ;
2011-04-14 03:25:01 -05:00
rtos_update_threads ( target ) ;
2008-08-13 07:21:57 -05:00
}
}
2010-01-20 01:30:36 -06:00
static int gdb_target_callback_event_handler ( struct target * target ,
enum target_event event , void * priv )
2008-02-25 11:48:04 -06:00
{
2008-10-14 08:14:52 -05:00
int retval ;
2009-11-13 10:10:43 -06:00
struct connection * connection = priv ;
2008-02-25 11:48:04 -06:00
2009-06-23 17:47:42 -05:00
target_handle_event ( target , event ) ;
2008-02-25 11:48:04 -06:00
switch ( event )
{
2009-10-08 07:53:25 -05:00
case TARGET_EVENT_GDB_HALT :
2008-08-13 07:21:57 -05:00
gdb_frontend_halted ( target , connection ) ;
2008-02-25 11:48:04 -06:00
break ;
2008-11-05 02:48:50 -06:00
case TARGET_EVENT_HALTED :
target_call_event_callbacks ( target , TARGET_EVENT_GDB_END ) ;
break ;
2008-08-24 13:20:49 -05:00
case TARGET_EVENT_GDB_FLASH_ERASE_START :
2009-06-23 17:47:42 -05:00
target_handle_event ( target , TARGET_EVENT_OLD_gdb_program_config ) ;
2009-06-23 17:35:09 -05:00
if ( ( retval = jtag_execute_queue ( ) ) ! = ERROR_OK )
2008-10-14 08:14:52 -05:00
{
return retval ;
}
2008-02-25 11:48:04 -06:00
break ;
default :
break ;
}
return ERROR_OK ;
}
2008-02-28 04:07:54 -06:00
2010-01-20 01:30:36 -06:00
static int gdb_new_connection ( struct connection * connection )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_connection = malloc ( sizeof ( struct gdb_connection ) ) ;
2009-11-13 10:06:52 -06:00
struct gdb_service * gdb_service = connection - > service - > priv ;
2008-02-25 11:48:04 -06:00
int retval ;
int initial_ack ;
connection - > priv = gdb_connection ;
/* initialize gdb connection information */
gdb_connection - > buf_p = gdb_connection - > buffer ;
gdb_connection - > buf_cnt = 0 ;
gdb_connection - > ctrl_c = 0 ;
gdb_connection - > frontend_state = TARGET_HALTED ;
gdb_connection - > vflash_image = NULL ;
gdb_connection - > closed = 0 ;
gdb_connection - > busy = 0 ;
2008-08-22 14:58:19 -05:00
gdb_connection - > noack_mode = 0 ;
2009-09-24 01:34:23 -05:00
gdb_connection - > sync = true ;
2010-03-16 08:45:07 -05:00
gdb_connection - > mem_write_error = false ;
2008-09-24 03:42:13 -05:00
2008-03-05 04:28:32 -06:00
/* send ACK to GDB for debug request */
gdb_write ( connection , " + " , 1 ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* output goes through gdb connection */
command_set_output_handler ( connection - > cmd_ctx , gdb_output , connection ) ;
2008-08-13 10:05:15 -05:00
/* we must remove all breakpoints registered to the target as a previous
2008-09-24 03:42:13 -05:00
* GDB session could leave dangling breakpoints if e . g . communication
2008-08-13 10:05:15 -05:00
* timed out .
*/
breakpoint_clear_target ( gdb_service - > target ) ;
watchpoint_clear_target ( gdb_service - > target ) ;
2008-09-24 03:42:13 -05:00
2008-02-25 11:48:04 -06:00
/* remove the initial ACK from the incoming buffer */
if ( ( retval = gdb_get_char ( connection , & initial_ack ) ) ! = ERROR_OK )
return retval ;
2008-09-24 03:42:13 -05:00
/* FIX!!!??? would we actually ever receive a + here???
2008-03-05 04:28:32 -06:00
* Not observed .
*/
2008-02-25 11:48:04 -06:00
if ( initial_ack ! = ' + ' )
gdb_putback_char ( connection , initial_ack ) ;
2009-06-23 17:47:42 -05:00
target_call_event_callbacks ( gdb_service - > target , TARGET_EVENT_GDB_ATTACH ) ;
2009-05-27 15:30:17 -05:00
2010-05-04 06:26:52 -05:00
if ( gdb_use_memory_map )
{
/* Connect must fail if the memory map can't be set up correctly.
*
* This will cause an auto_probe to be invoked , which is either
* a no - op or it will fail when the target isn ' t ready ( e . g . not halted ) .
*/
int i ;
for ( i = 0 ; i < flash_get_bank_count ( ) ; i + + )
{
struct flash_bank * p ;
retval = get_flash_bank_by_num ( i , & p ) ;
if ( retval ! = ERROR_OK )
{
2010-11-11 01:50:22 -06:00
LOG_ERROR ( " Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use 'gdb_memory_map disable'. " ) ;
2010-05-04 06:26:52 -05:00
return retval ;
}
}
}
2009-05-27 15:30:17 -05:00
gdb_actual_connections + + ;
2009-06-27 21:54:19 -05:00
LOG_DEBUG ( " New GDB Connection: %d, Target %s, state: %s " ,
gdb_actual_connections ,
2009-11-25 18:38:08 -06:00
target_name ( gdb_service - > target ) ,
2009-06-27 21:54:19 -05:00
target_state_name ( gdb_service - > target ) ) ;
2009-05-27 15:30:17 -05:00
2010-11-13 06:03:29 -06:00
/* DANGER! If we fail subsequently, we must remove this handler,
* otherwise we occasionally see crashes as the timer can invoke the
* callback fn .
*
* register callback to be informed about target events */
target_register_event_callback ( gdb_target_callback_event_handler , connection ) ;
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_connection_closed ( struct connection * connection )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:52 -06:00
struct gdb_service * gdb_service = connection - > service - > priv ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_connection = connection - > priv ;
2008-02-25 11:48:04 -06:00
2009-07-27 13:56:43 -05:00
/* we're done forwarding messages. Tear down callback before
* cleaning up connection .
*/
log_remove_callback ( gdb_log_callback , connection ) ;
2009-05-27 15:30:17 -05:00
gdb_actual_connections - - ;
2009-09-21 13:40:55 -05:00
LOG_DEBUG ( " GDB Close, Target: %s, state: %s, gdb_actual_connections=%d " ,
2009-11-25 18:38:08 -06:00
target_name ( gdb_service - > target ) ,
2009-06-27 21:54:19 -05:00
target_state_name ( gdb_service - > target ) ,
gdb_actual_connections ) ;
2009-05-27 15:30:17 -05:00
2008-02-25 11:48:04 -06:00
/* see if an image built with vFlash commands is left */
if ( gdb_connection - > vflash_image )
{
image_close ( gdb_connection - > vflash_image ) ;
free ( gdb_connection - > vflash_image ) ;
gdb_connection - > vflash_image = NULL ;
}
/* if this connection registered a debug-message receiver delete it */
delete_debug_msg_receiver ( connection - > cmd_ctx , gdb_service - > target ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( connection - > priv )
{
free ( connection - > priv ) ;
connection - > priv = NULL ;
}
else
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: connection->priv == NULL " ) ;
2008-02-25 11:48:04 -06:00
}
2009-07-27 13:56:43 -05:00
2008-02-25 11:48:04 -06:00
target_unregister_event_callback ( gdb_target_callback_event_handler , connection ) ;
2009-07-27 13:56:43 -05:00
2008-11-05 02:48:50 -06:00
target_call_event_callbacks ( gdb_service - > target , TARGET_EVENT_GDB_END ) ;
2008-02-25 11:48:04 -06:00
2009-06-23 17:47:42 -05:00
target_call_event_callbacks ( gdb_service - > target , TARGET_EVENT_GDB_DETACH ) ;
2008-10-14 15:58:28 -05:00
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
2010-01-20 01:30:36 -06:00
static void gdb_send_error ( struct connection * connection , uint8_t the_error )
2008-02-25 11:48:04 -06:00
{
char err [ 4 ] ;
2009-06-23 17:47:42 -05:00
snprintf ( err , 4 , " E%2.2X " , the_error ) ;
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , err , 3 ) ;
}
2010-01-20 01:30:36 -06:00
static int gdb_last_signal_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
char sig_reply [ 4 ] ;
2010-06-17 08:30:25 -05:00
int signal_var ;
2008-02-25 11:48:04 -06:00
2010-06-17 08:30:25 -05:00
signal_var = gdb_last_signal ( target ) ;
2008-02-25 11:48:04 -06:00
2010-06-17 08:30:25 -05:00
snprintf ( sig_reply , 4 , " S%2.2x " , signal_var ) ;
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , sig_reply , 3 ) ;
return ERROR_OK ;
}
2009-11-13 12:11:13 -06:00
static int gdb_reg_pos ( struct target * target , int pos , int len )
2008-11-18 13:26:07 -06:00
{
if ( target - > endianness = = TARGET_LITTLE_ENDIAN )
return pos ;
else
return len - 1 - pos ;
}
/* Convert register to string of bytes. NB! The # of bits in the
2008-02-25 11:48:04 -06:00
* register might be non - divisible by 8 ( a byte ) , in which
2008-11-18 13:26:07 -06:00
* case an entire byte is shown .
*
2009-11-24 13:01:15 -06:00
* NB ! the format on the wire is the target endianness
2008-11-18 13:26:07 -06:00
*
* The format of reg - > value is little endian
*
*/
2010-01-20 01:30:36 -06:00
static void gdb_str_to_target ( struct target * target ,
char * tstr , struct reg * reg )
2008-02-25 11:48:04 -06:00
{
int i ;
2009-06-18 02:07:12 -05:00
uint8_t * buf ;
2008-02-25 11:48:04 -06:00
int buf_len ;
buf = reg - > value ;
2009-11-16 04:53:57 -06:00
buf_len = DIV_ROUND_UP ( reg - > size , 8 ) ;
2008-02-25 11:48:04 -06:00
2008-03-10 09:14:15 -05:00
for ( i = 0 ; i < buf_len ; i + + )
2008-02-25 11:48:04 -06:00
{
2008-11-18 13:26:07 -06:00
int j = gdb_reg_pos ( target , i , buf_len ) ;
tstr [ i * 2 ] = DIGITS [ ( buf [ j ] > > 4 ) & 0xf ] ;
2009-06-23 17:44:17 -05:00
tstr [ i * 2 + 1 ] = DIGITS [ buf [ j ] & 0xf ] ;
2008-02-28 04:07:54 -06:00
}
2008-02-25 11:48:04 -06:00
}
2009-12-26 12:19:19 -06:00
static int hextoint ( int c )
2008-02-25 11:48:04 -06:00
{
2008-11-18 13:26:07 -06:00
if ( c > = ' 0 ' & & c < = ' 9 ' )
{
return c - ' 0 ' ;
}
2009-06-23 17:42:54 -05:00
c = toupper ( c ) ;
2008-11-18 13:26:07 -06:00
if ( c > = ' A ' & & c < = ' F ' )
{
return c - ' A ' + 10 ;
}
LOG_ERROR ( " BUG: invalid register value %08x " , c ) ;
return 0 ;
}
2008-02-25 11:48:04 -06:00
2008-11-18 13:26:07 -06:00
/* copy over in register buffer */
2010-01-20 01:30:36 -06:00
static void gdb_target_to_reg ( struct target * target ,
char * tstr , int str_len , uint8_t * bin )
2008-11-18 13:26:07 -06:00
{
2008-02-25 11:48:04 -06:00
if ( str_len % 2 )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: gdb value with uneven number of characters encountered " ) ;
2008-02-25 11:48:04 -06:00
exit ( - 1 ) ;
}
2008-11-18 13:26:07 -06:00
int i ;
2009-06-23 17:39:18 -05:00
for ( i = 0 ; i < str_len ; i + = 2 )
2008-02-25 11:48:04 -06:00
{
2009-06-23 17:41:13 -05:00
uint8_t t = hextoint ( tstr [ i ] ) < < 4 ;
2009-06-23 17:44:17 -05:00
t | = hextoint ( tstr [ i + 1 ] ) ;
2008-11-18 13:26:07 -06:00
int j = gdb_reg_pos ( target , i / 2 , str_len / 2 ) ;
bin [ j ] = t ;
2008-02-28 04:07:54 -06:00
}
2008-02-25 11:48:04 -06:00
}
2010-01-20 01:30:36 -06:00
static int gdb_get_registers_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
2009-11-13 11:55:49 -06:00
struct reg * * reg_list ;
2008-02-25 11:48:04 -06:00
int reg_list_size ;
int retval ;
int reg_packet_size = 0 ;
char * reg_packet ;
char * reg_packet_p ;
int i ;
# ifdef _DEBUG_GDB_IO_
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " - " ) ;
2008-02-25 11:48:04 -06:00
# endif
2011-04-14 03:25:01 -05:00
if ( ( target - > rtos ! = NULL ) & &
( ERROR_FAIL ! = rtos_get_gdb_reg_list ( connection , target , & reg_list , & reg_list_size ) ) )
{
return ERROR_OK ;
}
2009-05-31 06:30:59 -05:00
if ( ( retval = target_get_gdb_reg_list ( target , & reg_list , & reg_list_size ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
2008-03-05 04:28:32 -06:00
return gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
}
for ( i = 0 ; i < reg_list_size ; i + + )
{
reg_packet_size + = reg_list [ i ] - > size ;
}
2009-11-16 04:53:57 -06:00
reg_packet = malloc ( DIV_ROUND_UP ( reg_packet_size , 8 ) * 2 ) ;
2008-02-25 11:48:04 -06:00
reg_packet_p = reg_packet ;
for ( i = 0 ; i < reg_list_size ; i + + )
{
gdb_str_to_target ( target , reg_packet_p , reg_list [ i ] ) ;
2009-11-16 04:53:57 -06:00
reg_packet_p + = DIV_ROUND_UP ( reg_list [ i ] - > size , 8 ) * 2 ;
2008-02-25 11:48:04 -06:00
}
# ifdef _DEBUG_GDB_IO_
{
char * reg_packet_p ;
2009-11-16 04:53:57 -06:00
reg_packet_p = strndup ( reg_packet , DIV_ROUND_UP ( reg_packet_size , 8 ) * 2 ) ;
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " reg_packet: %s " , reg_packet_p ) ;
2008-02-25 11:48:04 -06:00
free ( reg_packet_p ) ;
}
# endif
2009-11-16 04:53:57 -06:00
gdb_put_packet ( connection , reg_packet , DIV_ROUND_UP ( reg_packet_size , 8 ) * 2 ) ;
2008-02-25 11:48:04 -06:00
free ( reg_packet ) ;
free ( reg_list ) ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_set_registers_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
int i ;
2009-11-13 11:55:49 -06:00
struct reg * * reg_list ;
2008-02-25 11:48:04 -06:00
int reg_list_size ;
int retval ;
char * packet_p ;
# ifdef _DEBUG_GDB_IO_
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " - " ) ;
2008-02-25 11:48:04 -06:00
# endif
/* skip command character */
packet + + ;
packet_size - - ;
if ( packet_size % 2 )
{
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " GDB set_registers packet with uneven characters received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2009-05-31 06:30:59 -05:00
if ( ( retval = target_get_gdb_reg_list ( target , & reg_list , & reg_list_size ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
2008-03-05 04:28:32 -06:00
return gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
}
packet_p = packet ;
for ( i = 0 ; i < reg_list_size ; i + + )
{
2009-06-18 02:07:12 -05:00
uint8_t * bin_buf ;
2009-11-16 04:53:57 -06:00
int chars = ( DIV_ROUND_UP ( reg_list [ i ] - > size , 8 ) * 2 ) ;
2008-02-25 11:48:04 -06:00
2008-11-18 13:26:07 -06:00
if ( packet_p + chars > packet + packet_size )
{
LOG_ERROR ( " BUG: register packet is too small for registers " ) ;
}
2008-02-25 11:48:04 -06:00
2009-11-16 04:53:57 -06:00
bin_buf = malloc ( DIV_ROUND_UP ( reg_list [ i ] - > size , 8 ) ) ;
2008-11-18 13:26:07 -06:00
gdb_target_to_reg ( target , packet_p , chars , bin_buf ) ;
2008-02-25 11:48:04 -06:00
2009-11-17 11:06:45 -06:00
reg_list [ i ] - > type - > set ( reg_list [ i ] , bin_buf ) ;
2008-02-25 11:48:04 -06:00
2008-02-28 04:07:54 -06:00
/* advance packet pointer */
2008-11-18 13:26:07 -06:00
packet_p + = chars ;
2008-02-25 11:48:04 -06:00
free ( bin_buf ) ;
}
2009-11-13 11:55:49 -06:00
/* free struct reg *reg_list[] array allocated by get_gdb_reg_list */
2008-02-25 11:48:04 -06:00
free ( reg_list ) ;
gdb_put_packet ( connection , " OK " , 2 ) ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_get_register_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
char * reg_packet ;
int reg_num = strtoul ( packet + 1 , NULL , 16 ) ;
2009-11-13 11:55:49 -06:00
struct reg * * reg_list ;
2008-02-25 11:48:04 -06:00
int reg_list_size ;
int retval ;
# ifdef _DEBUG_GDB_IO_
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " - " ) ;
2008-02-25 11:48:04 -06:00
# endif
2009-05-31 06:30:59 -05:00
if ( ( retval = target_get_gdb_reg_list ( target , & reg_list , & reg_list_size ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
2008-03-05 04:28:32 -06:00
return gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
}
if ( reg_list_size < = reg_num )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " gdb requested a non-existing register " ) ;
2008-02-25 11:48:04 -06:00
exit ( - 1 ) ;
}
2009-11-16 04:53:57 -06:00
reg_packet = malloc ( DIV_ROUND_UP ( reg_list [ reg_num ] - > size , 8 ) * 2 ) ;
2008-02-25 11:48:04 -06:00
gdb_str_to_target ( target , reg_packet , reg_list [ reg_num ] ) ;
2009-11-16 04:53:57 -06:00
gdb_put_packet ( connection , reg_packet , DIV_ROUND_UP ( reg_list [ reg_num ] - > size , 8 ) * 2 ) ;
2008-02-25 11:48:04 -06:00
free ( reg_list ) ;
free ( reg_packet ) ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_set_register_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
char * separator ;
2009-06-18 02:07:12 -05:00
uint8_t * bin_buf ;
2008-02-25 11:48:04 -06:00
int reg_num = strtoul ( packet + 1 , & separator , 16 ) ;
2009-11-13 11:55:49 -06:00
struct reg * * reg_list ;
2008-02-25 11:48:04 -06:00
int reg_list_size ;
int retval ;
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " - " ) ;
2008-02-25 11:48:04 -06:00
2009-05-31 06:30:59 -05:00
if ( ( retval = target_get_gdb_reg_list ( target , & reg_list , & reg_list_size ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
2008-03-05 04:28:32 -06:00
return gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
}
if ( reg_list_size < reg_num )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " gdb requested a non-existing register " ) ;
2008-09-24 03:42:13 -05:00
return ERROR_SERVER_REMOTE_CLOSED ;
2008-02-25 11:48:04 -06:00
}
if ( * separator ! = ' = ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " GDB 'set register packet', but no '=' following the register number " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
/* convert from GDB-string (target-endian) to hex-string (big-endian) */
2009-11-16 04:53:57 -06:00
bin_buf = malloc ( DIV_ROUND_UP ( reg_list [ reg_num ] - > size , 8 ) ) ;
int chars = ( DIV_ROUND_UP ( reg_list [ reg_num ] - > size , 8 ) * 2 ) ;
2008-11-18 13:26:07 -06:00
/* fix!!! add some sanity checks on packet size here */
2008-02-25 11:48:04 -06:00
2008-11-18 13:26:07 -06:00
gdb_target_to_reg ( target , separator + 1 , chars , bin_buf ) ;
2009-11-17 11:06:45 -06:00
reg_list [ reg_num ] - > type - > set ( reg_list [ reg_num ] , bin_buf ) ;
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , " OK " , 2 ) ;
free ( bin_buf ) ;
free ( reg_list ) ;
return ERROR_OK ;
}
2010-06-07 08:14:04 -05:00
/* No attempt is made to translate the "retval" to
* GDB speak . This has to be done at the calling
* site as no mapping really exists .
*/
2010-01-20 01:30:36 -06:00
static int gdb_error ( struct connection * connection , int retval )
2008-02-25 11:48:04 -06:00
{
2010-06-07 08:14:04 -05:00
LOG_DEBUG ( " Reporting %i to GDB as generic error " , retval ) ;
gdb_send_error ( connection , EFAULT ) ;
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
/* We don't have to worry about the default 2 second timeout for GDB packets,
* because GDB breaks up large memory reads into smaller reads .
2008-02-28 04:07:54 -06:00
*
2008-02-25 11:48:04 -06:00
* 8191 bytes by the looks of it . Why 8191 bytes instead of 8192 ? ? ? ? ?
*/
2010-01-20 01:30:36 -06:00
static int gdb_read_memory_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
char * separator ;
2009-06-18 02:11:11 -05:00
uint32_t addr = 0 ;
uint32_t len = 0 ;
2008-02-25 11:48:04 -06:00
2009-06-18 02:07:12 -05:00
uint8_t * buffer ;
2008-02-25 11:48:04 -06:00
char * hex_buffer ;
int retval = ERROR_OK ;
/* skip command character */
packet + + ;
addr = strtoul ( packet , & separator , 16 ) ;
if ( * separator ! = ' , ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete read memory packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2009-06-23 17:44:17 -05:00
len = strtoul ( separator + 1 , NULL , 16 ) ;
2008-02-25 11:48:04 -06:00
buffer = malloc ( len ) ;
2009-06-20 22:01:21 -05:00
LOG_DEBUG ( " addr: 0x%8.8 " PRIx32 " , len: 0x%8.8 " PRIx32 " " , addr , len ) ;
2008-02-25 11:48:04 -06:00
retval = target_read_buffer ( target , addr , len , buffer ) ;
2009-06-23 17:38:12 -05:00
if ( ( retval ! = ERROR_OK ) & & ! gdb_report_data_abort )
2008-02-25 11:48:04 -06:00
{
/* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
* At some point this might be fixed in GDB , in which case this code can be removed .
2008-02-28 04:07:54 -06:00
*
2008-02-25 11:48:04 -06:00
* OpenOCD developers are acutely aware of this problem , but there is nothing
* gained by involving the user in this problem that hopefully will get resolved
* eventually
2008-02-28 04:07:54 -06:00
*
2009-06-23 17:42:54 -05:00
* http : //sourceware.org/cgi-bin/gnatsweb.pl?cmd = view%20audit-trail&database = gdb&pr = 2395
2008-02-25 11:48:04 -06:00
*
* For now , the default is to fix up things to make current GDB versions work .
* This can be overwritten using the gdb_report_data_abort < ' enable ' | ' disable ' > command .
*/
memset ( buffer , 0 , len ) ;
retval = ERROR_OK ;
}
if ( retval = = ERROR_OK )
{
hex_buffer = malloc ( len * 2 + 1 ) ;
2009-06-18 02:11:11 -05:00
uint32_t i ;
2008-02-25 11:48:04 -06:00
for ( i = 0 ; i < len ; i + + )
{
2009-06-18 02:07:12 -05:00
uint8_t t = buffer [ i ] ;
2008-02-25 11:48:04 -06:00
hex_buffer [ 2 * i ] = DIGITS [ ( t > > 4 ) & 0xf ] ;
hex_buffer [ 2 * i + 1 ] = DIGITS [ t & 0xf ] ;
}
gdb_put_packet ( connection , hex_buffer , len * 2 ) ;
free ( hex_buffer ) ;
}
else
{
2008-03-05 04:28:32 -06:00
retval = gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
}
free ( buffer ) ;
return retval ;
}
2010-01-20 01:30:36 -06:00
static int gdb_write_memory_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
char * separator ;
2009-06-18 02:11:11 -05:00
uint32_t addr = 0 ;
uint32_t len = 0 ;
2008-02-25 11:48:04 -06:00
2009-06-18 02:07:12 -05:00
uint8_t * buffer ;
2008-02-25 11:48:04 -06:00
2009-06-18 02:11:11 -05:00
uint32_t i ;
2008-02-25 11:48:04 -06:00
int retval ;
/* skip command character */
packet + + ;
addr = strtoul ( packet , & separator , 16 ) ;
if ( * separator ! = ' , ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete write memory packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2009-06-23 17:44:17 -05:00
len = strtoul ( separator + 1 , & separator , 16 ) ;
2008-02-25 11:48:04 -06:00
if ( * ( separator + + ) ! = ' : ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete write memory packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
buffer = malloc ( len ) ;
2009-06-20 22:01:21 -05:00
LOG_DEBUG ( " addr: 0x%8.8 " PRIx32 " , len: 0x%8.8 " PRIx32 " " , addr , len ) ;
2008-02-25 11:48:04 -06:00
2009-06-23 17:45:47 -05:00
for ( i = 0 ; i < len ; i + + )
2008-02-25 11:48:04 -06:00
{
2009-06-18 02:11:11 -05:00
uint32_t tmp ;
2009-06-20 22:01:21 -05:00
sscanf ( separator + 2 * i , " %2 " SCNx32 , & tmp ) ;
2008-02-25 11:48:04 -06:00
buffer [ i ] = tmp ;
}
retval = target_write_buffer ( target , addr , len , buffer ) ;
if ( retval = = ERROR_OK )
{
gdb_put_packet ( connection , " OK " , 2 ) ;
}
else
{
2008-03-10 07:11:07 -05:00
retval = gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
}
free ( buffer ) ;
2008-03-10 07:11:07 -05:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2010-01-20 01:30:36 -06:00
static int gdb_write_memory_binary_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
char * separator ;
2009-06-18 02:11:11 -05:00
uint32_t addr = 0 ;
uint32_t len = 0 ;
2008-02-25 11:48:04 -06:00
2010-03-16 08:45:07 -05:00
int retval = ERROR_OK ;
2008-02-25 11:48:04 -06:00
/* skip command character */
packet + + ;
addr = strtoul ( packet , & separator , 16 ) ;
if ( * separator ! = ' , ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete write memory binary packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2009-06-23 17:44:17 -05:00
len = strtoul ( separator + 1 , & separator , 16 ) ;
2008-02-25 11:48:04 -06:00
if ( * ( separator + + ) ! = ' : ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete write memory binary packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2010-03-16 08:45:07 -05:00
struct gdb_connection * gdb_connection = connection - > priv ;
2008-02-25 11:48:04 -06:00
2010-03-16 08:45:07 -05:00
if ( gdb_connection - > mem_write_error )
{
retval = ERROR_FAIL ;
/* now that we have reported the memory write error, we can clear the condition */
gdb_connection - > mem_write_error = false ;
2008-02-25 11:48:04 -06:00
}
2010-03-16 08:45:07 -05:00
/* By replying the packet *immediately* GDB will send us a new packet
* while we write the last one to the target .
*/
2008-02-25 11:48:04 -06:00
if ( retval = = ERROR_OK )
{
gdb_put_packet ( connection , " OK " , 2 ) ;
}
else
{
2008-03-05 04:28:32 -06:00
if ( ( retval = gdb_error ( connection , retval ) ) ! = ERROR_OK )
2008-02-28 04:07:54 -06:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2010-03-16 08:45:07 -05:00
if ( len )
{
LOG_DEBUG ( " addr: 0x%8.8 " PRIx32 " , len: 0x%8.8 " PRIx32 " " , addr , len ) ;
retval = target_write_buffer ( target , addr , len , ( uint8_t * ) separator ) ;
if ( retval ! = ERROR_OK )
{
gdb_connection - > mem_write_error = true ;
}
}
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_step_continue_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
int current = 0 ;
2009-06-18 02:11:11 -05:00
uint32_t address = 0x0 ;
2009-06-23 17:42:54 -05:00
int retval = ERROR_OK ;
2008-02-25 11:48:04 -06:00
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " - " ) ;
2008-02-25 11:48:04 -06:00
if ( packet_size > 1 )
{
packet [ packet_size ] = 0 ;
address = strtoul ( packet + 1 , NULL , 16 ) ;
}
else
{
current = 1 ;
}
if ( packet [ 0 ] = = ' c ' )
{
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " continue " ) ;
2009-06-23 17:47:42 -05:00
target_handle_event ( target , TARGET_EVENT_OLD_pre_resume ) ;
2009-06-23 17:42:54 -05:00
retval = target_resume ( target , current , address , 0 , 0 ) ; /* resume at current address, don't handle breakpoints, not debugging */
2008-02-25 11:48:04 -06:00
}
else if ( packet [ 0 ] = = ' s ' )
{
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " step " ) ;
2009-05-31 06:31:11 -05:00
/* step at current or address, don't handle breakpoints */
retval = target_step ( target , current , address , 0 ) ;
2008-02-25 11:48:04 -06:00
}
2008-08-13 07:21:57 -05:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2010-01-20 01:30:36 -06:00
static int gdb_breakpoint_watchpoint_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
int type ;
enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */ ;
2010-01-11 02:22:08 -06:00
enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */ ;
2009-06-18 02:11:11 -05:00
uint32_t address ;
uint32_t size ;
2008-02-25 11:48:04 -06:00
char * separator ;
int retval ;
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " - " ) ;
2008-02-25 11:48:04 -06:00
type = strtoul ( packet + 1 , & separator , 16 ) ;
if ( type = = 0 ) /* memory breakpoint */
bp_type = BKPT_SOFT ;
else if ( type = = 1 ) /* hardware breakpoint */
bp_type = BKPT_HARD ;
else if ( type = = 2 ) /* write watchpoint */
wp_type = WPT_WRITE ;
else if ( type = = 3 ) /* read watchpoint */
wp_type = WPT_READ ;
else if ( type = = 4 ) /* access watchpoint */
wp_type = WPT_ACCESS ;
2010-01-11 02:22:08 -06:00
else
{
LOG_ERROR ( " invalid gdb watch/breakpoint type(%d), dropping connection " , type ) ;
return ERROR_SERVER_REMOTE_CLOSED ;
}
2008-09-24 03:42:13 -05:00
2009-06-23 17:42:03 -05:00
if ( gdb_breakpoint_override & & ( ( bp_type = = BKPT_SOFT ) | | ( bp_type = = BKPT_HARD ) ) )
2008-08-13 15:42:07 -05:00
{
2009-06-23 17:42:54 -05:00
bp_type = gdb_breakpoint_override_type ;
2008-08-13 15:42:07 -05:00
}
2008-02-25 11:48:04 -06:00
if ( * separator ! = ' , ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete breakpoint/watchpoint packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2009-06-23 17:44:17 -05:00
address = strtoul ( separator + 1 , & separator , 16 ) ;
2008-02-25 11:48:04 -06:00
if ( * separator ! = ' , ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete breakpoint/watchpoint packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2009-06-23 17:44:17 -05:00
size = strtoul ( separator + 1 , & separator , 16 ) ;
2008-02-25 11:48:04 -06:00
switch ( type )
{
case 0 :
case 1 :
if ( packet [ 0 ] = = ' Z ' )
{
if ( ( retval = breakpoint_add ( target , address , size , bp_type ) ) ! = ERROR_OK )
{
2008-03-05 04:28:32 -06:00
if ( ( retval = gdb_error ( connection , retval ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
return retval ;
}
else
{
gdb_put_packet ( connection , " OK " , 2 ) ;
}
}
else
{
breakpoint_remove ( target , address ) ;
gdb_put_packet ( connection , " OK " , 2 ) ;
}
break ;
case 2 :
case 3 :
case 4 :
{
if ( packet [ 0 ] = = ' Z ' )
{
2010-01-11 02:22:08 -06:00
if ( ( retval = watchpoint_add ( target , address , size , wp_type , 0 , 0xffffffffu ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
2008-03-05 04:28:32 -06:00
if ( ( retval = gdb_error ( connection , retval ) ) ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
return retval ;
}
else
{
gdb_put_packet ( connection , " OK " , 2 ) ;
}
}
else
{
watchpoint_remove ( target , address ) ;
gdb_put_packet ( connection , " OK " , 2 ) ;
}
break ;
}
default :
break ;
}
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
/* print out a string and allocate more space as needed,
* mainly used for XML at this point
*/
static void xml_printf ( int * retval , char * * xml , int * pos , int * size ,
const char * fmt , . . . )
2008-02-25 11:48:04 -06:00
{
if ( * retval ! = ERROR_OK )
{
return ;
}
int first = 1 ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
for ( ; ; )
{
if ( ( * xml = = NULL ) | | ( ! first ) )
{
/* start by 0 to exercise all the code paths.
* Need minimum 2 bytes to fit 1 char and 0 terminator . */
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
* size = * size * 2 + 2 ;
char * t = * xml ;
* xml = realloc ( * xml , * size ) ;
if ( * xml = = NULL )
{
if ( t )
free ( t ) ;
* retval = ERROR_SERVER_REMOTE_CLOSED ;
return ;
}
}
2008-02-28 04:07:54 -06:00
2008-03-06 06:04:27 -06:00
va_list ap ;
int ret ;
va_start ( ap , fmt ) ;
ret = vsnprintf ( * xml + * pos , * size - * pos , fmt , ap ) ;
va_end ( ap ) ;
if ( ( ret > 0 ) & & ( ( ret + 1 ) < * size - * pos ) )
{
* pos + = ret ;
return ;
}
/* there was just enough or not enough space, allocate more. */
first = 0 ;
2008-02-25 11:48:04 -06:00
}
}
static int decode_xfer_read ( char * buf , char * * annex , int * ofs , unsigned int * len )
{
char * separator ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* Extract and NUL-terminate the annex. */
* annex = buf ;
while ( * buf & & * buf ! = ' : ' )
buf + + ;
if ( * buf = = ' \0 ' )
return - 1 ;
* buf + + = 0 ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* After the read marker and annex, qXfer looks like a
* traditional ' m ' packet . */
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
* ofs = strtoul ( buf , & separator , 16 ) ;
if ( * separator ! = ' , ' )
return - 1 ;
2009-06-23 17:44:17 -05:00
* len = strtoul ( separator + 1 , NULL , 16 ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
return 0 ;
}
2008-04-23 03:07:39 -05:00
static int compare_bank ( const void * a , const void * b )
{
2009-11-13 13:32:28 -06:00
struct flash_bank * b1 , * b2 ;
b1 = * ( ( struct flash_bank * * ) a ) ;
b2 = * ( ( struct flash_bank * * ) b ) ;
2008-09-24 03:42:13 -05:00
2009-06-23 17:42:03 -05:00
if ( b1 - > base = = b2 - > base )
2008-04-23 03:07:39 -05:00
{
return 0 ;
2009-06-23 17:45:47 -05:00
} else if ( b1 - > base > b2 - > base )
2008-04-23 03:07:39 -05:00
{
return 1 ;
} else
{
return - 1 ;
}
}
2010-01-20 01:32:54 -06:00
static int gdb_memory_map ( struct connection * connection ,
2010-01-20 01:30:36 -06:00
struct target * target , char * packet , int packet_size )
2010-01-20 01:32:54 -06:00
{
/* We get away with only specifying flash here. Regions that are not
* specified are treated as if we provided no memory map ( if not we
* could detect the holes and mark them as RAM ) .
* Normally we only execute this code once , but no big deal if we
* have to regenerate it a couple of times .
*/
struct flash_bank * p ;
char * xml = NULL ;
int size = 0 ;
int pos = 0 ;
int retval = ERROR_OK ;
struct flash_bank * * banks ;
int offset ;
int length ;
char * separator ;
uint32_t ram_start = 0 ;
int i ;
2010-07-05 08:06:34 -05:00
int target_flash_banks = 0 ;
2010-01-20 01:32:54 -06:00
/* skip command character */
packet + = 23 ;
offset = strtoul ( packet , & separator , 16 ) ;
length = strtoul ( separator + 1 , & separator , 16 ) ;
xml_printf ( & retval , & xml , & pos , & size , " <memory-map> \n " ) ;
/* Sort banks in ascending order. We need to report non-flash
* memory as ram ( or rather read / write ) by default for GDB , since
* it has no concept of non - cacheable read / write memory ( i / o etc ) .
*
* FIXME Most non - flash addresses are * NOT * RAM ! Don ' t lie .
2010-01-20 12:43:32 -06:00
* Current versions of GDB assume unlisted addresses are RAM . . .
2010-01-20 01:32:54 -06:00
*/
banks = malloc ( sizeof ( struct flash_bank * ) * flash_get_bank_count ( ) ) ;
for ( i = 0 ; i < flash_get_bank_count ( ) ; i + + ) {
2010-05-04 06:26:52 -05:00
retval = get_flash_bank_by_num ( i , & p ) ;
if ( retval ! = ERROR_OK )
{
2010-01-20 01:32:54 -06:00
free ( banks ) ;
2010-06-07 08:14:04 -05:00
gdb_error ( connection , retval ) ;
2010-01-20 01:32:54 -06:00
return retval ;
}
2010-07-05 08:06:34 -05:00
if ( p - > target = = target )
banks [ target_flash_banks + + ] = p ;
2010-01-20 01:32:54 -06:00
}
2010-07-05 08:06:34 -05:00
qsort ( banks , target_flash_banks , sizeof ( struct flash_bank * ) ,
2010-01-20 01:32:54 -06:00
compare_bank ) ;
for ( i = 0 ; i < flash_get_bank_count ( ) ; i + + ) {
2010-01-20 12:43:32 -06:00
int j ;
unsigned sector_size = 0 ;
uint32_t start , end ;
2010-01-20 01:32:54 -06:00
p = banks [ i ] ;
2010-01-20 12:43:32 -06:00
start = p - > base ;
end = p - > base + p - > size ;
2010-01-20 01:32:54 -06:00
if ( ram_start < p - > base )
xml_printf ( & retval , & xml , & pos , & size ,
" <memory type= \" ram \" start= \" 0x%x \" "
" length= \" 0x%x \" /> \n " ,
2010-01-20 12:43:32 -06:00
ram_start , p - > base - ram_start ) ;
2010-01-20 01:32:54 -06:00
2010-01-20 12:43:32 -06:00
/* Report adjacent groups of same-size sectors. So for
* example top boot CFI flash will list an initial region
* with several large sectors ( maybe 128 KB ) and several
* smaller ones at the end ( maybe 32 KB ) . STR7 will have
* regions with 8 KB , 32 KB , and 64 KB sectors ; etc .
2010-01-20 01:32:54 -06:00
*/
2010-01-20 12:43:32 -06:00
for ( j = 0 ; j < p - > num_sectors ; j + + ) {
unsigned group_len ;
/* Maybe start a new group of sectors. */
if ( sector_size = = 0 ) {
start = p - > base + p - > sectors [ j ] . offset ;
xml_printf ( & retval , & xml , & pos , & size ,
" <memory type= \" flash \" "
" start= \" 0x%x \" " ,
start ) ;
sector_size = p - > sectors [ j ] . size ;
}
/* Does this finish a group of sectors?
* If not , continue an already - started group .
*/
if ( j = = p - > num_sectors - 1 )
group_len = ( p - > base + p - > size ) - start ;
else if ( p - > sectors [ j + 1 ] . size ! = sector_size )
group_len = p - > base + p - > sectors [ j + 1 ] . offset
- start ;
else
continue ;
xml_printf ( & retval , & xml , & pos , & size ,
" length= \" 0x%x \" > \n "
" <property name= \" blocksize \" > "
" 0x%x</property> \n "
" </memory> \n " ,
group_len ,
sector_size ) ;
sector_size = 0 ;
}
2010-01-20 01:32:54 -06:00
ram_start = p - > base + p - > size ;
}
if ( ram_start ! = 0 )
xml_printf ( & retval , & xml , & pos , & size ,
" <memory type= \" ram \" start= \" 0x%x \" "
" length= \" 0x%x \" /> \n " ,
ram_start , 0 - ram_start ) ;
/* ELSE a flash chip could be at the very end of the 32 bit address
* space , in which case ram_start will be precisely 0
*/
free ( banks ) ;
banks = NULL ;
xml_printf ( & retval , & xml , & pos , & size , " </memory-map> \n " ) ;
if ( retval ! = ERROR_OK ) {
2010-06-07 08:14:04 -05:00
gdb_error ( connection , retval ) ;
2010-01-20 01:32:54 -06:00
return retval ;
}
if ( offset + length > pos )
length = pos - offset ;
char * t = malloc ( length + 1 ) ;
t [ 0 ] = ' l ' ;
memcpy ( t + 1 , xml + offset , length ) ;
gdb_put_packet ( connection , t , length + 1 ) ;
free ( t ) ;
free ( xml ) ;
return ERROR_OK ;
}
static int gdb_query_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
2009-11-13 15:25:47 -06:00
struct command_context * cmd_ctx = connection - > cmd_ctx ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_connection = connection - > priv ;
2008-09-24 03:42:13 -05:00
2008-02-25 11:48:04 -06:00
if ( strstr ( packet , " qRcmd, " ) )
{
if ( packet_size > 6 )
{
char * cmd ;
int i ;
cmd = malloc ( ( packet_size - 6 ) / 2 + 1 ) ;
2009-06-23 17:42:54 -05:00
for ( i = 0 ; i < ( packet_size - 6 ) / 2 ; i + + )
2008-02-25 11:48:04 -06:00
{
2009-06-18 02:11:11 -05:00
uint32_t tmp ;
2009-06-20 22:01:21 -05:00
sscanf ( packet + 6 + 2 * i , " %2 " SCNx32 , & tmp ) ;
2008-02-25 11:48:04 -06:00
cmd [ i ] = tmp ;
}
cmd [ ( packet_size - 6 ) / 2 ] = 0x0 ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* We want to print all debug output to GDB connection */
log_add_callback ( gdb_log_callback , connection ) ;
2008-03-13 05:14:41 -05:00
target_call_timer_callbacks_now ( ) ;
2009-09-24 01:34:23 -05:00
/* some commands need to know the GDB connection, make note of current
* GDB connection . */
current_gdb_connection = gdb_connection ;
2008-02-25 11:48:04 -06:00
command_run_line ( cmd_ctx , cmd ) ;
2009-09-24 01:34:23 -05:00
current_gdb_connection = NULL ;
2008-03-13 05:14:41 -05:00
target_call_timer_callbacks_now ( ) ;
2008-03-01 08:36:13 -06:00
log_remove_callback ( gdb_log_callback , connection ) ;
2008-02-25 11:48:04 -06:00
free ( cmd ) ;
}
gdb_put_packet ( connection , " OK " , 2 ) ;
return ERROR_OK ;
}
else if ( strstr ( packet , " qCRC: " ) )
{
if ( packet_size > 5 )
{
int retval ;
char gdb_reply [ 10 ] ;
char * separator ;
2009-06-18 02:11:11 -05:00
uint32_t checksum ;
uint32_t addr = 0 ;
uint32_t len = 0 ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* skip command character */
packet + = 5 ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
addr = strtoul ( packet , & separator , 16 ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( * separator ! = ' , ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete read memory packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
len = strtoul ( separator + 1 , NULL , 16 ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
retval = target_checksum_memory ( target , addr , len , & checksum ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( retval = = ERROR_OK )
{
2009-06-20 22:01:21 -05:00
snprintf ( gdb_reply , 10 , " C%8.8 " PRIx32 " " , checksum ) ;
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , gdb_reply , 9 ) ;
}
else
{
2008-03-05 04:28:32 -06:00
if ( ( retval = gdb_error ( connection , retval ) ) ! = ERROR_OK )
2008-02-28 04:07:54 -06:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
}
else if ( strstr ( packet , " qSupported " ) )
{
/* we currently support packet size and qXfer:memory-map:read (if enabled)
* disable qXfer : features : read for the moment */
int retval = ERROR_OK ;
char * buffer = NULL ;
int pos = 0 ;
int size = 0 ;
2008-02-28 04:07:54 -06:00
xml_printf ( & retval , & buffer , & pos , & size ,
2008-08-22 14:58:19 -05:00
" PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+ " ,
2009-06-23 17:45:47 -05:00
( GDB_BUFFER_SIZE - 1 ) , ( ( gdb_use_memory_map = = 1 ) & & ( flash_get_bank_count ( ) > 0 ) ) ? ' + ' : ' - ' ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( retval ! = ERROR_OK )
{
gdb_send_error ( connection , 01 ) ;
return ERROR_OK ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , buffer , strlen ( buffer ) ) ;
free ( buffer ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
2010-01-20 01:32:54 -06:00
else if ( strstr ( packet , " qXfer:memory-map:read:: " )
& & ( flash_get_bank_count ( ) > 0 ) )
return gdb_memory_map ( connection , target , packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
else if ( strstr ( packet , " qXfer:features:read: " ) )
2008-02-28 04:07:54 -06:00
{
2008-02-25 11:48:04 -06:00
char * xml = NULL ;
int size = 0 ;
int pos = 0 ;
int retval = ERROR_OK ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
int offset ;
unsigned int length ;
char * annex ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* skip command character */
packet + = 20 ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( decode_xfer_read ( packet , & annex , & offset , & length ) < 0 )
{
gdb_send_error ( connection , 01 ) ;
return ERROR_OK ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( strcmp ( annex , " target.xml " ) ! = 0 )
{
gdb_send_error ( connection , 01 ) ;
return ERROR_OK ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
xml_printf ( & retval , & xml , & pos , & size , \
2009-06-23 17:45:47 -05:00
" l < target version= \" 1.0 \" > \n < architecture > arm</architecture> \n </target> \n " ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( retval ! = ERROR_OK )
{
2010-06-07 08:14:04 -05:00
gdb_error ( connection , retval ) ;
2008-02-25 11:48:04 -06:00
return retval ;
}
2008-02-28 04:07:54 -06:00
2008-03-22 09:19:46 -05:00
gdb_put_packet ( connection , xml , strlen ( xml ) ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
free ( xml ) ;
return ERROR_OK ;
}
2008-08-22 14:58:19 -05:00
else if ( strstr ( packet , " QStartNoAckMode " ) )
{
gdb_connection - > noack_mode = 1 ;
gdb_put_packet ( connection , " OK " , 2 ) ;
return ERROR_OK ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , " " , 0 ) ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_v_packet ( struct connection * connection ,
struct target * target , char * packet , int packet_size )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_connection = connection - > priv ;
2009-11-13 10:06:52 -06:00
struct gdb_service * gdb_service = connection - > service - > priv ;
2008-02-25 11:48:04 -06:00
int result ;
/* if flash programming disabled - send a empty reply */
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( gdb_flash_program = = 0 )
{
gdb_put_packet ( connection , " " , 0 ) ;
return ERROR_OK ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( strstr ( packet , " vFlashErase: " ) )
{
unsigned long addr ;
unsigned long length ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
char * parse = packet + 12 ;
if ( * parse = = ' \0 ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete vFlashErase packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
addr = strtoul ( parse , & parse , 16 ) ;
if ( * ( parse + + ) ! = ' , ' | | * parse = = ' \0 ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete vFlashErase packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
length = strtoul ( parse , & parse , 16 ) ;
if ( * parse ! = ' \0 ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete vFlashErase packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* assume all sectors need erasing - stops any problems
* when flash_write is called multiple times */
flash_set_dirty ( ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* perform any target specific operations before the erase */
2010-01-14 01:33:25 -06:00
target_call_event_callbacks ( gdb_service - > target ,
TARGET_EVENT_GDB_FLASH_ERASE_START ) ;
/* vFlashErase:addr,length messages require region start and
* end to be " block " aligned . . . if padding is ever needed ,
* GDB will have become dangerously confused .
*/
result = flash_erase_address_range ( gdb_service - > target ,
false , addr , length ) ;
/* perform any target specific operations after the erase */
target_call_event_callbacks ( gdb_service - > target ,
TARGET_EVENT_GDB_FLASH_ERASE_END ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* perform erase */
2008-09-01 02:20:21 -05:00
if ( result ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
/* GDB doesn't evaluate the actual error number returned,
* treat a failed erase as an I / O error
*/
gdb_send_error ( connection , EIO ) ;
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " flash_erase returned %i " , result ) ;
2008-02-25 11:48:04 -06:00
}
else
gdb_put_packet ( connection , " OK " , 2 ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
if ( strstr ( packet , " vFlashWrite: " ) )
{
2008-10-14 08:14:52 -05:00
int retval ;
2008-02-25 11:48:04 -06:00
unsigned long addr ;
unsigned long length ;
char * parse = packet + 12 ;
if ( * parse = = ' \0 ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete vFlashErase packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
addr = strtoul ( parse , & parse , 16 ) ;
if ( * ( parse + + ) ! = ' : ' )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " incomplete vFlashErase packet received, dropping connection " ) ;
2008-02-25 11:48:04 -06:00
return ERROR_SERVER_REMOTE_CLOSED ;
}
length = packet_size - ( parse - packet ) ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
/* create a new image if there isn't already one */
if ( gdb_connection - > vflash_image = = NULL )
{
2009-11-13 11:46:21 -06:00
gdb_connection - > vflash_image = malloc ( sizeof ( struct image ) ) ;
2008-02-25 11:48:04 -06:00
image_open ( gdb_connection - > vflash_image , " " , " build " ) ;
}
/* create new section with content from packet buffer */
2009-06-23 17:35:09 -05:00
if ( ( retval = image_add_section ( gdb_connection - > vflash_image , addr , length , 0x0 , ( uint8_t * ) parse ) ) ! = ERROR_OK )
2008-10-14 08:14:52 -05:00
{
return retval ;
}
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , " OK " , 2 ) ;
return ERROR_OK ;
}
if ( ! strcmp ( packet , " vFlashDone " ) )
{
2009-06-18 02:11:11 -05:00
uint32_t written ;
2008-02-25 11:48:04 -06:00
/* process the flashing buffer. No need to erase as GDB
* always issues a vFlashErase first . */
2008-09-01 02:20:21 -05:00
target_call_event_callbacks ( gdb_service - > target , TARGET_EVENT_GDB_FLASH_WRITE_START ) ;
result = flash_write ( gdb_service - > target , gdb_connection - > vflash_image , & written , 0 ) ;
target_call_event_callbacks ( gdb_service - > target , TARGET_EVENT_GDB_FLASH_WRITE_END ) ;
2009-06-23 17:46:23 -05:00
if ( result ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
{
if ( result = = ERROR_FLASH_DST_OUT_OF_BANK )
gdb_put_packet ( connection , " E.memtype " , 9 ) ;
else
gdb_send_error ( connection , EIO ) ;
}
else
{
2009-06-20 22:01:21 -05:00
LOG_DEBUG ( " wrote %u bytes from vFlash image to flash " , ( unsigned ) written ) ;
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , " OK " , 2 ) ;
}
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
image_close ( gdb_connection - > vflash_image ) ;
free ( gdb_connection - > vflash_image ) ;
gdb_connection - > vflash_image = NULL ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
gdb_put_packet ( connection , " " , 0 ) ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_detach ( struct connection * connection , struct target * target )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:06:52 -06:00
struct gdb_service * gdb_service = connection - > service - > priv ;
2008-09-01 02:20:21 -05:00
2010-01-20 01:30:36 -06:00
target_call_event_callbacks ( gdb_service - > target ,
TARGET_EVENT_GDB_DETACH ) ;
2008-02-28 04:07:54 -06:00
2009-10-13 06:44:15 -05:00
return gdb_put_packet ( connection , " OK " , 2 ) ;
2008-02-25 11:48:04 -06:00
}
2009-11-09 08:12:02 -06:00
static void gdb_log_callback ( void * priv , const char * file , unsigned line ,
2008-02-29 05:16:38 -06:00
const char * function , const char * string )
2008-02-25 11:48:04 -06:00
{
2009-11-13 10:10:43 -06:00
struct connection * connection = priv ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-28 04:07:54 -06:00
2008-02-25 11:48:04 -06:00
if ( gdb_con - > busy )
{
/* do not reply this using the O packet */
return ;
}
2008-02-29 05:16:38 -06:00
gdb_output_con ( connection , string ) ;
2008-02-25 11:48:04 -06:00
}
2009-11-13 10:10:43 -06:00
static void gdb_sig_halted ( struct connection * connection )
2008-08-13 07:21:57 -05:00
{
char sig_reply [ 4 ] ;
snprintf ( sig_reply , 4 , " T%2.2x " , 2 ) ;
gdb_put_packet ( connection , sig_reply , 3 ) ;
}
2010-01-20 01:30:36 -06:00
static int gdb_input_inner ( struct connection * connection )
2008-02-25 11:48:04 -06:00
{
2010-01-20 01:30:36 -06:00
/* Do not allocate this on the stack */
static char gdb_packet_buffer [ GDB_BUFFER_SIZE ] ;
2009-11-13 10:06:52 -06:00
struct gdb_service * gdb_service = connection - > service - > priv ;
2009-11-13 12:11:13 -06:00
struct target * target = gdb_service - > target ;
2009-06-23 17:42:54 -05:00
char * packet = gdb_packet_buffer ;
2008-02-25 11:48:04 -06:00
int packet_size ;
int retval ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
static int extended_protocol = 0 ;
2010-06-16 01:24:51 -05:00
/* drain input buffer. If one of the packets fail, then an error
* packet is replied , if applicable .
*
* This loop will terminate and the error code is returned .
*
* The calling fn will check if this error is something that
* can be recovered from , or if the connection must be closed .
*
* If the error is recoverable , this fn is called again to
* drain the rest of the buffer .
*/
2008-02-25 11:48:04 -06:00
do
{
packet_size = GDB_BUFFER_SIZE - 1 ;
2010-01-20 01:30:36 -06:00
retval = gdb_get_packet ( connection , packet , & packet_size ) ;
if ( retval ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
return retval ;
/* terminate with zero */
packet [ packet_size ] = 0 ;
2009-06-23 17:49:06 -05:00
if ( LOG_LEVEL_IS ( LOG_LVL_DEBUG ) ) {
if ( packet [ 0 ] = = ' X ' ) {
2008-10-22 04:30:33 -05:00
// binary packets spew junk into the debug log stream
2008-10-11 01:13:21 -05:00
char buf [ 50 ] ;
int x ;
2009-06-23 17:49:06 -05:00
for ( x = 0 ; ( x < 49 ) & & ( packet [ x ] ! = ' : ' ) ; x + + ) {
2008-10-11 01:13:21 -05:00
buf [ x ] = packet [ x ] ;
}
buf [ x ] = 0 ;
2009-06-23 17:47:42 -05:00
LOG_DEBUG ( " received packet: '%s:<binary-data>' " , buf ) ;
2008-10-11 01:13:21 -05:00
} else {
2009-06-23 17:47:42 -05:00
LOG_DEBUG ( " received packet: '%s' " , packet ) ;
2008-10-11 01:13:21 -05:00
}
}
2008-02-25 11:48:04 -06:00
if ( packet_size > 0 )
{
retval = ERROR_OK ;
switch ( packet [ 0 ] )
{
2011-04-14 03:25:01 -05:00
case ' T ' : // Is thread alive?
gdb_thread_packet ( connection , target , packet , packet_size ) ;
break ;
case ' H ' : // Set current thread ( 'c' for step and continue, 'g' for all other operations )
gdb_thread_packet ( connection , target , packet , packet_size ) ;
break ;
2008-02-25 11:48:04 -06:00
case ' q ' :
2008-08-22 14:58:19 -05:00
case ' Q ' :
2011-04-14 03:25:01 -05:00
retval = gdb_thread_packet ( connection ,
target , packet ,
packet_size ) ;
if ( retval = = GDB_THREAD_PACKET_NOT_CONSUMED )
{
retval = gdb_query_packet ( connection ,
target , packet ,
packet_size ) ;
}
2008-02-25 11:48:04 -06:00
break ;
case ' g ' :
2010-01-20 01:30:36 -06:00
retval = gdb_get_registers_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' G ' :
2010-01-20 01:30:36 -06:00
retval = gdb_set_registers_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' p ' :
2010-01-20 01:30:36 -06:00
retval = gdb_get_register_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' P ' :
2010-01-20 01:30:36 -06:00
retval = gdb_set_register_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' m ' :
2010-01-20 01:30:36 -06:00
retval = gdb_read_memory_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' M ' :
2010-01-20 01:30:36 -06:00
retval = gdb_write_memory_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' z ' :
case ' Z ' :
retval = gdb_breakpoint_watchpoint_packet ( connection , target , packet , packet_size ) ;
break ;
case ' ? ' :
2010-01-20 01:30:36 -06:00
gdb_last_signal_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' c ' :
case ' s ' :
{
2009-09-24 01:34:23 -05:00
log_add_callback ( gdb_log_callback , connection ) ;
2010-03-16 08:45:07 -05:00
if ( gdb_con - > mem_write_error )
{
LOG_ERROR ( " Memory write failure! " ) ;
/* now that we have reported the memory write error, we can clear the condition */
gdb_con - > mem_write_error = false ;
}
2009-09-24 01:34:23 -05:00
bool nostep = false ;
2010-01-20 16:36:57 -06:00
bool already_running = false ;
2009-09-24 01:34:23 -05:00
if ( target - > state = = TARGET_RUNNING )
{
2010-01-20 16:36:57 -06:00
LOG_WARNING ( " WARNING! The target is already running. "
" All changes GDB did to registers will be discarded! "
" Waiting for target to halt. " ) ;
already_running = true ;
2009-09-24 01:34:23 -05:00
} else if ( target - > state ! = TARGET_HALTED )
{
LOG_WARNING ( " The target is not in the halted nor running stated, stepi/continue ignored. " ) ;
nostep = true ;
} else if ( ( packet [ 0 ] = = ' s ' ) & & gdb_con - > sync )
{
/* Hmm..... when you issue a continue in GDB, then a "stepi" is
* sent by GDB first to OpenOCD , thus defeating the check to
* make only the single stepping have the sync feature . . .
*/
nostep = true ;
LOG_WARNING ( " stepi ignored. GDB will now fetch the register state from the target. " ) ;
}
gdb_con - > sync = false ;
2010-06-16 01:24:51 -05:00
if ( ! already_running & & nostep )
2008-04-13 08:29:33 -05:00
{
2009-09-24 01:34:23 -05:00
/* Either the target isn't in the halted state, then we can't
2008-04-13 08:29:33 -05:00
* step / continue . This might be early setup , etc .
2009-09-24 01:34:23 -05:00
*
* Or we want to allow GDB to pick up a fresh set of
* register values without modifying the target state .
*
2008-04-13 08:29:33 -05:00
*/
2008-08-13 07:21:57 -05:00
gdb_sig_halted ( connection ) ;
2009-09-24 01:34:23 -05:00
/* stop forwarding log packets! */
log_remove_callback ( gdb_log_callback , connection ) ;
2008-04-13 08:29:33 -05:00
} else
{
/* We're running/stepping, in which case we can
2008-09-24 03:42:13 -05:00
* forward log output until the target is halted
2008-04-13 08:29:33 -05:00
*/
gdb_con - > frontend_state = TARGET_RUNNING ;
2008-11-05 02:48:50 -06:00
target_call_event_callbacks ( target , TARGET_EVENT_GDB_START ) ;
2010-01-20 16:36:57 -06:00
if ( ! already_running )
2008-08-13 07:21:57 -05:00
{
2010-06-16 01:24:51 -05:00
/* Here we don't want packet processing to stop even if this fails,
* so we use a local variable instead of retval . */
retval = gdb_step_continue_packet ( connection , target , packet , packet_size ) ;
2010-01-20 16:36:57 -06:00
if ( retval ! = ERROR_OK )
{
/* we'll never receive a halted condition... issue a false one.. */
gdb_frontend_halted ( target , connection ) ;
}
2008-08-13 07:21:57 -05:00
}
2008-04-13 08:29:33 -05:00
}
2008-02-25 11:48:04 -06:00
}
break ;
case ' v ' :
2010-01-20 01:30:36 -06:00
retval = gdb_v_packet (
connection , target ,
packet , packet_size ) ;
2008-02-25 11:48:04 -06:00
break ;
case ' D ' :
retval = gdb_detach ( connection , target ) ;
extended_protocol = 0 ;
break ;
case ' X ' :
2010-01-20 01:30:36 -06:00
retval = gdb_write_memory_binary_packet (
connection , target ,
packet , packet_size ) ;
if ( retval ! = ERROR_OK )
2008-02-25 11:48:04 -06:00
return retval ;
break ;
case ' k ' :
if ( extended_protocol ! = 0 )
break ;
gdb_put_packet ( connection , " OK " , 2 ) ;
return ERROR_SERVER_REMOTE_CLOSED ;
case ' ! ' :
/* handle extended remote protocol */
extended_protocol = 1 ;
gdb_put_packet ( connection , " OK " , 2 ) ;
break ;
case ' R ' :
/* handle extended restart packet */
2008-08-23 13:47:42 -05:00
breakpoint_clear_target ( gdb_service - > target ) ;
watchpoint_clear_target ( gdb_service - > target ) ;
2009-08-30 12:30:14 -05:00
command_run_linef ( connection - > cmd_ctx ,
" ocd_gdb_restart %s " ,
2009-11-25 18:38:08 -06:00
target_name ( target ) ) ;
2008-02-25 11:48:04 -06:00
break ;
2011-04-19 01:43:33 -05:00
case ' j ' :
/* packet supported only by smp target i.e cortex_a.c*/
/* handle smp packet replying coreid played to gbd */
gdb_read_smp_packet (
connection , target ,
packet , packet_size ) ;
break ;
case ' J ' :
/* packet supported only by smp target i.e cortex_a.c */
/* handle smp packet setting coreid to be played at next
* resume to gdb */
gdb_write_smp_packet (
connection , target ,
packet , packet_size ) ;
break ;
2008-02-25 11:48:04 -06:00
default :
2009-11-24 13:01:15 -06:00
/* ignore unknown packets */
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " ignoring 0x%2.2x packet " , packet [ 0 ] ) ;
2008-02-25 11:48:04 -06:00
gdb_put_packet ( connection , NULL , 0 ) ;
break ;
}
/* if a packet handler returned an error, exit input loop */
if ( retval ! = ERROR_OK )
return retval ;
}
if ( gdb_con - > ctrl_c )
{
if ( target - > state = = TARGET_RUNNING )
{
2009-10-09 03:31:40 -05:00
retval = target_halt ( target ) ;
if ( retval ! = ERROR_OK )
{
target_call_event_callbacks ( target , TARGET_EVENT_GDB_HALT ) ;
}
2008-02-25 11:48:04 -06:00
gdb_con - > ctrl_c = 0 ;
2009-10-12 02:27:27 -05:00
} else
{
LOG_INFO ( " The target is not running when halt was requested, stopping GDB. " ) ;
target_call_event_callbacks ( target , TARGET_EVENT_GDB_HALT ) ;
2008-02-25 11:48:04 -06:00
}
}
} while ( gdb_con - > buf_cnt > 0 ) ;
return ERROR_OK ;
}
2010-01-20 01:30:36 -06:00
static int gdb_input ( struct connection * connection )
2008-02-25 11:48:04 -06:00
{
int retval = gdb_input_inner ( connection ) ;
2009-11-13 10:06:49 -06:00
struct gdb_connection * gdb_con = connection - > priv ;
2008-02-25 11:48:04 -06:00
if ( retval = = ERROR_SERVER_REMOTE_CLOSED )
return retval ;
2008-03-05 04:28:32 -06:00
2008-12-15 03:43:26 -06:00
/* logging does not propagate the error, yet can set the gdb_con->closed flag */
2008-03-05 04:28:32 -06:00
if ( gdb_con - > closed )
return ERROR_SERVER_REMOTE_CLOSED ;
2008-09-24 03:42:13 -05:00
2008-02-25 11:48:04 -06:00
/* we'll recover from any other errors(e.g. temporary timeouts, etc.) */
return ERROR_OK ;
}
2010-09-27 01:50:49 -05:00
static int gdb_target_start ( struct target * target , const char * port )
2008-02-25 11:48:04 -06:00
{
2011-04-19 01:43:33 -05:00
struct gdb_service * gdb_service ;
int ret ;
gdb_service = malloc ( sizeof ( struct gdb_service ) ) ;
2009-11-28 20:56:23 -06:00
if ( NULL = = gdb_service )
return - ENOMEM ;
2008-02-25 11:48:04 -06:00
2009-11-28 20:56:23 -06:00
gdb_service - > target = target ;
2011-04-19 01:43:33 -05:00
gdb_service - > core [ 0 ] = - 1 ;
gdb_service - > core [ 1 ] = - 1 ;
target - > gdb_service = gdb_service ;
2008-02-25 11:48:04 -06:00
2011-04-19 01:43:33 -05:00
ret = add_service ( " gdb " ,
2009-11-28 20:56:23 -06:00
port , 1 , & gdb_new_connection , & gdb_input ,
& gdb_connection_closed , gdb_service ) ;
2011-04-19 01:43:33 -05:00
/* initialialize all targets gdb service with the same pointer */
{
struct target_list * head ;
struct target * curr ;
head = target - > head ;
while ( head ! = ( struct target_list * ) NULL )
{
curr = head - > target ;
if ( curr ! = target ) curr - > gdb_service = gdb_service ;
head = head - > next ;
}
}
return ret ;
2009-11-28 20:56:23 -06:00
}
2010-01-20 01:30:36 -06:00
static int gdb_target_add_one ( struct target * target )
2009-11-28 20:56:23 -06:00
{
2011-04-19 01:43:33 -05:00
/* one gdb instance per smp list */
if ( ( target - > smp ) & & ( target - > gdb_service ) ) return ERROR_OK ;
2010-09-27 01:50:49 -05:00
int retval = gdb_target_start ( target , gdb_port_next ) ;
2011-04-19 01:43:33 -05:00
if ( retval = = ERROR_OK )
2009-12-03 07:13:45 -06:00
{
2010-09-27 01:48:31 -05:00
long portnumber ;
/* If we can parse the port number
* then we increment the port number for the next target .
*/
char * end ;
2010-10-05 10:29:37 -05:00
portnumber = strtol ( gdb_port_next , & end , 0 ) ;
2010-09-27 01:48:31 -05:00
if ( ! * end )
{
if ( parse_long ( gdb_port_next , & portnumber ) = = ERROR_OK )
{
free ( ( void * ) gdb_port_next ) ;
gdb_port_next = alloc_printf ( " %d " , portnumber + 1 ) ;
}
}
2009-12-03 07:13:45 -06:00
}
2010-09-27 01:48:31 -05:00
return retval ;
2009-11-28 20:56:23 -06:00
}
int gdb_target_add_all ( struct target * target )
{
if ( NULL = = target )
{
LOG_WARNING ( " gdb services need one or more targets defined " ) ;
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
2009-11-28 20:56:23 -06:00
while ( NULL ! = target )
2008-12-15 03:43:26 -06:00
{
2009-11-28 20:56:23 -06:00
int retval = gdb_target_add_one ( target ) ;
if ( ERROR_OK ! = retval )
return retval ;
2009-08-30 12:30:14 -05:00
2009-11-28 20:56:23 -06:00
target = target - > next ;
2008-12-15 03:43:26 -06:00
}
2008-12-16 04:55:08 -06:00
2008-02-25 11:48:04 -06:00
return ERROR_OK ;
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_gdb_sync_command )
2009-09-24 01:34:23 -05:00
{
2009-11-15 06:57:12 -06:00
if ( CMD_ARGC ! = 0 )
2009-09-24 01:34:23 -05:00
{
return ERROR_COMMAND_SYNTAX_ERROR ;
}
if ( current_gdb_connection = = NULL )
{
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX ,
2009-09-24 01:34:23 -05:00
" gdb_sync command can only be run from within gdb using \" monitor gdb_sync \" " ) ;
return ERROR_FAIL ;
}
current_gdb_connection - > sync = true ;
return ERROR_OK ;
}
2008-02-25 11:48:04 -06:00
/* daemon configuration command gdb_port */
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_gdb_port_command )
2008-02-25 11:48:04 -06:00
{
2010-09-27 01:48:31 -05:00
int retval = CALL_COMMAND_HANDLER ( server_pipe_command , & gdb_port ) ;
2010-10-04 14:35:33 -05:00
if ( ERROR_OK = = retval ) {
free ( ( void * ) gdb_port_next ) ;
2010-09-27 01:48:31 -05:00
gdb_port_next = strdup ( gdb_port ) ;
2010-10-04 14:35:33 -05:00
}
2009-12-03 07:13:45 -06:00
return retval ;
2008-02-25 11:48:04 -06:00
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_gdb_memory_map_command )
2008-02-25 11:48:04 -06:00
{
2010-05-17 04:17:21 -05:00
if ( CMD_ARGC ! = 1 )
return ERROR_COMMAND_SYNTAX_ERROR ;
2008-02-28 04:07:54 -06:00
2010-05-17 04:17:21 -05:00
COMMAND_PARSE_ENABLE ( CMD_ARGV [ 0 ] , gdb_use_memory_map ) ;
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_gdb_flash_program_command )
2008-02-25 11:48:04 -06:00
{
2010-05-17 04:17:21 -05:00
if ( CMD_ARGC ! = 1 )
return ERROR_COMMAND_SYNTAX_ERROR ;
2008-02-28 04:07:54 -06:00
2010-05-17 04:17:21 -05:00
COMMAND_PARSE_ENABLE ( CMD_ARGV [ 0 ] , gdb_flash_program ) ;
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_gdb_report_data_abort_command )
2008-02-25 11:48:04 -06:00
{
2010-05-17 04:17:21 -05:00
if ( CMD_ARGC ! = 1 )
return ERROR_COMMAND_SYNTAX_ERROR ;
2008-02-28 04:07:54 -06:00
2010-05-17 04:17:21 -05:00
COMMAND_PARSE_ENABLE ( CMD_ARGV [ 0 ] , gdb_report_data_abort ) ;
return ERROR_OK ;
2008-02-25 11:48:04 -06:00
}
2008-10-22 04:30:33 -05:00
/* gdb_breakpoint_override */
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_gdb_breakpoint_override_command )
2008-08-13 15:42:07 -05:00
{
2009-11-15 06:57:12 -06:00
if ( CMD_ARGC = = 0 )
2008-08-13 15:42:07 -05:00
{
2008-09-24 03:42:13 -05:00
2009-11-15 06:57:12 -06:00
} else if ( CMD_ARGC = = 1 )
2008-08-13 15:42:07 -05:00
{
gdb_breakpoint_override = 1 ;
2009-11-15 10:15:59 -06:00
if ( strcmp ( CMD_ARGV [ 0 ] , " hard " ) = = 0 )
2008-08-13 15:42:07 -05:00
{
2009-06-23 17:42:54 -05:00
gdb_breakpoint_override_type = BKPT_HARD ;
2009-11-15 10:15:59 -06:00
} else if ( strcmp ( CMD_ARGV [ 0 ] , " soft " ) = = 0 )
2008-08-13 15:42:07 -05:00
{
2009-06-23 17:42:54 -05:00
gdb_breakpoint_override_type = BKPT_SOFT ;
2009-11-15 10:15:59 -06:00
} else if ( strcmp ( CMD_ARGV [ 0 ] , " disable " ) = = 0 )
2008-08-13 15:42:07 -05:00
{
gdb_breakpoint_override = 0 ;
}
} else
{
return ERROR_COMMAND_SYNTAX_ERROR ;
}
if ( gdb_breakpoint_override )
{
2009-06-23 17:42:03 -05:00
LOG_USER ( " force %s breakpoints " , ( gdb_breakpoint_override_type = = BKPT_HARD ) ? " hard " : " soft " ) ;
2008-08-13 15:42:07 -05:00
} else
{
2009-11-24 13:01:15 -06:00
LOG_USER ( " breakpoint type is not overridden " ) ;
2008-08-13 15:42:07 -05:00
}
2008-09-24 03:42:13 -05:00
2008-08-13 15:42:07 -05:00
return ERROR_OK ;
}
2009-11-21 16:42:05 -06:00
static const struct command_registration gdb_command_handlers [ ] = {
{
. name = " gdb_sync " ,
2010-01-09 02:55:41 -06:00
. handler = handle_gdb_sync_command ,
2009-11-21 16:42:05 -06:00
. mode = COMMAND_ANY ,
. help = " next stepi will return immediately allowing "
" GDB to fetch register state without affecting "
" target state " ,
} ,
{
. name = " gdb_port " ,
2010-01-09 02:55:41 -06:00
. handler = handle_gdb_port_command ,
2010-01-05 07:57:45 -06:00
. mode = COMMAND_ANY ,
2010-09-27 15:55:30 -05:00
. help = " Normally gdb listens to a TCP/IP port. Each subsequent GDB "
" server listens for the next port number after the "
" base port number specified. "
" No arguments reports GDB port. \" pipe \" means listen to stdin "
" output to stdout, an integer is base port number, \" disable \" disables "
" port. Any other string is are interpreted as named pipe to listen to. "
" Output pipe is the same name as input pipe, but with 'o' appended. " ,
2010-01-09 02:55:41 -06:00
. usage = " [port_num] " ,
2009-11-21 16:42:05 -06:00
} ,
{
. name = " gdb_memory_map " ,
2010-01-09 02:55:41 -06:00
. handler = handle_gdb_memory_map_command ,
2009-11-21 16:42:05 -06:00
. mode = COMMAND_CONFIG ,
. help = " enable or disable memory map " ,
2010-01-09 02:55:41 -06:00
. usage = " ('enable'|'disable') "
2009-11-21 16:42:05 -06:00
} ,
{
. name = " gdb_flash_program " ,
2010-01-09 02:55:41 -06:00
. handler = handle_gdb_flash_program_command ,
2009-11-21 16:42:05 -06:00
. mode = COMMAND_CONFIG ,
. help = " enable or disable flash program " ,
2010-01-09 02:55:41 -06:00
. usage = " ('enable'|'disable') "
2009-11-21 16:42:05 -06:00
} ,
{
. name = " gdb_report_data_abort " ,
2010-01-09 02:55:41 -06:00
. handler = handle_gdb_report_data_abort_command ,
2009-11-21 16:42:05 -06:00
. mode = COMMAND_CONFIG ,
. help = " enable or disable reporting data aborts " ,
2010-01-09 02:55:41 -06:00
. usage = " ('enable'|'disable') "
2009-11-21 16:42:05 -06:00
} ,
{
. name = " gdb_breakpoint_override " ,
2010-01-09 02:55:41 -06:00
. handler = handle_gdb_breakpoint_override_command ,
2010-01-13 18:58:07 -06:00
. mode = COMMAND_ANY ,
2010-01-09 02:55:41 -06:00
. help = " Display or specify type of breakpoint "
" to be used by gdb 'break' commands. " ,
. usage = " ('hard'|'soft'|'disable') "
2009-11-21 16:42:05 -06:00
} ,
COMMAND_REGISTRATION_DONE
} ;
int gdb_register_commands ( struct command_context * cmd_ctx )
2008-02-25 11:48:04 -06:00
{
2010-09-27 01:48:31 -05:00
gdb_port = strdup ( " 3333 " ) ;
gdb_port_next = strdup ( " 3333 " ) ;
2009-11-21 16:42:05 -06:00
return register_commands ( cmd_ctx , NULL , gdb_command_handlers ) ;
2008-02-25 11:48:04 -06:00
}