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