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>
|
||||
|
||||
* mips-stub.c (handle_exception): Prototype changed to be an RTEMS
|
||||
|
||||
@@ -17,6 +17,61 @@
|
||||
#ifndef _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.
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define GDB_STUB_ENABLE_THREAD_SUPPORT 1
|
||||
/*******************************************************************************
|
||||
|
||||
THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
@@ -126,6 +127,12 @@
|
||||
#include <rtems.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 */
|
||||
#define EXC_INT 0 /* External interrupt */
|
||||
@@ -184,13 +191,18 @@
|
||||
*/
|
||||
#if (__mips == 3)
|
||||
typedef long long mips_register_t;
|
||||
#define R_SZ 8
|
||||
#elif (__mips == 1)
|
||||
typedef unsigned int mips_register_t;
|
||||
#define R_SZ 4
|
||||
#else
|
||||
#error "unknown MIPS ISA"
|
||||
#endif
|
||||
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.
|
||||
@@ -210,14 +222,31 @@ extern void putDebugChar (char);
|
||||
static char inBuffer[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.
|
||||
*/
|
||||
static const char hexchars[] = "0123456789abcdef";
|
||||
const char gdb_hexchars[] = "0123456789abcdef";
|
||||
|
||||
#define highhex(x) hexchars [(x >> 4) & 0xf]
|
||||
#define lowhex(x) hexchars [x & 0xf]
|
||||
#define highhex(x) gdb_hexchars [(x >> 4) & 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.
|
||||
*/
|
||||
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 */
|
||||
{
|
||||
long long *source = (long long *) (addr);
|
||||
@@ -238,7 +269,7 @@ mem2hex (int addr, int length, char *buf)
|
||||
long long k = *source++;
|
||||
|
||||
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 */
|
||||
@@ -252,7 +283,7 @@ mem2hex (int addr, int length, char *buf)
|
||||
int k = *source++;
|
||||
|
||||
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 */
|
||||
@@ -266,7 +297,7 @@ mem2hex (int addr, int length, char *buf)
|
||||
short k = *source++;
|
||||
|
||||
for (i = 3; i >= 0; i--)
|
||||
*buf++ = hexchars [(k >> (i*4)) & 0xf];
|
||||
*buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
|
||||
}
|
||||
}
|
||||
else /* byte aligned */
|
||||
@@ -280,7 +311,7 @@ mem2hex (int addr, int length, char *buf)
|
||||
char k = *source++;
|
||||
|
||||
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.
|
||||
*/
|
||||
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 */
|
||||
{
|
||||
long long *target = (long long *) (addr);
|
||||
@@ -450,6 +482,45 @@ hex2mem (char *buf, int addr, int length)
|
||||
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>.
|
||||
@@ -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:
|
||||
* it figures out why it was activated and tells gdb, and then it
|
||||
* reacts to gdb's requests.
|
||||
*/
|
||||
|
||||
CPU_Interrupt_frame current_thread_registers;
|
||||
|
||||
void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
||||
{
|
||||
int host_has_detached = 0;
|
||||
int sigval;
|
||||
int regno, addr, length;
|
||||
long long regval;
|
||||
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;
|
||||
|
||||
/* reply to host that an exception has occurred */
|
||||
sigval = computeSignal ();
|
||||
outBuffer[0] = 'S';
|
||||
outBuffer[1] = highhex (sigval);
|
||||
outBuffer[2] = lowhex (sigval);
|
||||
outBuffer[3] = '\0';
|
||||
thread = 0;
|
||||
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||
if (do_threads) {
|
||||
thread = rtems_gdb_stub_get_current_thread();
|
||||
}
|
||||
#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
|
||||
@@ -804,32 +933,43 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
||||
*/
|
||||
undoSStep ();
|
||||
|
||||
while (!(host_has_detached))
|
||||
{
|
||||
while (!(host_has_detached)) {
|
||||
outBuffer[0] = '\0';
|
||||
getpacket (inBuffer);
|
||||
binary = 0;
|
||||
|
||||
switch (inBuffer[0])
|
||||
{
|
||||
switch (inBuffer[0]) {
|
||||
case '?':
|
||||
outBuffer[0] = 'S';
|
||||
outBuffer[1] = highhex (sigval);
|
||||
outBuffer[2] = lowhex (sigval);
|
||||
outBuffer[3] = '\0';
|
||||
gdb_stub_report_exception_info(vector, frame, thread);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
/* toggle debug flag */
|
||||
case 'd': /* toggle debug flag */
|
||||
/* can print ill-formed commands in valid packets & checksum errors */
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
/* return the values of the CPU registers */
|
||||
mem2hex ((int) registers, sizeof registers, outBuffer);
|
||||
case 'D':
|
||||
/* remote system is detaching - return OK and exit from debugger */
|
||||
strcpy (outBuffer, "OK");
|
||||
host_has_detached = 1;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
/* set the values of the CPU registers - return OK */
|
||||
if (hex2mem (&inBuffer[1], (int) registers, sizeof registers))
|
||||
case 'g': /* return the values of the CPU registers */
|
||||
regptr = 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");
|
||||
else
|
||||
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)
|
||||
&& is_readable (addr, length)
|
||||
&& (length < (BUFMAX - 4)/2))
|
||||
mem2hex (addr, length, outBuffer);
|
||||
mem2hex ((void *)addr, length, outBuffer);
|
||||
else
|
||||
strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
|
||||
break;
|
||||
|
||||
case 'X': /* XAA..AA,LLLL:<binary data>#cs */
|
||||
binary = 1;
|
||||
case 'M':
|
||||
/* MAA..AA,LLLL: Write LLLL bytes at address AA..AA - return OK */
|
||||
ptr = &inBuffer[1];
|
||||
@@ -869,9 +1011,13 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
||||
&& *ptr++ == ','
|
||||
&& hexToInt (&ptr, &length)
|
||||
&& *ptr++ == ':'
|
||||
&& is_writeable (addr, length)
|
||||
&& hex2mem (ptr, addr, length))
|
||||
strcpy (outBuffer, "OK");
|
||||
&& is_writeable (addr, length) ) {
|
||||
if ( binary )
|
||||
hex2mem (ptr, (void *)addr, length);
|
||||
else
|
||||
bin2mem (ptr, (void *)addr, length);
|
||||
strcpy (outBuffer, "OK");
|
||||
}
|
||||
else
|
||||
strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
|
||||
break;
|
||||
@@ -891,16 +1037,256 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
||||
}
|
||||
return;
|
||||
|
||||
case 'D':
|
||||
/* remote system is detaching - return OK and exit from debugger */
|
||||
strcpy (outBuffer, "OK");
|
||||
host_has_detached = 1;
|
||||
case 'k': /* remove all zbreaks if any */
|
||||
{
|
||||
int ret;
|
||||
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;
|
||||
|
||||
default:
|
||||
/* do nothing */
|
||||
case 'q': /* queries */
|
||||
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||
rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
|
||||
#endif
|
||||
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 */
|
||||
putpacket (outBuffer);
|
||||
@@ -919,13 +1305,33 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
||||
return;
|
||||
}
|
||||
|
||||
static char initialized; /* 0 means we are not initialized */
|
||||
|
||||
void mips_gdb_stub_install(void)
|
||||
{
|
||||
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( handle_exception, MIPS_EXCEPTION_BREAK, &old ); */
|
||||
|
||||
initialized = 1;
|
||||
/* 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