forked from Imagelibrary/rtems
2001-02-27 Joel Sherrill <joel@OARcorp.com>
* Significant modifications including adding thread support, the 'X' command, and reorganizing so that target CPU independent routines could be reused. * gdb_if.h: Added numerous prototypes. * mips-stub.c: Added thread support as well as 'X' command. Also noticed that the 'P' command was from the mips protocol. * rtems-stub-glue.c: New file. This file contains all generic support which should be able to be reused on another target CPU.
This commit is contained in:
@@ -1,3 +1,14 @@
|
|||||||
|
2001-02-27 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
|
* Significant modifications including adding thread support, the 'X'
|
||||||
|
command, and reorganizing so that target CPU independent routines
|
||||||
|
could be reused.
|
||||||
|
* gdb_if.h: Added numerous prototypes.
|
||||||
|
* mips-stub.c: Added thread support as well as 'X' command.
|
||||||
|
Also noticed that the 'P' command was from the mips protocol.
|
||||||
|
* rtems-stub-glue.c: New file. This file contains all generic
|
||||||
|
support which should be able to be reused on another target CPU.
|
||||||
|
|
||||||
2002-02-08 Joel Sherrill <joel@OARcorp.com>
|
2002-02-08 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
* mips-stub.c (handle_exception): Prototype changed to be an RTEMS
|
* mips-stub.c (handle_exception): Prototype changed to be an RTEMS
|
||||||
|
|||||||
@@ -17,6 +17,61 @@
|
|||||||
#ifndef _GDB_IF_H
|
#ifndef _GDB_IF_H
|
||||||
#define _GDB_IF_H
|
#define _GDB_IF_H
|
||||||
|
|
||||||
|
/* Max number of threads in qM response */
|
||||||
|
#define QM_MAX_THREADS (20)
|
||||||
|
|
||||||
|
struct rtems_gdb_stub_thread_info {
|
||||||
|
char display[256];
|
||||||
|
char name[256];
|
||||||
|
char more_display[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len);
|
||||||
|
|
||||||
|
|
||||||
|
char* mem2hstr(char *buf, const unsigned char *mem, int count);
|
||||||
|
int hstr2mem(unsigned char *mem, const char *buf, int count);
|
||||||
|
void set_mem_err(void);
|
||||||
|
unsigned char get_byte(const unsigned char *ptr);
|
||||||
|
void set_byte(unsigned char *ptr, int val);
|
||||||
|
char* thread2vhstr(char *buf, int thread);
|
||||||
|
char* thread2fhstr(char *buf, int thread);
|
||||||
|
const char* fhstr2thread(const char *buf, int *thread);
|
||||||
|
const char* vhstr2thread(const char *buf, int *thread);
|
||||||
|
char* int2fhstr(char *buf, int val);
|
||||||
|
char* int2vhstr(char *buf, int vali);
|
||||||
|
const char* fhstr2int(const char *buf, int *ival);
|
||||||
|
const char* vhstr2int(const char *buf, int *ival);
|
||||||
|
int hstr2byte(const char *buf, int *bval);
|
||||||
|
int hstr2nibble(const char *buf, int *nibble);
|
||||||
|
|
||||||
|
int rtems_gdb_stub_thread_support_ok(void);
|
||||||
|
int rtems_gdb_stub_get_current_thread(void);
|
||||||
|
int rtems_gdb_stub_get_next_thread(int);
|
||||||
|
int rtems_gdb_stub_get_offsets(
|
||||||
|
unsigned char **text_addr,
|
||||||
|
unsigned char **data_addr,
|
||||||
|
unsigned char **bss_addr
|
||||||
|
);
|
||||||
|
int rtems_gdb_stub_get_thread_regs(
|
||||||
|
int thread,
|
||||||
|
unsigned int *registers
|
||||||
|
);
|
||||||
|
int rtems_gdb_stub_set_thread_regs(
|
||||||
|
int thread,
|
||||||
|
unsigned int *registers
|
||||||
|
);
|
||||||
|
void rtems_gdb_process_query(
|
||||||
|
char *inbuffer,
|
||||||
|
char *outbuffer,
|
||||||
|
int do_threads,
|
||||||
|
int thread
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIPS registers, numbered in the order in which gdb expects to see them.
|
* MIPS registers, numbered in the order in which gdb expects to see them.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#define GDB_STUB_ENABLE_THREAD_SUPPORT 1
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
THIS SOFTWARE IS NOT COPYRIGHTED
|
THIS SOFTWARE IS NOT COPYRIGHTED
|
||||||
@@ -126,6 +127,12 @@
|
|||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
|
|
||||||
|
extern int printk(const char *fmt, ...);
|
||||||
|
|
||||||
|
/* Change it to something meaningful when debugging */
|
||||||
|
#undef ASSERT
|
||||||
|
#define ASSERT(x) if(!(x)) printk("ASSERT: stub: %d\n", __LINE__)
|
||||||
|
|
||||||
/***************/
|
/***************/
|
||||||
/* Exception Codes */
|
/* Exception Codes */
|
||||||
#define EXC_INT 0 /* External interrupt */
|
#define EXC_INT 0 /* External interrupt */
|
||||||
@@ -184,13 +191,18 @@
|
|||||||
*/
|
*/
|
||||||
#if (__mips == 3)
|
#if (__mips == 3)
|
||||||
typedef long long mips_register_t;
|
typedef long long mips_register_t;
|
||||||
|
#define R_SZ 8
|
||||||
#elif (__mips == 1)
|
#elif (__mips == 1)
|
||||||
typedef unsigned int mips_register_t;
|
typedef unsigned int mips_register_t;
|
||||||
|
#define R_SZ 4
|
||||||
#else
|
#else
|
||||||
#error "unknown MIPS ISA"
|
#error "unknown MIPS ISA"
|
||||||
#endif
|
#endif
|
||||||
static mips_register_t *registers;
|
static mips_register_t *registers;
|
||||||
|
|
||||||
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
static char do_threads; /* != 0 means we are supporting threads */
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following external functions provide character input and output.
|
* The following external functions provide character input and output.
|
||||||
@@ -210,14 +222,31 @@ extern void putDebugChar (char);
|
|||||||
static char inBuffer[BUFMAX];
|
static char inBuffer[BUFMAX];
|
||||||
static char outBuffer[BUFMAX];
|
static char outBuffer[BUFMAX];
|
||||||
|
|
||||||
|
/* Structure to keep info on a z-breaks */
|
||||||
|
#define BREAKNUM 32
|
||||||
|
struct z0break
|
||||||
|
{
|
||||||
|
/* List support */
|
||||||
|
struct z0break *next;
|
||||||
|
struct z0break *prev;
|
||||||
|
|
||||||
|
/* Location, preserved data */
|
||||||
|
unsigned char *address;
|
||||||
|
char buf[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct z0break z0break_arr[BREAKNUM];
|
||||||
|
static struct z0break *z0break_avail = NULL;
|
||||||
|
static struct z0break *z0break_list = NULL;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert an int to hex.
|
* Convert an int to hex.
|
||||||
*/
|
*/
|
||||||
static const char hexchars[] = "0123456789abcdef";
|
const char gdb_hexchars[] = "0123456789abcdef";
|
||||||
|
|
||||||
#define highhex(x) hexchars [(x >> 4) & 0xf]
|
#define highhex(x) gdb_hexchars [(x >> 4) & 0xf]
|
||||||
#define lowhex(x) hexchars [x & 0xf]
|
#define lowhex(x) gdb_hexchars [x & 0xf]
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -225,8 +254,10 @@ static const char hexchars[] = "0123456789abcdef";
|
|||||||
* result in buf. Return a pointer to the last (null) char in buf.
|
* result in buf. Return a pointer to the last (null) char in buf.
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
mem2hex (int addr, int length, char *buf)
|
mem2hex (void *_addr, int length, char *buf)
|
||||||
{
|
{
|
||||||
|
unsigned int addr = (unsigned int) _addr;
|
||||||
|
|
||||||
if (((addr & 0x7) == 0) && ((length & 0x7) == 0)) /* dword aligned */
|
if (((addr & 0x7) == 0) && ((length & 0x7) == 0)) /* dword aligned */
|
||||||
{
|
{
|
||||||
long long *source = (long long *) (addr);
|
long long *source = (long long *) (addr);
|
||||||
@@ -238,7 +269,7 @@ mem2hex (int addr, int length, char *buf)
|
|||||||
long long k = *source++;
|
long long k = *source++;
|
||||||
|
|
||||||
for (i = 15; i >= 0; i--)
|
for (i = 15; i >= 0; i--)
|
||||||
*buf++ = hexchars [(k >> (i*4)) & 0xf];
|
*buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
|
else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
|
||||||
@@ -252,7 +283,7 @@ mem2hex (int addr, int length, char *buf)
|
|||||||
int k = *source++;
|
int k = *source++;
|
||||||
|
|
||||||
for (i = 7; i >= 0; i--)
|
for (i = 7; i >= 0; i--)
|
||||||
*buf++ = hexchars [(k >> (i*4)) & 0xf];
|
*buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
|
else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
|
||||||
@@ -266,7 +297,7 @@ mem2hex (int addr, int length, char *buf)
|
|||||||
short k = *source++;
|
short k = *source++;
|
||||||
|
|
||||||
for (i = 3; i >= 0; i--)
|
for (i = 3; i >= 0; i--)
|
||||||
*buf++ = hexchars [(k >> (i*4)) & 0xf];
|
*buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else /* byte aligned */
|
else /* byte aligned */
|
||||||
@@ -280,7 +311,7 @@ mem2hex (int addr, int length, char *buf)
|
|||||||
char k = *source++;
|
char k = *source++;
|
||||||
|
|
||||||
for (i = 1; i >= 0; i--)
|
for (i = 1; i >= 0; i--)
|
||||||
*buf++ = hexchars [(k >> (i*4)) & 0xf];
|
*buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,8 +403,9 @@ hexToLongLong (char **ptr, long long *intValue)
|
|||||||
* then return 0; otherwise return 1.
|
* then return 0; otherwise return 1.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
hex2mem (char *buf, int addr, int length)
|
hex2mem (char *buf, void *_addr, int length)
|
||||||
{
|
{
|
||||||
|
unsigned int addr = (unsigned int) _addr;
|
||||||
if (((addr & 0x7) == 0) && ((length & 0x7) == 0)) /* dword aligned */
|
if (((addr & 0x7) == 0) && ((length & 0x7) == 0)) /* dword aligned */
|
||||||
{
|
{
|
||||||
long long *target = (long long *) (addr);
|
long long *target = (long long *) (addr);
|
||||||
@@ -450,6 +482,45 @@ hex2mem (char *buf, int addr, int length)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert the binary stream in BUF to memory.
|
||||||
|
|
||||||
|
Gdb will escape $, #, and the escape char (0x7d).
|
||||||
|
COUNT is the total number of bytes to write into
|
||||||
|
memory. */
|
||||||
|
static unsigned char *
|
||||||
|
bin2mem (
|
||||||
|
unsigned char *buf,
|
||||||
|
unsigned char *mem,
|
||||||
|
int count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
/* Check for any escaped characters. Be paranoid and
|
||||||
|
only unescape chars that should be escaped. */
|
||||||
|
if (*buf == 0x7d) {
|
||||||
|
switch (*(buf+1)) {
|
||||||
|
case 0x3: /* # */
|
||||||
|
case 0x4: /* $ */
|
||||||
|
case 0x5d: /* escape char */
|
||||||
|
buf++;
|
||||||
|
*buf |= 0x20;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*mem++ = *buf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the input stream for a sequence for the form $<data>#<checksum>.
|
* Scan the input stream for a sequence for the form $<data>#<checksum>.
|
||||||
@@ -773,30 +844,88 @@ computeSignal (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This support function prepares and sends the message containing the
|
||||||
|
* basic information about this exception.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void gdb_stub_report_exception_info(
|
||||||
|
rtems_vector_number vector,
|
||||||
|
CPU_Interrupt_frame *frame,
|
||||||
|
int thread
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *optr;
|
||||||
|
int sigval;
|
||||||
|
|
||||||
|
optr = outBuffer;
|
||||||
|
*optr++ = 'T';
|
||||||
|
sigval = computeSignal ();
|
||||||
|
*optr++ = highhex (sigval);
|
||||||
|
*optr++ = lowhex (sigval);
|
||||||
|
|
||||||
|
*optr++ = gdb_hexchars[SP];
|
||||||
|
*optr++ = ':';
|
||||||
|
optr = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
|
||||||
|
*optr++ = ';';
|
||||||
|
|
||||||
|
*optr++ = gdb_hexchars[PC];
|
||||||
|
*optr++ = ':';
|
||||||
|
optr = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
|
||||||
|
*optr++ = ';';
|
||||||
|
|
||||||
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
if (do_threads) {
|
||||||
|
*optr++ = 't';
|
||||||
|
*optr++ = 'h';
|
||||||
|
*optr++ = 'r';
|
||||||
|
*optr++ = 'e';
|
||||||
|
*optr++ = 'a';
|
||||||
|
*optr++ = 'd';
|
||||||
|
*optr++ = ':';
|
||||||
|
optr = thread2vhstr(optr, thread);
|
||||||
|
*optr++ = ';';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
putpacket (outBuffer);
|
||||||
|
|
||||||
|
*optr++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function handles all exceptions. It only does two things:
|
* This function handles all exceptions. It only does two things:
|
||||||
* it figures out why it was activated and tells gdb, and then it
|
* it figures out why it was activated and tells gdb, and then it
|
||||||
* reacts to gdb's requests.
|
* reacts to gdb's requests.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
CPU_Interrupt_frame current_thread_registers;
|
||||||
|
|
||||||
void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
||||||
{
|
{
|
||||||
int host_has_detached = 0;
|
int host_has_detached = 0;
|
||||||
int sigval;
|
|
||||||
int regno, addr, length;
|
int regno, addr, length;
|
||||||
long long regval;
|
long long regval;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
int current_thread; /* current generic thread */
|
||||||
|
int thread; /* stopped thread: context exception happened in */
|
||||||
|
void *regptr;
|
||||||
|
int binary;
|
||||||
|
|
||||||
registers = (mips_register_t *)frame;
|
registers = (mips_register_t *)frame;
|
||||||
|
|
||||||
/* reply to host that an exception has occurred */
|
thread = 0;
|
||||||
sigval = computeSignal ();
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
outBuffer[0] = 'S';
|
if (do_threads) {
|
||||||
outBuffer[1] = highhex (sigval);
|
thread = rtems_gdb_stub_get_current_thread();
|
||||||
outBuffer[2] = lowhex (sigval);
|
}
|
||||||
outBuffer[3] = '\0';
|
#endif
|
||||||
|
current_thread = thread;
|
||||||
|
|
||||||
|
/* reply to host that an exception has occurred with some basic info */
|
||||||
|
gdb_stub_report_exception_info(vector, frame, thread);
|
||||||
|
|
||||||
putpacket (outBuffer);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore the saved instruction at
|
* Restore the saved instruction at
|
||||||
@@ -804,32 +933,43 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
*/
|
*/
|
||||||
undoSStep ();
|
undoSStep ();
|
||||||
|
|
||||||
while (!(host_has_detached))
|
while (!(host_has_detached)) {
|
||||||
{
|
|
||||||
outBuffer[0] = '\0';
|
outBuffer[0] = '\0';
|
||||||
getpacket (inBuffer);
|
getpacket (inBuffer);
|
||||||
|
binary = 0;
|
||||||
|
|
||||||
switch (inBuffer[0])
|
switch (inBuffer[0]) {
|
||||||
{
|
|
||||||
case '?':
|
case '?':
|
||||||
outBuffer[0] = 'S';
|
gdb_stub_report_exception_info(vector, frame, thread);
|
||||||
outBuffer[1] = highhex (sigval);
|
|
||||||
outBuffer[2] = lowhex (sigval);
|
|
||||||
outBuffer[3] = '\0';
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd': /* toggle debug flag */
|
||||||
/* toggle debug flag */
|
/* can print ill-formed commands in valid packets & checksum errors */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'g':
|
case 'D':
|
||||||
/* return the values of the CPU registers */
|
/* remote system is detaching - return OK and exit from debugger */
|
||||||
mem2hex ((int) registers, sizeof registers, outBuffer);
|
strcpy (outBuffer, "OK");
|
||||||
|
host_has_detached = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'G':
|
case 'g': /* return the values of the CPU registers */
|
||||||
/* set the values of the CPU registers - return OK */
|
regptr = registers;
|
||||||
if (hex2mem (&inBuffer[1], (int) registers, sizeof registers))
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
if (do_threads && current_thread != thread )
|
||||||
|
regptr = ¤t_thread_registers;
|
||||||
|
#endif
|
||||||
|
mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'G': /* set the values of the CPU registers - return OK */
|
||||||
|
regptr = registers;
|
||||||
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
if (do_threads && current_thread != thread )
|
||||||
|
regptr = ¤t_thread_registers;
|
||||||
|
#endif
|
||||||
|
if (hex2mem (&inBuffer[1], regptr, NUM_REGS * (sizeof registers)))
|
||||||
strcpy (outBuffer, "OK");
|
strcpy (outBuffer, "OK");
|
||||||
else
|
else
|
||||||
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
|
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
|
||||||
@@ -857,11 +997,13 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
&& hexToInt (&ptr, &length)
|
&& hexToInt (&ptr, &length)
|
||||||
&& is_readable (addr, length)
|
&& is_readable (addr, length)
|
||||||
&& (length < (BUFMAX - 4)/2))
|
&& (length < (BUFMAX - 4)/2))
|
||||||
mem2hex (addr, length, outBuffer);
|
mem2hex ((void *)addr, length, outBuffer);
|
||||||
else
|
else
|
||||||
strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
|
strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'X': /* XAA..AA,LLLL:<binary data>#cs */
|
||||||
|
binary = 1;
|
||||||
case 'M':
|
case 'M':
|
||||||
/* MAA..AA,LLLL: Write LLLL bytes at address AA..AA - return OK */
|
/* MAA..AA,LLLL: Write LLLL bytes at address AA..AA - return OK */
|
||||||
ptr = &inBuffer[1];
|
ptr = &inBuffer[1];
|
||||||
@@ -869,9 +1011,13 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
&& *ptr++ == ','
|
&& *ptr++ == ','
|
||||||
&& hexToInt (&ptr, &length)
|
&& hexToInt (&ptr, &length)
|
||||||
&& *ptr++ == ':'
|
&& *ptr++ == ':'
|
||||||
&& is_writeable (addr, length)
|
&& is_writeable (addr, length) ) {
|
||||||
&& hex2mem (ptr, addr, length))
|
if ( binary )
|
||||||
|
hex2mem (ptr, (void *)addr, length);
|
||||||
|
else
|
||||||
|
bin2mem (ptr, (void *)addr, length);
|
||||||
strcpy (outBuffer, "OK");
|
strcpy (outBuffer, "OK");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
|
strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
|
||||||
break;
|
break;
|
||||||
@@ -891,16 +1037,256 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'D':
|
case 'k': /* remove all zbreaks if any */
|
||||||
/* remote system is detaching - return OK and exit from debugger */
|
{
|
||||||
strcpy (outBuffer, "OK");
|
int ret;
|
||||||
host_has_detached = 1;
|
struct z0break *z0, *z0last;
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
z0last = NULL;
|
||||||
|
|
||||||
|
for (z0=z0break_list; z0!=NULL; z0=z0->next) {
|
||||||
|
if (!hstr2mem(z0->address, z0->buf, 1)) {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
z0last = z0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free entries if any */
|
||||||
|
if (z0last != NULL) {
|
||||||
|
z0last->next = z0break_avail;
|
||||||
|
z0break_avail = z0break_list;
|
||||||
|
z0break_list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case 'q': /* queries */
|
||||||
/* do nothing */
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
} /* switch */
|
|
||||||
|
case 'H': /* set new thread */
|
||||||
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
if (inBuffer[1] != 'g') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!do_threads) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int tmp, ret;
|
||||||
|
|
||||||
|
/* Set new generic thread */
|
||||||
|
if (vhstr2thread(&inBuffer[2], &tmp) == NULL) {
|
||||||
|
strcpy(outBuffer, "E01");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 0 means `thread' */
|
||||||
|
if (tmp == 0) {
|
||||||
|
tmp = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp == current_thread) {
|
||||||
|
/* No changes */
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save current thread registers if necessary */
|
||||||
|
if (current_thread != thread) {
|
||||||
|
ret = rtems_gdb_stub_set_thread_regs(
|
||||||
|
current_thread, (unsigned int *) ¤t_thread_registers);
|
||||||
|
ASSERT(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read new registers if necessary */
|
||||||
|
if (tmp != thread) {
|
||||||
|
ret = rtems_gdb_stub_get_thread_regs(
|
||||||
|
tmp, (unsigned int *) ¤t_thread_registers);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
/* Thread does not exist */
|
||||||
|
strcpy(outBuffer, "E02");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_thread = tmp;
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Z': /* Add breakpoint */
|
||||||
|
{
|
||||||
|
int ret, type, len;
|
||||||
|
unsigned char *address;
|
||||||
|
struct z0break *z0;
|
||||||
|
|
||||||
|
ret = parse_zbreak(inBuffer, &type, &address, &len);
|
||||||
|
if (!ret) {
|
||||||
|
strcpy(outBuffer, "E01");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != 0) {
|
||||||
|
/* We support only software break points so far */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != 1) {
|
||||||
|
strcpy(outBuffer, "E02");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let us check whether this break point already set */
|
||||||
|
for (z0=z0break_list; z0!=NULL; z0=z0->next) {
|
||||||
|
if (z0->address == address) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z0 != NULL) {
|
||||||
|
/* Repeated packet */
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let us allocate new break point */
|
||||||
|
if (z0break_avail == NULL) {
|
||||||
|
strcpy(outBuffer, "E03");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get entry */
|
||||||
|
z0 = z0break_avail;
|
||||||
|
z0break_avail = z0break_avail->next;
|
||||||
|
|
||||||
|
/* Let us copy memory from address add stuff the break point in */
|
||||||
|
if (mem2hstr(z0->buf, address, 1) == NULL ||
|
||||||
|
!hstr2mem(address, "cc" , 1)) {
|
||||||
|
/* Memory error */
|
||||||
|
z0->next = z0break_avail;
|
||||||
|
z0break_avail = z0;
|
||||||
|
strcpy(outBuffer, "E03");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill it */
|
||||||
|
z0->address = address;
|
||||||
|
|
||||||
|
/* Add to the list */
|
||||||
|
z0->next = z0break_list;
|
||||||
|
z0->prev = NULL;
|
||||||
|
|
||||||
|
if (z0break_list != NULL) {
|
||||||
|
z0break_list->prev = z0;
|
||||||
|
}
|
||||||
|
|
||||||
|
z0break_list = z0;
|
||||||
|
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'z': /* remove breakpoint */
|
||||||
|
{
|
||||||
|
int ret, type, len;
|
||||||
|
unsigned char *address;
|
||||||
|
struct z0break *z0, *z0last;
|
||||||
|
|
||||||
|
if (inBuffer[1] == 'z') {
|
||||||
|
/* zz packet - remove all breaks */
|
||||||
|
ret = 1;
|
||||||
|
z0last = NULL;
|
||||||
|
for (z0=z0break_list; z0!=NULL; z0=z0->next) {
|
||||||
|
if(!hstr2mem(z0->address, z0->buf, 1)) {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
z0last = z0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free entries if any */
|
||||||
|
if (z0last != NULL) {
|
||||||
|
z0last->next = z0break_avail;
|
||||||
|
z0break_avail = z0break_list;
|
||||||
|
z0break_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
} else {
|
||||||
|
strcpy(outBuffer, "E04");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = parse_zbreak(inBuffer, &type, &address, &len);
|
||||||
|
if (!ret) {
|
||||||
|
strcpy(outBuffer, "E01");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != 0) {
|
||||||
|
/* We support only software break points so far */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != 1) {
|
||||||
|
strcpy(outBuffer, "E02");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let us check whether this break point set */
|
||||||
|
for (z0=z0break_list; z0!=NULL; z0=z0->next) {
|
||||||
|
if (z0->address == address) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z0 == NULL) {
|
||||||
|
/* Unknown breakpoint */
|
||||||
|
strcpy(outBuffer, "E03");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hstr2mem(z0->address, z0->buf, 1)) {
|
||||||
|
strcpy(outBuffer, "E04");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlink entry */
|
||||||
|
if (z0->prev == NULL) {
|
||||||
|
z0break_list = z0->next;
|
||||||
|
if (z0break_list != NULL) {
|
||||||
|
z0break_list->prev = NULL;
|
||||||
|
}
|
||||||
|
} else if (z0->next == NULL) {
|
||||||
|
z0->prev->next = NULL;
|
||||||
|
} else {
|
||||||
|
z0->prev->next = z0->next;
|
||||||
|
z0->next->prev = z0->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
z0->next = z0break_avail;
|
||||||
|
z0break_avail = z0;
|
||||||
|
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default: /* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* reply to the request */
|
/* reply to the request */
|
||||||
putpacket (outBuffer);
|
putpacket (outBuffer);
|
||||||
@@ -919,13 +1305,33 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char initialized; /* 0 means we are not initialized */
|
||||||
|
|
||||||
void mips_gdb_stub_install(void)
|
void mips_gdb_stub_install(void)
|
||||||
{
|
{
|
||||||
rtems_isr_entry old;
|
rtems_isr_entry old;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (initialized) {
|
||||||
|
ASSERT(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* z0breaks */
|
||||||
|
for (i=0; i<(sizeof(z0break_arr)/sizeof(z0break_arr[0]))-1; i++) {
|
||||||
|
z0break_arr[i].next = &z0break_arr[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
z0break_arr[i].next = NULL;
|
||||||
|
z0break_avail = &z0break_arr[0];
|
||||||
|
z0break_list = NULL;
|
||||||
|
|
||||||
|
|
||||||
rtems_interrupt_catch( (rtems_isr_entry) handle_exception, MIPS_EXCEPTION_SYSCALL, &old );
|
rtems_interrupt_catch( (rtems_isr_entry) handle_exception, MIPS_EXCEPTION_SYSCALL, &old );
|
||||||
/* rtems_interrupt_catch( handle_exception, MIPS_EXCEPTION_BREAK, &old ); */
|
/* rtems_interrupt_catch( handle_exception, MIPS_EXCEPTION_BREAK, &old ); */
|
||||||
|
|
||||||
|
initialized = 1;
|
||||||
/* get the attention of gdb */
|
/* get the attention of gdb */
|
||||||
mips_break();
|
mips_break(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1299
c/src/lib/libbsp/mips/shared/gdbstub/rtems-stub-glue.c
Normal file
1299
c/src/lib/libbsp/mips/shared/gdbstub/rtems-stub-glue.c
Normal file
File diff suppressed because it is too large
Load Diff
1299
c/src/lib/libbsp/shared/gdbstub/rtems-stub-glue.c
Normal file
1299
c/src/lib/libbsp/shared/gdbstub/rtems-stub-glue.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user