import gdb-1999-07-12 snapshot
[platform/upstream/binutils.git] / gdb / serial.c
1 /* Generic serial interface routines
2    Copyright 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include "defs.h"
22 #include <ctype.h>
23 #include "serial.h"
24 #include "gdb_string.h"
25 #include "gdbcmd.h"
26
27 extern void _initialize_serial PARAMS ((void));
28
29 /* Linked list of serial I/O handlers */
30
31 static struct serial_ops *serial_ops_list = NULL;
32
33 /* This is the last serial stream opened.  Used by connect command. */
34
35 static serial_t last_serial_opened = NULL;
36
37 /* Pointer to list of scb's. */
38
39 static serial_t scb_base;
40
41 /* Non-NULL gives filename which contains a recording of the remote session,
42    suitable for playback by gdbserver. */
43
44 static char *serial_logfile = NULL;
45 static GDB_FILE *serial_logfp = NULL;
46
47 static struct serial_ops *serial_interface_lookup PARAMS ((char *));
48 static void serial_logchar PARAMS ((int, int, int));
49 static char logbase_hex[] = "hex";
50 static char logbase_octal[] = "octal";
51 static char logbase_ascii[] = "ascii";
52 static char *logbase_enums[] =
53 {logbase_hex, logbase_octal, logbase_ascii, NULL};
54 static char *serial_logbase = logbase_ascii;
55 \f
56
57 static int serial_current_type = 0;
58
59 /* Log char CH of type CHTYPE, with TIMEOUT */
60
61 /* Define bogus char to represent a BREAK.  Should be careful to choose a value
62    that can't be confused with a normal char, or an error code.  */
63 #define SERIAL_BREAK 1235
64
65 static void
66 serial_logchar (ch_type, ch, timeout)
67      int ch_type;
68      int ch;
69      int timeout;
70 {
71   if (ch_type != serial_current_type)
72     {
73       fprintf_unfiltered (serial_logfp, "\n%c ", ch_type);
74       serial_current_type = ch_type;
75     }
76
77   if (serial_logbase != logbase_ascii)
78     fputc_unfiltered (' ', serial_logfp);
79
80   switch (ch)
81     {
82     case SERIAL_TIMEOUT:
83       fprintf_unfiltered (serial_logfp, "<Timeout: %d seconds>", timeout);
84       return;
85     case SERIAL_ERROR:
86       fprintf_unfiltered (serial_logfp, "<Error: %s>", safe_strerror (errno));
87       return;
88     case SERIAL_EOF:
89       fputs_unfiltered ("<Eof>", serial_logfp);
90       return;
91     case SERIAL_BREAK:
92       fputs_unfiltered ("<Break>", serial_logfp);
93       return;
94     default:
95       if (serial_logbase == logbase_hex)
96         fprintf_unfiltered (serial_logfp, "%02x", ch & 0xff);
97       else if (serial_logbase == logbase_octal)
98         fprintf_unfiltered (serial_logfp, "%03o", ch & 0xff);
99       else
100         switch (ch)
101           {
102           case '\\':
103             fputs_unfiltered ("\\\\", serial_logfp);
104             break;
105           case '\b':
106             fputs_unfiltered ("\\b", serial_logfp);
107             break;
108           case '\f':
109             fputs_unfiltered ("\\f", serial_logfp);
110             break;
111           case '\n':
112             fputs_unfiltered ("\\n", serial_logfp);
113             break;
114           case '\r':
115             fputs_unfiltered ("\\r", serial_logfp);
116             break;
117           case '\t':
118             fputs_unfiltered ("\\t", serial_logfp);
119             break;
120           case '\v':
121             fputs_unfiltered ("\\v", serial_logfp);
122             break;
123           default:
124             fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF);
125             break;
126           }
127     }
128 }
129
130 void
131 serial_log_command (cmd)
132      const char *cmd;
133 {
134   if (!serial_logfp)
135     return;
136
137   serial_current_type = 'c';
138
139   fputs_unfiltered ("\nc ", serial_logfp);
140   fputs_unfiltered (cmd, serial_logfp);
141
142   /* Make sure that the log file is as up-to-date as possible,
143      in case we are getting ready to dump core or something. */
144   gdb_flush (serial_logfp);
145 }
146
147 int
148 serial_write (scb, str, len)
149      serial_t scb;
150      const char *str;
151      int len;
152 {
153   if (serial_logfp != NULL)
154     {
155       int count;
156
157       for (count = 0; count < len; count++)
158         serial_logchar ('w', str[count] & 0xff, 0);
159
160       /* Make sure that the log file is as up-to-date as possible,
161          in case we are getting ready to dump core or something. */
162       gdb_flush (serial_logfp);
163     }
164
165   return (scb->ops->write (scb, str, len));
166 }
167
168 int
169 serial_readchar (scb, timeout)
170      serial_t scb;
171      int timeout;
172 {
173   int ch;
174
175   ch = scb->ops->readchar (scb, timeout);
176   if (serial_logfp != NULL)
177     {
178       serial_logchar ('r', ch, timeout);
179
180       /* Make sure that the log file is as up-to-date as possible,
181          in case we are getting ready to dump core or something. */
182       gdb_flush (serial_logfp);
183     }
184
185   return (ch);
186 }
187
188 int
189 serial_send_break (scb)
190      serial_t scb;
191 {
192   if (serial_logfp != NULL)
193     serial_logchar ('w', SERIAL_BREAK, 0);
194
195   return (scb->ops->send_break (scb));
196 }
197
198 static struct serial_ops *
199 serial_interface_lookup (name)
200      char *name;
201 {
202   struct serial_ops *ops;
203
204   for (ops = serial_ops_list; ops; ops = ops->next)
205     if (strcmp (name, ops->name) == 0)
206       return ops;
207
208   return NULL;
209 }
210
211 void
212 serial_add_interface (optable)
213      struct serial_ops *optable;
214 {
215   optable->next = serial_ops_list;
216   serial_ops_list = optable;
217 }
218
219 /* Open up a device or a network socket, depending upon the syntax of NAME. */
220
221 serial_t
222 serial_open (name)
223      const char *name;
224 {
225   serial_t scb;
226   struct serial_ops *ops;
227
228   for (scb = scb_base; scb; scb = scb->next)
229     if (scb->name && strcmp (scb->name, name) == 0)
230       {
231         scb->refcnt++;
232         return scb;
233       }
234
235   if (strcmp (name, "ocd") == 0)
236     ops = serial_interface_lookup ("ocd");
237   else if (strcmp (name, "pc") == 0)
238     ops = serial_interface_lookup ("pc");
239   else if (strchr (name, ':'))
240     ops = serial_interface_lookup ("tcp");
241   else if (strncmp (name, "lpt", 3) == 0)
242     ops = serial_interface_lookup ("parallel");
243   else if (strncmp (name, "|", 1) == 0)
244     ops = serial_interface_lookup ("pipe");
245   else
246     ops = serial_interface_lookup ("hardwire");
247
248   if (!ops)
249     return NULL;
250
251   scb = (serial_t) xmalloc (sizeof (struct _serial_t));
252
253   scb->ops = ops;
254
255   scb->bufcnt = 0;
256   scb->bufp = scb->buf;
257
258   if (scb->ops->open (scb, name))
259     {
260       free (scb);
261       return NULL;
262     }
263
264   scb->name = strsave (name);
265   scb->next = scb_base;
266   scb->refcnt = 1;
267   scb_base = scb;
268
269   last_serial_opened = scb;
270
271   if (serial_logfile != NULL)
272     {
273       serial_logfp = gdb_fopen (serial_logfile, "w");
274       if (serial_logfp == NULL)
275         perror_with_name (serial_logfile);
276     }
277
278   return scb;
279 }
280
281 serial_t
282 serial_fdopen (fd)
283      const int fd;
284 {
285   serial_t scb;
286   struct serial_ops *ops;
287
288   for (scb = scb_base; scb; scb = scb->next)
289     if (scb->fd == fd)
290       {
291         scb->refcnt++;
292         return scb;
293       }
294
295   ops = serial_interface_lookup ("hardwire");
296
297   if (!ops)
298     return NULL;
299
300   scb = (serial_t) xmalloc (sizeof (struct _serial_t));
301
302   scb->ops = ops;
303
304   scb->bufcnt = 0;
305   scb->bufp = scb->buf;
306
307   scb->fd = fd;
308
309   scb->name = NULL;
310   scb->next = scb_base;
311   scb->refcnt = 1;
312   scb_base = scb;
313
314   last_serial_opened = scb;
315
316   return scb;
317 }
318
319 void
320 serial_close (scb, really_close)
321      serial_t scb;
322      int really_close;
323 {
324   serial_t tmp_scb;
325
326   last_serial_opened = NULL;
327
328   if (serial_logfp)
329     {
330       fputs_unfiltered ("\nEnd of log\n", serial_logfp);
331       serial_current_type = 0;
332
333       /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
334       gdb_fclose (&serial_logfp);
335       serial_logfp = NULL;
336     }
337
338 /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
339    should fix your code instead.  */
340
341   if (!scb)
342     return;
343
344   scb->refcnt--;
345   if (scb->refcnt > 0)
346     return;
347
348   if (really_close)
349     scb->ops->close (scb);
350
351   if (scb->name)
352     free (scb->name);
353
354   if (scb_base == scb)
355     scb_base = scb_base->next;
356   else
357     for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
358       {
359         if (tmp_scb->next != scb)
360           continue;
361
362         tmp_scb->next = tmp_scb->next->next;
363         break;
364       }
365
366   free (scb);
367 }
368
369 #if 0
370 /*
371    The connect command is #if 0 because I hadn't thought of an elegant
372    way to wait for I/O on two serial_t's simultaneously.  Two solutions
373    came to mind:
374
375    1) Fork, and have have one fork handle the to user direction,
376    and have the other hand the to target direction.  This
377    obviously won't cut it for MSDOS.
378
379    2) Use something like select.  This assumes that stdin and
380    the target side can both be waited on via the same
381    mechanism.  This may not be true for DOS, if GDB is
382    talking to the target via a TCP socket.
383    -grossman, 8 Jun 93
384  */
385
386 /* Connect the user directly to the remote system.  This command acts just like
387    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
388
389 static serial_t tty_desc;       /* Controlling terminal */
390
391 static void
392 cleanup_tty (ttystate)
393      serial_ttystate ttystate;
394 {
395   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
396   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
397   free (ttystate);
398   SERIAL_CLOSE (tty_desc);
399 }
400
401 static void
402 connect_command (args, fromtty)
403      char *args;
404      int fromtty;
405 {
406   int c;
407   char cur_esc = 0;
408   serial_ttystate ttystate;
409   serial_t port_desc;           /* TTY port */
410
411   dont_repeat ();
412
413   if (args)
414     fprintf_unfiltered (gdb_stderr, "This command takes no args.  They have been ignored.\n");
415
416   printf_unfiltered ("[Entering connect mode.  Use ~. or ~^D to escape]\n");
417
418   tty_desc = SERIAL_FDOPEN (0);
419   port_desc = last_serial_opened;
420
421   ttystate = SERIAL_GET_TTY_STATE (tty_desc);
422
423   SERIAL_RAW (tty_desc);
424   SERIAL_RAW (port_desc);
425
426   make_cleanup (cleanup_tty, ttystate);
427
428   while (1)
429     {
430       int mask;
431
432       mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
433
434       if (mask & 2)
435         {                       /* tty input */
436           char cx;
437
438           while (1)
439             {
440               c = SERIAL_READCHAR (tty_desc, 0);
441
442               if (c == SERIAL_TIMEOUT)
443                 break;
444
445               if (c < 0)
446                 perror_with_name ("connect");
447
448               cx = c;
449               SERIAL_WRITE (port_desc, &cx, 1);
450
451               switch (cur_esc)
452                 {
453                 case 0:
454                   if (c == '\r')
455                     cur_esc = c;
456                   break;
457                 case '\r':
458                   if (c == '~')
459                     cur_esc = c;
460                   else
461                     cur_esc = 0;
462                   break;
463                 case '~':
464                   if (c == '.' || c == '\004')
465                     return;
466                   else
467                     cur_esc = 0;
468                 }
469             }
470         }
471
472       if (mask & 1)
473         {                       /* Port input */
474           char cx;
475
476           while (1)
477             {
478               c = SERIAL_READCHAR (port_desc, 0);
479
480               if (c == SERIAL_TIMEOUT)
481                 break;
482
483               if (c < 0)
484                 perror_with_name ("connect");
485
486               cx = c;
487
488               SERIAL_WRITE (tty_desc, &cx, 1);
489             }
490         }
491     }
492 }
493 #endif /* 0 */
494
495 /* VARARGS */
496 void
497 #ifdef ANSI_PROTOTYPES
498 serial_printf (serial_t desc, const char *format,...)
499 #else
500 serial_printf (va_alist)
501      va_dcl
502 #endif
503 {
504   va_list args;
505   char *buf;
506 #ifdef ANSI_PROTOTYPES
507   va_start (args, format);
508 #else
509   serial_t desc;
510   char *format;
511
512   va_start (args);
513   desc = va_arg (args, serial_t);
514   format = va_arg (args, char *);
515 #endif
516
517   vasprintf (&buf, format, args);
518   SERIAL_WRITE (desc, buf, strlen (buf));
519
520   free (buf);
521   va_end (args);
522 }
523
524 void
525 _initialize_serial ()
526 {
527 #if 0
528   add_com ("connect", class_obscure, connect_command,
529            "Connect the terminal directly up to the command monitor.\n\
530 Use <CR>~. or <CR>~^D to break out.");
531 #endif /* 0 */
532
533   add_show_from_set
534     (add_set_cmd ("remotelogfile", no_class,
535                   var_filename, (char *) &serial_logfile,
536                   "Set filename for remote session recording.\n\
537 This file is used to record the remote session for future playback\n\
538 by gdbserver.",
539                   &setlist),
540      &showlist);
541
542   add_show_from_set
543     (add_set_enum_cmd ("remotelogbase", no_class,
544                        logbase_enums, (char *) &serial_logbase,
545                        "Set numerical base for remote session logging",
546                        &setlist),
547      &showlist);
548 }