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