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