]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/serial.c
import gdb-1999-07-12 snapshot
[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");
43e526b9
JM
243 else if (strncmp (name, "|", 1) == 0)
244 ops = serial_interface_lookup ("pipe");
c906108c
SS
245 else
246 ops = serial_interface_lookup ("hardwire");
247
248 if (!ops)
249 return NULL;
250
c5aa993b 251 scb = (serial_t) xmalloc (sizeof (struct _serial_t));
c906108c
SS
252
253 scb->ops = ops;
254
255 scb->bufcnt = 0;
256 scb->bufp = scb->buf;
257
c5aa993b 258 if (scb->ops->open (scb, name))
c906108c
SS
259 {
260 free (scb);
261 return NULL;
262 }
263
264 scb->name = strsave (name);
265 scb->next = scb_base;
266 scb->refcnt = 1;
267 scb_base = scb;
268
269 last_serial_opened = scb;
270
271 if (serial_logfile != NULL)
272 {
273 serial_logfp = gdb_fopen (serial_logfile, "w");
274 if (serial_logfp == NULL)
275 perror_with_name (serial_logfile);
276 }
277
278 return scb;
279}
280
281serial_t
282serial_fdopen (fd)
283 const int fd;
284{
285 serial_t scb;
286 struct serial_ops *ops;
287
288 for (scb = scb_base; scb; scb = scb->next)
289 if (scb->fd == fd)
290 {
291 scb->refcnt++;
292 return scb;
293 }
294
295 ops = serial_interface_lookup ("hardwire");
296
297 if (!ops)
298 return NULL;
299
c5aa993b 300 scb = (serial_t) xmalloc (sizeof (struct _serial_t));
c906108c
SS
301
302 scb->ops = ops;
303
304 scb->bufcnt = 0;
305 scb->bufp = scb->buf;
306
307 scb->fd = fd;
308
309 scb->name = NULL;
310 scb->next = scb_base;
311 scb->refcnt = 1;
312 scb_base = scb;
313
314 last_serial_opened = scb;
315
316 return scb;
317}
318
319void
320serial_close (scb, really_close)
321 serial_t scb;
322 int really_close;
323{
324 serial_t tmp_scb;
325
326 last_serial_opened = NULL;
327
328 if (serial_logfp)
329 {
330 fputs_unfiltered ("\nEnd of log\n", serial_logfp);
331 serial_current_type = 0;
332
333 /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
c5aa993b 334 gdb_fclose (&serial_logfp);
c906108c
SS
335 serial_logfp = NULL;
336 }
337
338/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
339 should fix your code instead. */
340
341 if (!scb)
342 return;
343
344 scb->refcnt--;
345 if (scb->refcnt > 0)
346 return;
347
348 if (really_close)
349 scb->ops->close (scb);
350
351 if (scb->name)
352 free (scb->name);
353
354 if (scb_base == scb)
355 scb_base = scb_base->next;
356 else
357 for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
358 {
359 if (tmp_scb->next != scb)
360 continue;
361
362 tmp_scb->next = tmp_scb->next->next;
363 break;
364 }
365
c5aa993b 366 free (scb);
c906108c
SS
367}
368
369#if 0
370/*
c5aa993b
JM
371 The connect command is #if 0 because I hadn't thought of an elegant
372 way to wait for I/O on two serial_t's simultaneously. Two solutions
373 came to mind:
c906108c 374
c5aa993b
JM
375 1) Fork, and have have one fork handle the to user direction,
376 and have the other hand the to target direction. This
377 obviously won't cut it for MSDOS.
c906108c 378
c5aa993b
JM
379 2) Use something like select. This assumes that stdin and
380 the target side can both be waited on via the same
381 mechanism. This may not be true for DOS, if GDB is
382 talking to the target via a TCP socket.
383 -grossman, 8 Jun 93
384 */
c906108c
SS
385
386/* Connect the user directly to the remote system. This command acts just like
387 the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
388
c5aa993b 389static serial_t tty_desc; /* Controlling terminal */
c906108c
SS
390
391static void
c5aa993b 392cleanup_tty (ttystate)
c906108c
SS
393 serial_ttystate ttystate;
394{
395 printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
396 SERIAL_SET_TTY_STATE (tty_desc, ttystate);
397 free (ttystate);
398 SERIAL_CLOSE (tty_desc);
399}
400
401static void
402connect_command (args, fromtty)
c5aa993b
JM
403 char *args;
404 int fromtty;
c906108c
SS
405{
406 int c;
407 char cur_esc = 0;
408 serial_ttystate ttystate;
409 serial_t port_desc; /* TTY port */
410
c5aa993b 411 dont_repeat ();
c906108c
SS
412
413 if (args)
c5aa993b
JM
414 fprintf_unfiltered (gdb_stderr, "This command takes no args. They have been ignored.\n");
415
416 printf_unfiltered ("[Entering connect mode. Use ~. or ~^D to escape]\n");
c906108c
SS
417
418 tty_desc = SERIAL_FDOPEN (0);
419 port_desc = last_serial_opened;
420
421 ttystate = SERIAL_GET_TTY_STATE (tty_desc);
422
423 SERIAL_RAW (tty_desc);
424 SERIAL_RAW (port_desc);
425
426 make_cleanup (cleanup_tty, ttystate);
427
428 while (1)
429 {
430 int mask;
431
432 mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
433
434 if (mask & 2)
435 { /* tty input */
436 char cx;
437
438 while (1)
439 {
c5aa993b 440 c = SERIAL_READCHAR (tty_desc, 0);
c906108c
SS
441
442 if (c == SERIAL_TIMEOUT)
c5aa993b 443 break;
c906108c
SS
444
445 if (c < 0)
c5aa993b 446 perror_with_name ("connect");
c906108c
SS
447
448 cx = c;
c5aa993b 449 SERIAL_WRITE (port_desc, &cx, 1);
c906108c
SS
450
451 switch (cur_esc)
452 {
453 case 0:
454 if (c == '\r')
455 cur_esc = c;
456 break;
457 case '\r':
458 if (c == '~')
459 cur_esc = c;
460 else
461 cur_esc = 0;
462 break;
463 case '~':
464 if (c == '.' || c == '\004')
465 return;
466 else
467 cur_esc = 0;
468 }
469 }
470 }
471
472 if (mask & 1)
473 { /* Port input */
474 char cx;
475
476 while (1)
477 {
c5aa993b 478 c = SERIAL_READCHAR (port_desc, 0);
c906108c
SS
479
480 if (c == SERIAL_TIMEOUT)
c5aa993b 481 break;
c906108c
SS
482
483 if (c < 0)
c5aa993b 484 perror_with_name ("connect");
c906108c
SS
485
486 cx = c;
487
c5aa993b 488 SERIAL_WRITE (tty_desc, &cx, 1);
c906108c
SS
489 }
490 }
491 }
492}
493#endif /* 0 */
494
495/* VARARGS */
496void
497#ifdef ANSI_PROTOTYPES
c5aa993b 498serial_printf (serial_t desc, const char *format,...)
c906108c
SS
499#else
500serial_printf (va_alist)
501 va_dcl
502#endif
503{
504 va_list args;
505 char *buf;
506#ifdef ANSI_PROTOTYPES
507 va_start (args, format);
508#else
509 serial_t desc;
510 char *format;
511
512 va_start (args);
513 desc = va_arg (args, serial_t);
514 format = va_arg (args, char *);
515#endif
516
517 vasprintf (&buf, format, args);
518 SERIAL_WRITE (desc, buf, strlen (buf));
519
520 free (buf);
521 va_end (args);
522}
523
524void
525_initialize_serial ()
526{
527#if 0
528 add_com ("connect", class_obscure, connect_command,
529 "Connect the terminal directly up to the command monitor.\n\
530Use <CR>~. or <CR>~^D to break out.");
531#endif /* 0 */
532
c5aa993b 533 add_show_from_set
c906108c
SS
534 (add_set_cmd ("remotelogfile", no_class,
535 var_filename, (char *) &serial_logfile,
536 "Set filename for remote session recording.\n\
537This file is used to record the remote session for future playback\n\
c5aa993b 538by gdbserver.",
c906108c
SS
539 &setlist),
540 &showlist);
541
c5aa993b 542 add_show_from_set
c906108c
SS
543 (add_set_enum_cmd ("remotelogbase", no_class,
544 logbase_enums, (char *) &serial_logbase,
545 "Set numerical base for remote session logging",
546 &setlist),
547 &showlist);
548}