X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fremote-utils.c;h=7cc9150b5355f85d480da7292c8207f9d7589833;hb=a1928bada5edd03fee8aaccce7775c273ae0fcd4;hp=5283404bdb0abbb4b91386b7b96880e7241b2d67;hpb=fa803dc60f0bf01297674c41d001798e18ade4dc;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 5283404bdb..7cc9150b53 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1,21 +1,24 @@ /* Remote utility routines for the remote server for GDB. - Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc. + Copyright 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. -This file is part of GDB. + This file is part of GDB. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ #include "server.h" #include "terminal.h" @@ -30,20 +33,38 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include +#include +#include +#include -int remote_debug = 1; +/* A cache entry for a successfully looked-up symbol. */ +struct sym_cache +{ + const char *name; + CORE_ADDR addr; + struct sym_cache *next; +}; + +/* The symbol cache. */ +static struct sym_cache *symbol_cache; + +int remote_debug = 0; +struct ui_file *gdb_stdlog; static int remote_desc; +/* FIXME headerize? */ +extern int using_threads; +extern int debug_threads; + /* Open a connection to a remote debugger. NAME is the filename used for communication. */ void -remote_open (name) - char *name; +remote_open (char *name) { int save_fcntl_flags; - + if (!strchr (name, ':')) { remote_desc = open (name, O_RDWR); @@ -53,17 +74,17 @@ remote_open (name) #ifdef HAVE_TERMIOS { struct termios termios; - tcgetattr(remote_desc, &termios); + tcgetattr (remote_desc, &termios); termios.c_iflag = 0; termios.c_oflag = 0; termios.c_lflag = 0; - termios.c_cflag &= ~(CSIZE|PARENB); + termios.c_cflag &= ~(CSIZE | PARENB); termios.c_cflag |= CLOCAL | CS8; - termios.c_cc[VMIN] = 0; + termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 0; - tcsetattr(remote_desc, TCSANOW, &termios); + tcsetattr (remote_desc, TCSANOW, &termios); } #endif @@ -75,9 +96,9 @@ remote_open (name) termio.c_iflag = 0; termio.c_oflag = 0; termio.c_lflag = 0; - termio.c_cflag &= ~(CSIZE|PARENB); + termio.c_cflag &= ~(CSIZE | PARENB); termio.c_cflag |= CLOCAL | CS8; - termio.c_cc[VMIN] = 0; + termio.c_cc[VMIN] = 1; termio.c_cc[VTIME] = 0; ioctl (remote_desc, TCSETA, &termio); @@ -94,7 +115,7 @@ remote_open (name) } #endif - + fprintf (stderr, "Remote debugging using %s\n", name); } else { @@ -102,7 +123,6 @@ remote_open (name) int port; struct sockaddr_in sockaddr; int tmp; - struct protoent *protoent; int tmp_desc; port_str = strchr (name, ':'); @@ -115,52 +135,56 @@ remote_open (name) /* Allow rapid reuse of this port. */ tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, - sizeof(tmp)); + setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, + sizeof (tmp)); sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons(port); + sockaddr.sin_port = htons (port); sockaddr.sin_addr.s_addr = INADDR_ANY; - if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr)) + if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) || listen (tmp_desc, 1)) perror_with_name ("Can't bind address"); + fprintf (stderr, "Listening on port %d\n", port); + tmp = sizeof (sockaddr); - remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp); + remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp); if (remote_desc == -1) perror_with_name ("Accept failed"); - protoent = getprotobyname ("tcp"); - if (!protoent) - perror_with_name ("getprotobyname"); - /* Enable TCP keep alive process. */ tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); + setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp)); /* Tell TCP not to delay small packets. This greatly speeds up - interactive response. */ + interactive response. */ tmp = 1; - setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY, - (char *)&tmp, sizeof(tmp)); + setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (tmp)); close (tmp_desc); /* No longer need this */ - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply - exits when the remote side dies. */ + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply + exits when the remote side dies. */ + + /* Convert IP address to string. */ + fprintf (stderr, "Remote debugging from host %s\n", + inet_ntoa (sockaddr.sin_addr)); } #if defined(F_SETFL) && defined (FASYNC) save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0); fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC); +#if defined (F_SETOWN) + fcntl (remote_desc, F_SETOWN, getpid ()); +#endif +#endif disable_async_io (); -#endif /* FASYNC */ - fprintf (stderr, "Remote debugging using %s\n", name); } void -remote_close() +remote_close (void) { close (remote_desc); } @@ -168,8 +192,7 @@ remote_close() /* Convert hex digit A to a number. */ static int -fromhex (a) - int a; +fromhex (int a) { if (a >= '0' && a <= '9') return a - '0'; @@ -177,13 +200,49 @@ fromhex (a) return a - 'a' + 10; else error ("Reply contains invalid hex digit"); + return 0; +} + +int +unhexify (char *bin, const char *hex, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + if (hex[0] == 0 || hex[1] == 0) + { + /* Hex string is short, or of uneven length. + Return the count that has been converted so far. */ + return i; + } + *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + return i; +} + +static void +decode_address (CORE_ADDR *addrp, const char *start, int len) +{ + CORE_ADDR addr; + char ch; + int i; + + addr = 0; + for (i = 0; i < len; i++) + { + ch = start[i]; + addr = addr << 4; + addr = addr | (fromhex (ch) & 0x0f); + } + *addrp = addr; } /* Convert number NIB to a hex digit. */ static int -tohex (nib) - int nib; +tohex (int nib) { if (nib < 10) return '0' + nib; @@ -191,20 +250,39 @@ tohex (nib) return 'a' + nib - 10; } +int +hexify (char *hex, const char *bin, int count) +{ + int i; + + /* May use a length, or a nul-terminated string as input. */ + if (count == 0) + count = strlen (bin); + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + /* Send a packet to the remote machine, with error checking. The data of the packet is in BUF. Returns >= 0 on success, -1 otherwise. */ int -putpkt (buf) - char *buf; +putpkt (char *buf) { int i; unsigned char csum = 0; - char buf2[2000]; + char *buf2; char buf3[1]; int cnt = strlen (buf); char *p; + buf2 = malloc (PBUFSIZ); + /* Copy the packet into buffer BUF2, encapsulating it and giving it a checksum. */ @@ -235,10 +313,17 @@ putpkt (buf) } if (remote_debug) - printf ("putpkt (\"%s\"); [looking for ack]\n", buf2); + { + fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2); + fflush (stderr); + } cc = read (remote_desc, buf3, 1); if (remote_debug) - printf ("[received '%c' (0x%x)]\n", buf3[0], buf3[0]); + { + fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]); + fflush (stderr); + } + if (cc <= 0) { if (cc == 0) @@ -246,11 +331,17 @@ putpkt (buf) else perror ("putpkt(read)"); + free (buf2); return -1; } + + /* Check for an input interrupt while we're here. */ + if (buf3[0] == '\003') + (*the_target->send_signal) (SIGINT); } while (buf3[0] != '+'); + free (buf2); return 1; /* Success! */ } @@ -260,38 +351,85 @@ putpkt (buf) will cause us to send a SIGINT to the child. */ static void -input_interrupt() +input_interrupt (int unused) { - int cc; - char c; + fd_set readset; + struct timeval immediate = { 0, 0 }; - cc = read (remote_desc, &c, 1); + /* Protect against spurious interrupts. This has been observed to + be a problem under NetBSD 1.4 and 1.5. */ - if (cc != 1 || c != '\003') + FD_ZERO (&readset); + FD_SET (remote_desc, &readset); + if (select (remote_desc + 1, &readset, 0, 0, &immediate) > 0) { - fprintf(stderr, "input_interrupt, cc = %d c = %d\n", cc, c); - return; + int cc; + char c = 0; + + cc = read (remote_desc, &c, 1); + + if (cc != 1 || c != '\003') + { + fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n", + cc, c, c); + return; + } + + (*the_target->send_signal) (SIGINT); } +} + +void +block_async_io (void) +{ + sigset_t sigio_set; + sigemptyset (&sigio_set); + sigaddset (&sigio_set, SIGIO); + sigprocmask (SIG_BLOCK, &sigio_set, NULL); +} - kill (inferior_pid, SIGINT); +void +unblock_async_io (void) +{ + sigset_t sigio_set; + sigemptyset (&sigio_set); + sigaddset (&sigio_set, SIGIO); + sigprocmask (SIG_UNBLOCK, &sigio_set, NULL); } +/* Asynchronous I/O support. SIGIO must be enabled when waiting, in order to + accept Control-C from the client, and must be disabled when talking to + the client. */ + +/* Current state of asynchronous I/O. */ +static int async_io_enabled; + +/* Enable asynchronous I/O. */ void -enable_async_io() +enable_async_io (void) { + if (async_io_enabled) + return; + signal (SIGIO, input_interrupt); + async_io_enabled = 1; } +/* Disable asynchronous I/O. */ void -disable_async_io() +disable_async_io (void) { + if (!async_io_enabled) + return; + signal (SIGIO, SIG_IGN); + async_io_enabled = 0; } /* Returns next char from remote GDB. -1 if error. */ static int -readchar () +readchar (void) { static char buf[BUFSIZ]; static int bufcnt = 0; @@ -321,8 +459,7 @@ readchar () and store it in BUF. Returns length of packet, or negative if error. */ int -getpkt (buf) - char *buf; +getpkt (char *buf) { char *bp; unsigned char csum, c1, c2; @@ -338,7 +475,11 @@ getpkt (buf) if (c == '$') break; if (remote_debug) - printf ("[getpkt: discarding char '%c']\n", c); + { + fprintf (stderr, "[getpkt: discarding char '%c']\n", c); + fflush (stderr); + } + if (c < 0) return -1; } @@ -358,7 +499,7 @@ getpkt (buf) c1 = fromhex (readchar ()); c2 = fromhex (readchar ()); - + if (csum == (c1 << 4) + c2) break; @@ -368,18 +509,24 @@ getpkt (buf) } if (remote_debug) - printf ("getpkt (\"%s\"); [sending ack] \n", buf); + { + fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf); + fflush (stderr); + } write (remote_desc, "+", 1); if (remote_debug) - printf ("[sent ack]\n"); + { + fprintf (stderr, "[sent ack]\n"); + fflush (stderr); + } + return bp - buf; } void -write_ok (buf) - char *buf; +write_ok (char *buf) { buf[0] = 'O'; buf[1] = 'K'; @@ -387,19 +534,17 @@ write_ok (buf) } void -write_enn (buf) - char *buf; +write_enn (char *buf) { + /* Some day, we should define the meanings of the error codes... */ buf[0] = 'E'; - buf[1] = 'N'; - buf[2] = 'N'; + buf[1] = '0'; + buf[2] = '1'; buf[3] = '\0'; } void -convert_int_to_ascii (from, to, n) - char *from, *to; - int n; +convert_int_to_ascii (char *from, char *to, int n) { int nib; char ch; @@ -416,9 +561,7 @@ convert_int_to_ascii (from, to, n) void -convert_ascii_to_int (from, to, n) - char *from, *to; - int n; +convert_ascii_to_int (char *from, char *to, int n) { int nib1, nib2; while (n--) @@ -430,61 +573,100 @@ convert_ascii_to_int (from, to, n) } static char * -outreg(regno, buf) - int regno; - char *buf; +outreg (int regno, char *buf) { - extern char registers[]; - int regsize = REGISTER_RAW_SIZE (regno); - - *buf++ = tohex (regno >> 4); + if ((regno >> 12) != 0) + *buf++ = tohex ((regno >> 12) & 0xf); + if ((regno >> 8) != 0) + *buf++ = tohex ((regno >> 8) & 0xf); + *buf++ = tohex ((regno >> 4) & 0xf); *buf++ = tohex (regno & 0xf); *buf++ = ':'; - convert_int_to_ascii (®isters[REGISTER_BYTE (regno)], buf, regsize); - buf += 2 * regsize; + collect_register_as_string (regno, buf); + buf += 2 * register_size (regno); *buf++ = ';'; return buf; } void -prepare_resume_reply (buf, status, signo) - char *buf; - char status; - unsigned char signo; +new_thread_notify (int id) { - int nib; + char own_buf[256]; + + /* The `n' response is not yet part of the remote protocol. Do nothing. */ + if (1) + return; + + if (server_waiting == 0) + return; + + sprintf (own_buf, "n%x", id); + disable_async_io (); + putpkt (own_buf); + enable_async_io (); +} + +void +dead_thread_notify (int id) +{ + char own_buf[256]; + + /* The `x' response is not yet part of the remote protocol. Do nothing. */ + if (1) + return; + + sprintf (own_buf, "x%x", id); + disable_async_io (); + putpkt (own_buf); + enable_async_io (); +} + +void +prepare_resume_reply (char *buf, char status, unsigned char signo) +{ + int nib, sig; *buf++ = status; - /* FIXME! Should be converting this signal number (numbered - according to the signal numbering of the system we are running on) - to the signal numbers used by the gdb protocol (see enum target_signal - in gdb/target.h). */ - nib = ((signo & 0xf0) >> 4); + sig = (int)target_signal_from_host (signo); + + nib = ((sig & 0xf0) >> 4); *buf++ = tohex (nib); - nib = signo & 0x0f; + nib = sig & 0x0f; *buf++ = tohex (nib); if (status == 'T') { - buf = outreg (PC_REGNUM, buf); - buf = outreg (FP_REGNUM, buf); - buf = outreg (SP_REGNUM, buf); -#ifdef NPC_REGNUM - buf = outreg (NPC_REGNUM, buf); -#endif -#ifdef O7_REGNUM - buf = outreg (O7_REGNUM, buf); -#endif + const char **regp = gdbserver_expedite_regs; + while (*regp) + { + buf = outreg (find_regno (*regp), buf); + regp ++; + } + + /* Formerly, if the debugger had not used any thread features we would not + burden it with a thread status response. This was for the benefit of + GDB 4.13 and older. However, in recent GDB versions the check + (``if (cont_thread != 0)'') does not have the desired effect because of + sillyness in the way that the remote protocol handles specifying a thread. + Since thread support relies on qSymbol support anyway, assume GDB can handle + threads. */ - /* If the debugger hasn't used any thread features, don't burden it with - threads. If we didn't check this, GDB 4.13 and older would choke. */ - if (cont_thread != 0) + if (using_threads) { - if (old_thread_from_wait != thread_from_wait) + /* FIXME right place to set this? */ + thread_from_wait = ((struct inferior_list_entry *)current_inferior)->id; + if (debug_threads) + fprintf (stderr, "Writing resume reply for %ld\n\n", thread_from_wait); + /* This if (1) ought to be unnecessary. But remote_wait in GDB + will claim this event belongs to inferior_ptid if we do not + specify a thread, and there's no way for gdbserver to know + what inferior_ptid is. */ + if (1 || old_thread_from_wait != thread_from_wait) { - sprintf (buf, "thread:%x;", thread_from_wait); + general_thread = thread_from_wait; + sprintf (buf, "thread:%lx;", thread_from_wait); buf += strlen (buf); old_thread_from_wait = thread_from_wait; } @@ -495,10 +677,7 @@ prepare_resume_reply (buf, status, signo) } void -decode_m_packet (from, mem_addr_ptr, len_ptr) - char *from; - CORE_ADDR *mem_addr_ptr; - unsigned int *len_ptr; +decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr) { int i = 0, j = 0; char ch; @@ -520,10 +699,8 @@ decode_m_packet (from, mem_addr_ptr, len_ptr) } void -decode_M_packet (from, mem_addr_ptr, len_ptr, to) - char *from, *to; - CORE_ADDR *mem_addr_ptr; - unsigned int *len_ptr; +decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, + char *to) { int i = 0; char ch; @@ -543,3 +720,65 @@ decode_M_packet (from, mem_addr_ptr, len_ptr, to) convert_ascii_to_int (&from[i++], to, *len_ptr); } + +/* Ask GDB for the address of NAME, and return it in ADDRP if found. + Returns 1 if the symbol is found, 0 if it is not, -1 on error. */ + +int +look_up_one_symbol (const char *name, CORE_ADDR *addrp) +{ + char own_buf[266], *p, *q; + int len; + struct sym_cache *sym; + + /* Check the cache first. */ + for (sym = symbol_cache; sym; sym = sym->next) + if (strcmp (name, sym->name) == 0) + { + *addrp = sym->addr; + return 1; + } + + /* Send the request. */ + strcpy (own_buf, "qSymbol:"); + hexify (own_buf + strlen ("qSymbol:"), name, strlen (name)); + if (putpkt (own_buf) < 0) + return -1; + + /* FIXME: Eventually add buffer overflow checking (to getpkt?) */ + len = getpkt (own_buf); + if (len < 0) + return -1; + + if (strncmp (own_buf, "qSymbol:", strlen ("qSymbol:")) != 0) + { + /* Malformed response. */ + if (remote_debug) + { + fprintf (stderr, "Malformed response to qSymbol, ignoring.\n"); + fflush (stderr); + } + + return -1; + } + + p = own_buf + strlen ("qSymbol:"); + q = p; + while (*q && *q != ':') + q++; + + /* Make sure we found a value for the symbol. */ + if (p == q || *q == '\0') + return 0; + + decode_address (addrp, p, q - p); + + /* Save the symbol in our cache. */ + sym = malloc (sizeof (*sym)); + sym->name = strdup (name); + sym->addr = *addrp; + sym->next = symbol_cache; + symbol_cache = sym; + + return 1; +}