mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-24 20:49:43 +00:00
d747e0af3d
* All GDB files that #include defs.h: Removed stdio.h. (defs.h): #include stdio.h. This has been tested by building GDBs for all targets hosted on Sun4. None of the build problems were related to stdio.h inclusion. (n.b. many configurations don't build for other reasons.)
1145 lines
24 KiB
C
1145 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 "defs.h"
|
||
#include <sys/errno.h>
|
||
#include <setjmp.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;
|
||
}
|