/* * Copyright (c) 1990, 1991, 1992 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Lawrence Berkeley Laboratory, * Berkeley, CA. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint static char rcsid[] = "@(#) $Header: /usr/src/contrib/gdb-4.7.lbl/gdb/RCS/remote-sl.c,v 1.2 1993/06/03 03:01:03 mccanne Exp $ (LBL)"; #endif #include <signal.h> #include <sys/param.h> #include <sys/file.h> #include <sys/time.h> #include <errno.h> extern int errno; #if BSD >= 199103 /* XXX ifdef on POSIX? */ #include <termios.h> #elif defined(HAVE_TERMIO) #include <termio.h> #else #include <sgtty.h> #endif #include <sys/ioctl.h> #ifdef USG #include <fcntl.h> #endif #ifndef FD_SETSIZE #define FD_SET(n, fdp) ((fdp)->fds_bits[0] |= (1 << (n))) #define FD_ISSET(n, fdp) ((fdp)->fds_bits[0] & (1 << (n))) #define FD_ZERO(fdp) ((fdp)->fds_bits[0] = 0) #endif #include "defs.h" #include "remote-sl.h" #include "remote.h" static int sl_send(); static int sl_recv(); /* * Descriptor for I/O to remote machine. */ static int sl_fd = -1; /* * User-configurable baud rate of serial line. * Default is 38400. */ static int speed = EXTB; /* * Command line argument. */ extern char *baud_rate; /* * Statistics. */ static int sl_errs; static int sl_inbytes; static int sl_outbytes;; static void sl_close() { if (sl_fd >= 0) { close(sl_fd); sl_fd = -1; } } static int getbaud(); /* * Configure the serial link. */ static void sl_conf(fd) int fd; { #if BSD >= 199103 struct termios tios; (void)tcgetattr(fd, &tios); cfmakeraw(&tios); /* Set 8 bit characters, enable receiver, non-dialup. */ tios.c_cflag = CS8|CREAD|CLOCAL; cfsetspeed(&tios, speed); (void)tcsetattr(fd, TCSANOW, &tios); #elif defined(HAVE_TERMIO) struct termio tios; ioctl(fd, TCGETA, &tios); tios.c_lflag &= ~(ICANON | ECHO); /* Set speed, 8 bit characters, enable receiver, non-dialup. */ tios.c_cflag = (speed & CBAUD)|CS8|CREAD|CLOCAL; ioctl(fd, TCSETA, &tios); #else struct sgttyb sg; ioctl(fd, TIOCGETP, &sg); sg.sg_flags = RAW | ANYP; sg.sg_ispeed = sg.sg_ospeed = speed; ioctl(fd, TIOCSETP, &sg); #endif } /* * Open a serial line for remote debugging. */ void sl_open(name, remote_fnp) char *name; struct remote_fn *remote_fnp; { char device[80]; sl_close(); if (name[0] != '/') { (void)sprintf(device, "/dev/%s", name); name = device; } /* * Use non-blocking mode so we don't wait for a carrier. * This allows the open to complete, then we set CLOCAL * mode since we don't need the modem control lines. */ sl_fd = open(name, O_RDWR|O_NONBLOCK); if (sl_fd < 0) { perror_with_name(name); /* NOTREACHED */ } if (baud_rate != 0) { speed = getbaud(baud_rate); baud_rate = 0; } sl_conf(sl_fd); remote_fnp->send = sl_send; remote_fnp->recv = sl_recv; remote_fnp->close = sl_close; remote_fnp->maxdata = SL_MAXDATA; remote_fnp->rpcsize = SL_RPCSIZE; sl_errs = 0; sl_inbytes = 0; sl_outbytes = 0; } /* * Remote input buffering. */ static u_char rib[2 * SL_MTU]; static u_char *rib_cp, *rib_ep; #define GETC(to) ((rib_cp < rib_ep) ? *rib_cp++ : rib_filbuf(to)) /* * Fill up the input buffer (with a non-blocking read). * On error, return the negation of the error code, otherwise * return the first character read and set things up so GETC will * read the remaining chars. */ static int rib_filbuf(to) int to; { int cc, fd = sl_fd; fd_set fds; struct timeval timeout, *tp; if (to < 0) tp = 0; else { timeout.tv_sec = to / 1000; timeout.tv_usec = to % 1000; tp = &timeout; } FD_ZERO(&fds); while (1) { FD_SET(fd, &fds); cc = select(fd + 1, &fds, (fd_set *)0, (fd_set *)0, tp); if (cc == 0) return (-EKGDB_TIMEOUT); else if (cc < 0) return (-EKGDB_IO); else { cc = read(fd, (caddr_t)rib, sizeof(rib)); if (cc < 0) return (-EKGDB_IO); rib_cp = &rib[1]; rib_ep = &rib[cc]; sl_inbytes += cc; return (rib[0]); } } } #define PUTESC(p, c) { \ if (c == FRAME_END) { \ *p++ = FRAME_ESCAPE; \ c = TRANS_FRAME_END; \ } else if (c == FRAME_ESCAPE) { \ *p++ = FRAME_ESCAPE; \ c = TRANS_FRAME_ESCAPE; \ } else if (c == FRAME_START) { \ *p++ = FRAME_ESCAPE; \ c = TRANS_FRAME_START; \ } \ *p++ = c; \ } /* * Send a message to the remote host. An error code is returned. */ static int sl_send(type, bp, len) register u_char type; register u_char *bp; register int len; { register u_char *p, *ep; register u_char csum, c; u_char buf[SL_MTU]; /* * Build a packet. The framing byte comes first, then the command * byte, the message, the checksum, and another framing character. * We must escape any bytes that match the framing or escape chars. */ p = buf; *p++ = FRAME_START; csum = type; PUTESC(p, type); for (ep = bp + len; bp < ep; ) { c = *bp++; csum += c; PUTESC(p, c); } csum = -csum; PUTESC(p, csum); *p++ = FRAME_END; len = p - buf; sl_outbytes += len; if (write(sl_fd, (caddr_t)buf, len) != len) return (EKGDB_IO); return (0); } /* * Read a packet from the remote machine. An error code is returned. */ static int sl_recv(tp, ip, lenp, to) int *tp; u_char *ip; int *lenp; int to; { register u_char csum, *bp; register int c; register int escape, len; register int type; u_char buf[SL_RPCSIZE + 1]; /* room for checksum at end of buffer */ /* * Allow immediate quit while reading from device, it could be hung. */ ++immediate_quit; /* * Throw away garbage characters until we see the start * of a frame (i.e., don't let framing errors propagate up). * If we don't do this, we can get pretty confused. */ while ((c = GETC(to)) != FRAME_START) if (c < 0) return (-c); restart: csum = len = escape = 0; type = -1; bp = buf; while (1) { c = GETC(to); if (c < 0) return (-c); switch (c) { case FRAME_ESCAPE: escape = 1; continue; case TRANS_FRAME_ESCAPE: if (escape) c = FRAME_ESCAPE; break; case TRANS_FRAME_END: if (escape) c = FRAME_END; break; case TRANS_FRAME_START: if (escape) c = FRAME_START; break; case FRAME_START: goto restart; case FRAME_END: if (type < 0 || --len < 0) { csum = len = escape = 0; continue; } if (csum != 0) { ++sl_errs; return (EKGDB_CSUM); } --immediate_quit; /* Store saved rpc reply type */ *tp = type; /* Store length of rpc reply packet */ if (lenp) *lenp = len; if (ip) bcopy((caddr_t)buf, (caddr_t)ip, len); return (0); } csum += c; if (type < 0) { type = c; escape = 0; continue; } if (++len > sizeof(buf)) { do { if ((c = GETC(to)) < 0) return (-c); } while (c != FRAME_END); return (EKGDB_2BIG); } *bp++ = c; escape = 0; } } static int getbaud(s) char *s; { switch (atoi(s)) { case 0: return (B0); case 50: return (B50); case 75: return (B75); case 110: return (B110); case 134: return (B134); case 150: return (B150); case 200: return (B200); case 300: return (B300); case 600: return (B600); case 1200: return (B1200); case 1800: return (B1800); case 2400: return (B2400); case 4800: return (B4800); case 9600: return (B9600); case 19200: return (EXTA); case 38400: return (EXTB); } return (-1); } static void set_sl_baudrate_command(arg, from_tty) char *arg; int from_tty; { int baudrate; if (arg == 0) error_no_arg("set remote-baudrate"); while (*arg == ' ' || *arg == '\t') ++arg; if (*arg == 0) error_no_arg("set remote-baudrate"); if (*arg < '0' || *arg > '9') error("non-numeric arg to \"set remote-baudrate\"."); baudrate = getbaud(arg); if (baudrate < 0) error("unknown baudrate for \"set remote-baudrate\"."); speed = baudrate; /* * Don't use command line option anymore. */ baud_rate = 0; } /* ARGSUSED */ static void sl_info(arg, from_tty) char *arg; int from_tty; { int linespeed; switch (speed) { default: linespeed = 0; break; case B50: linespeed = 50; break; case B75: linespeed = 75; break; case B110: linespeed = 110; break; case B134: linespeed = 134; break; case B150: linespeed = 150; break; case B200: linespeed = 200; break; case B300: linespeed = 300; break; case B600: linespeed = 600; break; case B1200: linespeed = 1200; break; case B1800: linespeed = 1800; break; case B2400: linespeed = 2400; break; case B4800: linespeed = 4800; break; case B9600: linespeed = 9600; break; case EXTA: linespeed = 19200; break; case EXTB: linespeed = 38400; break; } printf("sl-baudrate %6d\n", linespeed); printf("bytes received %6d\n", sl_inbytes); printf("bytes sent %6d\n", sl_outbytes); printf("checksum errors %6d\n", sl_errs); } extern struct cmd_list_element *setlist; void _initialize_sl() { add_info("sl", sl_info, "Show current settings of serial line debugging options."); add_cmd("sl-baudrate", class_support, set_sl_baudrate_command, "Set remote debug serial line baudrate.", &setlist); }