import gdb-1999-07-07 post reformat
[deliverable/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
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, 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
392a587b
JM
26extern void _initialize_serial PARAMS ((void));
27
c906108c
SS
28/* Linked list of serial I/O handlers */
29
30static struct serial_ops *serial_ops_list = NULL;
31
32/* This is the last serial stream opened. Used by connect command. */
33
34static serial_t last_serial_opened = NULL;
35
36/* Pointer to list of scb's. */
37
38static serial_t scb_base;
39
40/* Non-NULL gives filename which contains a recording of the remote session,
41 suitable for playback by gdbserver. */
42
43static char *serial_logfile = NULL;
44static GDB_FILE *serial_logfp = NULL;
45
46static struct serial_ops *serial_interface_lookup PARAMS ((char *));
47static void serial_logchar PARAMS ((int, int, int));
48static char logbase_hex[] = "hex";
49static char logbase_octal[] = "octal";
50static char logbase_ascii[] = "ascii";
51static char *logbase_enums[] = {logbase_hex, logbase_octal, logbase_ascii, NULL};
52static char *serial_logbase = logbase_ascii;
53
54\f
55static int serial_current_type = 0;
56
57/* Log char CH of type CHTYPE, with TIMEOUT */
58
59/* Define bogus char to represent a BREAK. Should be careful to choose a value
60 that can't be confused with a normal char, or an error code. */
61#define SERIAL_BREAK 1235
62
63static void
64serial_logchar (ch_type, ch, timeout)
65 int ch_type;
66 int ch;
67 int timeout;
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 {
100 case '\\': fputs_unfiltered ("\\\\", serial_logfp); break;
101 case '\b': fputs_unfiltered ("\\b", serial_logfp); break;
102 case '\f': fputs_unfiltered ("\\f", serial_logfp); break;
103 case '\n': fputs_unfiltered ("\\n", serial_logfp); break;
104 case '\r': fputs_unfiltered ("\\r", serial_logfp); break;
105 case '\t': fputs_unfiltered ("\\t", serial_logfp); break;
106 case '\v': fputs_unfiltered ("\\v", serial_logfp); break;
107 default: fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break;
108 }
109 }
110}
111
112void
113serial_log_command (cmd)
114 const char *cmd;
115{
116 if (!serial_logfp)
117 return;
118
119 serial_current_type = 'c';
120
121 fputs_unfiltered ("\nc ", serial_logfp);
122 fputs_unfiltered (cmd, serial_logfp);
123
124 /* Make sure that the log file is as up-to-date as possible,
125 in case we are getting ready to dump core or something. */
126 gdb_flush (serial_logfp);
127}
128
129int
130serial_write (scb, str, len)
131 serial_t scb;
132 const char *str;
133 int len;
134{
135 if (serial_logfp != NULL)
136 {
137 int count;
138
139 for (count = 0; count < len; count++)
140 serial_logchar ('w', str[count] & 0xff, 0);
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 return (scb -> ops -> write (scb, str, len));
148}
149
150int
151serial_readchar (scb, timeout)
152 serial_t scb;
153 int timeout;
154{
155 int ch;
156
157 ch = scb -> ops -> readchar (scb, timeout);
158 if (serial_logfp != NULL)
159 {
160 serial_logchar ('r', ch, timeout);
161
162 /* Make sure that the log file is as up-to-date as possible,
163 in case we are getting ready to dump core or something. */
164 gdb_flush (serial_logfp);
165 }
166
167 return (ch);
168}
169
170int
171serial_send_break (scb)
172 serial_t scb;
173{
174 if (serial_logfp != NULL)
175 serial_logchar ('w', SERIAL_BREAK, 0);
176
177 return (scb -> ops -> send_break (scb));
178}
179
180static struct serial_ops *
181serial_interface_lookup (name)
182 char *name;
183{
184 struct serial_ops *ops;
185
186 for (ops = serial_ops_list; ops; ops = ops->next)
187 if (strcmp (name, ops->name) == 0)
188 return ops;
189
190 return NULL;
191}
192
193void
194serial_add_interface(optable)
195 struct serial_ops *optable;
196{
197 optable->next = serial_ops_list;
198 serial_ops_list = optable;
199}
200
201/* Open up a device or a network socket, depending upon the syntax of NAME. */
202
203serial_t
204serial_open (name)
205 const char *name;
206{
207 serial_t scb;
208 struct serial_ops *ops;
209
210 for (scb = scb_base; scb; scb = scb->next)
211 if (scb->name && strcmp (scb->name, name) == 0)
212 {
213 scb->refcnt++;
214 return scb;
215 }
216
217 if (strcmp (name, "ocd") == 0)
218 ops = serial_interface_lookup ("ocd");
219 else if (strcmp (name, "pc") == 0)
220 ops = serial_interface_lookup ("pc");
221 else if (strchr (name, ':'))
222 ops = serial_interface_lookup ("tcp");
223 else if (strncmp (name, "lpt", 3) == 0)
224 ops = serial_interface_lookup ("parallel");
225 else
226 ops = serial_interface_lookup ("hardwire");
227
228 if (!ops)
229 return NULL;
230
231 scb = (serial_t)xmalloc (sizeof (struct _serial_t));
232
233 scb->ops = ops;
234
235 scb->bufcnt = 0;
236 scb->bufp = scb->buf;
237
238 if (scb->ops->open(scb, name))
239 {
240 free (scb);
241 return NULL;
242 }
243
244 scb->name = strsave (name);
245 scb->next = scb_base;
246 scb->refcnt = 1;
247 scb_base = scb;
248
249 last_serial_opened = scb;
250
251 if (serial_logfile != NULL)
252 {
253 serial_logfp = gdb_fopen (serial_logfile, "w");
254 if (serial_logfp == NULL)
255 perror_with_name (serial_logfile);
256 }
257
258 return scb;
259}
260
261serial_t
262serial_fdopen (fd)
263 const int fd;
264{
265 serial_t scb;
266 struct serial_ops *ops;
267
268 for (scb = scb_base; scb; scb = scb->next)
269 if (scb->fd == fd)
270 {
271 scb->refcnt++;
272 return scb;
273 }
274
275 ops = serial_interface_lookup ("hardwire");
276
277 if (!ops)
278 return NULL;
279
280 scb = (serial_t)xmalloc (sizeof (struct _serial_t));
281
282 scb->ops = ops;
283
284 scb->bufcnt = 0;
285 scb->bufp = scb->buf;
286
287 scb->fd = fd;
288
289 scb->name = NULL;
290 scb->next = scb_base;
291 scb->refcnt = 1;
292 scb_base = scb;
293
294 last_serial_opened = scb;
295
296 return scb;
297}
298
299void
300serial_close (scb, really_close)
301 serial_t scb;
302 int really_close;
303{
304 serial_t tmp_scb;
305
306 last_serial_opened = NULL;
307
308 if (serial_logfp)
309 {
310 fputs_unfiltered ("\nEnd of log\n", serial_logfp);
311 serial_current_type = 0;
312
313 /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
314 gdb_fclose (&serial_logfp);
315 serial_logfp = NULL;
316 }
317
318/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
319 should fix your code instead. */
320
321 if (!scb)
322 return;
323
324 scb->refcnt--;
325 if (scb->refcnt > 0)
326 return;
327
328 if (really_close)
329 scb->ops->close (scb);
330
331 if (scb->name)
332 free (scb->name);
333
334 if (scb_base == scb)
335 scb_base = scb_base->next;
336 else
337 for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
338 {
339 if (tmp_scb->next != scb)
340 continue;
341
342 tmp_scb->next = tmp_scb->next->next;
343 break;
344 }
345
346 free(scb);
347}
348
349#if 0
350/*
351The connect command is #if 0 because I hadn't thought of an elegant
352way to wait for I/O on two serial_t's simultaneously. Two solutions
353came to mind:
354
355 1) Fork, and have have one fork handle the to user direction,
356 and have the other hand the to target direction. This
357 obviously won't cut it for MSDOS.
358
359 2) Use something like select. This assumes that stdin and
360 the target side can both be waited on via the same
361 mechanism. This may not be true for DOS, if GDB is
362 talking to the target via a TCP socket.
363-grossman, 8 Jun 93
364*/
365
366/* Connect the user directly to the remote system. This command acts just like
367 the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
368
369static serial_t tty_desc; /* Controlling terminal */
370
371static void
372cleanup_tty(ttystate)
373 serial_ttystate ttystate;
374{
375 printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
376 SERIAL_SET_TTY_STATE (tty_desc, ttystate);
377 free (ttystate);
378 SERIAL_CLOSE (tty_desc);
379}
380
381static void
382connect_command (args, fromtty)
383 char *args;
384 int fromtty;
385{
386 int c;
387 char cur_esc = 0;
388 serial_ttystate ttystate;
389 serial_t port_desc; /* TTY port */
390
391 dont_repeat();
392
393 if (args)
394 fprintf_unfiltered(gdb_stderr, "This command takes no args. They have been ignored.\n");
395
396 printf_unfiltered("[Entering connect mode. Use ~. or ~^D to escape]\n");
397
398 tty_desc = SERIAL_FDOPEN (0);
399 port_desc = last_serial_opened;
400
401 ttystate = SERIAL_GET_TTY_STATE (tty_desc);
402
403 SERIAL_RAW (tty_desc);
404 SERIAL_RAW (port_desc);
405
406 make_cleanup (cleanup_tty, ttystate);
407
408 while (1)
409 {
410 int mask;
411
412 mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
413
414 if (mask & 2)
415 { /* tty input */
416 char cx;
417
418 while (1)
419 {
420 c = SERIAL_READCHAR(tty_desc, 0);
421
422 if (c == SERIAL_TIMEOUT)
423 break;
424
425 if (c < 0)
426 perror_with_name("connect");
427
428 cx = c;
429 SERIAL_WRITE(port_desc, &cx, 1);
430
431 switch (cur_esc)
432 {
433 case 0:
434 if (c == '\r')
435 cur_esc = c;
436 break;
437 case '\r':
438 if (c == '~')
439 cur_esc = c;
440 else
441 cur_esc = 0;
442 break;
443 case '~':
444 if (c == '.' || c == '\004')
445 return;
446 else
447 cur_esc = 0;
448 }
449 }
450 }
451
452 if (mask & 1)
453 { /* Port input */
454 char cx;
455
456 while (1)
457 {
458 c = SERIAL_READCHAR(port_desc, 0);
459
460 if (c == SERIAL_TIMEOUT)
461 break;
462
463 if (c < 0)
464 perror_with_name("connect");
465
466 cx = c;
467
468 SERIAL_WRITE(tty_desc, &cx, 1);
469 }
470 }
471 }
472}
473#endif /* 0 */
474
475/* VARARGS */
476void
477#ifdef ANSI_PROTOTYPES
478serial_printf (serial_t desc, const char *format, ...)
479#else
480serial_printf (va_alist)
481 va_dcl
482#endif
483{
484 va_list args;
485 char *buf;
486#ifdef ANSI_PROTOTYPES
487 va_start (args, format);
488#else
489 serial_t desc;
490 char *format;
491
492 va_start (args);
493 desc = va_arg (args, serial_t);
494 format = va_arg (args, char *);
495#endif
496
497 vasprintf (&buf, format, args);
498 SERIAL_WRITE (desc, buf, strlen (buf));
499
500 free (buf);
501 va_end (args);
502}
503
504void
505_initialize_serial ()
506{
507#if 0
508 add_com ("connect", class_obscure, connect_command,
509 "Connect the terminal directly up to the command monitor.\n\
510Use <CR>~. or <CR>~^D to break out.");
511#endif /* 0 */
512
513 add_show_from_set
514 (add_set_cmd ("remotelogfile", no_class,
515 var_filename, (char *) &serial_logfile,
516 "Set filename for remote session recording.\n\
517This file is used to record the remote session for future playback\n\
518by gdbserver.",
519 &setlist),
520 &showlist);
521
522 add_show_from_set
523 (add_set_enum_cmd ("remotelogbase", no_class,
524 logbase_enums, (char *) &serial_logbase,
525 "Set numerical base for remote session logging",
526 &setlist),
527 &showlist);
528}
This page took 0.051311 seconds and 4 git commands to generate.