📄 gdb.c
字号:
}
else
{
if( verbose )
{
printf( "(To Host : %s)", s );
}
}
}
/************************************************************************
* setup_single_step
************************************************************************/
static bool
setup_single_step( void )
{
UINT32 epc, instruction, opcode, function, rt;
UINT32 addr_kseg0;
UINT32 i;
bool branch;
INT16 offset;
/* Read EPC (only support for 32 bit) */
epc = (UINT32)*shell_get_epc(&context);
/* Validate address */
if( sys_validate_range( epc,
sizeof(UINT32),
sizeof(UINT32),
FALSE ) != OK )
{
return FALSE;
}
/* Convert to KSEG0 */
sys_kseg0( epc, &addr_kseg0 );
/* Read next instruction */
instruction = REG32( addr_kseg0 );
/* Defaults */
branch = FALSE;
ss_count = 1;
ss_addr[0] = epc + 4;
/* Determine where to set BREAK(s) */
opcode = MIPS_OPCODE(instruction);
switch( opcode )
{
case OPC_SPECIAL :
function = MIPS_FUNCTION( instruction );
switch( function )
{
case FUNC_JR :
case FUNC_JALR :
ss_addr[0] =
(UINT32)SYS_CPUREG(&context, MIPS_RS(instruction));
break;
default :
break;
}
break;
case OPC_REGIM :
rt = MIPS_RT( instruction );
switch( rt )
{
case RT_BLTZ :
case RT_BGEZ :
case RT_BLTZL :
case RT_BGEZL :
case RT_BLTZAL :
case RT_BGEZAL :
case RT_BLTZALL :
case RT_BGEZALL :
branch = TRUE;
break;
default :
break;
}
break;
case OPC_BEQ :
case OPC_BNE :
case OPC_BLEZ :
case OPC_BGTZ :
case OPC_BEQL :
case OPC_BNEL :
case OPC_BLEZL :
case OPC_BGTZL :
branch = TRUE;
break;
case OPC_J :
case OPC_JAL :
ss_addr[0] = ((epc + 4) & (MSK(4) << 28)) |
(MIPS_TARGET( instruction ) << 2);
break;
default :
break;
}
if( branch )
{
/* We need to set two breakpoints, one if the branch is
* taken, and one if it is not taken.
*/
ss_addr[0] = epc + 8;
offset = (INT16)MIPS_OFFSET(instruction);
ss_addr[1] = epc + 4;
ss_addr[1] = (UINT32) ((INT32)offset * 4 + (INT32)(ss_addr[1]));
if( ss_addr[0] != ss_addr[1] )
ss_count = 2;
}
/* Set BREAK(s) */
for( i=0; i < ss_count; i++ )
{
/* Validate address */
if( sys_validate_range( ss_addr[i],
sizeof(UINT32),
sizeof(UINT32),
TRUE ) != OK )
{
return FALSE;
}
/* Convert to KSEG0 */
sys_kseg0( ss_addr[i], &addr_kseg0 );
/* Store original instruction */
ss_instr[i] = REG32( addr_kseg0 );
/* Insert break */
REG32( addr_kseg0 ) = OPCODE_BREAK;
/*
* Flush D-cache in order to store data in
* physical memory.
* Invalidate I-cache since new instructions may
* have been stored;
*/
sys_flush_cache_line( (void *)addr_kseg0 );
}
return TRUE;
}
/************************************************************************
* cleanup_single_step
************************************************************************/
static bool
cleanup_single_step( void )
{
UINT32 i;
UINT32 addr_kseg0;
/* Write back original instruction(s) */
for( i=0; i<ss_count; i++)
{
/* Validate address */
if( sys_validate_range( ss_addr[i],
sizeof(UINT32),
sizeof(UINT32),
TRUE ) != OK )
{
return FALSE;
}
/* Convert to KSEG0 */
sys_kseg0( ss_addr[i], &addr_kseg0 );
REG32( addr_kseg0 ) = ss_instr[i];
/*
* Flush D-cache in order to store data in
* physical memory.
* Invalidate I-cache since new instructions may
* have been stored;
*/
sys_flush_cache_line( (void *)addr_kseg0 );
}
return TRUE;
}
/************************************************************************
* get_char
************************************************************************/
static char
get_char(
bool *ctrl_c )
{
char ch;
do
{
*ctrl_c = GETCHAR_CTRLC( DEFAULT_PORT );
}
while( !(*ctrl_c) && !GETCHAR( GDB_PORT, &ch ) );
return ch;
}
/************************************************************************
* valid_hex
************************************************************************/
static bool
valid_hex(
char ch )
{
if( (ch >= '0') && (ch <= '9') )
return TRUE;
ch = tolower( ch );
if( (ch >= 'a') && (ch <= 'f') )
return TRUE;
return FALSE;
}
/************************************************************************
* char2hex
************************************************************************/
static UINT8
char2hex(
char ch )
{
if( (ch >= '0') && (ch <= '9') )
return ch - '0';
ch = tolower( ch );
if( (ch >= 'a') && (ch <= 'f') )
return ch - 'a' + 10;
return 0;
}
/************************************************************************
* hex2char
************************************************************************/
static char
hex2char(
UINT8 val )
{
if( val < 10 )
return '0' + val;
else
return val - 10 + 'a';
}
/************************************************************************
* getval
************************************************************************/
static UINT32
getval(
char **in_buf,
UINT64 *val,
UINT8 size,
bool strict )
{
UINT32 i;
bool valid;
*val = 0;
valid = FALSE;
for( i=0; i < 2*size; i++ )
{
if( !valid_hex( **in_buf ) )
{
if( strict )
return GDB_ERROR_GENERAL;
else
{
break;
}
}
else
{
valid = TRUE;
*val <<= 4;
*val += char2hex(**in_buf);
(*in_buf)++;
}
}
if( !valid )
return GDB_ERROR_GENERAL;
else
{
#ifdef EL
if( size == sizeof(UINT32) )
*val = SWAPEND32( (UINT32)(*val) );
if( size == sizeof(UINT64) )
*val = SWAPEND64( *val );
#endif
return GDB_OK;
}
}
/************************************************************************
* setval
************************************************************************/
static void
setval(
char **out_buf,
UINT64 val,
UINT8 size )
{
UINT32 i;
#ifdef EL
if( size == sizeof(UINT32) )
val = SWAPEND32( (UINT32)val );
if( size == sizeof(UINT64) )
val = SWAPEND64( val );
#endif
for( i = 2*size; i > 0; i-- )
{
(*out_buf)[i-1] = hex2char(val & 0xF);
val >>= 4;
}
(*out_buf) += size * 2;
}
/************************************************************************
* write_regs
************************************************************************/
static UINT32
write_regs(
char *in_buf,
UINT32 size )
{
UINT64 *regs;
UINT64 val;
UINT32 i;
UINT32 rc;
regs = (UINT64 *)&context;
for( i=0; i<GDB_REG_COUNT; i++ )
{
rc = getval( &in_buf, &val, size, TRUE );
if( rc != GDB_OK )
return rc;
else
regs[i] = val;
}
}
/************************************************************************
* read_regs
************************************************************************/
static void
read_regs(
char *out_buf,
UINT32 size )
{
UINT64 *regs;
UINT32 i;
UINT32 rc;
regs = (UINT64 *)&context;
for( i=0; i<GDB_REG_COUNT; i++ )
{
setval( &out_buf, regs[i], size );
}
*out_buf = '\0';
}
/************************************************************************
* gethex
************************************************************************/
static UINT64
gethex(
char *in_buf,
char **ptr,
UINT32 *rc )
{
int ch;
UINT64 val, tmp;
if( rc )
*rc = GDB_ERROR_GENERAL; /* Default */
val = 0;
while( valid_hex( *in_buf ) )
{
/* We have at least one valid hex digit */
if( rc )
*rc = GDB_OK;
ch = *in_buf++;
if( ch >= '0' && ch <= '9' )
val = (val << 4) + (ch - '0');
else if( ch >= 'a' && ch <= 'f' )
val = (val << 4) + (ch + 10 - 'a');
else
val = (val << 4) + (ch + 10 - 'A');
}
if( ptr )
*ptr = in_buf;
return val;
}
/* Command definition for help */
static t_cmd cmd_def =
{
"gdb",
gdb,
"gdb [-v][-c] [. <args>]",
"Setup connection to GDB debugger on port "
#if (GDB_PORT == PORT_TTY0)
"tty0"
#else
"tty1"
#endif
".\n"
"The Standard GDB remote protocol is used.\n"
"\n"
"If the user application is not currently running, and Ctrl-C\n"
"is typed at the console port, YAMON will leave GDB mode and\n"
"return to the command prompt.\n"
"\n"
"<args> is broken up in substrings and passed to the application.\n"
"The list of arguments to be passed must begin with a '.'.\n"
"The '.' is not passed as an argument. The first\n"
"argument (argv[0]) will be the string 'gdb'.\n"
"\n"
"a0 is set to the number of substrings (argc).\n"
"a1 is set to the address of an array of pointers to the substrings (argv).\n"
"a2 is set to the address of the environment table.\n"
"a3 is set to the memory size.\n"
"ra holds the return address to YAMON.\n"
"\n"
"The application may return to YAMON by jumping to the address\n"
"specified in ra or by calling the exit(rc) function supplied by YAMON.\n"
"\n"
"The verbose (-v) option will cause the commands from the\n"
"GDB host and the responses from YAMON to be displayed on the\n"
"console port.\n"
"\n"
"The checksum off (-c) option will disable validation of\n"
"the cheksum used in GDB commands. This is useful in case\n"
"the user wishes to enter commands manually. Two checksum\n"
"characters should still be used in the commands, but the\n"
"values are don't care.",
options,
OPTION_COUNT,
FALSE
};
/************************************************************************
* Implementation : Public functions
************************************************************************/
/************************************************************************
*
* shell_gdb_init
* Description :
* -------------
*
* Initialise command
*
* Return values :
* ---------------
*
* void
*
************************************************************************/
t_cmd *
shell_gdb_init( void )
{
return &cmd_def;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -