Wed Jul 31 14:46:11 1996 Martin M. Hunt <hunt@pizza.cygnus.com>
[deliverable/binutils-gdb.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.039438 seconds and 4 git commands to generate.