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