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