mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-29 20:23:28 +08:00
25286543da
* Makefile.in (CLIBS): Reorder to make Lynx ld happy. * (HFILES): New file thread.h. * (OBS): New file thread.c. * configure.in: Host config for Lynx/386. * fork-child.c (fork_inferior): Call init_thread_list(). * infrun.c (resume): Add pid to invocation of target_resume(). * (wait_for_inferior): Pay attention to pid from target_wait(). Multi-threading code now uses this to determine what to do. * inftarg.c (child_wait): Conditionalize based on CHILD_WAIT macro. Use target_pid_to_str() macro throughout when printing pid. * inferior.h (child_resume): Add pid to prototype. * hppab-nat.c hppah-nat.c infptrace.c (child_resume): Pass in pid as argument, instead of using inferior_pid. * procfs.c (procfs_resume): Pass in pid as argument. Ignored for now. Use target_pid_to_str() macro throughout for printing process id. * remote-adapt.c (adapt_resume): Pass in pid as argument. * remote-eb.c (eb_resume): Pass in pid as argument. * remote-es.c (es1800_resume): Pass in pid as argument. * remote-hms.c (hms_resume): Pass in pid as argument. * remote-mips.c (mips_resume): Pass in pid as argument. * remote-mm.c (mm_resume): Pass in pid as argument. * remote-monitor.c (monitor_resume): Pass in pid as argument. * remote-nindy.c (nindy_resume): Pass in pid as argument. * remote-sa.sparc.c (remote_resume): Pass in pid as argument. * remote-sim.c (rem_resume): Pass in pid as argument. * remote-sp64sim.c (simif_resume): Pass in pid as argument. * remote-st.c (st2000_resume): Pass in pid as argument. * remote-udi.c (udi_resume): Pass in pid as argument. * remote-vx.c (vx_resume): Pass in pid as argument. * remote-z8k.c (rem_resume): Pass in pid as argument. * remote.c (remote_resume): Pass in pid as argument. * solib.c (solid_create_inferior_hook): Pass inferior_pid to target_resume(). * target.c (normal_pid_to_str): New routine to print out process ID normally. * target.h (struct target_ops): Add pid to prototype at to_resume(). (target_resume): Add pid argument. * (target_pid_to_str): Default definition for normal type pids. * thread.c, thread.c: New modules for multi thread/process control.
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 (pid, step, signal)
|
||
int pid, 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;
|
||
}
|