forked from Imagelibrary/rtems
2001-03-05 Greg Menke <gregory.menke@gsfc.nasa.gov>
* mips-stub.c: Debugged & tweaked the gdb command processing, zbreak stuff, breakpoint and step code. Implemented 'T' command support and debugged remote gdb support w/ the Mongoose bsp. Added the memory segment support. * memlimits.h: Disabled all contents in favor of memory sement support. This file could probably go away. * rtems-stub-glue.c (rtems_gdb_index_to_stub_id()): New routine. rtems_gdb_stub_get_register_from_context(): Implemented MIPS version. rtems_gdb_stub_get_offsets(): Implemented MIPS version. * README: Updated.
This commit is contained in:
@@ -1,3 +1,16 @@
|
|||||||
|
2001-03-05 Greg Menke <gregory.menke@gsfc.nasa.gov>
|
||||||
|
|
||||||
|
* mips-stub.c: Debugged & tweaked the gdb command processing,
|
||||||
|
zbreak stuff, breakpoint and step code. Implemented 'T' command
|
||||||
|
support and debugged remote gdb support w/ the Mongoose bsp.
|
||||||
|
Added the memory segment support.
|
||||||
|
* memlimits.h: Disabled all contents in favor of memory sement
|
||||||
|
support. This file could probably go away.
|
||||||
|
* rtems-stub-glue.c (rtems_gdb_index_to_stub_id()): New routine.
|
||||||
|
rtems_gdb_stub_get_register_from_context(): Implemented MIPS version.
|
||||||
|
rtems_gdb_stub_get_offsets(): Implemented MIPS version.
|
||||||
|
* README: Updated.
|
||||||
|
|
||||||
2001-03-01 Joel Sherrill <joel@OARcorp.com>
|
2001-03-01 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
* ChangeLog: Corrected previous entry.
|
* ChangeLog: Corrected previous entry.
|
||||||
|
|||||||
@@ -2,6 +2,29 @@
|
|||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
|
|
||||||
|
/*****************************************************/
|
||||||
|
|
||||||
|
Debugged this stub against the MongooseV bsp. Relies on putting break
|
||||||
|
instructions on breakpoints and step targets- normal stuff, and does not
|
||||||
|
employ hardware breakpoint support at this time. As written, a single
|
||||||
|
breakpoint in a loop will not be reasserted unless the user steps or has
|
||||||
|
a 2nd one, since breakpoints are only reset when the gdb stub is
|
||||||
|
re-entered. A useful enhancement would be to fix the break instruction
|
||||||
|
management so the stub could invisibly put a 2nd break after the 1st
|
||||||
|
"official" one so it can silently reset breakpoints. Shouldn't be too
|
||||||
|
hard, mostly a matter of working it out.
|
||||||
|
|
||||||
|
This was tested only against an R3000 MIPS. It should work OK on a
|
||||||
|
R4000. Needs to be tested at some point.
|
||||||
|
|
||||||
|
This stub supports threads as implemented by gdb 5 and doesn't have any
|
||||||
|
bugs I'm aware of.
|
||||||
|
|
||||||
|
Greg Menke
|
||||||
|
3/5/2002
|
||||||
|
|
||||||
|
/*****************************************************/
|
||||||
|
|
||||||
|
|
||||||
The contents of this directory are based upon the "r46kstub.tar.gz" package
|
The contents of this directory are based upon the "r46kstub.tar.gz" package
|
||||||
released to the net by
|
released to the net by
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const char* vhstr2int(const char *buf, int *ival);
|
|||||||
int hstr2byte(const char *buf, int *bval);
|
int hstr2byte(const char *buf, int *bval);
|
||||||
int hstr2nibble(const char *buf, int *nibble);
|
int hstr2nibble(const char *buf, int *nibble);
|
||||||
|
|
||||||
|
Thread_Control *rtems_gdb_index_to_stub_id(int);
|
||||||
int rtems_gdb_stub_thread_support_ok(void);
|
int rtems_gdb_stub_thread_support_ok(void);
|
||||||
int rtems_gdb_stub_get_current_thread(void);
|
int rtems_gdb_stub_get_current_thread(void);
|
||||||
int rtems_gdb_stub_get_next_thread(int);
|
int rtems_gdb_stub_get_next_thread(int);
|
||||||
@@ -159,4 +160,21 @@ void rtems_gdb_process_query(
|
|||||||
|
|
||||||
#define NUM_REGS 72
|
#define NUM_REGS 72
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mips_gdb_stub_install(int enableThreads) ;
|
||||||
|
|
||||||
|
|
||||||
|
#define MEMOPT_READABLE 1
|
||||||
|
#define MEMOPT_WRITEABLE 2
|
||||||
|
|
||||||
|
#define NUM_MEMSEGS 10
|
||||||
|
|
||||||
|
int gdbstub_add_memsegment(unsigned,unsigned,int);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _GDB_IF_H */
|
#endif /* _GDB_IF_H */
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LIMITS_H_
|
#ifndef _MEMLIMITS_H_
|
||||||
#define _LIMITS_H_
|
#define _MEMLIMITS_H_
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The macros in this file are specific to a given implementation.
|
* The macros in this file are specific to a given implementation.
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
* to have different readability and/or writeability attributes.
|
* to have different readability and/or writeability attributes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
#define K0_LIMIT_FOR_READ (K0BASE+0x18000000)
|
#define K0_LIMIT_FOR_READ (K0BASE+0x18000000)
|
||||||
#define K1_LIMIT_FOR_READ (K1BASE+K1SIZE)
|
#define K1_LIMIT_FOR_READ (K1BASE+K1SIZE)
|
||||||
|
|
||||||
@@ -67,4 +68,21 @@
|
|||||||
&& (((K0BASE <= (int)ptr) && ((int)ptr < K0_LIMIT_FOR_STEP)) \
|
&& (((K0BASE <= (int)ptr) && ((int)ptr < K0_LIMIT_FOR_STEP)) \
|
||||||
|| ((K1BASE <= (int)ptr) && ((int)ptr < K1_LIMIT_FOR_STEP))))
|
|| ((K1BASE <= (int)ptr) && ((int)ptr < K1_LIMIT_FOR_STEP))))
|
||||||
|
|
||||||
#endif /* _LIMITS_H_ */
|
struct memseg
|
||||||
|
{
|
||||||
|
unsigned begin, end, opts;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MEMOPT_READABLE 1
|
||||||
|
#define MEMOPT_WRITEABLE 2
|
||||||
|
|
||||||
|
#define NUM_MEMSEGS 10
|
||||||
|
|
||||||
|
|
||||||
|
int add_memsegment(unsigned,unsigned,int);
|
||||||
|
int is_readable(unsigned,unsigned);
|
||||||
|
int is_writeable(unsigned,unsigned);
|
||||||
|
int is_steppable(unsigned);
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* _MEMLIMITS_H_ */
|
||||||
|
|||||||
@@ -123,7 +123,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "mips_opcode.h"
|
#include "mips_opcode.h"
|
||||||
#include "memlimits.h"
|
/* #include "memlimits.h" */
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
|
|
||||||
@@ -208,10 +208,27 @@ static char do_threads; /* != 0 means we are supporting threads */
|
|||||||
* The following external functions provide character input and output.
|
* The following external functions provide character input and output.
|
||||||
*/
|
*/
|
||||||
extern char getDebugChar (void);
|
extern char getDebugChar (void);
|
||||||
|
|
||||||
extern void putDebugChar (char);
|
extern void putDebugChar (char);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following definitions are used for the gdb stub memory map
|
||||||
|
*/
|
||||||
|
struct memseg
|
||||||
|
{
|
||||||
|
unsigned begin, end, opts;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int is_readable(unsigned,unsigned);
|
||||||
|
static int is_writeable(unsigned,unsigned);
|
||||||
|
static int is_steppable(unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BUFMAX defines the maximum number of characters in the inbound & outbound
|
* BUFMAX defines the maximum number of characters in the inbound & outbound
|
||||||
* packet buffers. At least 4+(sizeof registers)*2 bytes will be needed for
|
* packet buffers. At least 4+(sizeof registers)*2 bytes will be needed for
|
||||||
@@ -224,6 +241,7 @@ static char outBuffer[BUFMAX];
|
|||||||
|
|
||||||
/* Structure to keep info on a z-breaks */
|
/* Structure to keep info on a z-breaks */
|
||||||
#define BREAKNUM 32
|
#define BREAKNUM 32
|
||||||
|
|
||||||
struct z0break
|
struct z0break
|
||||||
{
|
{
|
||||||
/* List support */
|
/* List support */
|
||||||
@@ -231,8 +249,8 @@ struct z0break
|
|||||||
struct z0break *prev;
|
struct z0break *prev;
|
||||||
|
|
||||||
/* Location, preserved data */
|
/* Location, preserved data */
|
||||||
unsigned char *address;
|
unsigned *address;
|
||||||
char buf[2];
|
unsigned instr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct z0break z0break_arr[BREAKNUM];
|
static struct z0break z0break_arr[BREAKNUM];
|
||||||
@@ -623,6 +641,11 @@ putpacket (char *buffer)
|
|||||||
while (getDebugChar () != '+');
|
while (getDebugChar () != '+');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Saved instruction data for single step support
|
* Saved instruction data for single step support
|
||||||
@@ -663,6 +686,7 @@ undoSStep (void)
|
|||||||
static void
|
static void
|
||||||
doSStep (void)
|
doSStep (void)
|
||||||
{
|
{
|
||||||
|
struct z0break *z0;
|
||||||
InstFmt inst;
|
InstFmt inst;
|
||||||
|
|
||||||
instrBuffer.targetAddr = (unsigned *)(registers[PC]+4); /* set default */
|
instrBuffer.targetAddr = (unsigned *)(registers[PC]+4); /* set default */
|
||||||
@@ -771,7 +795,8 @@ doSStep (void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_steppable (instrBuffer.targetAddr)
|
|
||||||
|
if( is_steppable((unsigned)instrBuffer.targetAddr) && *(instrBuffer.targetAddr) != BREAK_INSTR )
|
||||||
{
|
{
|
||||||
instrBuffer.savedInstr = *instrBuffer.targetAddr;
|
instrBuffer.savedInstr = *instrBuffer.targetAddr;
|
||||||
*instrBuffer.targetAddr = BREAK_INSTR;
|
*instrBuffer.targetAddr = BREAK_INSTR;
|
||||||
@@ -784,6 +809,10 @@ doSStep (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Translate the R4600 exception code into a Unix-compatible signal.
|
* Translate the R4600 exception code into a Unix-compatible signal.
|
||||||
@@ -864,18 +893,21 @@ void gdb_stub_report_exception_info(
|
|||||||
*optr++ = highhex (sigval);
|
*optr++ = highhex (sigval);
|
||||||
*optr++ = lowhex (sigval);
|
*optr++ = lowhex (sigval);
|
||||||
|
|
||||||
*optr++ = gdb_hexchars[SP];
|
*optr++ = highhex(SP); /*gdb_hexchars[SP]; */
|
||||||
|
*optr++ = lowhex(SP);
|
||||||
*optr++ = ':';
|
*optr++ = ':';
|
||||||
optr = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
|
optr = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
|
||||||
*optr++ = ';';
|
*optr++ = ';';
|
||||||
|
|
||||||
*optr++ = gdb_hexchars[PC];
|
*optr++ = highhex(PC); /*gdb_hexchars[PC]; */
|
||||||
|
*optr++ = lowhex(PC);
|
||||||
*optr++ = ':';
|
*optr++ = ':';
|
||||||
optr = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
|
optr = mem2hstr(optr, (unsigned char *)&frame->epc, R_SZ );
|
||||||
*optr++ = ';';
|
*optr++ = ';';
|
||||||
|
|
||||||
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
if (do_threads) {
|
if (do_threads)
|
||||||
|
{
|
||||||
*optr++ = 't';
|
*optr++ = 't';
|
||||||
*optr++ = 'h';
|
*optr++ = 'h';
|
||||||
*optr++ = 'r';
|
*optr++ = 'r';
|
||||||
@@ -887,32 +919,40 @@ void gdb_stub_report_exception_info(
|
|||||||
*optr++ = ';';
|
*optr++ = ';';
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
putpacket (outBuffer);
|
|
||||||
|
|
||||||
*optr++ = '\0';
|
*optr++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scratch frame used to retrieve contexts for different threads, so as
|
||||||
|
* not to disrupt our current context on the stack
|
||||||
|
*/
|
||||||
|
CPU_Interrupt_frame current_thread_registers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 regno, addr, length;
|
int regno, addr, length;
|
||||||
long long regval;
|
|
||||||
char *ptr;
|
char *ptr;
|
||||||
int current_thread; /* current generic thread */
|
int current_thread; /* current generic thread */
|
||||||
int thread; /* stopped thread: context exception happened in */
|
int thread; /* stopped thread: context exception happened in */
|
||||||
|
|
||||||
|
long long regval;
|
||||||
void *regptr;
|
void *regptr;
|
||||||
int binary;
|
int binary;
|
||||||
|
|
||||||
|
|
||||||
registers = (mips_register_t *)frame;
|
registers = (mips_register_t *)frame;
|
||||||
|
|
||||||
thread = 0;
|
thread = 0;
|
||||||
@@ -923,15 +963,69 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
#endif
|
#endif
|
||||||
current_thread = thread;
|
current_thread = thread;
|
||||||
|
|
||||||
/* reply to host that an exception has occurred with some basic info */
|
|
||||||
gdb_stub_report_exception_info(vector, frame, thread);
|
|
||||||
|
|
||||||
|
{
|
||||||
|
/* reapply all breakpoints regardless of how we came in */
|
||||||
|
struct z0break *z0, *zother;
|
||||||
|
|
||||||
|
for (zother=z0break_list; zother!=NULL; zother=zother->next)
|
||||||
|
{
|
||||||
|
if( zother->instr == 0xffffffff )
|
||||||
|
{
|
||||||
|
/* grab the instruction */
|
||||||
|
zother->instr = *(zother->address);
|
||||||
|
/* and insert the breakpoint */
|
||||||
|
*(zother->address) = BREAK_INSTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* see if we're coming from a breakpoint */
|
||||||
|
if( *((unsigned *)frame->epc) == BREAK_INSTR )
|
||||||
|
{
|
||||||
|
/* see if its one of our zbreaks */
|
||||||
|
for (z0=z0break_list; z0!=NULL; z0=z0->next)
|
||||||
|
{
|
||||||
|
if( (unsigned)z0->address == frame->epc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( z0 )
|
||||||
|
{
|
||||||
|
/* restore the original instruction */
|
||||||
|
*(z0->address) = z0->instr;
|
||||||
|
/* flag the breakpoint */
|
||||||
|
z0->instr = 0xffffffff;
|
||||||
|
|
||||||
|
/*
|
||||||
|
now when we return, we'll execute the original code in
|
||||||
|
the original state. This leaves our breakpoint inactive
|
||||||
|
since the break instruction isn't there, but we'll reapply
|
||||||
|
it the next time we come in via step or breakpoint
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* not a zbreak, see if its our trusty stepping code */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore the saved instruction at
|
* Restore the saved instruction at
|
||||||
* the single-step target address.
|
* the single-step target address.
|
||||||
*/
|
*/
|
||||||
undoSStep();
|
undoSStep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* reply to host that an exception has occurred with some basic info */
|
||||||
|
gdb_stub_report_exception_info(vector, frame, thread);
|
||||||
|
putpacket (outBuffer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while (!(host_has_detached)) {
|
while (!(host_has_detached)) {
|
||||||
outBuffer[0] = '\0';
|
outBuffer[0] = '\0';
|
||||||
@@ -960,9 +1054,9 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
regptr = ¤t_thread_registers;
|
regptr = ¤t_thread_registers;
|
||||||
#endif
|
#endif
|
||||||
mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer);
|
mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 'G': /* set the values of the CPU registers - return OK */
|
case 'G': /* set the values of the CPU registers - return OK */
|
||||||
regptr = registers;
|
regptr = registers;
|
||||||
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
@@ -975,6 +1069,7 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
|
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
/* Pn...=r... Write register n... with value r... - return OK */
|
/* Pn...=r... Write register n... with value r... - return OK */
|
||||||
ptr = &inBuffer[1];
|
ptr = &inBuffer[1];
|
||||||
@@ -989,6 +1084,7 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
|
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
||||||
ptr = &inBuffer[1];
|
ptr = &inBuffer[1];
|
||||||
@@ -1002,6 +1098,7 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
|
strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 'X': /* XAA..AA,LLLL:<binary data>#cs */
|
case 'X': /* XAA..AA,LLLL:<binary data>#cs */
|
||||||
binary = 1;
|
binary = 1;
|
||||||
case 'M':
|
case 'M':
|
||||||
@@ -1022,6 +1119,8 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
|
strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
/* cAA..AA Continue at address AA..AA(optional) */
|
/* cAA..AA Continue at address AA..AA(optional) */
|
||||||
case 's':
|
case 's':
|
||||||
@@ -1035,40 +1134,75 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
if (inBuffer[0] == 's')
|
if (inBuffer[0] == 's')
|
||||||
doSStep ();
|
doSStep ();
|
||||||
}
|
}
|
||||||
return;
|
goto stubexit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'k': /* remove all zbreaks if any */
|
case 'k': /* remove all zbreaks if any */
|
||||||
|
dumpzbreaks:
|
||||||
{
|
{
|
||||||
int ret;
|
{
|
||||||
struct z0break *z0, *z0last;
|
/* Unlink the entire list */
|
||||||
|
struct z0break *z0, *znxt;
|
||||||
|
|
||||||
ret = 1;
|
while( (z0= z0break_list) )
|
||||||
z0last = NULL;
|
{
|
||||||
|
|
||||||
for (z0=z0break_list; z0!=NULL; z0=z0->next) {
|
/* put back the instruction */
|
||||||
if (!hstr2mem(z0->address, z0->buf, 1)) {
|
if( z0->instr != 0xffffffff )
|
||||||
ret = 0;
|
*(z0->address) = z0->instr;
|
||||||
}
|
|
||||||
|
|
||||||
z0last = z0;
|
/* pop off the top entry */
|
||||||
}
|
znxt = z0->next;
|
||||||
|
if( znxt ) znxt->prev = NULL;
|
||||||
|
z0break_list = znxt;
|
||||||
|
|
||||||
/* Free entries if any */
|
/* and put it on the free list */
|
||||||
if (z0last != NULL) {
|
z0->prev = NULL;
|
||||||
z0last->next = z0break_avail;
|
z0->next = z0break_avail;
|
||||||
z0break_avail = z0break_list;
|
z0break_avail = z0;
|
||||||
z0break_list = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'q': /* queries */
|
case 'q': /* queries */
|
||||||
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
|
rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
|
case 'T':
|
||||||
|
{
|
||||||
|
int testThread;
|
||||||
|
|
||||||
|
if( vhstr2thread(&inBuffer[1], &testThread) == NULL )
|
||||||
|
{
|
||||||
|
strcpy(outBuffer, "E01");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rtems_gdb_index_to_stub_id(testThread) == NULL )
|
||||||
|
{
|
||||||
|
strcpy(outBuffer, "E02");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 'H': /* set new thread */
|
case 'H': /* set new thread */
|
||||||
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
if (inBuffer[1] != 'g') {
|
if (inBuffer[1] != 'g') {
|
||||||
@@ -1121,14 +1255,143 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
current_thread = tmp;
|
current_thread = tmp;
|
||||||
strcpy(outBuffer, "OK");
|
strcpy(outBuffer, "OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'Z': /* Add breakpoint */
|
case 'Z': /* Add breakpoint */
|
||||||
{
|
{
|
||||||
int ret, type, len;
|
int ret, type, len;
|
||||||
unsigned char *address;
|
unsigned *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 */
|
||||||
|
strcpy(outBuffer, "E02");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != R_SZ) { /* was 1 */
|
||||||
|
strcpy(outBuffer, "E03");
|
||||||
|
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) {
|
||||||
|
/* we already have a breakpoint for this address */
|
||||||
|
strcpy(outBuffer, "E04");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let us allocate new break point */
|
||||||
|
if (z0break_avail == NULL) {
|
||||||
|
strcpy(outBuffer, "E05");
|
||||||
|
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, "E05");
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* Fill it */
|
||||||
|
z0->address = address;
|
||||||
|
|
||||||
|
if( z0->address == frame->epc )
|
||||||
|
{
|
||||||
|
/* re-asserting the breakpoint that put us in here, so
|
||||||
|
we'll add the breakpoint but leave the code in place
|
||||||
|
since we'll be returning to it when the user continues */
|
||||||
|
z0->instr = 0xffffffff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* grab the instruction */
|
||||||
|
z0->instr = *(z0->address);
|
||||||
|
/* and insert the break */
|
||||||
|
*(z0->address) = BREAK_INSTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add to the list */
|
||||||
|
{
|
||||||
|
struct z0break *znxt = z0break_list;
|
||||||
|
|
||||||
|
z0->prev = NULL;
|
||||||
|
z0->next = znxt;
|
||||||
|
|
||||||
|
if( znxt ) znxt->prev = z0;
|
||||||
|
z0break_list = z0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(outBuffer, "OK");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'z': /* remove breakpoint */
|
||||||
|
if (inBuffer[1] == 'z')
|
||||||
|
{
|
||||||
|
goto dumpzbreaks;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* zz packet - remove all breaks *
|
||||||
|
z0last = NULL;
|
||||||
|
|
||||||
|
for (z0=z0break_list; z0!=NULL; z0=z0->next)
|
||||||
|
{
|
||||||
|
if(!hstr2mem(z0->address, z0->buf, R_SZ))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int ret, type, len;
|
||||||
|
unsigned *address;
|
||||||
struct z0break *z0;
|
struct z0break *z0;
|
||||||
|
|
||||||
ret = parse_zbreak(inBuffer, &type, &address, &len);
|
ret = parse_zbreak(inBuffer, &type, &address, &len);
|
||||||
@@ -1142,106 +1405,7 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len != 1) {
|
if (len != R_SZ) {
|
||||||
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");
|
strcpy(outBuffer, "E02");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1259,31 +1423,39 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hstr2mem(z0->address, z0->buf, 1)) {
|
/*
|
||||||
|
if (!hstr2mem(z0->address, z0->buf, R_SZ)) {
|
||||||
strcpy(outBuffer, "E04");
|
strcpy(outBuffer, "E04");
|
||||||
break;
|
break;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if( z0->instr != 0xffffffff )
|
||||||
|
{
|
||||||
|
/* put the old instruction back */
|
||||||
|
*(z0->address) = z0->instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlink entry */
|
/* Unlink entry */
|
||||||
if (z0->prev == NULL) {
|
{
|
||||||
z0break_list = z0->next;
|
struct z0break *zprv = z0->prev, *znxt = z0->next;
|
||||||
if (z0break_list != NULL) {
|
|
||||||
z0break_list->prev = NULL;
|
if( zprv ) zprv->next = znxt;
|
||||||
}
|
if( znxt ) znxt->prev = zprv;
|
||||||
} else if (z0->next == NULL) {
|
|
||||||
z0->prev->next = NULL;
|
if( !zprv ) z0break_list = znxt;
|
||||||
} else {
|
|
||||||
z0->prev->next = z0->next;
|
znxt = z0break_avail;
|
||||||
z0->next->prev = z0->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
z0->next = z0break_avail;
|
|
||||||
z0break_avail = z0;
|
z0break_avail = z0;
|
||||||
|
z0->prev = NULL;
|
||||||
|
z0->next = znxt;
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(outBuffer, "OK");
|
strcpy(outBuffer, "OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
default: /* do nothing */
|
default: /* do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1292,6 +1464,8 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
putpacket (outBuffer);
|
putpacket (outBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stubexit:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The original code did this in the assembly wrapper. We should consider
|
* The original code did this in the assembly wrapper. We should consider
|
||||||
* doing it here before we return.
|
* doing it here before we return.
|
||||||
@@ -1299,15 +1473,115 @@ void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
|
|||||||
* On exit from the exception handler invalidate each line in the I-cache
|
* On exit from the exception handler invalidate each line in the I-cache
|
||||||
* and write back each dirty line in the D-cache. This needs to be done
|
* and write back each dirty line in the D-cache. This needs to be done
|
||||||
* before the target program is resumed in order to ensure that software
|
* before the target program is resumed in order to ensure that software
|
||||||
* breakpoints and downloaded code will actually take effect.
|
* breakpoints and downloaded code will actually take effect. This
|
||||||
|
* is because modifications to code in ram will affect the D-cache,
|
||||||
|
* but not necessarily the I-cache.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
extern void clear_cache();
|
||||||
|
clear_cache();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char initialized; /* 0 means we are not initialized */
|
|
||||||
|
|
||||||
void mips_gdb_stub_install(void)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int numsegs;
|
||||||
|
static struct memseg memsegments[NUM_MEMSEGS];
|
||||||
|
|
||||||
|
int gdbstub_add_memsegment( unsigned base, unsigned end, int opts )
|
||||||
|
{
|
||||||
|
if( numsegs == NUM_MEMSEGS ) return -1;
|
||||||
|
|
||||||
|
memsegments[numsegs].begin = base;
|
||||||
|
memsegments[numsegs].end = end;
|
||||||
|
memsegments[numsegs].opts = opts;
|
||||||
|
|
||||||
|
++numsegs;
|
||||||
|
return RTEMS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int is_readable(unsigned ptr, unsigned len)
|
||||||
|
{
|
||||||
|
struct memseg *ms;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( (ptr & 0x3) ) return -1;
|
||||||
|
|
||||||
|
for(i=0; i<numsegs; i++)
|
||||||
|
{
|
||||||
|
ms= &memsegments[i];
|
||||||
|
|
||||||
|
if( ms->begin <= ptr && ptr+len <= ms->end && (ms->opts & MEMOPT_READABLE) )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int is_writeable(unsigned ptr, unsigned len)
|
||||||
|
{
|
||||||
|
struct memseg *ms;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( (ptr & 0x3) ) return -1;
|
||||||
|
|
||||||
|
for(i=0; i<numsegs; i++)
|
||||||
|
{
|
||||||
|
ms= &memsegments[i];
|
||||||
|
|
||||||
|
if( ms->begin <= ptr && ptr+len <= ms->end && (ms->opts & MEMOPT_WRITEABLE) )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int is_steppable(unsigned ptr)
|
||||||
|
{
|
||||||
|
struct memseg *ms;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( (ptr & 0x3) ) return -1;
|
||||||
|
|
||||||
|
for(i=0; i<numsegs; i++)
|
||||||
|
{
|
||||||
|
ms= &memsegments[i];
|
||||||
|
|
||||||
|
if( ms->begin <= ptr && ptr <= ms->end && (ms->opts & MEMOPT_WRITEABLE) )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char initialized = 0; /* 0 means we are not initialized */
|
||||||
|
|
||||||
|
void mips_gdb_stub_install(int enableThreads)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
These are the RTEMS-defined vectors for all the MIPS exceptions
|
These are the RTEMS-defined vectors for all the MIPS exceptions
|
||||||
@@ -1334,20 +1608,37 @@ void mips_gdb_stub_install(void)
|
|||||||
int i;
|
int i;
|
||||||
rtems_isr_entry old;
|
rtems_isr_entry old;
|
||||||
|
|
||||||
if (initialized) {
|
if (initialized)
|
||||||
|
{
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* z0breaks */
|
memset( memsegments,0,sizeof(struct memseg)*NUM_MEMSEGS );
|
||||||
for (i=0; i<(sizeof(z0break_arr)/sizeof(z0break_arr[0]))-1; i++) {
|
numsegs = 0;
|
||||||
z0break_arr[i].next = &z0break_arr[i+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
z0break_arr[i].next = NULL;
|
#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
|
||||||
z0break_avail = &z0break_arr[0];
|
if( enableThreads )
|
||||||
|
do_threads = 1;
|
||||||
|
else
|
||||||
|
do_threads = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
struct z0break *z0;
|
||||||
|
|
||||||
|
z0break_avail = NULL;
|
||||||
z0break_list = NULL;
|
z0break_list = NULL;
|
||||||
|
|
||||||
|
/* z0breaks list init, now we'll do it so it makes sense... */
|
||||||
|
for (i=0; i<BREAKNUM; i++)
|
||||||
|
{
|
||||||
|
memset( (z0= &z0break_arr[i]), 0, sizeof(struct z0break));
|
||||||
|
|
||||||
|
z0->next = z0break_avail;
|
||||||
|
z0break_avail = z0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(i=0; exceptionVector[i] > -1; i++)
|
for(i=0; exceptionVector[i] > -1; i++)
|
||||||
{
|
{
|
||||||
@@ -1355,8 +1646,9 @@ void mips_gdb_stub_install(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
|
||||||
/* get the attention of gdb */
|
/* get the attention of gdb */
|
||||||
mips_break(1);
|
/* mips_break(1); disabled so user code can choose to invoke it or not */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
@@ -40,6 +39,7 @@
|
|||||||
|
|
||||||
extern const char gdb_hexchars[];
|
extern const char gdb_hexchars[];
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes for CPU dependent routines that are conditional
|
* Prototypes for CPU dependent routines that are conditional
|
||||||
* at the bottom of this file.
|
* at the bottom of this file.
|
||||||
@@ -50,6 +50,12 @@ void rtems_gdb_stub_get_registers_from_context(
|
|||||||
Thread_Control *th
|
Thread_Control *th
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether it is OK to enable thread support */
|
/* Check whether it is OK to enable thread support */
|
||||||
int rtems_gdb_stub_thread_support_ok(void)
|
int rtems_gdb_stub_thread_support_ok(void)
|
||||||
{
|
{
|
||||||
@@ -59,6 +65,10 @@ int rtems_gdb_stub_thread_support_ok(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rtems_gdb_stub_id_to_index
|
* rtems_gdb_stub_id_to_index
|
||||||
*
|
*
|
||||||
@@ -101,12 +111,84 @@ int rtems_gdb_stub_id_to_index(
|
|||||||
return first_posix_id + (thread_obj_id - min_id);
|
return first_posix_id + (thread_obj_id - min_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the RTEMS thread id from a gdb thread id */
|
||||||
|
Thread_Control *rtems_gdb_index_to_stub_id(
|
||||||
|
int thread
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Objects_Id thread_obj_id;
|
||||||
|
Objects_Id min_id, max_id;
|
||||||
|
int first_posix_id, first_rtems_id;
|
||||||
|
Objects_Information *obj_info;
|
||||||
|
Thread_Control *th;
|
||||||
|
|
||||||
|
ASSERT(registers != NULL);
|
||||||
|
|
||||||
|
if (_System_state_Get() != SYSTEM_STATE_UP || thread <= 0) {
|
||||||
|
/* Should not happen */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread == 1) {
|
||||||
|
th = _Thread_Idle;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let us get object associtated with current thread */
|
||||||
|
first_rtems_id = 2;
|
||||||
|
|
||||||
|
thread_obj_id = _Thread_Executing->Object.id;
|
||||||
|
|
||||||
|
/* Let us figure out thread_id for gdb */
|
||||||
|
obj_info = _Objects_Information_table[OBJECTS_RTEMS_TASKS];
|
||||||
|
|
||||||
|
min_id = obj_info->minimum_id;
|
||||||
|
max_id = obj_info->maximum_id;
|
||||||
|
|
||||||
|
if (thread <= (first_rtems_id + (max_id - min_id))) {
|
||||||
|
th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]);
|
||||||
|
|
||||||
|
if (th != NULL) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Thread does not exist */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
first_posix_id = first_rtems_id + (max_id - min_id) + 1;
|
||||||
|
|
||||||
|
obj_info = _Objects_Information_table[OBJECTS_POSIX_THREADS];
|
||||||
|
|
||||||
|
min_id = obj_info->minimum_id;
|
||||||
|
max_id = obj_info->maximum_id;
|
||||||
|
|
||||||
|
th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
|
||||||
|
if (th == NULL) {
|
||||||
|
/* Thread does not exist */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
return th;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get id of the thread stopped by exception */
|
/* Get id of the thread stopped by exception */
|
||||||
int rtems_gdb_stub_get_current_thread(void)
|
int rtems_gdb_stub_get_current_thread(void)
|
||||||
{
|
{
|
||||||
return rtems_gdb_stub_id_to_index( _Thread_Executing->Object.id );
|
return rtems_gdb_stub_id_to_index( _Thread_Executing->Object.id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get id of the next thread after athread, if argument <= 0 find the
|
/* Get id of the next thread after athread, if argument <= 0 find the
|
||||||
first available thread, return thread if found or 0 if not */
|
first available thread, return thread if found or 0 if not */
|
||||||
int rtems_gdb_stub_get_next_thread(int athread)
|
int rtems_gdb_stub_get_next_thread(int athread)
|
||||||
@@ -176,6 +258,10 @@ int rtems_gdb_stub_get_next_thread(int athread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get thread registers, return 0 if thread does not
|
/* Get thread registers, return 0 if thread does not
|
||||||
exist, and 1 otherwise */
|
exist, and 1 otherwise */
|
||||||
int rtems_gdb_stub_get_thread_regs(
|
int rtems_gdb_stub_get_thread_regs(
|
||||||
@@ -183,70 +269,27 @@ int rtems_gdb_stub_get_thread_regs(
|
|||||||
unsigned int *registers
|
unsigned int *registers
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Objects_Id thread_obj_id;
|
|
||||||
Objects_Id min_id, max_id;
|
|
||||||
int first_posix_id, first_rtems_id;
|
|
||||||
Objects_Information *obj_info;
|
|
||||||
Thread_Control *th;
|
Thread_Control *th;
|
||||||
|
|
||||||
ASSERT(registers != NULL);
|
th= rtems_gdb_index_to_stub_id(thread);
|
||||||
|
|
||||||
if (_System_state_Get() != SYSTEM_STATE_UP || thread <= 0) {
|
|
||||||
/* Should not happen */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread == 1) {
|
|
||||||
th = _Thread_Idle;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Let us get object associtated with current thread */
|
|
||||||
first_rtems_id = 2;
|
|
||||||
|
|
||||||
thread_obj_id = _Thread_Executing->Object.id;
|
|
||||||
|
|
||||||
/* Let us figure out thread_id for gdb */
|
|
||||||
obj_info = _Objects_Information_table[OBJECTS_RTEMS_TASKS];
|
|
||||||
|
|
||||||
min_id = obj_info->minimum_id;
|
|
||||||
max_id = obj_info->maximum_id;
|
|
||||||
|
|
||||||
if (thread <= (first_rtems_id + (max_id - min_id))) {
|
|
||||||
th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]);
|
|
||||||
|
|
||||||
if (th != NULL) {
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thread does not exist */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
first_posix_id = first_rtems_id + (max_id - min_id) + 1;
|
|
||||||
|
|
||||||
obj_info = _Objects_Information_table[OBJECTS_POSIX_THREADS];
|
|
||||||
|
|
||||||
min_id = obj_info->minimum_id;
|
|
||||||
max_id = obj_info->maximum_id;
|
|
||||||
|
|
||||||
th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
|
|
||||||
if (th == NULL) {
|
|
||||||
/* Thread does not exist */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
found:
|
|
||||||
|
|
||||||
|
if( th )
|
||||||
|
{
|
||||||
rtems_gdb_stub_get_registers_from_context( registers, th );
|
rtems_gdb_stub_get_registers_from_context( registers, th );
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Set thread registers, return 0 if thread does not
|
/* Set thread registers, return 0 if thread does not
|
||||||
exist or register values will screw up the threads,
|
exist or register values will screw up the threads,
|
||||||
and 1 otherwise */
|
and 1 otherwise */
|
||||||
|
|
||||||
int rtems_gdb_stub_set_thread_regs(
|
int rtems_gdb_stub_set_thread_regs(
|
||||||
int thread,
|
int thread,
|
||||||
unsigned int *registers
|
unsigned int *registers
|
||||||
@@ -260,6 +303,10 @@ int rtems_gdb_stub_set_thread_regs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get thread information, return 0 if thread does not
|
/* Get thread information, return 0 if thread does not
|
||||||
exist and 1 otherwise */
|
exist and 1 otherwise */
|
||||||
int rtems_gdb_stub_get_thread_info(
|
int rtems_gdb_stub_get_thread_info(
|
||||||
@@ -383,6 +430,10 @@ int rtems_gdb_stub_get_thread_info(
|
|||||||
/*******************************************************/
|
/*******************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */
|
/* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */
|
||||||
int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len)
|
int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len)
|
||||||
{
|
{
|
||||||
@@ -613,11 +664,20 @@ pack_qm_header(char *out, int count, int done, int athread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread2fhstr(out, athread);
|
thread2fhstr(out, athread);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void rtems_gdb_process_query(
|
void rtems_gdb_process_query(
|
||||||
char *inbuffer,
|
char *inbuffer,
|
||||||
char *outbuffer,
|
char *outbuffer,
|
||||||
@@ -642,6 +702,9 @@ void rtems_gdb_process_query(
|
|||||||
*optr = 0;
|
*optr = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
/* Thread info query */
|
/* Thread info query */
|
||||||
if (!do_threads) {
|
if (!do_threads) {
|
||||||
@@ -669,10 +732,14 @@ void rtems_gdb_process_query(
|
|||||||
/* Build response */
|
/* Build response */
|
||||||
pack_qq(outbuffer, mask, rthread, &info);
|
pack_qq(outbuffer, mask, rthread, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
/* Thread info query */
|
/* Thread list query */
|
||||||
if (!do_threads) {
|
if (!do_threads) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -724,9 +791,14 @@ void rtems_gdb_process_query(
|
|||||||
|
|
||||||
/* Fill header */
|
/* Fill header */
|
||||||
pack_qm_header(outbuffer, i, done, athread);
|
pack_qm_header(outbuffer, i, done, athread);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (memcmp(inbuffer, "qOffsets", 8) == 0) {
|
if (memcmp(inbuffer, "qOffsets", 8) == 0) {
|
||||||
unsigned char *t, *d, *b;
|
unsigned char *t, *d, *b;
|
||||||
@@ -772,9 +844,13 @@ void rtems_gdb_process_query(
|
|||||||
/* qCRC, qRcmd, qu and qz will be added here */
|
/* qCRC, qRcmd, qu and qz will be added here */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Present thread in the variable length string format */
|
/* Present thread in the variable length string format */
|
||||||
char*
|
char*
|
||||||
thread2vhstr(char *buf, int thread)
|
thread2vhstr(char *buf, int thread)
|
||||||
@@ -1196,6 +1272,7 @@ set_mem_err (void)
|
|||||||
that the compiler won't save any registers (if there is a fault
|
that the compiler won't save any registers (if there is a fault
|
||||||
to mem_fault, they won't get restored, so there better not be any
|
to mem_fault, they won't get restored, so there better not be any
|
||||||
saved). */
|
saved). */
|
||||||
|
|
||||||
unsigned char
|
unsigned char
|
||||||
get_byte (const unsigned char *addr)
|
get_byte (const unsigned char *addr)
|
||||||
{
|
{
|
||||||
@@ -1210,6 +1287,12 @@ set_byte (unsigned char *addr, int val)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* From here down, the code is CPU model specific and generally maps
|
* From here down, the code is CPU model specific and generally maps
|
||||||
* the RTEMS thread context format to gdb's.
|
* the RTEMS thread context format to gdb's.
|
||||||
@@ -1273,24 +1356,53 @@ int rtems_gdb_stub_get_offsets(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
|
|
||||||
|
|
||||||
void rtems_gdb_stub_get_registers_from_context(
|
void rtems_gdb_stub_get_registers_from_context(
|
||||||
int *registers,
|
int *registers,
|
||||||
Thread_Control *th
|
Thread_Control *th
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
registers[S0] = (unsigned)th->Registers.s0;
|
||||||
|
registers[S1] = (unsigned)th->Registers.s1;
|
||||||
|
registers[S2] = (unsigned)th->Registers.s2;
|
||||||
|
registers[S3] = (unsigned)th->Registers.s3;
|
||||||
|
registers[S4] = (unsigned)th->Registers.s4;
|
||||||
|
registers[S5] = (unsigned)th->Registers.s5;
|
||||||
|
registers[S6] = (unsigned)th->Registers.s6;
|
||||||
|
registers[S7] = (unsigned)th->Registers.s7;
|
||||||
|
|
||||||
|
registers[SP] = (unsigned)th->Registers.sp;
|
||||||
|
registers[RA] = (unsigned)th->Registers.ra;
|
||||||
|
|
||||||
|
registers[SR] = (unsigned)th->Registers.c0_sr;
|
||||||
|
registers[PC] = (unsigned)th->Registers.c0_epc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int rtems_gdb_stub_get_offsets(
|
int rtems_gdb_stub_get_offsets(
|
||||||
unsigned char **text_addr,
|
unsigned char **text_addr,
|
||||||
unsigned char **data_addr,
|
unsigned char **data_addr,
|
||||||
unsigned char **bss_addr
|
unsigned char **bss_addr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
extern unsigned32 _ftext;
|
||||||
|
extern unsigned32 _fdata;
|
||||||
|
extern unsigned32 _bss_start;
|
||||||
|
|
||||||
|
*text_addr = &_ftext;
|
||||||
|
*data_addr = &_fdata;
|
||||||
|
*bss_addr = &_bss_start;
|
||||||
|
*/
|
||||||
*text_addr = 0;
|
*text_addr = 0;
|
||||||
*data_addr = 0;
|
*data_addr = 0;
|
||||||
*bss_addr = 0;
|
*bss_addr = 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
@@ -40,6 +39,7 @@
|
|||||||
|
|
||||||
extern const char gdb_hexchars[];
|
extern const char gdb_hexchars[];
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes for CPU dependent routines that are conditional
|
* Prototypes for CPU dependent routines that are conditional
|
||||||
* at the bottom of this file.
|
* at the bottom of this file.
|
||||||
@@ -50,6 +50,12 @@ void rtems_gdb_stub_get_registers_from_context(
|
|||||||
Thread_Control *th
|
Thread_Control *th
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether it is OK to enable thread support */
|
/* Check whether it is OK to enable thread support */
|
||||||
int rtems_gdb_stub_thread_support_ok(void)
|
int rtems_gdb_stub_thread_support_ok(void)
|
||||||
{
|
{
|
||||||
@@ -59,6 +65,10 @@ int rtems_gdb_stub_thread_support_ok(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rtems_gdb_stub_id_to_index
|
* rtems_gdb_stub_id_to_index
|
||||||
*
|
*
|
||||||
@@ -101,12 +111,84 @@ int rtems_gdb_stub_id_to_index(
|
|||||||
return first_posix_id + (thread_obj_id - min_id);
|
return first_posix_id + (thread_obj_id - min_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the RTEMS thread id from a gdb thread id */
|
||||||
|
Thread_Control *rtems_gdb_index_to_stub_id(
|
||||||
|
int thread
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Objects_Id thread_obj_id;
|
||||||
|
Objects_Id min_id, max_id;
|
||||||
|
int first_posix_id, first_rtems_id;
|
||||||
|
Objects_Information *obj_info;
|
||||||
|
Thread_Control *th;
|
||||||
|
|
||||||
|
ASSERT(registers != NULL);
|
||||||
|
|
||||||
|
if (_System_state_Get() != SYSTEM_STATE_UP || thread <= 0) {
|
||||||
|
/* Should not happen */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread == 1) {
|
||||||
|
th = _Thread_Idle;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let us get object associtated with current thread */
|
||||||
|
first_rtems_id = 2;
|
||||||
|
|
||||||
|
thread_obj_id = _Thread_Executing->Object.id;
|
||||||
|
|
||||||
|
/* Let us figure out thread_id for gdb */
|
||||||
|
obj_info = _Objects_Information_table[OBJECTS_RTEMS_TASKS];
|
||||||
|
|
||||||
|
min_id = obj_info->minimum_id;
|
||||||
|
max_id = obj_info->maximum_id;
|
||||||
|
|
||||||
|
if (thread <= (first_rtems_id + (max_id - min_id))) {
|
||||||
|
th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]);
|
||||||
|
|
||||||
|
if (th != NULL) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Thread does not exist */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
first_posix_id = first_rtems_id + (max_id - min_id) + 1;
|
||||||
|
|
||||||
|
obj_info = _Objects_Information_table[OBJECTS_POSIX_THREADS];
|
||||||
|
|
||||||
|
min_id = obj_info->minimum_id;
|
||||||
|
max_id = obj_info->maximum_id;
|
||||||
|
|
||||||
|
th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
|
||||||
|
if (th == NULL) {
|
||||||
|
/* Thread does not exist */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
return th;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get id of the thread stopped by exception */
|
/* Get id of the thread stopped by exception */
|
||||||
int rtems_gdb_stub_get_current_thread(void)
|
int rtems_gdb_stub_get_current_thread(void)
|
||||||
{
|
{
|
||||||
return rtems_gdb_stub_id_to_index( _Thread_Executing->Object.id );
|
return rtems_gdb_stub_id_to_index( _Thread_Executing->Object.id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get id of the next thread after athread, if argument <= 0 find the
|
/* Get id of the next thread after athread, if argument <= 0 find the
|
||||||
first available thread, return thread if found or 0 if not */
|
first available thread, return thread if found or 0 if not */
|
||||||
int rtems_gdb_stub_get_next_thread(int athread)
|
int rtems_gdb_stub_get_next_thread(int athread)
|
||||||
@@ -176,6 +258,10 @@ int rtems_gdb_stub_get_next_thread(int athread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get thread registers, return 0 if thread does not
|
/* Get thread registers, return 0 if thread does not
|
||||||
exist, and 1 otherwise */
|
exist, and 1 otherwise */
|
||||||
int rtems_gdb_stub_get_thread_regs(
|
int rtems_gdb_stub_get_thread_regs(
|
||||||
@@ -183,70 +269,27 @@ int rtems_gdb_stub_get_thread_regs(
|
|||||||
unsigned int *registers
|
unsigned int *registers
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Objects_Id thread_obj_id;
|
|
||||||
Objects_Id min_id, max_id;
|
|
||||||
int first_posix_id, first_rtems_id;
|
|
||||||
Objects_Information *obj_info;
|
|
||||||
Thread_Control *th;
|
Thread_Control *th;
|
||||||
|
|
||||||
ASSERT(registers != NULL);
|
th= rtems_gdb_index_to_stub_id(thread);
|
||||||
|
|
||||||
if (_System_state_Get() != SYSTEM_STATE_UP || thread <= 0) {
|
|
||||||
/* Should not happen */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread == 1) {
|
|
||||||
th = _Thread_Idle;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Let us get object associtated with current thread */
|
|
||||||
first_rtems_id = 2;
|
|
||||||
|
|
||||||
thread_obj_id = _Thread_Executing->Object.id;
|
|
||||||
|
|
||||||
/* Let us figure out thread_id for gdb */
|
|
||||||
obj_info = _Objects_Information_table[OBJECTS_RTEMS_TASKS];
|
|
||||||
|
|
||||||
min_id = obj_info->minimum_id;
|
|
||||||
max_id = obj_info->maximum_id;
|
|
||||||
|
|
||||||
if (thread <= (first_rtems_id + (max_id - min_id))) {
|
|
||||||
th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]);
|
|
||||||
|
|
||||||
if (th != NULL) {
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thread does not exist */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
first_posix_id = first_rtems_id + (max_id - min_id) + 1;
|
|
||||||
|
|
||||||
obj_info = _Objects_Information_table[OBJECTS_POSIX_THREADS];
|
|
||||||
|
|
||||||
min_id = obj_info->minimum_id;
|
|
||||||
max_id = obj_info->maximum_id;
|
|
||||||
|
|
||||||
th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
|
|
||||||
if (th == NULL) {
|
|
||||||
/* Thread does not exist */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
found:
|
|
||||||
|
|
||||||
|
if( th )
|
||||||
|
{
|
||||||
rtems_gdb_stub_get_registers_from_context( registers, th );
|
rtems_gdb_stub_get_registers_from_context( registers, th );
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Set thread registers, return 0 if thread does not
|
/* Set thread registers, return 0 if thread does not
|
||||||
exist or register values will screw up the threads,
|
exist or register values will screw up the threads,
|
||||||
and 1 otherwise */
|
and 1 otherwise */
|
||||||
|
|
||||||
int rtems_gdb_stub_set_thread_regs(
|
int rtems_gdb_stub_set_thread_regs(
|
||||||
int thread,
|
int thread,
|
||||||
unsigned int *registers
|
unsigned int *registers
|
||||||
@@ -260,6 +303,10 @@ int rtems_gdb_stub_set_thread_regs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get thread information, return 0 if thread does not
|
/* Get thread information, return 0 if thread does not
|
||||||
exist and 1 otherwise */
|
exist and 1 otherwise */
|
||||||
int rtems_gdb_stub_get_thread_info(
|
int rtems_gdb_stub_get_thread_info(
|
||||||
@@ -383,6 +430,10 @@ int rtems_gdb_stub_get_thread_info(
|
|||||||
/*******************************************************/
|
/*******************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */
|
/* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */
|
||||||
int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len)
|
int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len)
|
||||||
{
|
{
|
||||||
@@ -613,11 +664,20 @@ pack_qm_header(char *out, int count, int done, int athread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread2fhstr(out, athread);
|
thread2fhstr(out, athread);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void rtems_gdb_process_query(
|
void rtems_gdb_process_query(
|
||||||
char *inbuffer,
|
char *inbuffer,
|
||||||
char *outbuffer,
|
char *outbuffer,
|
||||||
@@ -642,6 +702,9 @@ void rtems_gdb_process_query(
|
|||||||
*optr = 0;
|
*optr = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
/* Thread info query */
|
/* Thread info query */
|
||||||
if (!do_threads) {
|
if (!do_threads) {
|
||||||
@@ -669,10 +732,14 @@ void rtems_gdb_process_query(
|
|||||||
/* Build response */
|
/* Build response */
|
||||||
pack_qq(outbuffer, mask, rthread, &info);
|
pack_qq(outbuffer, mask, rthread, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
/* Thread info query */
|
/* Thread list query */
|
||||||
if (!do_threads) {
|
if (!do_threads) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -724,9 +791,14 @@ void rtems_gdb_process_query(
|
|||||||
|
|
||||||
/* Fill header */
|
/* Fill header */
|
||||||
pack_qm_header(outbuffer, i, done, athread);
|
pack_qm_header(outbuffer, i, done, athread);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (memcmp(inbuffer, "qOffsets", 8) == 0) {
|
if (memcmp(inbuffer, "qOffsets", 8) == 0) {
|
||||||
unsigned char *t, *d, *b;
|
unsigned char *t, *d, *b;
|
||||||
@@ -772,9 +844,13 @@ void rtems_gdb_process_query(
|
|||||||
/* qCRC, qRcmd, qu and qz will be added here */
|
/* qCRC, qRcmd, qu and qz will be added here */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Present thread in the variable length string format */
|
/* Present thread in the variable length string format */
|
||||||
char*
|
char*
|
||||||
thread2vhstr(char *buf, int thread)
|
thread2vhstr(char *buf, int thread)
|
||||||
@@ -1196,6 +1272,7 @@ set_mem_err (void)
|
|||||||
that the compiler won't save any registers (if there is a fault
|
that the compiler won't save any registers (if there is a fault
|
||||||
to mem_fault, they won't get restored, so there better not be any
|
to mem_fault, they won't get restored, so there better not be any
|
||||||
saved). */
|
saved). */
|
||||||
|
|
||||||
unsigned char
|
unsigned char
|
||||||
get_byte (const unsigned char *addr)
|
get_byte (const unsigned char *addr)
|
||||||
{
|
{
|
||||||
@@ -1210,6 +1287,12 @@ set_byte (unsigned char *addr, int val)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* From here down, the code is CPU model specific and generally maps
|
* From here down, the code is CPU model specific and generally maps
|
||||||
* the RTEMS thread context format to gdb's.
|
* the RTEMS thread context format to gdb's.
|
||||||
@@ -1273,24 +1356,53 @@ int rtems_gdb_stub_get_offsets(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
|
|
||||||
|
|
||||||
void rtems_gdb_stub_get_registers_from_context(
|
void rtems_gdb_stub_get_registers_from_context(
|
||||||
int *registers,
|
int *registers,
|
||||||
Thread_Control *th
|
Thread_Control *th
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
registers[S0] = (unsigned)th->Registers.s0;
|
||||||
|
registers[S1] = (unsigned)th->Registers.s1;
|
||||||
|
registers[S2] = (unsigned)th->Registers.s2;
|
||||||
|
registers[S3] = (unsigned)th->Registers.s3;
|
||||||
|
registers[S4] = (unsigned)th->Registers.s4;
|
||||||
|
registers[S5] = (unsigned)th->Registers.s5;
|
||||||
|
registers[S6] = (unsigned)th->Registers.s6;
|
||||||
|
registers[S7] = (unsigned)th->Registers.s7;
|
||||||
|
|
||||||
|
registers[SP] = (unsigned)th->Registers.sp;
|
||||||
|
registers[RA] = (unsigned)th->Registers.ra;
|
||||||
|
|
||||||
|
registers[SR] = (unsigned)th->Registers.c0_sr;
|
||||||
|
registers[PC] = (unsigned)th->Registers.c0_epc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int rtems_gdb_stub_get_offsets(
|
int rtems_gdb_stub_get_offsets(
|
||||||
unsigned char **text_addr,
|
unsigned char **text_addr,
|
||||||
unsigned char **data_addr,
|
unsigned char **data_addr,
|
||||||
unsigned char **bss_addr
|
unsigned char **bss_addr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
extern unsigned32 _ftext;
|
||||||
|
extern unsigned32 _fdata;
|
||||||
|
extern unsigned32 _bss_start;
|
||||||
|
|
||||||
|
*text_addr = &_ftext;
|
||||||
|
*data_addr = &_fdata;
|
||||||
|
*bss_addr = &_bss_start;
|
||||||
|
*/
|
||||||
*text_addr = 0;
|
*text_addr = 0;
|
||||||
*data_addr = 0;
|
*data_addr = 0;
|
||||||
*bss_addr = 0;
|
*bss_addr = 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user