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