serial.c revision 46283
119370Spst/* Generic serial interface routines
246283Sdfr   Copyright 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
319370Spst
419370SpstThis file is part of GDB.
519370Spst
619370SpstThis program is free software; you can redistribute it and/or modify
719370Spstit under the terms of the GNU General Public License as published by
819370Spstthe Free Software Foundation; either version 2 of the License, or
919370Spst(at your option) any later version.
1019370Spst
1119370SpstThis program is distributed in the hope that it will be useful,
1219370Spstbut WITHOUT ANY WARRANTY; without even the implied warranty of
1319370SpstMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1419370SpstGNU General Public License for more details.
1519370Spst
1619370SpstYou should have received a copy of the GNU General Public License
1719370Spstalong with this program; if not, write to the Free Software
1819370SpstFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1919370Spst
2019370Spst#include "defs.h"
2119370Spst#include <ctype.h>
2219370Spst#include "serial.h"
2319370Spst#include "gdb_string.h"
2419370Spst#include "gdbcmd.h"
2519370Spst
2619370Spst/* Linked list of serial I/O handlers */
2719370Spst
2819370Spststatic struct serial_ops *serial_ops_list = NULL;
2919370Spst
3019370Spst/* This is the last serial stream opened.  Used by connect command. */
3119370Spst
3219370Spststatic serial_t last_serial_opened = NULL;
3319370Spst
3419370Spst/* Pointer to list of scb's. */
3519370Spst
3619370Spststatic serial_t scb_base;
3719370Spst
3819370Spst/* Non-NULL gives filename which contains a recording of the remote session,
3919370Spst   suitable for playback by gdbserver. */
4019370Spst
4146283Sdfrstatic char *serial_logfile = NULL;
4246283Sdfrstatic GDB_FILE *serial_logfp = NULL;
4319370Spst
4446283Sdfrstatic struct serial_ops *serial_interface_lookup PARAMS ((char *));
4546283Sdfrstatic void serial_logchar PARAMS ((int, int, int));
4646283Sdfrstatic char logbase_hex[] = "hex";
4746283Sdfrstatic char logbase_octal[] = "octal";
4846283Sdfrstatic char logbase_ascii[] = "ascii";
4946283Sdfrstatic char *logbase_enums[] = {logbase_hex, logbase_octal, logbase_ascii, NULL};
5046283Sdfrstatic char *serial_logbase = logbase_ascii;
5146283Sdfr
5219370Spst
5346283Sdfrstatic int serial_current_type = 0;
5419370Spst
5546283Sdfr/* Log char CH of type CHTYPE, with TIMEOUT */
5646283Sdfr
5746283Sdfr/* Define bogus char to represent a BREAK.  Should be careful to choose a value
5846283Sdfr   that can't be confused with a normal char, or an error code.  */
5946283Sdfr#define SERIAL_BREAK 1235
6046283Sdfr
6146283Sdfrstatic void
6246283Sdfrserial_logchar (ch_type, ch, timeout)
6346283Sdfr     int ch_type;
6446283Sdfr     int ch;
6546283Sdfr     int timeout;
6619370Spst{
6746283Sdfr  if (ch_type != serial_current_type)
6819370Spst    {
6946283Sdfr      fprintf_unfiltered (serial_logfp, "\n%c ", ch_type);
7046283Sdfr      serial_current_type = ch_type;
7119370Spst    }
7219370Spst
7346283Sdfr  if (serial_logbase != logbase_ascii)
7446283Sdfr    fputc_unfiltered (' ', serial_logfp);
7546283Sdfr
7619370Spst  switch (ch)
7719370Spst    {
7846283Sdfr    case SERIAL_TIMEOUT:
7946283Sdfr      fprintf_unfiltered (serial_logfp, "<Timeout: %d seconds>", timeout);
8046283Sdfr      return;
8146283Sdfr    case SERIAL_ERROR:
8246283Sdfr      fprintf_unfiltered (serial_logfp, "<Error: %s>", safe_strerror (errno));
8346283Sdfr      return;
8446283Sdfr    case SERIAL_EOF:
8546283Sdfr      fputs_unfiltered ("<Eof>", serial_logfp);
8646283Sdfr      return;
8746283Sdfr    case SERIAL_BREAK:
8846283Sdfr      fputs_unfiltered ("<Break>", serial_logfp);
8946283Sdfr      return;
9046283Sdfr    default:
9146283Sdfr      if (serial_logbase == logbase_hex)
9246283Sdfr	fprintf_unfiltered (serial_logfp, "%02x", ch & 0xff);
9346283Sdfr      else if (serial_logbase == logbase_octal)
9446283Sdfr	fprintf_unfiltered (serial_logfp, "%03o", ch & 0xff);
9546283Sdfr      else
9646283Sdfr	switch (ch)
9746283Sdfr	  {
9846283Sdfr	  case '\\':	fputs_unfiltered ("\\\\", serial_logfp); break;
9946283Sdfr	  case '\b':	fputs_unfiltered ("\\b", serial_logfp); break;
10046283Sdfr	  case '\f':	fputs_unfiltered ("\\f", serial_logfp); break;
10146283Sdfr	  case '\n':	fputs_unfiltered ("\\n", serial_logfp); break;
10246283Sdfr	  case '\r':	fputs_unfiltered ("\\r", serial_logfp); break;
10346283Sdfr	  case '\t':	fputs_unfiltered ("\\t", serial_logfp); break;
10446283Sdfr	  case '\v':	fputs_unfiltered ("\\v", serial_logfp); break;
10546283Sdfr	  default:	fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break;
10646283Sdfr	  }
10719370Spst    }
10819370Spst}
10919370Spst
11046283Sdfrvoid
11146283Sdfrserial_log_command (cmd)
11246283Sdfr     const char *cmd;
11346283Sdfr{
11446283Sdfr  if (!serial_logfp)
11546283Sdfr    return;
11646283Sdfr
11746283Sdfr  serial_current_type = 'c';
11846283Sdfr
11946283Sdfr  fputs_unfiltered ("\nc ", serial_logfp);
12046283Sdfr  fputs_unfiltered (cmd, serial_logfp);
12146283Sdfr
12246283Sdfr  /* Make sure that the log file is as up-to-date as possible,
12346283Sdfr     in case we are getting ready to dump core or something. */
12446283Sdfr  gdb_flush (serial_logfp);
12546283Sdfr}
12646283Sdfr
12719370Spstint
12819370Spstserial_write (scb, str, len)
12919370Spst     serial_t scb;
13019370Spst     const char *str;
13119370Spst     int len;
13219370Spst{
13319370Spst  if (serial_logfp != NULL)
13419370Spst    {
13546283Sdfr      int count;
13646283Sdfr
13719370Spst      for (count = 0; count < len; count++)
13846283Sdfr	serial_logchar ('w', str[count] & 0xff, 0);
13946283Sdfr
14019370Spst      /* Make sure that the log file is as up-to-date as possible,
14119370Spst	 in case we are getting ready to dump core or something. */
14246283Sdfr      gdb_flush (serial_logfp);
14319370Spst    }
14446283Sdfr
14519370Spst  return (scb -> ops -> write (scb, str, len));
14619370Spst}
14719370Spst
14819370Spstint
14919370Spstserial_readchar (scb, timeout)
15019370Spst     serial_t scb;
15119370Spst     int timeout;
15219370Spst{
15319370Spst  int ch;
15419370Spst
15519370Spst  ch = scb -> ops -> readchar (scb, timeout);
15619370Spst  if (serial_logfp != NULL)
15719370Spst    {
15846283Sdfr      serial_logchar ('r', ch, timeout);
15946283Sdfr
16019370Spst      /* Make sure that the log file is as up-to-date as possible,
16119370Spst	 in case we are getting ready to dump core or something. */
16246283Sdfr      gdb_flush (serial_logfp);
16319370Spst    }
16446283Sdfr
16519370Spst  return (ch);
16619370Spst}
16719370Spst
16846283Sdfrint
16946283Sdfrserial_send_break (scb)
17046283Sdfr     serial_t scb;
17146283Sdfr{
17246283Sdfr  if (serial_logfp != NULL)
17346283Sdfr    serial_logchar ('w', SERIAL_BREAK, 0);
17446283Sdfr
17546283Sdfr  return (scb -> ops -> send_break (scb));
17646283Sdfr}
17746283Sdfr
17819370Spststatic struct serial_ops *
17919370Spstserial_interface_lookup (name)
18019370Spst     char *name;
18119370Spst{
18219370Spst  struct serial_ops *ops;
18319370Spst
18419370Spst  for (ops = serial_ops_list; ops; ops = ops->next)
18519370Spst    if (strcmp (name, ops->name) == 0)
18619370Spst      return ops;
18719370Spst
18819370Spst  return NULL;
18919370Spst}
19019370Spst
19119370Spstvoid
19219370Spstserial_add_interface(optable)
19319370Spst     struct serial_ops *optable;
19419370Spst{
19519370Spst  optable->next = serial_ops_list;
19619370Spst  serial_ops_list = optable;
19719370Spst}
19819370Spst
19919370Spst/* Open up a device or a network socket, depending upon the syntax of NAME. */
20019370Spst
20119370Spstserial_t
20219370Spstserial_open (name)
20319370Spst     const char *name;
20419370Spst{
20519370Spst  serial_t scb;
20619370Spst  struct serial_ops *ops;
20719370Spst
20819370Spst  for (scb = scb_base; scb; scb = scb->next)
20919370Spst    if (scb->name && strcmp (scb->name, name) == 0)
21019370Spst      {
21119370Spst	scb->refcnt++;
21219370Spst	return scb;
21319370Spst      }
21419370Spst
21546283Sdfr  if (strcmp (name, "ocd") == 0)
21646283Sdfr    ops = serial_interface_lookup ("ocd");
21746283Sdfr  else if (strcmp (name, "pc") == 0)
21819370Spst    ops = serial_interface_lookup ("pc");
21919370Spst  else if (strchr (name, ':'))
22019370Spst    ops = serial_interface_lookup ("tcp");
22119370Spst  else if (strncmp (name, "lpt", 3) == 0)
22219370Spst    ops = serial_interface_lookup ("parallel");
22319370Spst  else
22419370Spst    ops = serial_interface_lookup ("hardwire");
22519370Spst
22619370Spst  if (!ops)
22719370Spst    return NULL;
22819370Spst
22919370Spst  scb = (serial_t)xmalloc (sizeof (struct _serial_t));
23019370Spst
23119370Spst  scb->ops = ops;
23219370Spst
23319370Spst  scb->bufcnt = 0;
23419370Spst  scb->bufp = scb->buf;
23519370Spst
23619370Spst  if (scb->ops->open(scb, name))
23719370Spst    {
23819370Spst      free (scb);
23919370Spst      return NULL;
24019370Spst    }
24119370Spst
24219370Spst  scb->name = strsave (name);
24319370Spst  scb->next = scb_base;
24419370Spst  scb->refcnt = 1;
24519370Spst  scb_base = scb;
24619370Spst
24719370Spst  last_serial_opened = scb;
24819370Spst
24919370Spst  if (serial_logfile != NULL)
25019370Spst    {
25146283Sdfr      serial_logfp = gdb_fopen (serial_logfile, "w");
25219370Spst      if (serial_logfp == NULL)
25346283Sdfr	perror_with_name (serial_logfile);
25419370Spst    }
25519370Spst
25619370Spst  return scb;
25719370Spst}
25819370Spst
25919370Spstserial_t
26019370Spstserial_fdopen (fd)
26119370Spst     const int fd;
26219370Spst{
26319370Spst  serial_t scb;
26419370Spst  struct serial_ops *ops;
26519370Spst
26619370Spst  for (scb = scb_base; scb; scb = scb->next)
26719370Spst    if (scb->fd == fd)
26819370Spst      {
26919370Spst	scb->refcnt++;
27019370Spst	return scb;
27119370Spst      }
27219370Spst
27319370Spst  ops = serial_interface_lookup ("hardwire");
27419370Spst
27519370Spst  if (!ops)
27619370Spst    return NULL;
27719370Spst
27819370Spst  scb = (serial_t)xmalloc (sizeof (struct _serial_t));
27919370Spst
28019370Spst  scb->ops = ops;
28119370Spst
28219370Spst  scb->bufcnt = 0;
28319370Spst  scb->bufp = scb->buf;
28419370Spst
28519370Spst  scb->fd = fd;
28619370Spst
28719370Spst  scb->name = NULL;
28819370Spst  scb->next = scb_base;
28919370Spst  scb->refcnt = 1;
29019370Spst  scb_base = scb;
29119370Spst
29219370Spst  last_serial_opened = scb;
29319370Spst
29419370Spst  return scb;
29519370Spst}
29619370Spst
29719370Spstvoid
29846283Sdfrserial_close (scb, really_close)
29919370Spst     serial_t scb;
30019370Spst     int really_close;
30119370Spst{
30219370Spst  serial_t tmp_scb;
30319370Spst
30419370Spst  last_serial_opened = NULL;
30519370Spst
30619370Spst  if (serial_logfp)
30719370Spst    {
30846283Sdfr      fputs_unfiltered ("\nEnd of log\n", serial_logfp);
30946283Sdfr      serial_current_type = 0;
31046283Sdfr
31146283Sdfr      /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
31246283Sdfr      gdb_fclose (&serial_logfp);
31319370Spst      serial_logfp = NULL;
31419370Spst    }
31519370Spst
31619370Spst/* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
31719370Spst   should fix your code instead.  */
31819370Spst
31919370Spst  if (!scb)
32019370Spst    return;
32119370Spst
32219370Spst  scb->refcnt--;
32319370Spst  if (scb->refcnt > 0)
32419370Spst    return;
32519370Spst
32619370Spst  if (really_close)
32719370Spst    scb->ops->close (scb);
32819370Spst
32919370Spst  if (scb->name)
33019370Spst    free (scb->name);
33119370Spst
33219370Spst  if (scb_base == scb)
33319370Spst    scb_base = scb_base->next;
33419370Spst  else
33519370Spst    for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
33619370Spst      {
33719370Spst	if (tmp_scb->next != scb)
33819370Spst	  continue;
33919370Spst
34019370Spst	tmp_scb->next = tmp_scb->next->next;
34119370Spst	break;
34219370Spst      }
34319370Spst
34419370Spst  free(scb);
34519370Spst}
34619370Spst
34719370Spst#if 0
34819370Spst/*
34919370SpstThe connect command is #if 0 because I hadn't thought of an elegant
35019370Spstway to wait for I/O on two serial_t's simultaneously.  Two solutions
35119370Spstcame to mind:
35219370Spst
35319370Spst	1) Fork, and have have one fork handle the to user direction,
35419370Spst	   and have the other hand the to target direction.  This
35519370Spst	   obviously won't cut it for MSDOS.
35619370Spst
35719370Spst	2) Use something like select.  This assumes that stdin and
35819370Spst	   the target side can both be waited on via the same
35919370Spst	   mechanism.  This may not be true for DOS, if GDB is
36019370Spst	   talking to the target via a TCP socket.
36119370Spst-grossman, 8 Jun 93
36219370Spst*/
36319370Spst
36419370Spst/* Connect the user directly to the remote system.  This command acts just like
36519370Spst   the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
36619370Spst
36719370Spststatic serial_t tty_desc;		/* Controlling terminal */
36819370Spst
36919370Spststatic void
37019370Spstcleanup_tty(ttystate)
37119370Spst     serial_ttystate ttystate;
37219370Spst{
37319370Spst  printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
37419370Spst  SERIAL_SET_TTY_STATE (tty_desc, ttystate);
37519370Spst  free (ttystate);
37619370Spst  SERIAL_CLOSE (tty_desc);
37719370Spst}
37819370Spst
37919370Spststatic void
38019370Spstconnect_command (args, fromtty)
38119370Spst     char	*args;
38219370Spst     int	fromtty;
38319370Spst{
38419370Spst  int c;
38519370Spst  char cur_esc = 0;
38619370Spst  serial_ttystate ttystate;
38719370Spst  serial_t port_desc;		/* TTY port */
38819370Spst
38919370Spst  dont_repeat();
39019370Spst
39119370Spst  if (args)
39219370Spst    fprintf_unfiltered(gdb_stderr, "This command takes no args.  They have been ignored.\n");
39319370Spst
39419370Spst  printf_unfiltered("[Entering connect mode.  Use ~. or ~^D to escape]\n");
39519370Spst
39619370Spst  tty_desc = SERIAL_FDOPEN (0);
39719370Spst  port_desc = last_serial_opened;
39819370Spst
39919370Spst  ttystate = SERIAL_GET_TTY_STATE (tty_desc);
40019370Spst
40119370Spst  SERIAL_RAW (tty_desc);
40219370Spst  SERIAL_RAW (port_desc);
40319370Spst
40419370Spst  make_cleanup (cleanup_tty, ttystate);
40519370Spst
40619370Spst  while (1)
40719370Spst    {
40819370Spst      int mask;
40919370Spst
41019370Spst      mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
41119370Spst
41219370Spst      if (mask & 2)
41319370Spst	{			/* tty input */
41419370Spst	  char cx;
41519370Spst
41619370Spst	  while (1)
41719370Spst	    {
41819370Spst	      c = SERIAL_READCHAR(tty_desc, 0);
41919370Spst
42019370Spst	      if (c == SERIAL_TIMEOUT)
42119370Spst		  break;
42219370Spst
42319370Spst	      if (c < 0)
42419370Spst		perror_with_name("connect");
42519370Spst
42619370Spst	      cx = c;
42719370Spst	      SERIAL_WRITE(port_desc, &cx, 1);
42819370Spst
42919370Spst	      switch (cur_esc)
43019370Spst		{
43119370Spst		case 0:
43219370Spst		  if (c == '\r')
43319370Spst		    cur_esc = c;
43419370Spst		  break;
43519370Spst		case '\r':
43619370Spst		  if (c == '~')
43719370Spst		    cur_esc = c;
43819370Spst		  else
43919370Spst		    cur_esc = 0;
44019370Spst		  break;
44119370Spst		case '~':
44219370Spst		  if (c == '.' || c == '\004')
44319370Spst		    return;
44419370Spst		  else
44519370Spst		    cur_esc = 0;
44619370Spst		}
44719370Spst	    }
44819370Spst	}
44919370Spst
45019370Spst      if (mask & 1)
45119370Spst	{			/* Port input */
45219370Spst	  char cx;
45319370Spst
45419370Spst	  while (1)
45519370Spst	    {
45619370Spst	      c = SERIAL_READCHAR(port_desc, 0);
45719370Spst
45819370Spst	      if (c == SERIAL_TIMEOUT)
45919370Spst		  break;
46019370Spst
46119370Spst	      if (c < 0)
46219370Spst		perror_with_name("connect");
46319370Spst
46419370Spst	      cx = c;
46519370Spst
46619370Spst	      SERIAL_WRITE(tty_desc, &cx, 1);
46719370Spst	    }
46819370Spst	}
46919370Spst    }
47019370Spst}
47119370Spst#endif /* 0 */
47219370Spst
47319370Spst/* VARARGS */
47419370Spstvoid
47519370Spst#ifdef ANSI_PROTOTYPES
47619370Spstserial_printf (serial_t desc, const char *format, ...)
47719370Spst#else
47819370Spstserial_printf (va_alist)
47919370Spst     va_dcl
48019370Spst#endif
48119370Spst{
48219370Spst  va_list args;
48319370Spst  char *buf;
48419370Spst#ifdef ANSI_PROTOTYPES
48519370Spst  va_start (args, format);
48619370Spst#else
48719370Spst  serial_t desc;
48819370Spst  char *format;
48919370Spst
49019370Spst  va_start (args);
49119370Spst  desc = va_arg (args, serial_t);
49219370Spst  format = va_arg (args, char *);
49319370Spst#endif
49419370Spst
49519370Spst  vasprintf (&buf, format, args);
49619370Spst  SERIAL_WRITE (desc, buf, strlen (buf));
49719370Spst
49819370Spst  free (buf);
49919370Spst  va_end (args);
50019370Spst}
50119370Spst
50219370Spstvoid
50319370Spst_initialize_serial ()
50419370Spst{
50519370Spst#if 0
50619370Spst  add_com ("connect", class_obscure, connect_command,
50719370Spst	   "Connect the terminal directly up to the command monitor.\n\
50819370SpstUse <CR>~. or <CR>~^D to break out.");
50919370Spst#endif /* 0 */
51019370Spst
51146283Sdfr  add_show_from_set
51246283Sdfr    (add_set_cmd ("remotelogfile", no_class,
51346283Sdfr		  var_filename, (char *) &serial_logfile,
51446283Sdfr		  "Set filename for remote session recording.\n\
51519370SpstThis file is used to record the remote session for future playback\n\
51646283Sdfrby gdbserver.",
51746283Sdfr		  &setlist),
51846283Sdfr     &showlist);
51919370Spst
52046283Sdfr  add_show_from_set
52146283Sdfr    (add_set_enum_cmd ("remotelogbase", no_class,
52246283Sdfr		       logbase_enums, (char *) &serial_logbase,
52346283Sdfr		       "Set numerical base for remote session logging",
52446283Sdfr		       &setlist),
52546283Sdfr     &showlist);
52619370Spst}
527