]> Git Repo - binutils.git/blob - gdb/serial.c
* gdb.base/signals.exp (test_handle_all_print): Test separately for
[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 char *serial_logfile = NULL;
42 FILE *serial_logfp = NULL;
43
44 static struct serial_ops *serial_interface_lookup PARAMS ((char *));
45 static void serial_logchar PARAMS ((int));
46
47 \f
48 static int serial_reading = 0;
49 static int serial_writing = 0;
50
51 void
52 serial_log_command (cmd)
53      const char *cmd;
54 {
55   if (serial_reading || serial_writing)
56     {
57       fputc_unfiltered ('\n', serial_logfp);
58       serial_reading = 0;
59       serial_writing = 0;
60     }
61   fprintf_unfiltered (serial_logfp, "c %s\n", cmd);
62   /* Make sure that the log file is as up-to-date as possible,
63      in case we are getting ready to dump core or something. */
64   fflush (serial_logfp);
65 }
66
67 static void
68 serial_logchar (ch)
69      int ch;
70 {
71   switch (ch)
72     {
73     case '\\':  fputs_unfiltered ("\\\\", serial_logfp); break; 
74     case '\b':  fputs_unfiltered ("\\b", serial_logfp); break;  
75     case '\f':  fputs_unfiltered ("\\f", serial_logfp); break;  
76     case '\n':  fputs_unfiltered ("\\n", serial_logfp); break;  
77     case '\r':  fputs_unfiltered ("\\r", serial_logfp); break;  
78     case '\t':  fputs_unfiltered ("\\t", serial_logfp); break;  
79     case '\v':  fputs_unfiltered ("\\v", serial_logfp); break;  
80     default:    fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break;
81     }
82 }
83
84 int
85 serial_write (scb, str, len)
86      serial_t scb;
87      const char *str;
88      int len;
89 {
90   int count;
91
92   if (serial_logfp != NULL)
93     {
94       if (serial_reading)
95         {
96           fputc_unfiltered ('\n', serial_logfp);
97           serial_reading = 0;
98         }
99       if (!serial_writing)
100         {
101           serial_logchar ('w');
102           serial_logchar (' ');
103           serial_writing = 1;
104         }
105       for (count = 0; count < len; count++)
106         {
107           serial_logchar (str[count]);
108         }
109       /* Make sure that the log file is as up-to-date as possible,
110          in case we are getting ready to dump core or something. */
111       fflush (serial_logfp);
112     }
113   return (scb -> ops -> write (scb, str, len));
114 }
115
116 int
117 serial_readchar (scb, timeout)
118      serial_t scb;
119      int timeout;
120 {
121   int ch;
122
123   ch = scb -> ops -> readchar (scb, timeout);
124   if (serial_logfp != NULL)
125     {
126       if (serial_writing)
127         {
128           fputc_unfiltered ('\n', serial_logfp);
129           serial_writing = 0;
130         }
131       if (!serial_reading)
132         {
133           serial_logchar ('r');
134           serial_logchar (' ');
135           serial_reading = 1;
136         }
137       serial_logchar (ch);
138       /* Make sure that the log file is as up-to-date as possible,
139          in case we are getting ready to dump core or something. */
140       fflush (serial_logfp);
141     }
142   return (ch);
143 }
144
145 static struct serial_ops *
146 serial_interface_lookup (name)
147      char *name;
148 {
149   struct serial_ops *ops;
150
151   for (ops = serial_ops_list; ops; ops = ops->next)
152     if (strcmp (name, ops->name) == 0)
153       return ops;
154
155   return NULL;
156 }
157
158 void
159 serial_add_interface(optable)
160      struct serial_ops *optable;
161 {
162   optable->next = serial_ops_list;
163   serial_ops_list = optable;
164 }
165
166 /* Open up a device or a network socket, depending upon the syntax of NAME. */
167
168 serial_t
169 serial_open (name)
170      const char *name;
171 {
172   serial_t scb;
173   struct serial_ops *ops;
174
175   for (scb = scb_base; scb; scb = scb->next)
176     if (scb->name && strcmp (scb->name, name) == 0)
177       {
178         scb->refcnt++;
179         return scb;
180       }
181
182   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
189     ops = serial_interface_lookup ("hardwire");
190
191   if (!ops)
192     return NULL;
193
194   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
195
196   scb->ops = ops;
197
198   scb->bufcnt = 0;
199   scb->bufp = scb->buf;
200
201   if (scb->ops->open(scb, name))
202     {
203       free (scb);
204       return NULL;
205     }
206
207   scb->name = strsave (name);
208   scb->next = scb_base;
209   scb->refcnt = 1;
210   scb_base = scb;
211
212   last_serial_opened = scb;
213
214   if (serial_logfile != NULL)
215     {
216       serial_logfp = fopen (serial_logfile, "w");
217       if (serial_logfp == NULL)
218         {
219           perror_with_name (serial_logfile);
220         }
221     }
222
223   return scb;
224 }
225
226 serial_t
227 serial_fdopen (fd)
228      const int fd;
229 {
230   serial_t scb;
231   struct serial_ops *ops;
232
233   for (scb = scb_base; scb; scb = scb->next)
234     if (scb->fd == fd)
235       {
236         scb->refcnt++;
237         return scb;
238       }
239
240   ops = serial_interface_lookup ("hardwire");
241
242   if (!ops)
243     return NULL;
244
245   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
246
247   scb->ops = ops;
248
249   scb->bufcnt = 0;
250   scb->bufp = scb->buf;
251
252   scb->fd = fd;
253
254   scb->name = NULL;
255   scb->next = scb_base;
256   scb->refcnt = 1;
257   scb_base = scb;
258
259   last_serial_opened = scb;
260
261   return scb;
262 }
263
264 void
265 serial_close(scb, really_close)
266      serial_t scb;
267      int really_close;
268 {
269   serial_t tmp_scb;
270
271   last_serial_opened = NULL;
272
273   if (serial_logfp)
274     {
275       if (serial_reading || serial_writing)
276         {
277           fputc_unfiltered ('\n', serial_logfp);
278           serial_reading = 0;
279           serial_writing = 0;
280         }
281       fclose (serial_logfp);
282       serial_logfp = NULL;
283     }
284
285 /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
286    should fix your code instead.  */
287
288   if (!scb)
289     return;
290
291   scb->refcnt--;
292   if (scb->refcnt > 0)
293     return;
294
295   if (really_close)
296     scb->ops->close (scb);
297
298   if (scb->name)
299     free (scb->name);
300
301   if (scb_base == scb)
302     scb_base = scb_base->next;
303   else
304     for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
305       {
306         if (tmp_scb->next != scb)
307           continue;
308
309         tmp_scb->next = tmp_scb->next->next;
310         break;
311       }
312
313   free(scb);
314 }
315
316 #if 0
317 /*
318 The connect command is #if 0 because I hadn't thought of an elegant
319 way to wait for I/O on two serial_t's simultaneously.  Two solutions
320 came to mind:
321
322         1) Fork, and have have one fork handle the to user direction,
323            and have the other hand the to target direction.  This
324            obviously won't cut it for MSDOS.
325
326         2) Use something like select.  This assumes that stdin and
327            the target side can both be waited on via the same
328            mechanism.  This may not be true for DOS, if GDB is
329            talking to the target via a TCP socket.
330 -grossman, 8 Jun 93
331 */
332
333 /* Connect the user directly to the remote system.  This command acts just like
334    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
335
336 static serial_t tty_desc;               /* Controlling terminal */
337
338 static void
339 cleanup_tty(ttystate)
340      serial_ttystate ttystate;
341 {
342   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
343   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
344   free (ttystate);
345   SERIAL_CLOSE (tty_desc);
346 }
347
348 static void
349 connect_command (args, fromtty)
350      char       *args;
351      int        fromtty;
352 {
353   int c;
354   char cur_esc = 0;
355   serial_ttystate ttystate;
356   serial_t port_desc;           /* TTY port */
357
358   dont_repeat();
359
360   if (args)
361     fprintf_unfiltered(gdb_stderr, "This command takes no args.  They have been ignored.\n");
362         
363   printf_unfiltered("[Entering connect mode.  Use ~. or ~^D to escape]\n");
364
365   tty_desc = SERIAL_FDOPEN (0);
366   port_desc = last_serial_opened;
367
368   ttystate = SERIAL_GET_TTY_STATE (tty_desc);
369
370   SERIAL_RAW (tty_desc);
371   SERIAL_RAW (port_desc);
372
373   make_cleanup (cleanup_tty, ttystate);
374
375   while (1)
376     {
377       int mask;
378
379       mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
380
381       if (mask & 2)
382         {                       /* tty input */
383           char cx;
384
385           while (1)
386             {
387               c = SERIAL_READCHAR(tty_desc, 0);
388
389               if (c == SERIAL_TIMEOUT)
390                   break;
391
392               if (c < 0)
393                 perror_with_name("connect");
394
395               cx = c;
396               SERIAL_WRITE(port_desc, &cx, 1);
397
398               switch (cur_esc)
399                 {
400                 case 0:
401                   if (c == '\r')
402                     cur_esc = c;
403                   break;
404                 case '\r':
405                   if (c == '~')
406                     cur_esc = c;
407                   else
408                     cur_esc = 0;
409                   break;
410                 case '~':
411                   if (c == '.' || c == '\004')
412                     return;
413                   else
414                     cur_esc = 0;
415                 }
416             }
417         }
418
419       if (mask & 1)
420         {                       /* Port input */
421           char cx;
422
423           while (1)
424             {
425               c = SERIAL_READCHAR(port_desc, 0);
426
427               if (c == SERIAL_TIMEOUT)
428                   break;
429
430               if (c < 0)
431                 perror_with_name("connect");
432
433               cx = c;
434
435               SERIAL_WRITE(tty_desc, &cx, 1);
436             }
437         }
438     }
439 }
440 #endif /* 0 */
441
442 /* VARARGS */
443 void
444 #ifdef ANSI_PROTOTYPES
445 serial_printf (serial_t desc, const char *format, ...)
446 #else
447 serial_printf (va_alist)
448      va_dcl
449 #endif
450 {
451   va_list args;
452   char *buf;
453 #ifdef ANSI_PROTOTYPES
454   va_start (args, format);
455 #else
456   serial_t desc;
457   char *format;
458
459   va_start (args);
460   desc = va_arg (args, serial_t);
461   format = va_arg (args, char *);
462 #endif
463
464   vasprintf (&buf, format, args);
465   SERIAL_WRITE (desc, buf, strlen (buf));
466
467   free (buf);
468   va_end (args);
469 }
470
471 void
472 _initialize_serial ()
473 {
474 #if 0
475   add_com ("connect", class_obscure, connect_command,
476            "Connect the terminal directly up to the command monitor.\n\
477 Use <CR>~. or <CR>~^D to break out.");
478 #endif /* 0 */
479
480   add_show_from_set (add_set_cmd ("remotelogfile", no_class,
481                                   var_filename, (char *)&serial_logfile,
482                                   "Set filename for remote session recording.\n\
483 This file is used to record the remote session for future playback\n\
484 by gdbserver.", &setlist),
485                      &showlist);
486
487 }
This page took 0.053509 seconds and 4 git commands to generate.