import gdb-1999-09-21
[external/binutils.git] / gdb / serial.c
1 /* Generic serial interface routines
2    Copyright 1992, 1993, 1996, 1997, 1999 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 (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 (char *);
48 static void serial_logchar (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
58 static int serial_current_type = 0;
59
60 /* Log char CH of type CHTYPE, with TIMEOUT */
61
62 /* Define bogus char to represent a BREAK.  Should be careful to choose a value
63    that can't be confused with a normal char, or an error code.  */
64 #define SERIAL_BREAK 1235
65
66 static void
67 serial_logchar (int ch_type, int ch, int timeout)
68 {
69   if (ch_type != serial_current_type)
70     {
71       fprintf_unfiltered (serial_logfp, "\n%c ", ch_type);
72       serial_current_type = ch_type;
73     }
74
75   if (serial_logbase != logbase_ascii)
76     fputc_unfiltered (' ', serial_logfp);
77
78   switch (ch)
79     {
80     case SERIAL_TIMEOUT:
81       fprintf_unfiltered (serial_logfp, "<Timeout: %d seconds>", timeout);
82       return;
83     case SERIAL_ERROR:
84       fprintf_unfiltered (serial_logfp, "<Error: %s>", safe_strerror (errno));
85       return;
86     case SERIAL_EOF:
87       fputs_unfiltered ("<Eof>", serial_logfp);
88       return;
89     case SERIAL_BREAK:
90       fputs_unfiltered ("<Break>", serial_logfp);
91       return;
92     default:
93       if (serial_logbase == logbase_hex)
94         fprintf_unfiltered (serial_logfp, "%02x", ch & 0xff);
95       else if (serial_logbase == logbase_octal)
96         fprintf_unfiltered (serial_logfp, "%03o", ch & 0xff);
97       else
98         switch (ch)
99           {
100           case '\\':
101             fputs_unfiltered ("\\\\", serial_logfp);
102             break;
103           case '\b':
104             fputs_unfiltered ("\\b", serial_logfp);
105             break;
106           case '\f':
107             fputs_unfiltered ("\\f", serial_logfp);
108             break;
109           case '\n':
110             fputs_unfiltered ("\\n", serial_logfp);
111             break;
112           case '\r':
113             fputs_unfiltered ("\\r", serial_logfp);
114             break;
115           case '\t':
116             fputs_unfiltered ("\\t", serial_logfp);
117             break;
118           case '\v':
119             fputs_unfiltered ("\\v", serial_logfp);
120             break;
121           default:
122             fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF);
123             break;
124           }
125     }
126 }
127
128 void
129 serial_log_command (const char *cmd)
130 {
131   if (!serial_logfp)
132     return;
133
134   serial_current_type = 'c';
135
136   fputs_unfiltered ("\nc ", serial_logfp);
137   fputs_unfiltered (cmd, serial_logfp);
138
139   /* Make sure that the log file is as up-to-date as possible,
140      in case we are getting ready to dump core or something. */
141   gdb_flush (serial_logfp);
142 }
143
144 \f
145 static struct serial_ops *
146 serial_interface_lookup (char *name)
147 {
148   struct serial_ops *ops;
149
150   for (ops = serial_ops_list; ops; ops = ops->next)
151     if (strcmp (name, ops->name) == 0)
152       return ops;
153
154   return NULL;
155 }
156
157 void
158 serial_add_interface (struct serial_ops *optable)
159 {
160   optable->next = serial_ops_list;
161   serial_ops_list = optable;
162 }
163
164 /* Open up a device or a network socket, depending upon the syntax of NAME. */
165
166 serial_t
167 serial_open (const char *name)
168 {
169   serial_t scb;
170   struct serial_ops *ops;
171   const char *open_name = name;
172
173   for (scb = scb_base; scb; scb = scb->next)
174     if (scb->name && strcmp (scb->name, name) == 0)
175       {
176         scb->refcnt++;
177         return scb;
178       }
179
180   if (strcmp (name, "ocd") == 0)
181     ops = serial_interface_lookup ("ocd");
182   else if (strcmp (name, "pc") == 0)
183     ops = serial_interface_lookup ("pc");
184   else if (strchr (name, ':'))
185     ops = serial_interface_lookup ("tcp");
186   else if (strncmp (name, "lpt", 3) == 0)
187     ops = serial_interface_lookup ("parallel");
188   else if (strncmp (name, "|", 1) == 0)
189     {
190       ops = serial_interface_lookup ("pipe");
191       open_name = name + 1; /* discard ``|'' */
192     }
193   else
194     ops = serial_interface_lookup ("hardwire");
195
196   if (!ops)
197     return NULL;
198
199   scb = (serial_t) xmalloc (sizeof (struct _serial_t));
200
201   scb->ops = ops;
202
203   scb->bufcnt = 0;
204   scb->bufp = scb->buf;
205
206   if (scb->ops->open (scb, open_name))
207     {
208       free (scb);
209       return NULL;
210     }
211
212   scb->name = strsave (name);
213   scb->next = scb_base;
214   scb->refcnt = 1;
215   scb->async_handler = NULL;
216   scb->async_context = NULL;
217   scb_base = scb;
218
219   last_serial_opened = scb;
220
221   if (serial_logfile != NULL)
222     {
223       serial_logfp = gdb_fopen (serial_logfile, "w");
224       if (serial_logfp == NULL)
225         perror_with_name (serial_logfile);
226     }
227
228   return scb;
229 }
230
231 serial_t
232 serial_fdopen (const int fd)
233 {
234   serial_t scb;
235   struct serial_ops *ops;
236
237   for (scb = scb_base; scb; scb = scb->next)
238     if (scb->fd == fd)
239       {
240         scb->refcnt++;
241         return scb;
242       }
243
244   ops = serial_interface_lookup ("hardwire");
245
246   if (!ops)
247     return NULL;
248
249   scb = (serial_t) xmalloc (sizeof (struct _serial_t));
250
251   scb->ops = ops;
252
253   scb->bufcnt = 0;
254   scb->bufp = scb->buf;
255
256   scb->fd = fd;
257
258   scb->name = NULL;
259   scb->next = scb_base;
260   scb->refcnt = 1;
261   scb->async_handler = NULL;
262   scb->async_context = NULL;
263   scb_base = scb;
264
265   last_serial_opened = scb;
266
267   return scb;
268 }
269
270 static void
271 do_serial_close (serial_t scb, int really_close)
272 {
273   serial_t tmp_scb;
274
275   last_serial_opened = NULL;
276
277   if (serial_logfp)
278     {
279       fputs_unfiltered ("\nEnd of log\n", serial_logfp);
280       serial_current_type = 0;
281
282       /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
283       gdb_fclose (&serial_logfp);
284       serial_logfp = NULL;
285     }
286
287 /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
288    should fix your code instead.  */
289
290   if (!scb)
291     return;
292
293   scb->refcnt--;
294   if (scb->refcnt > 0)
295     return;
296
297   /* ensure that the FD has been taken out of async mode */
298   if (scb->async_handler != NULL)
299     serial_async (scb, NULL, NULL);
300
301   if (really_close)
302     scb->ops->close (scb);
303
304   if (scb->name)
305     free (scb->name);
306
307   if (scb_base == scb)
308     scb_base = scb_base->next;
309   else
310     for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
311       {
312         if (tmp_scb->next != scb)
313           continue;
314
315         tmp_scb->next = tmp_scb->next->next;
316         break;
317       }
318
319   free (scb);
320 }
321
322 void
323 serial_close (serial_t scb)
324 {
325   do_serial_close (scb, 1);
326 }
327
328 void
329 serial_un_fdopen (serial_t scb)
330 {
331   do_serial_close (scb, 0);
332 }
333
334 int
335 serial_readchar (serial_t scb, int timeout)
336 {
337   int ch;
338
339   ch = scb->ops->readchar (scb, timeout);
340   if (serial_logfp != NULL)
341     {
342       serial_logchar ('r', ch, timeout);
343
344       /* Make sure that the log file is as up-to-date as possible,
345          in case we are getting ready to dump core or something. */
346       gdb_flush (serial_logfp);
347     }
348
349   return (ch);
350 }
351
352 int
353 serial_write (serial_t scb, const char *str, int len)
354 {
355   if (serial_logfp != NULL)
356     {
357       int count;
358
359       for (count = 0; count < len; count++)
360         serial_logchar ('w', str[count] & 0xff, 0);
361
362       /* Make sure that the log file is as up-to-date as possible,
363          in case we are getting ready to dump core or something. */
364       gdb_flush (serial_logfp);
365     }
366
367   return (scb->ops->write (scb, str, len));
368 }
369
370 void
371 serial_printf (serial_t desc, const char *format,...)
372 {
373   va_list args;
374   char *buf;
375   va_start (args, format);
376
377   vasprintf (&buf, format, args);
378   SERIAL_WRITE (desc, buf, strlen (buf));
379
380   free (buf);
381   va_end (args);
382 }
383
384 int
385 serial_drain_output (serial_t scb)
386 {
387   return scb->ops->drain_output (scb);
388 }
389
390 int
391 serial_flush_output (serial_t scb)
392 {
393   return scb->ops->flush_output (scb);
394 }
395
396 int
397 serial_flush_input (serial_t scb)
398 {
399   return scb->ops->flush_input (scb);
400 }
401
402 int
403 serial_send_break (serial_t scb)
404 {
405   if (serial_logfp != NULL)
406     serial_logchar ('w', SERIAL_BREAK, 0);
407
408   return (scb->ops->send_break (scb));
409 }
410
411 void
412 serial_raw (serial_t scb)
413 {
414   scb->ops->go_raw (scb);
415 }
416
417 serial_ttystate
418 serial_get_tty_state (serial_t scb)
419 {
420   return scb->ops->get_tty_state (scb);
421 }
422
423 int
424 serial_set_tty_state (serial_t scb, serial_ttystate ttystate)
425 {
426   return scb->ops->set_tty_state (scb, ttystate);
427 }
428
429 void
430 serial_print_tty_state (serial_t scb,
431                         serial_ttystate ttystate,
432                         struct gdb_file *stream)
433 {
434   scb->ops->print_tty_state (scb, ttystate, stream);
435 }
436
437 int
438 serial_noflush_set_tty_state (serial_t scb,
439                               serial_ttystate new_ttystate,
440                               serial_ttystate old_ttystate)
441 {
442   return scb->ops->noflush_set_tty_state (scb, new_ttystate, old_ttystate);
443 }
444
445 int
446 serial_setbaudrate (serial_t scb, int rate)
447 {
448   return scb->ops->setbaudrate (scb, rate);
449 }
450
451 int
452 serial_setstopbits (serial_t scb, int num)
453 {
454   return scb->ops->setstopbits (scb, num);
455 }
456
457 int
458 serial_can_async_p (serial_t scb)
459 {
460   return (scb->ops->async != NULL);
461 }
462
463 int
464 serial_is_async_p (serial_t scb)
465 {
466   return (scb->ops->async != NULL) && (scb->async_handler != NULL);
467 }
468
469 void
470 serial_async (serial_t scb,
471               serial_event_ftype *handler,
472               void *context)
473 {
474   /* Only change mode if there is a need. */
475   if ((scb->async_handler == NULL)
476       != (handler == NULL))
477     scb->ops->async (scb, handler != NULL);
478   scb->async_handler = handler;
479   scb->async_context = context;
480 }
481
482 int
483 deprecated_serial_fd (serial_t scb)
484 {
485   /* FIXME: should this output a warning that deprecated code is being
486      called? */
487   if (scb->fd < 0)
488     {
489       internal_error ("serial: FD not valid");
490     }
491   return scb->fd; /* sigh */
492 }
493
494 #if 0
495 /*
496    The connect command is #if 0 because I hadn't thought of an elegant
497    way to wait for I/O on two serial_t's simultaneously.  Two solutions
498    came to mind:
499
500    1) Fork, and have have one fork handle the to user direction,
501    and have the other hand the to target direction.  This
502    obviously won't cut it for MSDOS.
503
504    2) Use something like select.  This assumes that stdin and
505    the target side can both be waited on via the same
506    mechanism.  This may not be true for DOS, if GDB is
507    talking to the target via a TCP socket.
508    -grossman, 8 Jun 93
509  */
510
511 /* Connect the user directly to the remote system.  This command acts just like
512    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
513
514 static serial_t tty_desc;       /* Controlling terminal */
515
516 static void
517 cleanup_tty (serial_ttystate ttystate)
518 {
519   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
520   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
521   free (ttystate);
522   SERIAL_CLOSE (tty_desc);
523 }
524
525 static void
526 connect_command (char *args, int fromtty)
527 {
528   int c;
529   char cur_esc = 0;
530   serial_ttystate ttystate;
531   serial_t port_desc;           /* TTY port */
532
533   dont_repeat ();
534
535   if (args)
536     fprintf_unfiltered (gdb_stderr, "This command takes no args.  They have been ignored.\n");
537
538   printf_unfiltered ("[Entering connect mode.  Use ~. or ~^D to escape]\n");
539
540   tty_desc = SERIAL_FDOPEN (0);
541   port_desc = last_serial_opened;
542
543   ttystate = SERIAL_GET_TTY_STATE (tty_desc);
544
545   SERIAL_RAW (tty_desc);
546   SERIAL_RAW (port_desc);
547
548   make_cleanup (cleanup_tty, ttystate);
549
550   while (1)
551     {
552       int mask;
553
554       mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
555
556       if (mask & 2)
557         {                       /* tty input */
558           char cx;
559
560           while (1)
561             {
562               c = SERIAL_READCHAR (tty_desc, 0);
563
564               if (c == SERIAL_TIMEOUT)
565                 break;
566
567               if (c < 0)
568                 perror_with_name ("connect");
569
570               cx = c;
571               SERIAL_WRITE (port_desc, &cx, 1);
572
573               switch (cur_esc)
574                 {
575                 case 0:
576                   if (c == '\r')
577                     cur_esc = c;
578                   break;
579                 case '\r':
580                   if (c == '~')
581                     cur_esc = c;
582                   else
583                     cur_esc = 0;
584                   break;
585                 case '~':
586                   if (c == '.' || c == '\004')
587                     return;
588                   else
589                     cur_esc = 0;
590                 }
591             }
592         }
593
594       if (mask & 1)
595         {                       /* Port input */
596           char cx;
597
598           while (1)
599             {
600               c = SERIAL_READCHAR (port_desc, 0);
601
602               if (c == SERIAL_TIMEOUT)
603                 break;
604
605               if (c < 0)
606                 perror_with_name ("connect");
607
608               cx = c;
609
610               SERIAL_WRITE (tty_desc, &cx, 1);
611             }
612         }
613     }
614 }
615 #endif /* 0 */
616
617 void
618 _initialize_serial (void)
619 {
620 #if 0
621   add_com ("connect", class_obscure, connect_command,
622            "Connect the terminal directly up to the command monitor.\n\
623 Use <CR>~. or <CR>~^D to break out.");
624 #endif /* 0 */
625
626   add_show_from_set
627     (add_set_cmd ("remotelogfile", no_class,
628                   var_filename, (char *) &serial_logfile,
629                   "Set filename for remote session recording.\n\
630 This file is used to record the remote session for future playback\n\
631 by gdbserver.",
632                   &setlist),
633      &showlist);
634
635   add_show_from_set
636     (add_set_enum_cmd ("remotelogbase", no_class,
637                        logbase_enums, (char *) &serial_logbase,
638                        "Set numerical base for remote session logging",
639                        &setlist),
640      &showlist);
641 }