* defs.h (memcmp): Add decl for memcmp to #ifndef MEM_FNS_DECLARED.
* findvar.c (write_register): See if we are writing back the same
value that's already in the register. If so, don't bother.
* remote.c (putpkt, getpkt): Improve handling of communication
problems.
* ser-go32.c: Prototype it to death. Update serial_ops and add
dummy routines where appropriate.
* ser-tcp.c: New module to implement serial I/O via TCP
connections.
* ser-unix.c: Clean up getting/setting of tty state. Get rid of
SERIAL_RESTORE, add SERIAL_{GET|SET}_TTY_STATE interfaces.
* serial.c: Add start of support for connect command.
(serial_open): Distinguish between tcp and local devices.
* serial.h (struct serial_ops): Get rid of restore, add
get_tty_state and set_tty_state. Define protoypes and macros for
this mess.
* gdbserver/remote-utils.c: Add tcp support. (readchar): Do
some real buffering. Handle error conditions gracefully.
* gdbserver/remote-inflow-sparc.c: Update to remote-inflow.c
(Lynx), remove lots of cruft.
+Fri May 28 17:18:05 1993 Stu Grossman (grossman@cygnus.com)
+
+ * Makefile.in: Add new file ser-tcp.c.
+ * defs.h (memcmp): Add decl for memcmp to #ifndef MEM_FNS_DECLARED.
+ * findvar.c (write_register): See if we are writing back the same
+ value that's already in the register. If so, don't bother.
+ * remote.c (putpkt, getpkt): Improve handling of communication
+ problems.
+ * ser-go32.c: Prototype it to death. Update serial_ops and add
+ dummy routines where appropriate.
+ * ser-tcp.c: New module to implement serial I/O via TCP
+ connections.
+ * ser-unix.c: Clean up getting/setting of tty state. Get rid of
+ SERIAL_RESTORE, add SERIAL_{GET|SET}_TTY_STATE interfaces.
+ * serial.c: Add start of support for connect command.
+ (serial_open): Distinguish between tcp and local devices.
+ * serial.h (struct serial_ops): Get rid of restore, add
+ get_tty_state and set_tty_state. Define protoypes and macros for
+ this mess.
+ * gdbserver/remote-utils.c: Add tcp support. (readchar): Do
+ some real buffering. Handle error conditions gracefully.
+ * gdbserver/remote-inflow-sparc.c: Update to remote-inflow.c
+ (Lynx), remove lots of cruft.
+
Fri May 28 17:24:51 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
* printcmd.c (print_address_symbolic): turn this into an assigment
# part of libiberty) a POSIX interface. But at least for now the
# host-dependent makefile fragment might need to use something else
# besides ser-unix.o
-SER_HARDWIRE=ser-unix.o
+SER_HARDWIRE=ser-unix.o ser-tcp.o
# Host and target-dependent makefile fragments come in here.
####
${srcdir}/target.c ${srcdir}/typeprint.c ${srcdir}/utils.c \
${srcdir}/valarith.c \
${srcdir}/valops.c ${srcdir}/valprint.c ${srcdir}/values.c \
- ${srcdir}/serial.c ${srcdir}/ser-unix.c
+ ${srcdir}/serial.c ${srcdir}/ser-unix.c ${srcdir}/ser-tcp.c
# Files that are not source code, but need to go into gdb-$(VERSION).tar.Z.
NONSRC = ${srcdir}/Makefile.in ${srcdir}/depend ${srcdir}/alldeps.mak \
/* Defaults for system-wide constants (if not defined by xm.h, we fake it). */
#if !defined (UINT_MAX)
-#define UINT_MAX 0xffffffff
-#endif
-
-#if !defined (LONG_MAX)
-#define LONG_MAX 0x7fffffff
+#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */
#endif
#if !defined (INT_MAX)
-#define INT_MAX 0x7fffffff
+#define INT_MAX (UINT_MAX >> 1) /* 0x7FFFFFFF for 32-bits */
#endif
#if !defined (INT_MIN)
-/* Two's complement, 32 bit. */
-#define INT_MIN -0x80000000
+#define INT_MIN (-INT_MAX - 1) /* 0x80000000 for 32-bits */
+#endif
+
+#if !defined (ULONG_MAX)
+#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */
+#endif
+
+#if !defined (LONG_MAX)
+#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */
#endif
/* Number of bits in a char or unsigned char for the target machine.
#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */
extern PTR
memcpy PARAMS ((void *, const void *, size_t)); /* 4.11.2.1 */
-#endif
extern int
memcmp PARAMS ((const void *, const void *, size_t)); /* 4.11.4.1 */
+#endif
extern char *
strchr PARAMS ((const char *, int)); /* 4.11.5.2 */
-/* Low level interface to ptrace, for GDB when running under Unix.
- Copyright (C) 1986, 1987 Free Software Foundation, Inc.
-*/
+/* Low level interface to ptrace, for the remote server for GDB.
+ Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
-#include "wait.h"
+#include "/usr/include/sys/wait.h"
#include "frame.h"
#include "inferior.h"
/***************************
extern int inferior_pid;
void error (), quit (), perror_with_name ();
int query ();
-void supply_register (), write_register ();
-CORE_ADDR read_register ();
-
-/* Nonzero if we are debugging an attached outside process
- rather than an inferior. */
-
/* Start an inferior process and returns its pid.
ALLARGS is a vector of program-name and args.
/*************inferior_died ();****VK**************/
}
-/* Resume execution of the inferior process.
- If STEP is nonzero, single-step it.
- If SIGNAL is nonzero, give it that signal. */
+/* Wait for process, returns status */
unsigned char
-myresume (step, signal, status)
- int step;
- int signal;
+mywait (status)
char *status;
{
int pid;
- WAITTYPE w;
+ union wait w;
- errno = 0;
- ptrace (step ? 9 : 7, inferior_pid, 1, signal);
- if (errno)
- perror_with_name ("ptrace");
pid = wait (&w);
if (pid != inferior_pid)
perror_with_name ("wait");
- fetch_inferior_registers (0);
-
if (WIFEXITED (w))
{
- printf ("\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+ fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
*status = 'E';
return ((unsigned char) WEXITSTATUS (w));
}
else if (!WIFSTOPPED (w))
{
- printf ("\nChild terminated with signal = %x \n", WTERMSIG (w));
+ fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
*status = 'T';
return ((unsigned char) WTERMSIG (w));
}
- else
- {
- printf ("\nChild stopped with signal = %x \n", WSTOPSIG (w));
- *status = 'S';
- return ((unsigned char) WSTOPSIG (w));
- }
+
+ fetch_inferior_registers (0);
+
+ *status = 'S';
+ return ((unsigned char) WSTOPSIG (w));
}
-#define INT_REGS 1
-#define STACK_REGS 2
-#define FP_REGS 4
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+myresume (step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+}
/* Fetch one or more registers from the inferior. REGNO == -1 to get
them all. We actually fetch more than requested, when convenient,
perror("ptrace_setfpregs");
}
-#if 0
-void
-fetch_inferior_registers ()
-{
- struct regs inferior_registers;
- struct fp_status inferior_fp_registers;
- extern char registers[];
-
- ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers);
- if (errno)
- perror_with_name ("ptrace");
- /**********debugging begin **********/
- print_some_registers (&inferior_registers);
- /**********debugging end **********/
- ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers);
- if (errno)
- perror_with_name ("ptrace");
-
- bcopy (&inferior_registers, registers, 16 * 4);
- bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
- sizeof inferior_fp_registers.fpu_regs);
- *(int *) ®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
- *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
- bcopy (&inferior_fp_registers.fpu_flags,
- ®isters[REGISTER_BYTE (FPC_REGNUM)],
- sizeof inferior_fp_registers - sizeof inferior_fp_registers.fpu_regs);
-}
-
-/* Store our register values back into the inferior.
- If REGNO is -1, do this for all registers.
- Otherwise, REGNO specifies which register (so we can save time). */
-
-store_inferior_registers (regno)
- int regno;
-{
- struct regs inferior_registers;
- struct fp_status inferior_fp_registers;
- extern char registers[];
-
- bcopy (registers, &inferior_registers, 16 * 4);
- bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
- sizeof inferior_fp_registers.fps_regs);
- inferior_registers.r_ps = *(int *) ®isters[REGISTER_BYTE (PS_REGNUM)];
- inferior_registers.r_pc = *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)];
- bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)],
- &inferior_fp_registers.fps_control,
- sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
-
- ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers);
- if (errno)
- perror_with_name ("ptrace");
- ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers);
- if (errno)
- perror_with_name ("ptrace");
-}
-#endif /* 0 */
-
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
in the NEW_SUN_PTRACE case.
It ought to be straightforward. But it appears that writing did
}
\f
void
-try_writing_regs_command ()
-{
- register int i;
- register int val;
-
- if (inferior_pid == 0)
- error ("There is no inferior process now.");
-
- fetch_inferior_registers (0);
- for (i = 0; i < 18; i++)
- {
- QUIT;
- errno = 0;
- val = read_register (i);
- write_register (i, val);
- if (errno == 0)
- {
- printf (" Succeeded with register %d; value 0x%x (%d).\n",
- i, val, val);
- }
- else
- printf (" Failed with register %d.\n", i);
- }
-}
-
-void
initialize ()
{
-
inferior_pid = 0;
-
-
-}
-
-
-/* Return the contents of register REGNO,
- regarding it as an integer. */
-
-CORE_ADDR
-read_register (regno)
- int regno;
-{
- /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
- return *(int *) ®isters[REGISTER_BYTE (regno)];
-}
-
-/* Store VALUE in the register number REGNO, regarded as an integer. */
-
-void
-write_register (regno, val)
- int regno, val;
-{
- /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
- *(int *) ®isters[REGISTER_BYTE (regno)] = val;
-
- if (have_inferior_p ())
- store_inferior_registers (regno);
}
-
int
have_inferior_p ()
{
return inferior_pid != 0;
}
-
-print_some_registers (regs)
- int regs[];
-{
- register int i;
- for (i = 0; i < 18; i++)
- {
- printf ("reg[%d] = %x\n", i, regs[i]);
- }
-}
#include <a.out.h>
#include <sys/file.h>
#include <sgtty.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/tcp.h>
+#include <sys/time.h>
extern int remote_desc;
extern int remote_debugging;
-extern int kiodebug;
void remote_open ();
void remote_send ();
remote_debugging = 0;
- remote_desc = open (name, O_RDWR);
- if (remote_desc < 0)
- perror_with_name ("Could not open remote device");
+ if (!strchr (name, ':'))
+ {
+ remote_desc = open (name, O_RDWR);
+ if (remote_desc < 0)
+ perror_with_name ("Could not open remote device");
+
+ ioctl (remote_desc, TIOCGETP, &sg);
+ sg.sg_flags = RAW;
+ ioctl (remote_desc, TIOCSETP, &sg);
+ }
+ else
+ {
+ char *port_str;
+ int port;
+ struct sockaddr_in sockaddr;
+ int tmp;
+
+ port_str = strchr (name, ':');
+
+ port = atoi (port_str + 1);
+
+ remote_desc = socket (PF_INET, SOCK_STREAM, 0);
+ if (remote_desc < 0)
+ perror_with_name ("Can't open socket");
+
+ /* Allow rapid reuse of this port. */
+ tmp = 1;
+ setsockopt (remote_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
+ sizeof(tmp));
+
+ /* Enable TCP keep alive process. */
+ tmp = 1;
+ setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_port = htons(port);
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
- ioctl (remote_desc, TIOCGETP, &sg);
- sg.sg_flags = RAW;
- ioctl (remote_desc, TIOCSETP, &sg);
+ if (bind (remote_desc, &sockaddr, sizeof (sockaddr))
+ || listen (remote_desc, 1))
+ perror_with_name ("Can't bind address");
+
+ tmp = sizeof (sockaddr);
+ remote_desc = accept (remote_desc, &sockaddr, &tmp);
+ if (remote_desc == -1)
+ perror_with_name ("Accept failed");
+
+ tmp = 1;
+ setsockopt (remote_desc, 6, TCP_NODELAY, (char *)&tmp, sizeof(tmp));
+ }
fprintf (stderr, "Remote debugging using %s\n", name);
remote_debugging = 1;
static int
readchar ()
{
- char buf[1];
- while (read (remote_desc, buf, 1) != 1);
- return buf[0] & 0x7f;
+ static char buf[BUFSIZ];
+ static int bufcnt = 0;
+ static char *bufp;
+
+ if (bufcnt-- > 0)
+ return *bufp++ & 0x7f;
+
+ bufcnt = read (remote_desc, buf, sizeof (buf));
+
+ if (bufcnt <= 0)
+ {
+ perror ("readchar");
+ fatal ("read error, quitting");
+ }
+
+ bufp = buf;
+ bufcnt--;
+ return *bufp++ & 0x7f;
}
/* Read a packet from the remote machine, with error checking,
char *buf;
{
char *bp;
- unsigned char csum, c, c1, c2;
- extern kiodebug;
+ unsigned char csum, c1, c2;
+ int c;
while (1)
{
csum = 0;
+
while ((c = readchar ()) != '$');
bp = buf;
#include "serial.h"
#include <sys/dos.h>
+/* This is unused for now. We just return a placeholder. */
+struct go32_ttystate
+{
+ int bogus;
+};
+
+static int go32_open PARAMS ((serial_t scb, const char *name));
+static void go32_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int go32_readchar PARAMS ((serial_t scb, int timeout));
+static int rate_to_code PARAMS ((int rate));
+static int go32_setbaudrate PARAMS ((serial_t scb, int rate));
+static int go32_write PARAMS ((serial_t scb, const char *str, int len));
+static void go32_restore PARAMS ((serial_t scb));
+static void go32_close PARAMS ((serial_t scb));
+serial_ttystate go32_get_tty_state PARAMS ((serial_t scb));
+static int go32_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+static int strncasecmp PARAMS ((char *str1, char *str2, int len));
+static char *aptr PARAMS ((short p));
+static ASYNC_STRUCT *getivec PARAMS ((int which));
+static int dos_async_init PARAMS ((int port));
+static void dos_async_tx PARAMS ((const char c));
+static int dos_async_ready PARAMS (());
+static int dos_async_rx PARAMS (());
+static int dosasync_read PARAMS ((int fd, char *buf, int len, int timeout));
+static int dosasync_write PARAMS ((int fd, const char *buf, int len, int timeout));
+
#define SIGNATURE 0x4154
#define VERSION 1
#define OFFSET 0x104
return SERIAL_TIMEOUT;
}
+/* go32_{get set}_tty_state() are both dummys to fill out the function
+ vector. Someday, they may do something real... */
+
+static serial_ttystate
+go32_get_tty_state(scb)
+ serial_t scb;
+{
+ struct go32_ttystate *state;
+
+ state = (struct go32_ttystate *)xmalloc(sizeof *state);
+
+ return (serial_ttystate)state;
+}
+
+static int
+go32_set_tty_state(scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct go32_ttystate *state;
+
+ return 0;
+}
+
static int
go32_setbaudrate (scb, rate)
serial_t scb;
{
}
-static void
-go32_restore (scb)
- serial_t scb;
-{
-}
-
static struct serial_ops go32_ops =
{
"hardwire",
go32_readchar,
go32_write,
go32_raw,
- go32_restore,
+ go32_get_tty_state,
+ go32_set_tty_state,
go32_setbaudrate
};
--- /dev/null
+/* Serial interface for raw TCP connections on Un*x like systems
+ Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "serial.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include "signals.h"
+
+struct tcp_ttystate
+{
+ int bogus;
+};
+
+static int tcp_open PARAMS ((serial_t scb, const char *name));
+static void tcp_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int tcp_readchar PARAMS ((serial_t scb, int timeout));
+static int tcp_setbaudrate PARAMS ((serial_t scb, int rate));
+static int tcp_write PARAMS ((serial_t scb, const char *str, int len));
+static void tcp_restore PARAMS ((serial_t scb));
+static void tcp_close PARAMS ((serial_t scb));
+static serial_ttystate tcp_get_tty_state PARAMS ((serial_t scb));
+static int tcp_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+
+/* Open up a raw tcp socket */
+
+static int
+tcp_open(scb, name)
+ serial_t scb;
+ const char *name;
+{
+ char *port_str;
+ int port;
+ struct hostent *hostent;
+ struct sockaddr_in sockaddr;
+ int tmp;
+ char hostname[100];
+
+ port_str = strchr (name, ':');
+
+ if (!port_str)
+ error ("tcp_open: No colon in host name!"); /* Shouldn't ever happen */
+
+ tmp = min(port_str - name + 1, sizeof hostname);
+ strncpy (hostname, name, tmp - 1); /* Don't want colon */
+ port = atoi (port_str + 1);
+
+ hostent = gethostbyname (hostname);
+
+ if (!hostent)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ scb->fd = socket (PF_INET, SOCK_STREAM, 0);
+ if (scb->fd < 0)
+ return -1;
+
+ /* Allow rapid reuse of this port. */
+ tmp = 1;
+ setsockopt (scb->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp));
+
+ /* Enable TCP keep alive process. */
+ tmp = 1;
+ setsockopt (scb->fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_port = htons(port);
+ memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
+ sizeof (struct in_addr));
+
+ if (connect(scb->fd, &sockaddr, sizeof(sockaddr)))
+ {
+ close(scb->fd);
+ return -1;
+ }
+
+ tmp = 1;
+ if (setsockopt (scb->fd, 6, TCP_NODELAY, (char *)&tmp, sizeof(tmp)))
+ return -1;
+
+ signal(SIGPIPE, SIG_IGN); /* If we don't do this, then GDB simply exits
+ when the remote side dies. */
+
+ return 0;
+}
+
+static serial_ttystate
+tcp_get_tty_state(scb)
+ serial_t scb;
+{
+ struct tcp_ttystate *state;
+
+ state = (struct tcp_ttystate *)xmalloc(sizeof *state);
+
+ return (serial_ttystate)state;
+}
+
+static int
+tcp_set_tty_state(scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct tcp_ttystate *state;
+
+ state = (struct tcp_ttystate *)ttystate;
+
+ return 0;
+}
+
+static void
+tcp_raw(scb)
+ serial_t scb;
+{
+ return; /* Always in raw mode */
+}
+
+/* Wait for input on scb, with timeout seconds. Returns 0 on success,
+ otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
+
+ For termio{s}, we actually just setup VTIME if necessary, and let the
+ timeout occur in the read() in tcp_read().
+ */
+
+static int
+wait_for(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ int numfds;
+ struct timeval tv;
+ fd_set readfds;
+
+ FD_ZERO (&readfds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_SET(scb->fd, &readfds);
+
+ if (timeout >= 0)
+ numfds = select(scb->fd+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(scb->fd+1, &readfds, 0, 0, 0);
+
+ if (numfds <= 0)
+ if (numfds == 0)
+ return SERIAL_TIMEOUT;
+ else
+ return SERIAL_ERROR; /* Got an error from select or poll */
+
+ return 0;
+}
+
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns -2 if timeout expired, EOF if line dropped
+ dead, or -3 for any other error (see errno in that case). */
+
+static int
+tcp_readchar(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ int status;
+
+ if (scb->bufcnt-- > 0)
+ return *scb->bufp++;
+
+ status = wait_for(scb, timeout);
+
+ if (status < 0)
+ return status;
+
+ scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
+
+ if (scb->bufcnt <= 0)
+ if (scb->bufcnt == 0)
+ return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to
+ distinguish between EOF & timeouts
+ someday] */
+ else
+ return SERIAL_ERROR; /* Got an error from read */
+
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+}
+
+static int
+tcp_setbaudrate(scb, rate)
+ serial_t scb;
+ int rate;
+{
+ return 0; /* Never fails! */
+}
+
+static int
+tcp_write(scb, str, len)
+ serial_t scb;
+ const char *str;
+ int len;
+{
+ int cc;
+
+ while (len > 0)
+ {
+ cc = write(scb->fd, str, len);
+
+ if (cc < 0)
+ return 1;
+ len -= cc;
+ str += cc;
+ }
+ return 0;
+}
+
+static void
+tcp_close(scb)
+ serial_t scb;
+{
+ if (scb->fd < 0)
+ return;
+
+ close(scb->fd);
+ scb->fd = -1;
+}
+
+static struct serial_ops tcp_ops =
+{
+ "tcp",
+ 0,
+ tcp_open,
+ tcp_close,
+ tcp_readchar,
+ tcp_write,
+ tcp_raw,
+ tcp_get_tty_state,
+ tcp_set_tty_state,
+ tcp_setbaudrate,
+};
+
+void
+_initialize_ser_tcp ()
+{
+ serial_add_interface (&tcp_ops);
+}
#ifdef HAVE_TERMIOS
#include <termios.h>
#include <unistd.h>
+
+struct hardwire_ttystate
+{
+ struct termios termios;
+};
#endif
+
#ifdef HAVE_TERMIO
#include <termio.h>
+
+struct hardwire_ttystate
+{
+ struct termio termio;
+};
#endif
+
#ifdef HAVE_SGTTY
#include <sgtty.h>
+
+struct hardwire_ttystate
+{
+ struct sgttyb sgttyb;
+};
#endif
static int hardwire_open PARAMS ((serial_t scb, const char *name));
static int hardwire_write PARAMS ((serial_t scb, const char *str, int len));
static void hardwire_restore PARAMS ((serial_t scb));
static void hardwire_close PARAMS ((serial_t scb));
+static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb));
+static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
/* Open up a real live device for serial I/O */
return 0;
}
-static void
-hardwire_raw(scb)
+static int
+get_tty_state(scb, state)
serial_t scb;
+ struct hardwire_ttystate *state;
{
#ifdef HAVE_TERMIOS
- struct termios termios;
+ return tcgetattr(scb->fd, &state->termios);
+#endif
- if (tcgetattr(scb->fd, &termios))
- {
- fprintf(stderr, "tcgetattr failed: %s\n", safe_strerror(errno));
- }
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCGETA, &state->termio);
+#endif
- termios.c_iflag = 0;
- termios.c_oflag = 0;
- termios.c_lflag = 0;
- termios.c_cflag &= ~(CSIZE|PARENB);
- termios.c_cflag |= CS8;
- termios.c_cc[VMIN] = 0;
- termios.c_cc[VTIME] = 0;
+#ifdef HAVE_SGTTY
+ return ioctl (scb->fd, TIOCGETP, &state->sgttyb);
+#endif
+}
- if (tcsetattr(scb->fd, TCSANOW, &termios))
- {
- fprintf(stderr, "tcsetattr failed: %s\n", safe_strerror(errno));
- }
+static int
+set_tty_state(scb, state)
+ serial_t scb;
+ struct hardwire_ttystate *state;
+{
+ int err;
+
+#ifdef HAVE_TERMIOS
+ return tcsetattr(scb->fd, TCSANOW, &state->termios);
#endif
#ifdef HAVE_TERMIO
- struct termio termio;
+ return ioctl (scb->fd, TCSETA, &state->termio);
+#endif
- if (ioctl (scb->fd, TCGETA, &termio))
- {
- fprintf(stderr, "TCGETA failed: %s\n", safe_strerror(errno));
- }
+#ifdef HAVE_SGTTY
+ return ioctl (scb->fd, TIOCSETP, &state->sgttyb);
+#endif
+}
- termio.c_iflag = 0;
- termio.c_oflag = 0;
- termio.c_lflag = 0;
- termio.c_cflag &= ~(CSIZE|PARENB);
- termio.c_cflag |= CS8;
- termio.c_cc[VMIN] = 0;
- termio.c_cc[VTIME] = 0;
+static serial_ttystate
+hardwire_get_tty_state(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate *state;
- if (ioctl (scb->fd, TCSETA, &termio))
- {
- fprintf(stderr, "TCSETA failed: %s\n", safe_strerror(errno));
- }
-#endif
+ state = (struct hardwire_ttystate *)xmalloc(sizeof *state);
-#ifdef HAVE_SGTTY
- struct sgttyb sgttyb;
+ if (get_tty_state(scb, state))
+ return NULL;
- if (ioctl (scb->fd, TIOCGETP, &sgttyb))
- fprintf(stderr, "TIOCGETP failed: %s\n", safe_strerror(errno));
+ return (serial_ttystate)state;
+}
- sgttyb.sg_flags |= RAW | ANYP;
- sgttyb.sg_flags &= ~(CBREAK | ECHO);
+static int
+hardwire_set_tty_state(scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct hardwire_ttystate *state;
- if (ioctl (scb->fd, TIOCSETP, &sgttyb))
- fprintf(stderr, "TIOCSETP failed: %s\n", safe_strerror(errno));
+ state = (struct hardwire_ttystate *)ttystate;
+
+ return set_tty_state(scb, state);
+}
+
+static void
+hardwire_raw(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_iflag = 0;
+ state.termios.c_oflag = 0;
+ state.termios.c_lflag = 0;
+ state.termios.c_cflag &= ~(CSIZE|PARENB);
+ state.termios.c_cflag |= CS8;
+ state.termios.c_cc[VMIN] = 0;
+ state.termios.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_TERMIO
+ state.termio.c_iflag = 0;
+ state.termio.c_oflag = 0;
+ state.termio.c_lflag = 0;
+ state.termio.c_cflag &= ~(CSIZE|PARENB);
+ state.termio.c_cflag |= CS8;
+ state.termio.c_cc[VMIN] = 0;
+ state.termio.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_flags |= RAW | ANYP;
+ state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
#endif
scb->current_timeout = 0;
+
+ if (set_tty_state (scb, &state))
+ fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
}
/* Wait for input on scb, with timeout seconds. Returns 0 on success,
return 0;
{
-#ifdef HAVE_TERMIOS
- struct termios termios;
-
- if (tcgetattr(scb->fd, &termios))
- fprintf(stderr, "wait_for() tcgetattr failed: %s\n", safe_strerror(errno));
+ struct hardwire_ttystate state;
- termios.c_cc[VTIME] = timeout * 10;
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
- if (tcsetattr(scb->fd, TCSANOW, &termios))
- fprintf(stderr, "wait_for() tcsetattr failed: %s\n", safe_strerror(errno));
-#endif /* HAVE_TERMIOS */
+#ifdef HAVE_TERMIOS
+ state.termios.c_cc[VTIME] = timeout * 10;
+#endif
#ifdef HAVE_TERMIO
- struct termio termio;
-
- if (ioctl (scb->fd, TCGETA, &termio))
- fprintf(stderr, "wait_for() TCGETA failed: %s\n", safe_strerror(errno));
+ state.termio.c_cc[VTIME] = timeout * 10;
+#endif
- termio.c_cc[VTIME] = timeout * 10;
+ scb->current_timeout = timeout;
- if (ioctl (scb->fd, TCSETA, &termio))
- fprintf(stderr, "TCSETA failed: %s\n", safe_strerror(errno));
-#endif /* HAVE_TERMIO */
+ if (set_tty_state (scb, &state))
+ fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
- scb->current_timeout = timeout;
return 0;
}
#endif /* HAVE_TERMIO || HAVE_TERMIOS */
serial_t scb;
int rate;
{
-#ifdef HAVE_TERMIOS
- struct termios termios;
+ struct hardwire_ttystate state;
- if (tcgetattr (scb->fd, &termios))
+ if (get_tty_state(scb, &state))
return -1;
- cfsetospeed (&termios, rate_to_code (rate));
- cfsetispeed (&termios, rate_to_code (rate));
-
- if (tcsetattr (scb->fd, TCSANOW, &termios))
- return -1;
+#ifdef HAVE_TERMIOS
+ cfsetospeed (&state.termios, rate_to_code (rate));
+ cfsetispeed (&state.termios, rate_to_code (rate));
#endif
#ifdef HAVE_TERMIO
- struct termio termio;
-
- if (ioctl (scb->fd, TCGETA, &termio))
- return -1;
-
#ifndef CIBAUD
#define CIBAUD CBAUD
#endif
- termio.c_cflag &= ~(CBAUD | CIBAUD);
- termio.c_cflag |= rate_to_code (rate);
-
- if (ioctl (scb->fd, TCSETA, &termio))
- return -1;
+ state.termio.c_cflag &= ~(CBAUD | CIBAUD);
+ state.termio.c_cflag |= rate_to_code (rate);
#endif
#ifdef HAVE_SGTTY
- struct sgttyb sgttyb;
-
- if (ioctl (scb->fd, TIOCGETP, &sgttyb))
- return -1;
-
- sgttyb.sg_ispeed = rate_to_code (rate);
- sgttyb.sg_ospeed = rate_to_code (rate);
-
- if (ioctl (scb->fd, TIOCSETP, &sgttyb))
- return -1;
+ state.sgttyb.sg_ispeed = rate_to_code (rate);
+ state.sgttyb.sg_ospeed = rate_to_code (rate);
#endif
- return 0;
+
+ return set_tty_state (scb, &state);
}
static int
}
static void
-hardwire_restore(scb)
- serial_t scb;
-{
-}
-
-static void
hardwire_close(scb)
serial_t scb;
{
hardwire_readchar,
hardwire_write,
hardwire_raw,
- hardwire_restore,
- hardwire_setbaudrate
+ hardwire_get_tty_state,
+ hardwire_set_tty_state,
+ hardwire_setbaudrate,
};
void
#include "defs.h"
#include "serial.h"
-/* Open up a device or a network socket, depending upon the syntax of NAME. */
+/* Linked list of serial I/O handlers */
static struct serial_ops *serial_ops_list = NULL;
+/* This is the last serial stream opened. Used by connect command. */
+
+static serial_t last_serial_opened = NULL;
+
static struct serial_ops *
serial_interface_lookup (name)
char *name;
serial_ops_list = optable;
}
+/* Open up a device or a network socket, depending upon the syntax of NAME. */
+
serial_t
serial_open(name)
const char *name;
serial_t scb;
struct serial_ops *ops;
- ops = serial_interface_lookup ("hardwire");
+ if (strchr (name, ':'))
+ ops = serial_interface_lookup ("tcp");
+ else
+ ops = serial_interface_lookup ("hardwire");
if (!ops)
return NULL;
return NULL;
}
+ last_serial_opened = scb;
+
+ return scb;
+}
+
+serial_t
+serial_fdopen(fd)
+ const int fd;
+{
+ serial_t scb;
+ struct serial_ops *ops;
+
+ ops = serial_interface_lookup ("hardwire");
+
+ if (!ops)
+ return NULL;
+
+ scb = (serial_t)xmalloc (sizeof (struct _serial_t));
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ scb->fd = fd;
+
+ last_serial_opened = scb;
+
return scb;
}
serial_close(scb)
serial_t scb;
{
+ last_serial_opened = NULL;
+
scb->ops->close(scb);
free(scb);
}
#if 0
+
/* Connect the user directly to the remote system. This command acts just like
the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
+static serial_t tty_desc; /* Controlling terminal */
+
static void
cleanup_tty(ttystate)
- struct ttystate ttystate;
+ serial_ttystate ttystate;
{
- printf("\r\n[Exiting connect mode]\r\n");
- serial_restore(0, &ttystate);
+ printf ("\r\n[Exiting connect mode]\r\n");
+ SERIAL_SET_TTY_STATE (tty_desc, ttystate);
+ free (ttystate);
+ SERIAL_CLOSE (tty_desc);
}
static void
char *args;
int fromtty;
{
- fd_set readfds;
- int numfds;
int c;
char cur_esc = 0;
- static struct ttystate ttystate;
+ serial_ttystate ttystate;
+ serial_t port_desc; /* TTY port */
dont_repeat();
- if (desc < 0)
- error("target not open.");
-
if (args)
- fprintf("This command takes no args. They have been ignored.\n");
+ fprintf(stderr, "This command takes no args. They have been ignored.\n");
printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
- serial_raw(0, &ttystate);
+ tty_desc = SERIAL_FDOPEN (0);
+ port_desc = last_serial_opened;
- make_cleanup(cleanup_tty, &ttystate);
+ ttystate = SERIAL_GET_TTY_STATE (tty_desc);
- FD_ZERO(&readfds);
+ SERIAL_RAW (tty_desc);
+ SERIAL_RAW (port_desc);
+
+ make_cleanup (cleanup_tty, ttystate);
while (1)
{
- do
- {
- FD_SET(0, &readfds);
- FD_SET(desc, &readfds);
- numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
- }
- while (numfds == 0);
+ int mask;
- if (numfds < 0)
- perror_with_name("select");
+ mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
- if (FD_ISSET(0, &readfds))
- { /* tty input, send to stdebug */
+ if (mask & 2)
+ { /* tty input */
char cx;
- c = serial_readchar(-1);
- if (c < 0)
- perror_with_name("connect");
-
- cx = c;
- serial_write(&cx, 1);
- switch (cur_esc)
+ while (1)
{
- case 0:
- if (c == '\r')
- cur_esc = c;
- break;
- case '\r':
- if (c == '~')
- cur_esc = c;
- else
- cur_esc = 0;
- break;
- case '~':
- if (c == '.' || c == '\004')
- return;
- else
- cur_esc = 0;
+ c = SERIAL_READCHAR(tty_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name("connect");
+
+ cx = c;
+ SERIAL_WRITE(port_desc, &cx, 1);
+
+ switch (cur_esc)
+ {
+ case 0:
+ if (c == '\r')
+ cur_esc = c;
+ break;
+ case '\r':
+ if (c == '~')
+ cur_esc = c;
+ else
+ cur_esc = 0;
+ break;
+ case '~':
+ if (c == '.' || c == '\004')
+ return;
+ else
+ cur_esc = 0;
+ }
}
}
- if (FD_ISSET(desc, &readfds))
- {
+ if (mask & 1)
+ { /* Port input */
+ char cx;
+
while (1)
{
- c = serial_readchar(-1);
+ c = SERIAL_READCHAR(port_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
if (c < 0)
- break;
- putchar(c);
+ perror_with_name("connect");
+
+ cx = c;
+
+ SERIAL_WRITE(tty_desc, &cx, 1);
}
- fflush(stdout);
}
}
}
-#endif
-#if 0
void
_initialize_serial ()
{
"Connect the terminal directly up to the command monitor.\n\
Use <CR>~. or <CR>~^D to break out.");
}
-#endif
+#endif /* 0 */
/* Terminal state pointer. This is specific to each type of interface. */
-typedef PTR ttystate;
+typedef PTR serial_ttystate;
struct _serial_t
{
int fd; /* File descriptor */
struct serial_ops *ops; /* Function vector */
- ttystate ttystate; /* Not used (yet) */
+ serial_ttystate ttystate; /* Not used (yet) */
int bufcnt; /* Amount of data in receive buffer */
unsigned char *bufp; /* Current byte */
unsigned char buf[BUFSIZ]; /* Da buffer itself */
int (*readchar) PARAMS ((serial_t, int timeout));
int (*write) PARAMS ((serial_t, const char *str, int len));
void (*go_raw) PARAMS ((serial_t));
- void (*restore) PARAMS ((serial_t));
+ serial_ttystate (*get_tty_state) PARAMS ((serial_t));
+ int (*set_tty_state) PARAMS ((serial_t, serial_ttystate));
int (*setbaudrate) PARAMS ((serial_t, int rate));
};
serial_t serial_open PARAMS ((const char *name));
+serial_t serial_fdopen PARAMS ((int fd));
+
/* For most routines, if a failure is indicated, then errno should be
examined. */
#define SERIAL_OPEN(NAME) serial_open(NAME)
+/* Open a new serial stream using a file handle. */
+
+#define SERIAL_FDOPEN(FD) serial_fdopen(FD)
+
/* Turn the port into raw mode. */
#define SERIAL_RAW(SERIAL_T) (SERIAL_T)->ops->go_raw((SERIAL_T))
+#define SERIAL_GET_TTY_STATE(SERIAL_T) (SERIAL_T)->ops->get_tty_state((SERIAL_T))
+
+#define SERIAL_SET_TTY_STATE(SERIAL_T, TTYSTATE) (SERIAL_T)->ops->set_tty_state((SERIAL_T), (TTYSTATE))
+
/* Read one char from the serial device with TIMEOUT seconds timeout.
Returns char if ok, else one of the following codes. Note that all
error codes are guaranteed to be < 0. */
#define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T)
-/* Restore the serial port to the state saved in oldstate. XXX - currently
- unused! */
-
-#define SERIAL_RESTORE(SERIAL_T) (SERIAL_T)->ops->restore((SERIAL_T))