]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/serial.c
import gdb-1999-08-09 snapshot
[thirdparty/binutils-gdb.git] / gdb / serial.c
1 /* Generic serial interface routines
2 Copyright 1992, 1993, 1996, 1997 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,
19 Boston, MA 02111-1307, USA. */
20
21 #include "defs.h"
22 #include <ctype.h>
23 #include "serial.h"
24 #include "gdb_string.h"
25 #include "gdbcmd.h"
26
27 extern void _initialize_serial PARAMS ((void));
28
29 /* Linked list of serial I/O handlers */
30
31 static struct serial_ops *serial_ops_list = NULL;
32
33 /* This is the last serial stream opened. Used by connect command. */
34
35 static serial_t last_serial_opened = NULL;
36
37 /* Pointer to list of scb's. */
38
39 static 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
44 static char *serial_logfile = NULL;
45 static GDB_FILE *serial_logfp = NULL;
46
47 static struct serial_ops *serial_interface_lookup PARAMS ((char *));
48 static void serial_logchar PARAMS ((int, int, int));
49 static char logbase_hex[] = "hex";
50 static char logbase_octal[] = "octal";
51 static char logbase_ascii[] = "ascii";
52 static char *logbase_enums[] =
53 {logbase_hex, logbase_octal, logbase_ascii, NULL};
54 static char *serial_logbase = logbase_ascii;
55 \f
56
57 static 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
65 static void
66 serial_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 {
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;
126 }
127 }
128 }
129
130 void
131 serial_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
147 int
148 serial_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,
161 in case we are getting ready to dump core or something. */
162 gdb_flush (serial_logfp);
163 }
164
165 return (scb->ops->write (scb, str, len));
166 }
167
168 int
169 serial_readchar (scb, timeout)
170 serial_t scb;
171 int timeout;
172 {
173 int ch;
174
175 ch = scb->ops->readchar (scb, timeout);
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,
181 in case we are getting ready to dump core or something. */
182 gdb_flush (serial_logfp);
183 }
184
185 return (ch);
186 }
187
188 int
189 serial_send_break (scb)
190 serial_t scb;
191 {
192 if (serial_logfp != NULL)
193 serial_logchar ('w', SERIAL_BREAK, 0);
194
195 return (scb->ops->send_break (scb));
196 }
197
198 static struct serial_ops *
199 serial_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
211 void
212 serial_add_interface (optable)
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
221 serial_t
222 serial_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 if (strncmp (name, "|", 1) == 0)
244 ops = serial_interface_lookup ("pipe");
245 else
246 ops = serial_interface_lookup ("hardwire");
247
248 if (!ops)
249 return NULL;
250
251 scb = (serial_t) xmalloc (sizeof (struct _serial_t));
252
253 scb->ops = ops;
254
255 scb->bufcnt = 0;
256 scb->bufp = scb->buf;
257
258 if (scb->ops->open (scb, name))
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
281 serial_t
282 serial_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
300 scb = (serial_t) xmalloc (sizeof (struct _serial_t));
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
319 void
320 serial_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? */
334 gdb_fclose (&serial_logfp);
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
366 free (scb);
367 }
368
369 #if 0
370 /*
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:
374
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.
378
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 */
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
389 static serial_t tty_desc; /* Controlling terminal */
390
391 static void
392 cleanup_tty (ttystate)
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
401 static void
402 connect_command (args, fromtty)
403 char *args;
404 int fromtty;
405 {
406 int c;
407 char cur_esc = 0;
408 serial_ttystate ttystate;
409 serial_t port_desc; /* TTY port */
410
411 dont_repeat ();
412
413 if (args)
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");
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 {
440 c = SERIAL_READCHAR (tty_desc, 0);
441
442 if (c == SERIAL_TIMEOUT)
443 break;
444
445 if (c < 0)
446 perror_with_name ("connect");
447
448 cx = c;
449 SERIAL_WRITE (port_desc, &cx, 1);
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 {
478 c = SERIAL_READCHAR (port_desc, 0);
479
480 if (c == SERIAL_TIMEOUT)
481 break;
482
483 if (c < 0)
484 perror_with_name ("connect");
485
486 cx = c;
487
488 SERIAL_WRITE (tty_desc, &cx, 1);
489 }
490 }
491 }
492 }
493 #endif /* 0 */
494
495 void
496 serial_printf (serial_t desc, const char *format,...)
497 {
498 va_list args;
499 char *buf;
500 va_start (args, format);
501
502 vasprintf (&buf, format, args);
503 SERIAL_WRITE (desc, buf, strlen (buf));
504
505 free (buf);
506 va_end (args);
507 }
508
509 void
510 _initialize_serial ()
511 {
512 #if 0
513 add_com ("connect", class_obscure, connect_command,
514 "Connect the terminal directly up to the command monitor.\n\
515 Use <CR>~. or <CR>~^D to break out.");
516 #endif /* 0 */
517
518 add_show_from_set
519 (add_set_cmd ("remotelogfile", no_class,
520 var_filename, (char *) &serial_logfile,
521 "Set filename for remote session recording.\n\
522 This file is used to record the remote session for future playback\n\
523 by gdbserver.",
524 &setlist),
525 &showlist);
526
527 add_show_from_set
528 (add_set_enum_cmd ("remotelogbase", no_class,
529 logbase_enums, (char *) &serial_logbase,
530 "Set numerical base for remote session logging",
531 &setlist),
532 &showlist);
533 }