michael@garfield.mun.edu (Michael Rendell) (06/13/89)
When I tried to use gdb as a remote debugger I ran into a few problems getting it going (this is version 1.31 compiled on a sun3 running os4). remote_fetch_registers() and remote_write_bytes() were not null terminating their requests. remote_open() - if a tty is already open, close it before opening another. readchar() - now reads in a buffer instead of a single char at a time (this is just for efficiency). remote_write() - added this function to check for errors when writing. print_spaces() - declared to be static in symmisc.c when it's defined as global. The code that is #ifdef'd RTTY is for attaching to a remote tty. I needed to add this because all the lines to our sun were taken up. I have included the source (rtty_serv.c) to the daemon that must run on the machine with the real tty (rather BSD specific). This is also very useful in debugging the protocol between gdb and the remote machine since it's easy to log the conversation. I also have code that runs on the remote machine - works for both the 68000 and the 68010 (and probably the 68020, but it isn't tested). If anyone is interested, let me know. #!/bin/sh # This is a shell archive - strip off everything before the #! line and # run through /bin/sh. # This file contains: # diffs # rtty_serv.c # Created by michael, on Mon Jun 12 10:26:11 1989 if test -f 'diffs' then echo 'will not over-write existing file diffs' else sed 's/^X//' << 'SHAR_E_O_F' > 'diffs' X*** orig.remote.c Sun May 7 17:20:06 1989 X--- remote.c Mon Jun 12 09:20:13 1989 X*************** X*** 79,84 **** X--- 79,95 ---- X #include <sys/ioctl.h> X #include <sys/file.h> X X+ #ifdef RTTY X+ #ifndef USG X+ #include <sys/types.h> X+ #endif /* USG */ X+ #include <sys/socket.h> X+ #include <netinet/in.h> X+ #include <netdb.h> X+ X+ char *index(); X+ #endif /* RTTY */ X+ X #ifdef HAVE_TERMIO X #include <termio.h> X #undef TIOCGETP X*************** X*** 106,111 **** X--- 117,125 ---- X static void putpkt (); X static void getpkt (); X static void dcache_flush (); X+ static int remote_write (); X+ static int readchar_index; X+ static int readchar_nbytes; X X X /* Open a connection to a remote debugger. X*************** X*** 121,137 **** X remote_debugging = 0; X dcache_init (); X X! remote_desc = open (name, O_RDWR); X! if (remote_desc < 0) X! perror_with_name (name); X X! ioctl (remote_desc, TIOCGETP, &sg); X #ifdef HAVE_TERMIO X! sg.c_lflag &= ~ICANON; X #else X! sg.sg_flags = RAW; X #endif X! ioctl (remote_desc, TIOCSETP, &sg); X X if (from_tty) X printf ("Remote debugging using %s\n", name); X--- 135,163 ---- X remote_debugging = 0; X dcache_init (); X X! readchar_index = readchar_nbytes = 0; X! if (remote_desc >= 0) X! close(remote_desc); X! #ifdef RTTY X! if (index (name, '@')) X! { X! remote_desc = rtty_open(name); X! } X! else X! #endif /* RTTY */ X! { X! remote_desc = open (name, O_RDWR); X! if (remote_desc < 0) X! perror_with_name (name); X X! ioctl (remote_desc, TIOCGETP, &sg); X #ifdef HAVE_TERMIO X! sg.c_lflag &= ~ICANON; X #else X! sg.sg_flags = RAW; X #endif X! ioctl (remote_desc, TIOCSETP, &sg); X! } X X if (from_tty) X printf ("Remote debugging using %s\n", name); X*************** X*** 244,249 **** X--- 270,276 ---- X *p++ = tohex ((regs[i] >> 4) & 0xf); X *p++ = tohex (regs[i] & 0xf); X } X+ *p = '\0'; X X remote_send (buf); X } X*************** X*** 310,315 **** X--- 337,343 ---- X *p++ = tohex ((myaddr[i] >> 4) & 0xf); X *p++ = tohex (myaddr[i] & 0xf); X } X+ *p = '\0'; X X remote_send (buf); X } X*************** X*** 396,402 **** X int i; X char csum = 0; X char buf2[500]; X- char buf3[1]; X int cnt = strlen (buf); X char *p; X X--- 424,429 ---- X*************** X*** 421,439 **** X /* Send it over and over until we get a positive ack. */ X X do { X! write (remote_desc, buf2, p - buf2); X! read (remote_desc, buf3, 1); X! } while (buf3[0] != '+'); X } X X static int X readchar () X { X! char buf[1]; X! while (read (remote_desc, buf, 1) != 1) ; X! return buf[0] & 0x7f; X } X X /* Read a packet from the remote machine, with error checking, X and store it in BUF. */ X X--- 448,484 ---- X /* Send it over and over until we get a positive ack. */ X X do { X! remote_write (buf2, p - buf2); X! } while (readchar() != '+'); X } X X static int X readchar () X { X! static char mybuf[64]; X! X! if (readchar_index >= readchar_nbytes) X! { X! readchar_index = 0; X! readchar_nbytes = read (remote_desc, mybuf, sizeof(mybuf)); X! if (readchar_nbytes <= 0) X! error ("read from remote failed"); X! } X! return mybuf[readchar_index++] & 0x7f; X } X X+ static int X+ remote_write (buf, nbytes) X+ char *buf; X+ int nbytes; X+ { X+ int nwrite; X+ X+ nwrite = write(remote_desc, buf, nbytes); X+ if (nwrite < 0) X+ error("write to remote failed"); X+ return nwrite; X+ } X /* Read a packet from the remote machine, with error checking, X and store it in BUF. */ X X*************** X*** 470,479 **** X break; X printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", X (c1 << 4) + c2, csum, buf); X! write (remote_desc, "-", 1); X } X X! write (remote_desc, "+", 1); X X if (kiodebug) X fprintf (stderr,"Packet received :%s\n", buf); X--- 515,524 ---- X break; X printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", X (c1 << 4) + c2, csum, buf); X! remote_write ("-", 1); X } X X! remote_write ("+", 1); X X if (kiodebug) X fprintf (stderr,"Packet received :%s\n", buf); X*************** X*** 621,623 **** X--- 666,726 ---- X insque (db, &dcache_free); X } X X+ #ifdef RTTY X+ X+ #ifndef RTTY_PORT X+ # define RTTY_PORT 3120 /* port the daemon listens to */ X+ #endif /* RTTY_PORT */ X+ X+ /* X+ * Open a connection to the rtty server on the remote machine. The X+ * daemon puts the tty in raw mode. X+ */ X+ int X+ rtty_open(dev) X+ char *dev; X+ { X+ char *host; X+ struct hostent *he; X+ struct sockaddr_in sin; X+ short val; X+ int sock; X+ int devlen; X+ X+ if (!(host = index(dev, '@'))) X+ return -1; X+ devlen = host++ - dev; X+ X+ if (!(he = gethostbyname(host))) X+ error("cannot find address for host \"%s\"", host); X+ X+ if (he->h_addrtype != AF_INET) X+ error("no inet address for host"); X+ X+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) X+ perror_with_name("socket"); X+ X+ bzero((char *) &sin, sizeof(sin)); X+ sin.sin_family = AF_INET; X+ sin.sin_port = htons(RTTY_PORT); X+ bcopy(he->h_addr, &sin.sin_addr.s_addr, sizeof(struct in_addr)); X+ if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { X+ close(sock); X+ perror_with_name("connect"); X+ } X+ X+ if (write(sock, dev, devlen) != devlen) { X+ close(sock); X+ error("could not write to socket"); X+ } X+ if (read(sock, (char *) &val, sizeof(val)) != sizeof(val)) { X+ close(sock); X+ error("could not read from socket"); X+ } X+ if (val = ntohs(val)) { X+ close(sock); X+ error("got error %d from host \"%s\"", (int) val, host); X+ } X+ return sock; X+ } X+ #endif /* RTTY */ X*** orig.symmisc.c Thu May 18 11:47:51 1989 X--- symmisc.c Thu May 18 11:47:54 1989 X*************** X*** 377,383 **** X } X X static int block_depth (); X! static void print_spaces (); X static void print_symbol (); X X void X--- 377,383 ---- X } X X static int block_depth (); X! extern void print_spaces (); X static void print_symbol (); X X void SHAR_E_O_F fi if test -f 'rtty_serv.c' then echo 'will not over-write existing file rtty_serv.c' else sed 's/^X//' << 'SHAR_E_O_F' > 'rtty_serv.c' X#include <stdio.h> X#include <memory.h> X#include <errno.h> X#include <malloc.h> X#include <varargs.h> X#include <fcntl.h> X#include <sys/types.h> X#include <sys/param.h> X#include <sys/ioctl.h> X#include <sys/socket.h> X#include <signal.h> X#include <netdb.h> X#include <netinet/in.h> X X/* X * Remote tty server - used by gdb to attach to a tty on another machine. X * There really should be a generic remote device daemon (i.e. a generic X * /etc/rmt) so this wouldn't be nessasary. X * X * Systems that do not have vfprintf() in libc should define NEED_VPRINTF X * when compiling. X * X * Usage: rtty_serv [-Dn] [> logfile] X * X * -Dn sets the debugging mask: X * 1 for transaction log - keeps track of connections and traffic X * 2 daemon debuggin - prints select masks, return values. X * All debugging goes to standard out (should be saved to a file). When X * a SIGHUP is received, the log file is truncated (they get big, quickly). X */ X X#ifndef RTTY_PORT X# define RTTY_PORT 3120 /* daemons master port number */ X#endif /* RTTY_PORT */ X X#ifndef FD_SET X/* for 4.2 systems */ X X#define NBBY 8 /* number of bits in a byte */ X/* X * Select uses bit masks of file descriptors in longs. X * These macros manipulate such bit fields (the filesystem macros use chars). X * FD_SETSIZE may be defined by the user, but the default here X * should be >= NOFILE (param.h). X */ X#ifndef FD_SETSIZE X#define FD_SETSIZE 64 X#endif X Xtypedef long fd_mask; X#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ X#ifndef howmany X#define howmany(x, y) (((x)+((y)-1))/(y)) X#endif X X#ifndef ultrix Xtypedef struct fd_set { X fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; X} fd_set; X#endif /* !ultrix */ X X#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) X#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) X#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) X#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) X#endif /* FS_SET */ X X#ifndef MAXHOSTNAMELEN X#define MAXHOSTNAMELEN 64 X#endif /* MAXHOSTNAMELEN */ X X#define ERRNO 0x1 X#define EXIT 0x2 X X#define D_IO 0x1 /* transcation debugging */ X#define D_DAEM 0x2 /* debug this daemon */ X#define D_ALL 0xff X X#define DEBUG(l,x) if (debug & (l)) (void) printf x; else X Xtypedef struct dev_str Dev; Xstruct dev_str { X char *d_name; /* path of device */ X int d_dev; /* device file descriptor */ X int d_sock; /* socket fd */ X Dev *d_next; X Dev *d_prev; X}; X Xextern int errno; X Xint set_nodelay(); Xvoid error(); Xvoid kill_dev(); Xvoid init_dev(); Xvoid readwrite(); Xvoid send_error(); Xint sig_hup(); Xchar *str_error(); Xchar *str_dup(); X Xchar *progname; XDev *dev_list; Xfd_set rmask; Xint maxfd; Xint debug; Xint got_hup; XFILE *efp; /* errors go here */ X Xvoid Xmain(argc, argv) X int argc; X char **argv; X{ X int msock; /* master socket */ X fd_set rsel; X Dev *dp; X struct sockaddr_in sain; X int nsel; X int err; X int fd; X X progname = argc > 0 ? argv[0] : "rtty_serv"; X debug = 0; X got_hup = 0; X efp = stderr; X X if (argc > 1 && strncmp(argv[1], "-D", 2) == 0) { X setlinebuf(stdout); X debug = atoi(&argv[1][2]); X } X X (void) memset((char *) &sain, 0, sizeof(sain)); X sain.sin_family = AF_INET; X sain.sin_port = htons(RTTY_PORT); X sain.sin_addr.s_addr = INADDR_ANY; X X if ((msock = socket(sain.sin_family, SOCK_STREAM, 0)) < 0) X error(ERRNO|EXIT, "socket failed", errno); X X if (bind(msock, &sain, sizeof(sain)) < 0) X error(ERRNO|EXIT, "bind failed", errno); X X if (listen(msock, 2) < 0) X error(ERRNO|EXIT, "listen failed", errno); X X if (set_nodelay(msock)) X /* error printed */ X exit(1); X X switch (fork()) { X case -1: X error(ERRNO|EXIT, "fork failed", errno); X /*NOTREACHED*/ X X case 0: /* child */ X /* X * Ack like a real daemon - goto / and get rid of the X * controlling tty. X */ X (void) chdir("/"); X (void) close(0); X (void) close(2); X if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { X (void) ioctl(fd, TIOCNOTTY, (char *) 0); X (void) close(fd); X } X /* errors go to stdout from now on */ X efp = stdout; X break; X X default: /* parent */ X exit(0); X } X X (void) signal(SIGHUP, sig_hup); X X FD_ZERO(&rmask); X FD_SET(msock, &rmask); X maxfd = msock; X dev_list = (Dev *) 0; X while (1) { X if (got_hup && !isatty(fileno(stdout))) { X got_hup = 0; X (void) fseek(stdout, 0L, 0); X (void) ftruncate(fileno(stdout), 0L); X } X DEBUG(D_DAEM, X ("maxfd %d, mask %x\n", maxfd, rmask.fds_bits[0])); X rsel = rmask; X if ((nsel = select(maxfd + 1, &rsel, (fd_set *) 0, X (fd_set *) 0, 0)) < 0) X { X if (errno == EINTR) X continue; X /* Should we exit or just wait a while? */ X error(ERRNO|EXIT, "select failed", errno); X } X DEBUG(D_DAEM, ("nsel %d, rsel %x\n", nsel, rsel.fds_bits[0])); X if (FD_ISSET(msock, &rsel)) { X int newsock; X int length; X X nsel--; X length = sizeof(sain); X if ((newsock = accept(msock, &sain, &length)) < 0) { X error(ERRNO, "accept failed", errno); X continue; X } X if (err = set_nodelay(newsock)) { X send_error(newsock, err); X (void) close(newsock); X continue; X } X if (!(dp = (Dev *) malloc(sizeof(Dev)))) { X error(0, "no memory"); X send_error(newsock, ENOMEM); X (void) close(newsock); X continue; X } X dp->d_sock = newsock; X dp->d_name = (char *) 0; X dp->d_dev = -1; X dp->d_prev = (Dev *) 0; X if (dp->d_next = dev_list) X dev_list->d_prev = dp; X dev_list = dp; X FD_SET(newsock, &rmask); X if (newsock > maxfd) X maxfd = newsock; X /* could save sain & length if we need to */ X DEBUG(D_IO, ("+ %d socket\n", newsock)); X } X for (dp = dev_list ; nsel > 0 && dp ; dp = dp->d_next) { X if (FD_ISSET(dp->d_sock, &rsel)) { X --nsel; X if (dp->d_dev < 0) X init_dev(dp); X else X readwrite(dp, 1); X } X if (dp->d_dev >= 0 && FD_ISSET(dp->d_dev, &rsel)) { X --nsel; X readwrite(dp, 0); X } X } X } X} X X/* X * Set the no delay flag for FD. X */ Xint Xset_nodelay(fd) X int fd; X{ X int flags; X int err; X X if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { X err = errno; X error(ERRNO, "F_GETFL failed", err); X return err; X } X flags |= FNDELAY; X if (fcntl(fd, F_SETFL, flags) < 0) { X err = errno; X error(ERRNO, "F_SETFL failed", err); X return err; X } X return 0; X} X X/*VARARGS2*/ Xvoid Xerror(flags, fmt, va_alist) X int flags; X char *fmt; X va_dcl X{ X va_list args; X int err; X X va_start(args); X (void) fprintf(efp, "%s: ", progname); X if (flags & ERRNO) X err = va_arg(args, int); X (void) vfprintf(efp, fmt, args); X if (flags & ERRNO) X (void) fprintf(efp, " - %s\n", str_error(err)); X else X (void) fprintf(efp, "\n"); X va_end(args); X if (flags & EXIT) X exit(1); X} X Xvoid Xkill_dev(dp) X Dev *dp; X{ X if (dp->d_prev) X dp->d_prev->d_next = dp->d_next; X if (dp->d_next) X dp->d_next->d_prev = dp->d_prev; X if (dev_list == dp) X dev_list = dp->d_next; X if (dp->d_dev >= 0) { X FD_CLR(dp->d_dev, &rmask); X (void) close(dp->d_dev); X if (dp->d_dev == maxfd) X maxfd--; X } X if (dp->d_sock >= 0) { X FD_CLR(dp->d_sock, &rmask); X (void) close(dp->d_sock); X if (dp->d_sock == maxfd) X maxfd--; X } X if (dp->d_name) X free(dp->d_name); X free((char *) dp); X} X Xvoid Xinit_dev(dp) X Dev *dp; X{ X int len; X int err; X int fd; X char buf[1024]; X struct sgttyb sg; X X len = read(dp->d_sock, buf, sizeof(buf) - 1); X if (len == 0) { X error(0, "read eof from uninited socket"); X kill_dev(dp); X return; X } X if (len < 0) { X err = errno; X error(ERRNO, "read from socket failed", err); X goto bad; X } X buf[len] = '\0'; X if (!(dp->d_name = str_dup(buf))) { X err = ENOMEM; X error(0, "no memory"); X goto bad; X } X if ((dp->d_dev = open(dp->d_name, O_RDWR, 0)) < 0) { X err = errno; X error(ERRNO, "%s: open failed", err, dp->d_name); X goto bad; X } X X if (err = set_nodelay(dp->d_dev)) X goto bad; X if (ioctl(dp->d_dev, TIOCGETP, (char *) &sg) < 0) { X err = errno; X error(ERRNO, "%s: ioctl getp failed", err, dp->d_name); X goto bad; X } X sg.sg_flags = RAW; X if (ioctl(dp->d_dev, TIOCSETP, (char *) &sg) < 0) { X err = errno; X error(ERRNO, "%s: ioctl setp failed", err, dp->d_name); X goto bad; X } X /* X * Don't latch onto this tty (need /dev/tty - ioctl failed on X * dp->d_dev) X */ X if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { X (void) ioctl(fd, TIOCNOTTY, (char *) 0); X (void) close(fd); X } X X FD_SET(dp->d_dev, &rmask); X if (dp->d_dev > maxfd) X maxfd = dp->d_dev; X DEBUG(D_IO, ("+ %d %s\n", dp->d_dev, dp->d_name)); X send_error(dp->d_sock, 0); /* all ok */ X return; Xbad: X send_error(dp->d_sock, err); X kill_dev(dp); X} X Xvoid Xreadwrite(dp, fromsock) X Dev *dp; X int fromsock; X{ X char buf[1024]; X int in, out; X int nread; X int nwriten; X X if (fromsock) { X in = dp->d_sock; X out = dp->d_dev; X } else { X in = dp->d_dev; X out = dp->d_sock; X } X nread = read(in, buf, sizeof(buf) - 1); X if (nread == 0) { X DEBUG(D_IO, ("- %d/%d\n", in, out)); X kill_dev(dp); X return; X } X if (nread < 0) { X if (errno == EWOULDBLOCK) X return; X error(ERRNO, "read from %s failed", errno, X fromsock ? "socket" : dp->d_name); X kill_dev(dp); X return; X } X buf[nread] = '\0'; X DEBUG(D_IO, ("%d>%d\t\"%s\"\n", in, out, buf)); X nwriten = write(out, buf, nread); X if (nwriten < 0) { X error(ERRNO, "write to %s failed", errno, X fromsock ? dp->d_name : "socket"); X kill_dev(dp); X } else if (nwriten != nread) X error(0, "wrote %d of %d bytes to %s", nwriten, nread, X fromsock ? dp->d_name : "socket"); X} X Xvoid Xsend_error(fd, err) X int fd; X int err; X{ X short val; X int nwriten; X X val = htons((short) err); X nwriten = write(fd, (char *) &val, sizeof(val)); X if (nwriten < 0) X error(ERRNO, "write to socket failed", errno); X else if (nwriten != sizeof(val)) X error(0, "wrote %d of %d to socket", nwriten, sizeof(val)); X} X Xint Xsig_hup() X{ X got_hup = 1; X return 0; X} X X/* X * Things that should be in libc but aren't on many systems. X */ X Xchar * Xstr_error(err) X int err; X{ X extern int sys_nerr; X extern char *sys_errlist[]; X static char buf[32]; X X char *p; X X if (err < 0 || err >= sys_nerr) X (void) sprintf(p = buf, "Error: %d", err); X else X p = sys_errlist[err]; X return p; X} X Xchar * Xstr_dup(s) X char *s; X{ X extern char *strcpy(); X X char *p; X X if ((p = malloc((unsigned) (strlen(s) + 1))) != (char *) 0) X (void) strcpy(p, s); X return p; X} X X#ifdef NEED_VPRINTF Xint Xvfprintf(fp, fmt, args) X FILE *fp; X char *fmt; X va_list args; X{ X extern int _doprnt(); X X _doprnt(fmt, args, fp); X return ferror(fp) ? EOF : 0; X} X#endif /* NEED_VPRINTF */ SHAR_E_O_F chmod u=rwx rtty_serv.c fi exit 0