From 4887063b3ce78e39fac8a79d01fa01234ab95174 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Thu, 8 Jun 1995 22:42:36 +0000 Subject: [PATCH] * defs.h maint.c monitor.c remote-mips.c remote.c: Add support for `watchdog' variable. This allows the user to put an upper limit on the amount of time that GDB will wait for the target to return from a step or continue operation. This will primarily be used for the testsuite, where it is difficult to come up with a reasonable timeout for things like function calls, which can take as long as three minutes under some circumstances. If the watchdog timer expires, GDB will generate an error that looks like `Watchdog has expired.', and will detach from the target. * remote-mips.c (mips_open): Setup initial frame from target. Print it out so that user is told where the program is stopped when they attach. * remote-nrom.c: Loads of cleanups. Use serial code to open network connections. Use expect() to wait for response to download command. * ser-tcp.c (tcp_open): Retry connection if we get ECONNREFUSED. * serial.c serial.h (serial_open serial_fdopen serial_close): Allow users to open the same device multiple times. They all get to share the same serial_t. This is about the only way to have multiple active targets use the same device (for download and debug). * sparcl-tdep.c: Keep #include away from GO32. * target.c: Add `targetdebug' variable. If this is non-zero, then a special target is put at the top of the target stack which will cause all calls through the target vector to have their args and results printed out. --- gdb/ChangeLog | 39 ++++++++++ gdb/maint.c | 16 ++++ gdb/remote-mips.c | 37 +++++++++- gdb/remote-nrom.c | 181 +++++++++++++++++++++------------------------- gdb/ser-tcp.c | 44 ++++++----- gdb/serial.c | 50 ++++++++++++- gdb/serial.h | 5 ++ gdb/sparcl-tdep.c | 2 +- 8 files changed, 253 insertions(+), 121 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 26b91f1a413..82a66a8d0a2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,42 @@ +Thu Jun 8 15:06:00 1995 Stu Grossman (grossman@cygnus.com) + + * defs.h maint.c monitor.c remote-mips.c remote.c: Add support + for `watchdog' variable. This allows the user to put an upper + limit on the amount of time that GDB will wait for the target to + return from a step or continue operation. This will primarily be + used for the testsuite, where it is difficult to come up with a + reasonable timeout for things like function calls, which can take + as long as three minutes under some circumstances. If the + watchdog timer expires, GDB will generate an error that looks like + `Watchdog has expired.', and will detach from the target. + + * remote-mips.c (mips_open): Setup initial frame from target. + Print it out so that user is told where the program is stopped + when they attach. + + * remote-nrom.c: Loads of cleanups. Use serial code to open + network connections. Use expect() to wait for response to + download command. + + * ser-tcp.c (tcp_open): Retry connection if we get ECONNREFUSED. + + * serial.c serial.h (serial_open serial_fdopen serial_close): + Allow users to open the same device multiple times. They all get + to share the same serial_t. This is about the only way to have + multiple active targets use the same device (for download and + debug). + + * sparcl-tdep.c: Keep #include away from GO32. + + * target.c: Add `targetdebug' variable. If this is non-zero, + then a special target is put at the top of the target stack which + will cause all calls through the target vector to have their args + and results printed out. + +Wed Jun 7 17:40:37 1995 Per Bothner + + * ch-exp.y: Handle "->" . + Wed Jun 7 17:46:33 1995 Michael Meissner * mem-break.c (LITTLE_BREAKPOINT): If BREAKPOINT and diff --git a/gdb/maint.c b/gdb/maint.c index 479ee6b5959..7f822ecfd9c 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -43,6 +43,14 @@ static void maintenance_time_display PARAMS ((char *, int)); static void maintenance_space_display PARAMS ((char *, int)); +/* Set this to the maximum number of seconds to wait instead of waiting forever + in target_wait(). If this timer times out, then it generates an error and + the command is aborted. This replaces most of the need for timeouts in the + GDB test suite, and makes it possible to distinguish between a hung target + and one with slow communications. */ + +int watchdog = 0; + /* LOCAL FUNCTION @@ -330,5 +338,13 @@ If a SOURCE file is specified, dump only that file's partial symbols.", add_cmd ("check-symtabs", class_maintenance, maintenance_check_symtabs, "Check consistency of psymtabs and symtabs.", &maintenancelist); + + add_show_from_set ( + add_set_cmd ("watchdog", class_maintenance, var_zinteger, (char *)&watchdog, + "Set watchdog timer.\n\ +When non-zero, this timeout is used instead of waiting forever for a target to\n\ +finish a low-level step or continue operation. If the specified amount of time\n\ +passes without a response from the target, an error occurs.", &setlist), + &showlist); #endif /* MAINTENANCE_CMDS */ } diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c index 170a6ba0746..6195dbbb0ba 100644 --- a/gdb/remote-mips.c +++ b/gdb/remote-mips.c @@ -1,5 +1,5 @@ /* Remote debugging interface for MIPS remote debugging protocol. - Copyright 1993, 1994 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995 Free Software Foundation, Inc. Contributed by Cygnus Support. Written by Ian Lance Taylor . @@ -128,7 +128,7 @@ extern struct target_ops mips_ops; The value is 0x40 + seq An acknowlegment packet contains the sequence number of the - packet being acknowledged plus 1 module 64. Data packets are + packet being acknowledged plus 1 modulo 64. Data packets are transmitted in sequence. There may only be one outstanding unacknowledged data packet at a time. The sequence numbers are independent in each direction. If an acknowledgement for @@ -334,10 +334,24 @@ mips_readchar (timeout) int ch; static int state = 0; static char nextstate[5] = { '<', 'I', 'D', 'T', '>' }; +#ifdef MAINTENANCE_CMDS + int i; + + i = timeout; + if (i == -1 && watchdog > 0) + i = watchdog; +#endif if (state == 5) timeout = 1; ch = SERIAL_READCHAR (mips_desc, timeout); +#ifdef MAINTENANCE_CMDS + if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */ + { + target_mourn_inferior (); + error ("Watchdog has expired. Target detached.\n"); + } +#endif if (ch == SERIAL_EOF) mips_error ("End of file from remote"); if (ch == SERIAL_ERROR) @@ -373,7 +387,10 @@ mips_readchar (timeout) state = 0; - mips_error ("Remote board reset"); + /* At this point, about the only thing we can do is abort the command + in progress and get back to command level as quickly as possible. */ + + error ("Remote board reset, debug protocol re-initialized."); } if (ch == nextstate[state]) @@ -874,7 +891,7 @@ mips_request (cmd, addr, data, perr, timeout) char rcmd; int rerrflg; int rresponse; - + if (cmd != '\0') { if (mips_need_reply) @@ -1031,6 +1048,18 @@ device is attached to the target board (e.g., /dev/ttya)."); ptype = mips_read_processor_type (); if (ptype) mips_set_processor_type_command (strsave (ptype), 0); + +/* This is really the job of start_remote however, that makes an assumption + that the target is about to print out a status message of some sort. That + doesn't happen here (in fact, it may not be possible to get the monitor to + send the appropriate packet). */ + + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc (); + set_current_frame (create_new_frame (read_fp (), stop_pc)); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, -1, 1); } /* Close a connection to the remote board. */ diff --git a/gdb/remote-nrom.c b/gdb/remote-nrom.c index 1699d4ce0bf..0a0a9594487 100644 --- a/gdb/remote-nrom.c +++ b/gdb/remote-nrom.c @@ -28,6 +28,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "defs.h" #include "gdbcmd.h" +#include "serial.h" + #include #include "inferior.h" #include "wait.h" @@ -229,6 +231,10 @@ static int nrom_load_sock = -1; static int nrom_targ_sock = -1; static int nrom_ctrl_sock = -1; +static serial_t load_desc = NULL; +static serial_t targ_desc = NULL; +static serial_t ctrl_desc = NULL; + /* For binding to the socket we ned a sockaddr_in structure. */ static struct sockaddr_in nrom_sin; @@ -256,6 +262,8 @@ static int bufindex = 0; static char workbuf[NROM_BUF_SIZE]; static char sendbuf[NROM_BUF_SIZE]; +static char nrom_hostname[100]; + /* Forward data declaration. */ extern struct target_ops nrom_ops; @@ -404,68 +412,75 @@ mem2hex (mem, buf, count) return buf; } +/* Scan input from the remote system, until STRING is found. If BUF is non- + zero, then collect input until we have collected either STRING or BUFLEN-1 + chars. In either case we terminate BUF with a 0. If input overflows BUF + because STRING can't be found, return -1, else return number of chars in BUF + (minus the terminating NUL). Note that in the non-overflow case, STRING + will be at the end of BUF. */ + static int -nrom_control_send (s, nbytes) - char *s; - int nbytes; +expect (string) + char *string; { - long len; - char buf[10]; - - /* clear leading characters */ - /* FIXME: The ioctl uses here seem bogus to me. -sts */ - len = 1; - while (len > 0) - { - if (ioctl (nrom_ctrl_sock, FIONREAD, &len) < 0) - { - perror ("nrom_control_send ioctl"); - return (-1); - } - if (len > 0) - { - if (read (nrom_ctrl_sock, buf, 1) < 0) - { - perror ("nrom_control_send read"); - return (-1); - } - } - } + char *p = string; + int c; - if (remote_debug) - printf_filtered ("nrom_control_send: sending '%s' (%d bytes) to NetROM\n", - s, nbytes); + immediate_quit = 1; - if (writen (nrom_ctrl_sock, s, nbytes) < 0) + while (1) { - perror ("nrom_control_send"); - return (-1); - } + c = SERIAL_READCHAR (ctrl_desc, 5); - /* clear trailing characters */ - len = 1; - while (len > 0) - { - if (ioctl (nrom_ctrl_sock, FIONREAD, &len) < 0) + if (c == *p++) { - perror ("nrom_control_send ioctl"); - return (-1); - } - if (len > 0) - { - if (read (nrom_ctrl_sock, buf, 1) < 0) + if (*p == '\0') { - perror ("nrom_control_send read"); - return (-1); + immediate_quit = 0; + + return 0; } } + else + { + fputc_unfiltered (c, gdb_stdout); + p = string; + if (c == *p) + p++; + } } +} + +static int +nrom_control_send (s, nbytes) + char *s; + int nbytes; +{ + SERIAL_WRITE (ctrl_desc, s, nbytes); + return 0; } static void nrom_kill () { + nrom_close (0); +} + +static serial_t +open_socket (name, port) + char *name; + int port; +{ + char sockname[100]; + serial_t desc; + + sprintf (sockname, "%s:%d", name, port); + desc = SERIAL_OPEN (sockname); + if (!desc) + perror_with_name (sockname); + + return desc; } /* Download a file specified in ARGS to the netROM. */ @@ -485,20 +500,9 @@ nrom_load (args, fromtty) if (nrom_control_send (downloadstring, strlen (downloadstring)) < 0) error ("nrom_load: control_send() of `%s' failed", downloadstring); - /* Wait for the download daemon to start up. */ - sleep (1); - - nrom_load_sock = socket (AF_INET, SOCK_STREAM, 0); - if (nrom_load_sock == -1) - error ("Could not create download socket, error %d", errno); - - memset (&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons (load_port); - sin.sin_addr.s_addr = htonl (nrom_ipaddr); + expect ("Waiting for a connection...\n"); - if (connect (nrom_load_sock, &sin, sizeof(sin)) == -1) - error ("Connect failed, error %d", errno); + load_desc = open_socket (nrom_hostname, load_port); pbfd = bfd_openr (args, 0); @@ -540,7 +544,7 @@ nrom_load (args, fromtty) bfd_get_section_contents (pbfd, section, buffer, fptr, count); - writen (nrom_load_sock, buffer, count); + SERIAL_WRITE (load_desc, buffer, count); section_address += count; fptr += count; section_size -= count; @@ -557,7 +561,8 @@ nrom_load (args, fromtty) else error ("\"%s\": Could not open", args); - close (nrom_load_sock); + SERIAL_CLOSE (load_desc); + load_desc = NULL; } /* This is called not only when we first attach, but also when the @@ -580,52 +585,24 @@ nrom_open (name, from_tty) { int errn; - if (name) - nrom_set_ipaddr (name, from_tty); - else if (nrom_ipaddr == 0) + if (!name || strchr (name, '/') || strchr (name, ':')) error ( "To open a NetROM connection, you must specify the hostname\n\ or IP address of the NetROM device you wish to use."); - push_target (&nrom_ops); - - /* Create the socket used for talking with the target. */ - nrom_targ_sock = socket (AF_INET, SOCK_STREAM, 0); - - /* Bind the socket. */ - nrom_sin.sin_family = AF_INET; - nrom_sin.sin_port = htons (target_port); - nrom_sin.sin_addr.S_un.S_addr = htonl (nrom_ipaddr); + strcpy (nrom_hostname, name); - /* Connect to the remote host. */ - if (connect (nrom_targ_sock, &nrom_sin, sizeof(nrom_sin)) == -1) - error ("Connect failed, error %d", errno); + target_preopen (from_tty); - /* Create the socket used for talking with the debugger services. */ - nrom_ctrl_sock = socket (AF_INET, SOCK_STREAM, 0); + unpush_target (&nrom_ops); - /* Bind the socket. */ - nrom_sin.sin_family = AF_INET; - nrom_sin.sin_port = htons (control_port); - nrom_sin.sin_addr.S_un.S_addr = htonl (nrom_ipaddr); + targ_desc = open_socket (nrom_hostname, target_port); + ctrl_desc = open_socket (nrom_hostname, control_port); - /* Connect to the remote host. */ - if (connect (nrom_ctrl_sock, &nrom_sin, sizeof(nrom_sin)) == -1) - { - errn = errno; - close (nrom_targ_sock); - error ("Connect control_socket failed, error %d", errn); - } + push_target (&nrom_ops); if (from_tty) - { - unsigned char *i; - - printf_filtered ("Connected to NetROM device \"%s\"", name); - i = (unsigned char *) &nrom_ipaddr; - printf_filtered (" (%d.%d.%d.%d)\n", - UC(i[0]), UC(i[1]), UC(i[2]), UC(i[3])); - } + printf_filtered ("Connected to NetROM device \"%s\"\n", nrom_hostname); } static int @@ -640,6 +617,16 @@ static void nrom_close (quitting) int quitting; { + if (load_desc) + SERIAL_CLOSE (load_desc); + if (targ_desc) + SERIAL_CLOSE (targ_desc); + if (ctrl_desc) + SERIAL_CLOSE (ctrl_desc); + + load_desc = NULL; + targ_desc = NULL; + ctrl_desc = NULL; } /* Attach to the target that is already loaded and possibly running */ @@ -1312,7 +1299,7 @@ struct target_ops nrom_ops = { nrom_can_run, 0, /* to_notice_signals */ 0, - process_stratum, /* to_stratum */ + download_stratum, /* to_stratum */ NULL, /* to_next */ 1, 1, diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c index 029a6259822..288ccb72601 100644 --- a/gdb/ser-tcp.c +++ b/gdb/ser-tcp.c @@ -79,28 +79,38 @@ tcp_open(scb, name) return -1; } - scb->fd = socket (PF_INET, SOCK_STREAM, 0); - if (scb->fd < 0) - return -1; + for (i = 1; i <= 15; i++) + { + scb->fd = socket (PF_INET, SOCK_STREAM, 0); + if (scb->fd < 0) + return -1; - /* Allow rapid reuse of this port. */ - tmp = 1; - setsockopt (scb->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp)); + /* Allow rapid reuse of this port. */ + tmp = 1; + setsockopt (scb->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp)); - /* Enable TCP keep alive process. */ - tmp = 1; - setsockopt (scb->fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); + /* Enable TCP keep alive process. */ + tmp = 1; + setsockopt (scb->fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); - sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons(port); - memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, - sizeof (struct in_addr)); + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons(port); + memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, + sizeof (struct in_addr)); - if (connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) - { - close(scb->fd); + if (!connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) + break; + + close (scb->fd); scb->fd = -1; - return -1; + +/* We retry for ECONNREFUSED because that is often a temporary condition, which + happens when the server is being restarted. */ + + if (errno != ECONNREFUSED) + return -1; + + sleep (1); } protoent = getprotobyname ("tcp"); diff --git a/gdb/serial.c b/gdb/serial.c index 631f0f3441e..291ff3da38c 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -58,6 +58,13 @@ serial_open (name) serial_t scb; struct serial_ops *ops; + for (scb = scb_base; scb; scb = scb->next) + if (scb->name && strcmp (scb->name, name) == 0) + { + scb->refcnt++; + return scb; + } + if (strcmp (name, "pc") == 0) ops = serial_interface_lookup ("pc"); else if (strchr (name, ':')) @@ -81,18 +88,30 @@ serial_open (name) return NULL; } + scb->name = strsave (name); + scb->next = scb_base; + scb->refcnt = 1; + scb_base = scb; + last_serial_opened = scb; return scb; } serial_t -serial_fdopen(fd) +serial_fdopen (fd) const int fd; { serial_t scb; struct serial_ops *ops; + for (scb = scb_base; scb; scb = scb->next) + if (scb->fd == fd) + { + scb->refcnt++; + return scb; + } + ops = serial_interface_lookup ("hardwire"); if (!ops) @@ -107,6 +126,11 @@ serial_fdopen(fd) scb->fd = fd; + scb->name = NULL; + scb->next = scb_base; + scb->refcnt = 1; + scb_base = scb; + last_serial_opened = scb; return scb; @@ -116,6 +140,8 @@ void serial_close(scb) serial_t scb; { + serial_t tmp_scb; + last_serial_opened = NULL; /* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you @@ -124,7 +150,27 @@ serial_close(scb) if (!scb) return; - scb->ops->close(scb); + scb->refcnt--; + if (scb->refcnt > 0) + return; + + scb->ops->close (scb); + + if (scb->name) + free (scb->name); + + if (scb_base == scb) + scb_base = scb_base->next; + else + for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next) + { + if (tmp_scb->next != scb) + continue; + + tmp_scb->next = tmp_scb->next->next; + break; + } + free(scb); } diff --git a/gdb/serial.h b/gdb/serial.h index 2dbb1aa8835..8f4222f2ed8 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -36,10 +36,15 @@ struct _serial_t /* ser-unix.c termio{,s} only, we still need to wait for this many more seconds. */ int timeout_remaining; + char *name; /* The name of the device or host */ + struct _serial_t *next; /* Pointer to the next serial_t */ + int refcnt; /* Number of pointers to this block */ }; typedef struct _serial_t *serial_t; +serial_t scb_base; /* Pointer to list of scb's */ + struct serial_ops { char *name; struct serial_ops *next; diff --git a/gdb/sparcl-tdep.c b/gdb/sparcl-tdep.c index bf3d87b61b6..89e293cd518 100644 --- a/gdb/sparcl-tdep.c +++ b/gdb/sparcl-tdep.c @@ -24,8 +24,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "serial.h" #include #include -#include #ifndef __GO32__ +#include #include #include #include -- 2.30.2