1147 lines
24 KiB
C
1147 lines
24 KiB
C
|
/* THIS FILE HAS NOT HAD ITS COPYRIGHT CHECKED...FSF SHOULD NOT
|
|||
|
DISTRIBUTE IT UNTIL THIS HAPPENS. */
|
|||
|
|
|||
|
/* Memory-access and commands for inferior process, for GDB.
|
|||
|
*/
|
|||
|
|
|||
|
#include <sys/errno.h>
|
|||
|
#include <setjmp.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include "defs.h"
|
|||
|
#include "param.h"
|
|||
|
#include "frame.h"
|
|||
|
#include "value.h"
|
|||
|
#include "inferior.h"
|
|||
|
#include "symtab.h"
|
|||
|
|
|||
|
#undef WSTOPSIG
|
|||
|
#undef WTERMSIG
|
|||
|
#include "wait.h"
|
|||
|
|
|||
|
#ifdef USG
|
|||
|
#include <sys/types.h>
|
|||
|
#include <fcntl.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include <signal.h>
|
|||
|
#include <sys/file.h>
|
|||
|
|
|||
|
#include <termios.h>
|
|||
|
#define TERMINAL struct termios
|
|||
|
|
|||
|
#define LONGTIMEOUT 5
|
|||
|
#define SHORTTIMEOUT 1
|
|||
|
|
|||
|
#define KD_MINUTAE 1
|
|||
|
#define KD_LINEDISCIPLINE 2
|
|||
|
#define KD_RETRY 4
|
|||
|
#define KD_BLOCKTRANSFER 8
|
|||
|
|
|||
|
#ifndef STDIN
|
|||
|
#define STDIN 0
|
|||
|
#endif
|
|||
|
|
|||
|
#define GL_READING 0 /* get line is reading data */
|
|||
|
#define GL_OK 1 /* Getline saw the "ok" string */
|
|||
|
#define GL_SUCCESS 2 /* Get line got data */
|
|||
|
#define GL_TIMEOUT 3 /* Get line timed out */
|
|||
|
#define GL_OVERRUN 4 /* Get line filled up the buffer */
|
|||
|
#define GL_EXCEPTION 5 /* Get line saw "Exception" */
|
|||
|
#define GL_PROMLINE 6 /* Get line saw prom specific info */
|
|||
|
#define GL_BLANKLINE 7 /* Get line saw a blank line */
|
|||
|
|
|||
|
static int kiodebug /* = KD_RETRY | KD_BLOCKTRANSFER */;
|
|||
|
|
|||
|
static CORE_ADDR remote_pc = 0;
|
|||
|
static CORE_ADDR remote_next_pc = 0;
|
|||
|
static CORE_ADDR remove_thisbp_next_pc = 0;
|
|||
|
static CORE_ADDR remove_thisbp_target = 0;
|
|||
|
|
|||
|
enum showDrainage {DONTSHOW , SHOW} ;
|
|||
|
|
|||
|
|
|||
|
/* Descriptor for I/O to remote machine. Initialize it to -1 so that
|
|||
|
remote_open knows that we don't have a file open when the program
|
|||
|
starts. */
|
|||
|
int remote_desc = -1;
|
|||
|
|
|||
|
int dontskipcrs = 0;
|
|||
|
|
|||
|
#define PBUFSIZ 400
|
|||
|
|
|||
|
unsigned char ignorebuf[PBUFSIZ];
|
|||
|
#define IGNORE &ignorebuf[0]
|
|||
|
|
|||
|
/* Maximum number of bytes to read/write at once. The value here
|
|||
|
is chosen to fill up a packet (the headers account for the 32). */
|
|||
|
#define MAXBUFBYTES ((PBUFSIZ-32)/2)
|
|||
|
|
|||
|
static void remote_send ();
|
|||
|
static void putpkt ();
|
|||
|
static int getpkt ();
|
|||
|
|
|||
|
|
|||
|
/* Open a connection to a remote debugger.
|
|||
|
NAME is the filename used for communication. */
|
|||
|
CORE_ADDR breakpoint_regs_addr;
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
remote_open (name, from_tty)
|
|||
|
char *name;
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
extern int frame_file_full_name;
|
|||
|
unsigned char buf[PBUFSIZ];
|
|||
|
TERMINAL sg;
|
|||
|
|
|||
|
remote_debugging = 0;
|
|||
|
|
|||
|
if (remote_desc >= 0)
|
|||
|
close (remote_desc);
|
|||
|
|
|||
|
breakpoint_regs_addr = parse_and_eval_address("&breakpoint_regs");
|
|||
|
|
|||
|
dontskipcrs = !frame_file_full_name; /* if we are running inside of
|
|||
|
emacs, this will be true.
|
|||
|
then skip carriage returns */
|
|||
|
|
|||
|
remote_desc = open (name, O_RDWR);
|
|||
|
if (remote_desc < 0)
|
|||
|
perror_with_name (name);
|
|||
|
|
|||
|
setup_remote();
|
|||
|
|
|||
|
if (from_tty)
|
|||
|
printf ("Remote debugging using %s\n", name);
|
|||
|
remote_debugging = 1;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
static char *boot_cmd = 0;
|
|||
|
|
|||
|
static print_boot_cmd()
|
|||
|
{
|
|||
|
fprintf(stderr, "boot command set to be \"%s\"\n", boot_cmd);
|
|||
|
}
|
|||
|
|
|||
|
remote_start()
|
|||
|
{
|
|||
|
WAITTYPE ignoredWaitType;
|
|||
|
|
|||
|
if (boot_cmd)
|
|||
|
{
|
|||
|
sendbreak();
|
|||
|
remote_wait (&ignoredWaitType);
|
|||
|
putpkt ("reset");
|
|||
|
sleep(10);
|
|||
|
sendbreak();
|
|||
|
remote_wait (&ignoredWaitType);
|
|||
|
sleep(10);
|
|||
|
print_boot_cmd();
|
|||
|
putpkt(boot_cmd);
|
|||
|
fprintf(stderr, "rgdb and nucleus synchronized, booting....\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
error("The boot command is null. Cannot start the remote kernel/nucleus");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Close the open connection to the remote debugger.
|
|||
|
Use this when you want to detach and do something else
|
|||
|
with your gdb. */
|
|||
|
void
|
|||
|
remote_close (from_tty)
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
if (!remote_debugging)
|
|||
|
error ("Can't close remote connection: not debugging remotely.");
|
|||
|
|
|||
|
close (remote_desc); /* This should never be called if
|
|||
|
there isn't something valid in
|
|||
|
remote_desc. */
|
|||
|
|
|||
|
/* Do not try to close remote_desc again, later in the program. */
|
|||
|
remote_desc = -1;
|
|||
|
|
|||
|
if (from_tty)
|
|||
|
printf ("Ending remote debugging\n");
|
|||
|
|
|||
|
remote_debugging = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert hex digit A to a number. */
|
|||
|
|
|||
|
static int
|
|||
|
fromhex (a)
|
|||
|
int a;
|
|||
|
{
|
|||
|
if (a >= '0' && a <= '9')
|
|||
|
return a - '0';
|
|||
|
else if (a >= 'a' && a <= 'f')
|
|||
|
return a - 'a' + 10;
|
|||
|
else
|
|||
|
error ("Reply contains invalid hex digit");
|
|||
|
}
|
|||
|
|
|||
|
/* Convert number NIB to a hex digit. */
|
|||
|
|
|||
|
static int
|
|||
|
tohex (nib)
|
|||
|
int nib;
|
|||
|
{
|
|||
|
if (nib < 10)
|
|||
|
return '0'+nib;
|
|||
|
else
|
|||
|
return 'a'+nib-10;
|
|||
|
}
|
|||
|
|
|||
|
/* Tell the remote machine to resume. */
|
|||
|
|
|||
|
extern int one_stepped; /* From machine dependent code */
|
|||
|
static int remote_set_one_stepped;
|
|||
|
|
|||
|
int
|
|||
|
remote_resume (step, signal)
|
|||
|
int step, signal;
|
|||
|
{
|
|||
|
if (step)
|
|||
|
{
|
|||
|
remote_single_step();
|
|||
|
}
|
|||
|
remote_set_one_stepped = step;
|
|||
|
putpkt("go");
|
|||
|
}
|
|||
|
|
|||
|
/* Wait until the remote machine stops, then return,
|
|||
|
storing status in STATUS just as `wait' would. */
|
|||
|
|
|||
|
int
|
|||
|
remote_wait (status)
|
|||
|
WAITTYPE *status;
|
|||
|
{
|
|||
|
char last, this;
|
|||
|
int pend, saveTheOh = 0;
|
|||
|
|
|||
|
user_terminal_raw();
|
|||
|
|
|||
|
WSETEXIT ((*status), 0177);
|
|||
|
last = this = 0;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
char buf[PBUFSIZ];
|
|||
|
int readUser, readProm, state;
|
|||
|
|
|||
|
doselect(&readUser, &readProm);
|
|||
|
if (readProm)
|
|||
|
{
|
|||
|
switch (state = getline(buf, PBUFSIZ, SHORTTIMEOUT))
|
|||
|
{
|
|||
|
case GL_BLANKLINE:
|
|||
|
if (remote_set_one_stepped)
|
|||
|
break;
|
|||
|
|
|||
|
/* fall through */
|
|||
|
|
|||
|
default:
|
|||
|
case GL_READING:
|
|||
|
case GL_SUCCESS:
|
|||
|
case GL_OVERRUN:
|
|||
|
case GL_TIMEOUT:
|
|||
|
if (kiodebug & KD_LINEDISCIPLINE)
|
|||
|
fprintf(stderr, "%d<%s>\n", state, buf);
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf(stderr, "%s", buf);
|
|||
|
fflush(stderr);
|
|||
|
}
|
|||
|
break;
|
|||
|
case GL_OK:
|
|||
|
remote_cleanup_after_stop();
|
|||
|
WSETSTOP ((*status), SIGTRAP);
|
|||
|
return;
|
|||
|
case GL_PROMLINE:
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (readUser)
|
|||
|
shuffleFromUserToProm();
|
|||
|
}
|
|||
|
}
|
|||
|
static TERMINAL userterminal;
|
|||
|
|
|||
|
user_terminal_restore()
|
|||
|
{
|
|||
|
#if 0
|
|||
|
int in_desc = fileno (stdin);
|
|||
|
ioctl (in_desc, TCSETS, &userterminal);
|
|||
|
#endif
|
|||
|
}
|
|||
|
static void set_term_raw();
|
|||
|
|
|||
|
user_terminal_raw()
|
|||
|
{
|
|||
|
#if 0
|
|||
|
TERMINAL tempterminal;
|
|||
|
int in_desc = fileno (stdin);
|
|||
|
ioctl (in_desc, TCGETS, &userterminal);
|
|||
|
tempterminal = userterminal;
|
|||
|
|
|||
|
tempterminal.c_lflag &= ~(ICANON|ISIG|IEXTEN);
|
|||
|
tempterminal.c_cc[VMIN] = 1;
|
|||
|
tempterminal.c_cc[VTIME] = 0;
|
|||
|
tempterminal.c_iflag &= ~(INPCK|IXON|IXOFF);
|
|||
|
tempterminal.c_oflag = 0;
|
|||
|
|
|||
|
ioctl (in_desc, TCSETS, &tempterminal);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
doselect(pReadUser, pReadProm)
|
|||
|
int *pReadUser, *pReadProm;
|
|||
|
{
|
|||
|
extern FILE *instream;
|
|||
|
int in_desc = fileno (stdin);
|
|||
|
int instreammask = 1 << in_desc;
|
|||
|
int remotemask = 1 << remote_desc;
|
|||
|
int rfds = instreammask | remotemask;
|
|||
|
|
|||
|
select (32, &rfds, 0, 0, (struct timeval *) 0); /* 0 = Block indefinitely */
|
|||
|
*pReadUser = (rfds & instreammask) == instreammask;
|
|||
|
*pReadProm = (rfds & remotemask) == remotemask;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Read the remote registers into the block pRegisters.
|
|||
|
implementation copied largely from fetch_inferior_registers ()
|
|||
|
in sparc-dep.c */
|
|||
|
|
|||
|
void
|
|||
|
remote_fetch_registers(ignored)
|
|||
|
int *ignored;
|
|||
|
{
|
|||
|
struct regs inferior_registers;
|
|||
|
extern char registers[];
|
|||
|
CORE_ADDR breakpoint_regs_target;
|
|||
|
|
|||
|
if (breakpoint_regs_addr == 0)
|
|||
|
{
|
|||
|
error("no address for breakpoint_regs\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
remote_read_inferior_memory(breakpoint_regs_addr, &breakpoint_regs_target,
|
|||
|
sizeof(breakpoint_regs_target));
|
|||
|
|
|||
|
bzero(registers, REGISTER_BYTES);
|
|||
|
registers[REGISTER_BYTE (0)] = 0;
|
|||
|
|
|||
|
if (breakpoint_regs_target)
|
|||
|
{
|
|||
|
remote_read_inferior_memory(breakpoint_regs_target, &inferior_registers,
|
|||
|
sizeof(inferior_registers));
|
|||
|
registers[REGISTER_BYTE (0)] = 0;
|
|||
|
bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4);
|
|||
|
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
|
|||
|
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
|
|||
|
*(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc;
|
|||
|
*(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y;
|
|||
|
remote_pc = inferior_registers.r_pc;
|
|||
|
remote_next_pc = inferior_registers.r_npc;
|
|||
|
remote_read_inferior_memory (inferior_registers.r_sp,
|
|||
|
®isters[REGISTER_BYTE (16)],
|
|||
|
16*4);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
error("breakpoint_regs == 0\n");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Write memory data directly to the remote machine.
|
|||
|
This does not inform the data cache; the data cache uses this.
|
|||
|
MEMADDR is the address in the remote memory space.
|
|||
|
MYADDR is the address of the buffer in our space.
|
|||
|
LEN is the number of bytes. */
|
|||
|
|
|||
|
int
|
|||
|
remote_write_bytes (memaddr, myaddr, len)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
unsigned char *myaddr;
|
|||
|
int len;
|
|||
|
{
|
|||
|
char buf[PBUFSIZ];
|
|||
|
int i;
|
|||
|
|
|||
|
/* Command describes registers byte by byte,
|
|||
|
each byte encoded as two hex characters. */
|
|||
|
|
|||
|
for (i = 0; i < len; i++)
|
|||
|
{
|
|||
|
sprintf(buf, "%x %x c!", myaddr[i], memaddr + i);
|
|||
|
remote_send (buf, buf);
|
|||
|
if (strstr(buf, "Exception"))
|
|||
|
{
|
|||
|
return EFAULT;
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Copy LEN bytes of data from debugger memory at MYADDR
|
|||
|
to inferior's memory at MEMADDR. Returns errno value. */
|
|||
|
int
|
|||
|
remote_write_inferior_memory (memaddr, myaddr, len)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
char *myaddr;
|
|||
|
int len;
|
|||
|
{
|
|||
|
int xfersize;
|
|||
|
int retval;
|
|||
|
|
|||
|
while (len > 0)
|
|||
|
{
|
|||
|
if (len > MAXBUFBYTES)
|
|||
|
xfersize = MAXBUFBYTES;
|
|||
|
else
|
|||
|
xfersize = len;
|
|||
|
|
|||
|
retval = remote_write_bytes(memaddr, myaddr, xfersize);
|
|||
|
if (retval)
|
|||
|
return retval; /* error */
|
|||
|
|
|||
|
memaddr += xfersize;
|
|||
|
myaddr += xfersize;
|
|||
|
len -= xfersize;
|
|||
|
}
|
|||
|
return 0; /* no error */
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* read a single character */
|
|||
|
|
|||
|
static int
|
|||
|
readCharFromProm ()
|
|||
|
{
|
|||
|
char buf;
|
|||
|
|
|||
|
buf = '\0';
|
|||
|
/* termio does the timeout for us. */
|
|||
|
read (remote_desc, &buf, 1);
|
|||
|
return buf & 0x7f;
|
|||
|
}
|
|||
|
|
|||
|
/* Send the command in BUF to the remote machine,
|
|||
|
and read the reply into BUF.
|
|||
|
Report an error if we get an error reply. */
|
|||
|
|
|||
|
static void
|
|||
|
remote_send (buf, buf2)
|
|||
|
char *buf, *buf2;
|
|||
|
{
|
|||
|
putpkt (buf);
|
|||
|
getpkt (buf2);
|
|||
|
}
|
|||
|
|
|||
|
/* Send a single character out over the wire */
|
|||
|
|
|||
|
static void
|
|||
|
putcharacter (ch)
|
|||
|
char ch;
|
|||
|
{
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
write(remote_desc, &ch, 1);
|
|||
|
for (i = 0; i < 100; i++)
|
|||
|
{
|
|||
|
char nch = 0;
|
|||
|
|
|||
|
if (read (remote_desc, &nch, 1) == 0)
|
|||
|
i++;
|
|||
|
if ((ch == nch)
|
|||
|
|| (ch == '\n' && nch == '\r')
|
|||
|
|| (ch == '\r' && nch == '\n'))
|
|||
|
return;
|
|||
|
if (kiodebug & KD_MINUTAE)
|
|||
|
fprintf (stderr, "Sent %c(%d) Received %c(%d)\n", ch, ch, nch, nch);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Send a packet to the remote machine, with error checking.
|
|||
|
The data of the packet is in BUF. */
|
|||
|
|
|||
|
static void
|
|||
|
putpkt (buf)
|
|||
|
char *buf;
|
|||
|
{
|
|||
|
int i;
|
|||
|
int cnt = strlen (buf);
|
|||
|
char ch;
|
|||
|
|
|||
|
if (kiodebug & KD_LINEDISCIPLINE)
|
|||
|
fprintf(stderr, "putpkt(%s)\n", buf);
|
|||
|
|
|||
|
for (i = 0; i < cnt; i++)
|
|||
|
putcharacter (buf[i]);
|
|||
|
putcharacter ('\n');
|
|||
|
}
|
|||
|
|
|||
|
jmp_buf getline_jmpbuf;
|
|||
|
|
|||
|
/* Read a line from the remote machine, and store it in BUF. */
|
|||
|
getline_timer()
|
|||
|
{
|
|||
|
alarm(0);
|
|||
|
|
|||
|
if (kiodebug & KD_RETRY)
|
|||
|
fprintf(stderr, "getline timed out\n");
|
|||
|
longjmp(getline_jmpbuf, 1);
|
|||
|
}
|
|||
|
|
|||
|
static int
|
|||
|
getline (buf, size, timeout)
|
|||
|
char *buf;
|
|||
|
int size, timeout;
|
|||
|
{
|
|||
|
int cnt = 0;
|
|||
|
int state;
|
|||
|
int isspace_state = 1;
|
|||
|
|
|||
|
if ((void (*)) signal (SIGALRM, getline_timer) == (void (*)) -1)
|
|||
|
perror ("remote_open: error in signal");
|
|||
|
|
|||
|
--size; /* back it up one so that we can read */
|
|||
|
|
|||
|
state = GL_READING;
|
|||
|
|
|||
|
if (setjmp(getline_jmpbuf))
|
|||
|
state = GL_TIMEOUT;
|
|||
|
else
|
|||
|
{
|
|||
|
alarm (timeout);
|
|||
|
do
|
|||
|
{
|
|||
|
char ch = readCharFromProm();
|
|||
|
isspace_state = isspace_state && isspace(ch);
|
|||
|
if (ch && (dontskipcrs || ch != '\r'))
|
|||
|
{
|
|||
|
buf[cnt++] = ch;
|
|||
|
buf[cnt] = '\0';
|
|||
|
}
|
|||
|
if (kiodebug & KD_MINUTAE)
|
|||
|
fprintf (stderr,"letter received :%c\n", buf[cnt - 1]);
|
|||
|
if (cnt >= 2 && buf[cnt - 2] == 'o' && buf[cnt - 1] == 'k')
|
|||
|
state = GL_OK;
|
|||
|
else if (buf[cnt - 1] == '\n' )
|
|||
|
state = isspace_state ? GL_BLANKLINE : GL_SUCCESS;
|
|||
|
else if (cnt == size)
|
|||
|
state = GL_OVERRUN;
|
|||
|
else if (strstr(buf, "Type 'go' to resume"))
|
|||
|
state = GL_PROMLINE;
|
|||
|
else if (strstr(buf, "Type help for more information"))
|
|||
|
state = GL_PROMLINE;
|
|||
|
else if (strstr(buf, "Exception"))
|
|||
|
state = GL_EXCEPTION;
|
|||
|
}
|
|||
|
while (state == GL_READING);
|
|||
|
}
|
|||
|
alarm (0);
|
|||
|
|
|||
|
if (kiodebug & KD_LINEDISCIPLINE)
|
|||
|
fprintf (stderr,"Line received :%s\n", buf);
|
|||
|
return state;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Read a packet from the remote machine, and store it in BUF. */
|
|||
|
|
|||
|
static int
|
|||
|
getpkt (buf)
|
|||
|
char *buf;
|
|||
|
{
|
|||
|
int cnt = 0;
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
char ch = readCharFromProm();
|
|||
|
if (ch)
|
|||
|
buf[cnt++] = ch;
|
|||
|
if (kiodebug & KD_MINUTAE)
|
|||
|
fprintf (stderr,"letter received :%c\n", buf[cnt - 1]);
|
|||
|
}
|
|||
|
while (cnt < 2 ||
|
|||
|
buf[cnt - 2] != 'o' &&
|
|||
|
buf[cnt - 1] != 'k');
|
|||
|
|
|||
|
buf[cnt] = '\0';
|
|||
|
if (kiodebug& KD_LINEDISCIPLINE)
|
|||
|
fprintf (stderr,"Packet received :%s\n", buf);
|
|||
|
return cnt;
|
|||
|
}
|
|||
|
|
|||
|
void remote_fetch_word (addr)
|
|||
|
CORE_ADDR addr;
|
|||
|
{
|
|||
|
error ("Internal error: remote_fetch_word is obsolete.\n");
|
|||
|
}
|
|||
|
void remote_store_word (addr)
|
|||
|
CORE_ADDR addr;
|
|||
|
{
|
|||
|
error ("Internal error: remote_store_word is obsolete.\n");
|
|||
|
}
|
|||
|
#include <termio.h>
|
|||
|
|
|||
|
draininput(showit)
|
|||
|
enum showDrainage showit;
|
|||
|
{
|
|||
|
unsigned char buf[PBUFSIZ];
|
|||
|
int cnt;
|
|||
|
|
|||
|
while ((cnt = read(remote_desc, buf, PBUFSIZ)) > 0)
|
|||
|
{
|
|||
|
buf[cnt] = 0;
|
|||
|
if (kiodebug& KD_LINEDISCIPLINE)
|
|||
|
fprintf (stderr,"Draining :%s\n", buf);
|
|||
|
else
|
|||
|
if (showit == SHOW)
|
|||
|
fprintf (stderr,"%s", buf);
|
|||
|
}
|
|||
|
if (kiodebug& KD_LINEDISCIPLINE)
|
|||
|
fprintf (stderr,"Drained\n");
|
|||
|
}
|
|||
|
sendbreak()
|
|||
|
{
|
|||
|
if (kiodebug & KD_RETRY)
|
|||
|
fprintf (stderr,"rgdb sending break to target...\n");
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf (stderr,"=");
|
|||
|
fflush(stderr);
|
|||
|
}
|
|||
|
|
|||
|
ioctl (remote_desc, TCSBRK, 0);
|
|||
|
sleep(5);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* shuffle a character from the user to remote debugger */
|
|||
|
|
|||
|
int
|
|||
|
shuffleFromUserToProm()
|
|||
|
{
|
|||
|
char ch;
|
|||
|
static int escape = 0;
|
|||
|
|
|||
|
extern FILE *instream;
|
|||
|
|
|||
|
ch = 0;
|
|||
|
if (read(STDIN, &ch , 1) != 1 || ch == 0)
|
|||
|
return;
|
|||
|
|
|||
|
if (escape) {
|
|||
|
if (ch == '#')
|
|||
|
sendbreak();
|
|||
|
else if (ch == '.')
|
|||
|
{
|
|||
|
while (ch != '\n')
|
|||
|
read(STDIN, &ch , 1);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
else {
|
|||
|
static char tilde = '~';
|
|||
|
|
|||
|
putcharacter(tilde);
|
|||
|
putcharacter(ch);
|
|||
|
}
|
|||
|
escape = 0;
|
|||
|
} else /* not escape */ {
|
|||
|
if (ch == '~')
|
|||
|
escape = 1;
|
|||
|
else
|
|||
|
putcharacter(ch);
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Tell the Prom put a breakpoint at memaddr */
|
|||
|
remote_insert_breakpoint(memaddr)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
{
|
|||
|
char buf[PBUFSIZ];
|
|||
|
|
|||
|
/* Command describes registers byte by byte,
|
|||
|
each byte encoded as two hex characters. */
|
|||
|
|
|||
|
sprintf(buf, "%x +bp", memaddr);
|
|||
|
remote_send(buf, buf);
|
|||
|
if (strstr(buf, "Exception"))
|
|||
|
{
|
|||
|
return EFAULT;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Tell the Prom remove the the breakpoint at memaddr */
|
|||
|
remote_remove_breakpoint(memaddr)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
{
|
|||
|
char buf[PBUFSIZ];
|
|||
|
|
|||
|
/* Command describes registers byte by byte,
|
|||
|
each byte encoded as two hex characters. */
|
|||
|
|
|||
|
sprintf(buf, "%x -bp", memaddr);
|
|||
|
remote_send(buf, buf);
|
|||
|
if (strstr(buf, "Exception"))
|
|||
|
{
|
|||
|
return EFAULT;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Read memory data directly from the remote machine.
|
|||
|
This does not use the data cache; the data cache uses this.
|
|||
|
MEMADDR is the address in the remote memory space.
|
|||
|
MYADDR is the address of the buffer in our space.
|
|||
|
LEN is the number of words. */
|
|||
|
|
|||
|
long
|
|||
|
remote_read(memaddr, myaddr, len, increment, promcommand)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
unsigned char *myaddr;
|
|||
|
int len, increment;
|
|||
|
char *promcommand;
|
|||
|
{
|
|||
|
char buf[PBUFSIZ];
|
|||
|
char buf2[PBUFSIZ];
|
|||
|
int i;
|
|||
|
unsigned long num;
|
|||
|
|
|||
|
/* Command describes registers byte by byte,
|
|||
|
each byte encoded as two hex characters. */
|
|||
|
|
|||
|
for (i = 0; i < len; i += increment)
|
|||
|
{
|
|||
|
sprintf(buf, promcommand, memaddr + i) ;
|
|||
|
remote_send(buf, buf2);
|
|||
|
remote_send(".", buf);
|
|||
|
if (strstr(buf2, "Exception"))
|
|||
|
{
|
|||
|
bzero(&myaddr[i], len - i);
|
|||
|
return -i;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
char *pBuf;
|
|||
|
for (pBuf = &buf[0]; *pBuf == '\r' || *pBuf == '\n'; pBuf++)
|
|||
|
;
|
|||
|
sscanf(pBuf, "%x\n", &num);
|
|||
|
switch (increment)
|
|||
|
{
|
|||
|
case 1: myaddr[i] = num;
|
|||
|
if (num > 255)
|
|||
|
fprintf(stderr, "number out of bounds %x truncating to %x\n",
|
|||
|
num, myaddr[i]);
|
|||
|
break;
|
|||
|
case 4: {unsigned long *p;
|
|||
|
p = (unsigned long *) &myaddr[i];
|
|||
|
*p = num;
|
|||
|
}
|
|||
|
break;
|
|||
|
default: fprintf(stderr, "unknown increment\n"); break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return i;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Read LEN bytes from inferior memory at MEMADDR. Put the result
|
|||
|
at debugger address MYADDR. Returns errno value. */
|
|||
|
int
|
|||
|
remote_read_inferior_memory(memaddr, myaddr, len)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
char *myaddr;
|
|||
|
int len;
|
|||
|
{
|
|||
|
int xfersize;
|
|||
|
while (len > 0)
|
|||
|
{
|
|||
|
int mod;
|
|||
|
|
|||
|
if (len > MAXBUFBYTES)
|
|||
|
xfersize = MAXBUFBYTES;
|
|||
|
else
|
|||
|
xfersize = len;
|
|||
|
|
|||
|
mod = memaddr % 4;
|
|||
|
if (mod == 0 && xfersize >= 4)
|
|||
|
if (mod == 0 && xfersize >= 16)
|
|||
|
{
|
|||
|
xfersize = remote_read_many(memaddr, myaddr, (len & ~3));
|
|||
|
getpkt(IGNORE);
|
|||
|
}
|
|||
|
else
|
|||
|
xfersize = remote_read(memaddr, myaddr, 4, 4, "%x @");
|
|||
|
else
|
|||
|
xfersize = remote_read(memaddr, myaddr, max(mod, 1), 1, "%x c@");
|
|||
|
if (xfersize <= 0)
|
|||
|
return EFAULT; /* error */
|
|||
|
memaddr += xfersize;
|
|||
|
myaddr += xfersize;
|
|||
|
len -= xfersize;
|
|||
|
}
|
|||
|
return 0; /* no error */
|
|||
|
}
|
|||
|
static int baud_rate=B38400;
|
|||
|
|
|||
|
static void set_term_raw(pTermio)
|
|||
|
TERMINAL *pTermio;
|
|||
|
{
|
|||
|
pTermio->c_cflag &= (CREAD|HUPCL|CLOCAL);
|
|||
|
pTermio->c_cflag |= baud_rate | CS8;
|
|||
|
pTermio->c_iflag = ISTRIP /* | IXON | IXOFF */;
|
|||
|
pTermio->c_oflag = 0;
|
|||
|
pTermio->c_lflag = 0;
|
|||
|
pTermio->c_cc[VMIN] = 0;
|
|||
|
pTermio->c_cc[VTIME] = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* setup the remote termio stream */
|
|||
|
setup_remote()
|
|||
|
{
|
|||
|
TERMINAL temptempio;
|
|||
|
|
|||
|
ioctl(remote_desc, TCGETS, &temptempio);
|
|||
|
set_term_raw(&temptempio);
|
|||
|
ioctl(remote_desc, TCSETS, &temptempio);
|
|||
|
}
|
|||
|
|
|||
|
/* step one machine instruction */
|
|||
|
remote_single_step ()
|
|||
|
{
|
|||
|
CORE_ADDR next_pc, npc4, target, pc;
|
|||
|
typedef enum
|
|||
|
{
|
|||
|
Error, not_branch, bicc, bicca, ba, baa, ticc, ta,
|
|||
|
} branch_type;
|
|||
|
branch_type br, isannulled();
|
|||
|
|
|||
|
npc4 = remote_next_pc + 4; /* branch not taken */
|
|||
|
|
|||
|
/* Always set breakpoint for NPC. */
|
|||
|
|
|||
|
remote_insert_breakpoint(remote_next_pc);
|
|||
|
remove_thisbp_next_pc = remote_next_pc;
|
|||
|
|
|||
|
/* printf ("set break at %x\n",remote_next_pc); */
|
|||
|
|
|||
|
br = isannulled (remote_pc, &target);
|
|||
|
|
|||
|
if (br == bicca)
|
|||
|
{
|
|||
|
/* Conditional annulled branch will either end up at
|
|||
|
npc (if taken) or at npc+4 (if not taken).
|
|||
|
Trap npc+4. */
|
|||
|
remote_insert_breakpoint(npc4);
|
|||
|
remove_thisbp_target = npc4;
|
|||
|
}
|
|||
|
else if (br == baa && target != remote_next_pc)
|
|||
|
{
|
|||
|
/* Unconditional annulled branch will always end up at
|
|||
|
the target. */
|
|||
|
remote_insert_breakpoint(target);
|
|||
|
remove_thisbp_target = target;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* read many words of memory */
|
|||
|
long
|
|||
|
remote_read_many(memaddr, myaddr, len)
|
|||
|
CORE_ADDR memaddr;
|
|||
|
unsigned char *myaddr;
|
|||
|
int len;
|
|||
|
{
|
|||
|
#define BLOCKSIZE 1024
|
|||
|
static int max_number_of_blocks = 24;
|
|||
|
|
|||
|
char buf[PBUFSIZ];
|
|||
|
char buf2[PBUFSIZ];
|
|||
|
int i;
|
|||
|
unsigned long *p;
|
|||
|
/* Command describes registers byte by byte,
|
|||
|
each byte encoded as two hex characters. */
|
|||
|
|
|||
|
len = min(len, max_number_of_blocks * BLOCKSIZE);
|
|||
|
|
|||
|
sprintf(buf, "%x %x do i @ . cr 4 +loop", memaddr + len, memaddr);
|
|||
|
putpkt(buf);
|
|||
|
getline(buf2, PBUFSIZ, LONGTIMEOUT); /* I don't care */
|
|||
|
|
|||
|
p = (unsigned long *) myaddr;
|
|||
|
for (i = 0; i < len; i += 4, p++)
|
|||
|
{
|
|||
|
extern int InspectIt;
|
|||
|
|
|||
|
if (!InspectIt && ((i % BLOCKSIZE) == 0))
|
|||
|
fprintf(stderr, "+"); /* let 'em know that we are working */
|
|||
|
switch (getline(buf2, PBUFSIZ, LONGTIMEOUT))
|
|||
|
{
|
|||
|
default:
|
|||
|
case GL_PROMLINE:
|
|||
|
case GL_READING:
|
|||
|
case GL_OK:
|
|||
|
case GL_OVERRUN:
|
|||
|
case GL_TIMEOUT:
|
|||
|
case GL_BLANKLINE:
|
|||
|
/* resync and retry */
|
|||
|
max_number_of_blocks = max(1, i / BLOCKSIZE);
|
|||
|
fprintf(stderr, "-"); /* let 'em know that we are working */
|
|||
|
|
|||
|
if (kiodebug & KD_BLOCKTRANSFER)
|
|||
|
fprintf(stderr, "failed read_many %d %d/%d (%s)\n",
|
|||
|
max_number_of_blocks, i, len, buf2);
|
|||
|
sendbreak();
|
|||
|
return remote_read_many(memaddr, myaddr, len);
|
|||
|
case GL_EXCEPTION:
|
|||
|
return -i;
|
|||
|
case GL_SUCCESS:
|
|||
|
sscanf(buf2, "%x\n", p);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (kiodebug & KD_BLOCKTRANSFER)
|
|||
|
fprintf(stderr, "success read_many %d %d/%d (%s)\n", max_number_of_blocks,
|
|||
|
i, len, buf2);
|
|||
|
return i;
|
|||
|
}
|
|||
|
/*
|
|||
|
* allow the user to type directly to the prom !
|
|||
|
*/
|
|||
|
prom_command()
|
|||
|
{
|
|||
|
int readUser, readProm;
|
|||
|
|
|||
|
user_terminal_raw();
|
|||
|
fprintf(stderr, "entering prom mode...\n");
|
|||
|
while (1)
|
|||
|
{
|
|||
|
doselect(&readUser, &readProm);
|
|||
|
if (readUser)
|
|||
|
if (shuffleFromUserToProm())
|
|||
|
{
|
|||
|
fprintf(stderr, "exiting prom mode\n");
|
|||
|
user_terminal_restore();
|
|||
|
return;
|
|||
|
}
|
|||
|
if (readProm)
|
|||
|
fprintf(stderr, "%c", readCharFromProm ());
|
|||
|
}
|
|||
|
}
|
|||
|
static char *boot_set_msg = "boot needs a string in quotes of the form \"boot vmunix\" ";
|
|||
|
static char *baud_set_msg = "baud rate should be of the form \"set baud=9600\"";
|
|||
|
|
|||
|
static void
|
|||
|
set_boot (arg, from_tty)
|
|||
|
char *arg;
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
int h, i;
|
|||
|
|
|||
|
if (!arg)
|
|||
|
{
|
|||
|
print_boot_cmd();
|
|||
|
error_no_arg (boot_set_msg);
|
|||
|
}
|
|||
|
|
|||
|
arg = tilde_expand (arg);
|
|||
|
make_cleanup (free, arg);
|
|||
|
|
|||
|
i = strlen (arg) - 1;
|
|||
|
|
|||
|
free (boot_cmd);
|
|||
|
|
|||
|
h = 0;
|
|||
|
while (*arg && h < i && (arg[h] == ' ' || arg[h] == '\t'))
|
|||
|
{
|
|||
|
h++;
|
|||
|
arg++;
|
|||
|
}
|
|||
|
while (i > 0 && (arg[i] == ' ' || arg[i] == '\t'))
|
|||
|
i--;
|
|||
|
|
|||
|
if (h >= i || !*arg || arg[h] != '"' || arg[i] != '"')
|
|||
|
error (boot_set_msg);
|
|||
|
else
|
|||
|
{
|
|||
|
boot_cmd = savestring (++arg, i);
|
|||
|
boot_cmd[i - 1] = '\0';
|
|||
|
}
|
|||
|
if (from_tty)
|
|||
|
print_boot_cmd();
|
|||
|
}
|
|||
|
|
|||
|
static int bauds[] = {
|
|||
|
0, 50, 75, 110, 134, 150, 200, 300, 600,
|
|||
|
1200, 1800, 2400, 4800, 9600, 19200, 38400, -1
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
static int convert_to_baud_B(n)
|
|||
|
int n;
|
|||
|
{
|
|||
|
register int *p;
|
|||
|
|
|||
|
for (p = bauds; *p != -1; p++)
|
|||
|
if (*p != 0 && *p == n)
|
|||
|
return (p - bauds);
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
static void print_acceptable_bauds()
|
|||
|
{
|
|||
|
register int *p;
|
|||
|
|
|||
|
for (p = bauds; *p != -1; p++)
|
|||
|
if (*p != 0 )
|
|||
|
fprintf(stderr, "%d\n", *p);
|
|||
|
}
|
|||
|
|
|||
|
static void print_baud()
|
|||
|
{
|
|||
|
fprintf(stderr, "the baud rate is now %d\n", bauds[baud_rate]);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
set_baud (arg, from_tty)
|
|||
|
char *arg;
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
int temp_baud_rate;
|
|||
|
|
|||
|
if (!arg)
|
|||
|
{
|
|||
|
print_baud();
|
|||
|
print_acceptable_bauds();
|
|||
|
error_no_arg (baud_set_msg);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
while (*arg && !isdigit(*arg))
|
|||
|
arg++;
|
|||
|
|
|||
|
if (*arg && (temp_baud_rate = convert_to_baud_B(atoi(arg))) != NULL)
|
|||
|
{
|
|||
|
baud_rate = temp_baud_rate;
|
|||
|
if (remote_debugging)
|
|||
|
setup_remote();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf(stderr, "bad baud rate %s, acceptable values are\n", arg);
|
|||
|
print_acceptable_bauds();
|
|||
|
}
|
|||
|
|
|||
|
print_baud();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
_initialize_remote()
|
|||
|
{
|
|||
|
/* Chain containing all defined set subcommands */
|
|||
|
|
|||
|
extern struct cmd_list_element *setlist;
|
|||
|
|
|||
|
|
|||
|
add_com ("prom", class_obscure, prom_command,
|
|||
|
"Conduct a dialogue directly with the prom. \
|
|||
|
only useful after an attach\n\
|
|||
|
Terminate by typing ~.");
|
|||
|
|
|||
|
add_cmd ("boot_cmd", class_support, set_boot, boot_set_msg, &setlist);
|
|||
|
|
|||
|
add_cmd ("baud", class_support, set_baud, baud_set_msg, &setlist);
|
|||
|
|
|||
|
set_boot ("\"boot nucleus -d\"", 0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Store the remote registers from the contents of the block REGS. */
|
|||
|
|
|||
|
void
|
|||
|
remote_store_registers (registers)
|
|||
|
char *registers;
|
|||
|
{
|
|||
|
CORE_ADDR core;
|
|||
|
struct regs inferior_registers;
|
|||
|
|
|||
|
core = parse_and_eval_address("breakpoint_regs");
|
|||
|
|
|||
|
bcopy (®isters[REGISTER_BYTE (1)],
|
|||
|
&inferior_registers.r_g1, 15 * 4);
|
|||
|
|
|||
|
inferior_registers.r_ps =
|
|||
|
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)];
|
|||
|
inferior_registers.r_pc =
|
|||
|
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)];
|
|||
|
inferior_registers.r_npc =
|
|||
|
*(int *)®isters[REGISTER_BYTE (NPC_REGNUM)];
|
|||
|
inferior_registers.r_y =
|
|||
|
*(int *)®isters[REGISTER_BYTE (Y_REGNUM)];
|
|||
|
|
|||
|
remote_write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)],
|
|||
|
®isters[REGISTER_BYTE (16)],
|
|||
|
16*4);
|
|||
|
remote_write_inferior_memory (core,
|
|||
|
&inferior_registers,
|
|||
|
sizeof(inferior_registers));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* we have stopped. do some cleanup */
|
|||
|
remote_cleanup_after_stop()
|
|||
|
{
|
|||
|
if (remove_thisbp_next_pc)
|
|||
|
{
|
|||
|
remote_remove_breakpoint (remove_thisbp_next_pc);
|
|||
|
remove_thisbp_next_pc = 0;
|
|||
|
}
|
|||
|
if (remove_thisbp_target)
|
|||
|
{
|
|||
|
remote_remove_breakpoint (remove_thisbp_target);
|
|||
|
remove_thisbp_target = 0;
|
|||
|
}
|
|||
|
user_terminal_restore();
|
|||
|
|
|||
|
one_stepped = remote_set_one_stepped;
|
|||
|
}
|