]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/serial.c
import gdb-1999-09-21
[thirdparty/binutils-gdb.git] / gdb / serial.c
CommitLineData
c906108c 1/* Generic serial interface routines
c2c6d25f 2 Copyright 1992, 1993, 1996, 1997, 1999 Free Software Foundation, Inc.
c906108c 3
c5aa993b 4 This file is part of GDB.
c906108c 5
c5aa993b
JM
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.
c906108c 10
c5aa993b
JM
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.
c906108c 15
c5aa993b
JM
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. */
c906108c
SS
20
21#include "defs.h"
22#include <ctype.h>
23#include "serial.h"
24#include "gdb_string.h"
25#include "gdbcmd.h"
26
c2c6d25f 27extern void _initialize_serial (void);
392a587b 28
c906108c
SS
29/* Linked list of serial I/O handlers */
30
31static struct serial_ops *serial_ops_list = NULL;
32
33/* This is the last serial stream opened. Used by connect command. */
34
35static serial_t last_serial_opened = NULL;
36
37/* Pointer to list of scb's. */
38
39static 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
44static char *serial_logfile = NULL;
45static GDB_FILE *serial_logfp = NULL;
46
c2c6d25f
JM
47static struct serial_ops *serial_interface_lookup (char *);
48static void serial_logchar (int, int, int);
c906108c
SS
49static char logbase_hex[] = "hex";
50static char logbase_octal[] = "octal";
51static char logbase_ascii[] = "ascii";
c5aa993b
JM
52static char *logbase_enums[] =
53{logbase_hex, logbase_octal, logbase_ascii, NULL};
c906108c 54static char *serial_logbase = logbase_ascii;
c906108c 55\f
c5aa993b 56
c2c6d25f 57
c906108c
SS
58static 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
66static void
c2c6d25f 67serial_logchar (int ch_type, int ch, int timeout)
c906108c
SS
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 {
c5aa993b
JM
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;
c906108c
SS
124 }
125 }
126}
127
128void
c2c6d25f 129serial_log_command (const char *cmd)
c906108c
SS
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
c2c6d25f 144\f
c906108c 145static struct serial_ops *
c2c6d25f 146serial_interface_lookup (char *name)
c906108c
SS
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
157void
c2c6d25f 158serial_add_interface (struct serial_ops *optable)
c906108c
SS
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
166serial_t
c2c6d25f 167serial_open (const char *name)
c906108c
SS
168{
169 serial_t scb;
170 struct serial_ops *ops;
c2c6d25f 171 const char *open_name = name;
c906108c
SS
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");
43e526b9 188 else if (strncmp (name, "|", 1) == 0)
c2c6d25f
JM
189 {
190 ops = serial_interface_lookup ("pipe");
191 open_name = name + 1; /* discard ``|'' */
192 }
c906108c
SS
193 else
194 ops = serial_interface_lookup ("hardwire");
195
196 if (!ops)
197 return NULL;
198
c5aa993b 199 scb = (serial_t) xmalloc (sizeof (struct _serial_t));
c906108c
SS
200
201 scb->ops = ops;
202
203 scb->bufcnt = 0;
204 scb->bufp = scb->buf;
205
c2c6d25f 206 if (scb->ops->open (scb, open_name))
c906108c
SS
207 {
208 free (scb);
209 return NULL;
210 }
211
212 scb->name = strsave (name);
213 scb->next = scb_base;
214 scb->refcnt = 1;
c2c6d25f
JM
215 scb->async_handler = NULL;
216 scb->async_context = NULL;
c906108c
SS
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
231serial_t
c2c6d25f 232serial_fdopen (const int fd)
c906108c
SS
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
c5aa993b 249 scb = (serial_t) xmalloc (sizeof (struct _serial_t));
c906108c
SS
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;
c2c6d25f
JM
261 scb->async_handler = NULL;
262 scb->async_context = NULL;
c906108c
SS
263 scb_base = scb;
264
265 last_serial_opened = scb;
266
267 return scb;
268}
269
c2c6d25f
JM
270static void
271do_serial_close (serial_t scb, int really_close)
c906108c
SS
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? */
c5aa993b 283 gdb_fclose (&serial_logfp);
c906108c
SS
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
c2c6d25f
JM
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
c906108c
SS
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
c5aa993b 319 free (scb);
c906108c
SS
320}
321
c2c6d25f
JM
322void
323serial_close (serial_t scb)
324{
325 do_serial_close (scb, 1);
326}
327
328void
329serial_un_fdopen (serial_t scb)
330{
331 do_serial_close (scb, 0);
332}
333
334int
335serial_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
352int
353serial_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
370void
371serial_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
384int
385serial_drain_output (serial_t scb)
386{
387 return scb->ops->drain_output (scb);
388}
389
390int
391serial_flush_output (serial_t scb)
392{
393 return scb->ops->flush_output (scb);
394}
395
396int
397serial_flush_input (serial_t scb)
398{
399 return scb->ops->flush_input (scb);
400}
401
402int
403serial_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
411void
412serial_raw (serial_t scb)
413{
414 scb->ops->go_raw (scb);
415}
416
417serial_ttystate
418serial_get_tty_state (serial_t scb)
419{
420 return scb->ops->get_tty_state (scb);
421}
422
423int
424serial_set_tty_state (serial_t scb, serial_ttystate ttystate)
425{
426 return scb->ops->set_tty_state (scb, ttystate);
427}
428
429void
430serial_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
437int
438serial_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
445int
446serial_setbaudrate (serial_t scb, int rate)
447{
448 return scb->ops->setbaudrate (scb, rate);
449}
450
451int
452serial_setstopbits (serial_t scb, int num)
453{
454 return scb->ops->setstopbits (scb, num);
455}
456
457int
458serial_can_async_p (serial_t scb)
459{
460 return (scb->ops->async != NULL);
461}
462
463int
464serial_is_async_p (serial_t scb)
465{
466 return (scb->ops->async != NULL) && (scb->async_handler != NULL);
467}
468
469void
470serial_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
482int
483deprecated_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
c906108c
SS
494#if 0
495/*
c5aa993b
JM
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:
c906108c 499
c5aa993b
JM
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.
c906108c 503
c5aa993b
JM
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 */
c906108c
SS
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
c5aa993b 514static serial_t tty_desc; /* Controlling terminal */
c906108c
SS
515
516static void
c2c6d25f 517cleanup_tty (serial_ttystate ttystate)
c906108c
SS
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
525static void
c2c6d25f 526connect_command (char *args, int fromtty)
c906108c
SS
527{
528 int c;
529 char cur_esc = 0;
530 serial_ttystate ttystate;
531 serial_t port_desc; /* TTY port */
532
c5aa993b 533 dont_repeat ();
c906108c
SS
534
535 if (args)
c5aa993b
JM
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");
c906108c
SS
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 {
c5aa993b 562 c = SERIAL_READCHAR (tty_desc, 0);
c906108c
SS
563
564 if (c == SERIAL_TIMEOUT)
c5aa993b 565 break;
c906108c
SS
566
567 if (c < 0)
c5aa993b 568 perror_with_name ("connect");
c906108c
SS
569
570 cx = c;
c5aa993b 571 SERIAL_WRITE (port_desc, &cx, 1);
c906108c
SS
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 {
c5aa993b 600 c = SERIAL_READCHAR (port_desc, 0);
c906108c
SS
601
602 if (c == SERIAL_TIMEOUT)
c5aa993b 603 break;
c906108c
SS
604
605 if (c < 0)
c5aa993b 606 perror_with_name ("connect");
c906108c
SS
607
608 cx = c;
609
c5aa993b 610 SERIAL_WRITE (tty_desc, &cx, 1);
c906108c
SS
611 }
612 }
613 }
614}
615#endif /* 0 */
616
c906108c 617void
c2c6d25f 618_initialize_serial (void)
c906108c
SS
619{
620#if 0
621 add_com ("connect", class_obscure, connect_command,
622 "Connect the terminal directly up to the command monitor.\n\
623Use <CR>~. or <CR>~^D to break out.");
624#endif /* 0 */
625
c5aa993b 626 add_show_from_set
c906108c
SS
627 (add_set_cmd ("remotelogfile", no_class,
628 var_filename, (char *) &serial_logfile,
629 "Set filename for remote session recording.\n\
630This file is used to record the remote session for future playback\n\
c5aa993b 631by gdbserver.",
c906108c
SS
632 &setlist),
633 &showlist);
634
c5aa993b 635 add_show_from_set
c906108c
SS
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}