/* Remote utility routines for the remote server for GDB.
Copyright (C) 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "server.h"
#include "terminal.h"
extern int using_threads;
extern int debug_threads;
+/* If true, then GDB has requested noack mode. */
+int noack_mode = 0;
+/* If true, then we tell GDB to use noack mode by default. */
+int transport_is_reliable = 0;
+
#ifdef USE_WIN32API
# define read(fd, buf, len) recv (fd, (char *) buf, len, 0)
# define write(fd, buf, len) send (fd, (char *) buf, len, 0)
fprintf (stderr, "Remote debugging using %s\n", name);
#endif /* USE_WIN32API */
+
+ transport_is_reliable = 0;
}
else
{
#ifdef USE_WIN32API
static int winsock_initialized;
#endif
- char *port_str;
int port;
struct sockaddr_in sockaddr;
socklen_t tmp;
int tmp_desc;
+ char *port_end;
- port_str = strchr (name, ':');
-
- port = atoi (port_str + 1);
+ port = strtoul (port_str + 1, &port_end, 10);
+ if (port_str[1] == '\0' || *port_end != '\0')
+ fatal ("Bad port argument: %s", name);
#ifdef USE_WIN32API
if (!winsock_initialized)
/* Enable TCP keep alive process. */
tmp = 1;
- setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
+ setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
+ (char *) &tmp, sizeof (tmp));
/* Tell TCP not to delay small packets. This greatly speeds up
interactive response. */
/* Convert IP address to string. */
fprintf (stderr, "Remote debugging from host %s\n",
inet_ntoa (sockaddr.sin_addr));
+
+ transport_is_reliable = 1;
}
#if defined(F_SETFL) && defined (FASYNC)
fcntl (remote_desc, F_SETOWN, getpid ());
#endif
#endif
- disable_async_io ();
}
void
char buf3[1];
char *p;
- buf2 = malloc (PBUFSIZ);
+ buf2 = xmalloc (PBUFSIZ);
/* Copy the packet into buffer BUF2, encapsulating it
and giving it a checksum. */
if (write (remote_desc, buf2, p - buf2) != p - buf2)
{
perror ("putpkt(write)");
+ free (buf2);
return -1;
}
+ if (noack_mode)
+ {
+ /* Don't expect an ack then. */
+ if (remote_debug)
+ {
+ fprintf (stderr, "putpkt (\"%s\"); [noack mode]\n", buf2);
+ fflush (stderr);
+ }
+ break;
+ }
+
if (remote_debug)
{
fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
}
/* Check for an input interrupt while we're here. */
- if (buf3[0] == '\003')
+ if (buf3[0] == '\003' && current_inferior != NULL)
(*the_target->request_interrupt) ();
}
while (buf3[0] != '+');
cc = read (remote_desc, &c, 1);
- if (cc != 1 || c != '\003')
+ if (cc != 1 || c != '\003' || current_inferior == NULL)
{
fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n",
cc, c, c);
accept Control-C from the client, and must be disabled when talking to
the client. */
-void
-block_async_io (void)
-{
-#ifndef USE_WIN32API
- sigset_t sigio_set;
- sigemptyset (&sigio_set);
- sigaddset (&sigio_set, SIGIO);
- sigprocmask (SIG_BLOCK, &sigio_set, NULL);
-#endif
-}
-
-void
+static void
unblock_async_io (void)
{
#ifndef USE_WIN32API
sigset_t sigio_set;
+
sigemptyset (&sigio_set);
sigaddset (&sigio_set, SIGIO);
sigprocmask (SIG_UNBLOCK, &sigio_set, NULL);
async_io_enabled = 0;
}
+void
+initialize_async_io (void)
+{
+ /* Make sure that async I/O starts disabled. */
+ async_io_enabled = 1;
+ disable_async_io ();
+
+ /* Make sure the signal is unblocked. */
+ unblock_async_io ();
+}
+
/* Returns next char from remote GDB. -1 if error. */
static int
bufp = buf;
bufcnt--;
- return *bufp++ & 0x7f;
+ return *bufp++;
}
/* Read a packet from the remote machine, with error checking,
if (csum == (c1 << 4) + c2)
break;
+ if (noack_mode)
+ {
+ fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s [no-ack-mode, Bad medium?]\n",
+ (c1 << 4) + c2, csum, buf);
+ /* Not much we can do, GDB wasn't expecting an ack/nac. */
+ break;
+ }
+
fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
(c1 << 4) + c2, csum, buf);
write (remote_desc, "-", 1);
}
- if (remote_debug)
+ if (!noack_mode)
{
- fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf);
- fflush (stderr);
- }
+ if (remote_debug)
+ {
+ fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf);
+ fflush (stderr);
+ }
- write (remote_desc, "+", 1);
+ write (remote_desc, "+", 1);
- if (remote_debug)
+ if (remote_debug)
+ {
+ fprintf (stderr, "[sent ack]\n");
+ fflush (stderr);
+ }
+ }
+ else
{
- fprintf (stderr, "[sent ack]\n");
- fflush (stderr);
+ if (remote_debug)
+ {
+ fprintf (stderr, "getpkt (\"%s\"); [no ack sent] \n", buf);
+ fflush (stderr);
+ }
}
return bp - buf;
Since thread support relies on qSymbol support anyway, assume GDB can handle
threads. */
- if (using_threads)
+ if (using_threads && !disable_packet_Tthread)
{
unsigned int gdb_id_from_wait;
old_thread_from_wait = thread_from_wait;
}
}
+
+ if (dlls_changed)
+ {
+ strcpy (buf, "library:;");
+ buf += strlen (buf);
+ dlls_changed = 0;
+ }
}
/* For W and X, we're done. */
*buf++ = 0;
return 0;
}
+/* Decode a qXfer write request. */
+int
+decode_xfer_write (char *buf, int packet_len, char **annex, CORE_ADDR *offset,
+ unsigned int *len, unsigned char *data)
+{
+ char ch;
+
+ /* Extract and NUL-terminate the annex. */
+ *annex = buf;
+ while (*buf && *buf != ':')
+ buf++;
+ if (*buf == '\0')
+ return -1;
+ *buf++ = 0;
+
+ /* Extract the offset. */
+ *offset = 0;
+ while ((ch = *buf++) != ':')
+ {
+ *offset = *offset << 4;
+ *offset |= fromhex (ch) & 0x0f;
+ }
+
+ /* Get encoded data. */
+ packet_len -= buf - *annex;
+ *len = remote_unescape_input ((const gdb_byte *) buf, packet_len,
+ data, packet_len);
+ return 0;
+}
+
+/* Decode the parameters of a qSearch:memory packet. */
+
+int
+decode_search_memory_packet (const char *buf, int packet_len,
+ CORE_ADDR *start_addrp,
+ CORE_ADDR *search_space_lenp,
+ gdb_byte *pattern, unsigned int *pattern_lenp)
+{
+ const char *p = buf;
+
+ p = decode_address_to_semicolon (start_addrp, p);
+ p = decode_address_to_semicolon (search_space_lenp, p);
+ packet_len -= p - buf;
+ *pattern_lenp = remote_unescape_input ((const gdb_byte *) p, packet_len,
+ pattern, packet_len);
+ return 0;
+}
+
/* 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. */
if (len < 0)
return -1;
+ /* We ought to handle pretty much any packet at this point while we
+ wait for the qSymbol "response". That requires re-entering the
+ main loop. For now, this is an adequate approximation; allow
+ GDB to read from memory while it figures out the address of the
+ symbol. */
+ while (own_buf[0] == 'm')
+ {
+ CORE_ADDR mem_addr;
+ unsigned char *mem_buf;
+ unsigned int mem_len;
+
+ decode_m_packet (&own_buf[1], &mem_addr, &mem_len);
+ mem_buf = xmalloc (mem_len);
+ if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
+ convert_int_to_ascii (mem_buf, own_buf, mem_len);
+ else
+ write_enn (own_buf);
+ free (mem_buf);
+ if (putpkt (own_buf) < 0)
+ return -1;
+ 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);
- }
-
+ warning ("Malformed response to qSymbol, ignoring: %s\n", own_buf);
return -1;
}
decode_address (addrp, p, q - p);
/* Save the symbol in our cache. */
- sym = malloc (sizeof (*sym));
- sym->name = strdup (name);
+ sym = xmalloc (sizeof (*sym));
+ sym->name = xstrdup (name);
sym->addr = *addrp;
sym->next = symbol_cache;
symbol_cache = sym;
void
monitor_output (const char *msg)
{
- char *buf = malloc (strlen (msg) * 2 + 2);
+ char *buf = xmalloc (strlen (msg) * 2 + 2);
buf[0] = 'O';
hexify (buf + 1, msg, 0);
putpkt (buf);
free (buf);
}
+
+/* Return a malloc allocated string with special characters from TEXT
+ replaced by entity references. */
+
+char *
+xml_escape_text (const char *text)
+{
+ char *result;
+ int i, special;
+
+ /* Compute the length of the result. */
+ for (i = 0, special = 0; text[i] != '\0'; i++)
+ switch (text[i])
+ {
+ case '\'':
+ case '\"':
+ special += 5;
+ break;
+ case '&':
+ special += 4;
+ break;
+ case '<':
+ case '>':
+ special += 3;
+ break;
+ default:
+ break;
+ }
+
+ /* Expand the result. */
+ result = xmalloc (i + special + 1);
+ for (i = 0, special = 0; text[i] != '\0'; i++)
+ switch (text[i])
+ {
+ case '\'':
+ strcpy (result + i + special, "'");
+ special += 5;
+ break;
+ case '\"':
+ strcpy (result + i + special, """);
+ special += 5;
+ break;
+ case '&':
+ strcpy (result + i + special, "&");
+ special += 4;
+ break;
+ case '<':
+ strcpy (result + i + special, "<");
+ special += 3;
+ break;
+ case '>':
+ strcpy (result + i + special, ">");
+ special += 3;
+ break;
+ default:
+ result[i + special] = text[i];
+ break;
+ }
+ result[i + special] = '\0';
+
+ return result;
+}
+
+void
+buffer_grow (struct buffer *buffer, const char *data, size_t size)
+{
+ char *new_buffer;
+ size_t new_buffer_size;
+
+ if (size == 0)
+ return;
+
+ new_buffer_size = buffer->buffer_size;
+
+ if (new_buffer_size == 0)
+ new_buffer_size = 1;
+
+ while (buffer->used_size + size > new_buffer_size)
+ new_buffer_size *= 2;
+ new_buffer = realloc (buffer->buffer, new_buffer_size);
+ if (!new_buffer)
+ abort ();
+ memcpy (new_buffer + buffer->used_size, data, size);
+ buffer->buffer = new_buffer;
+ buffer->buffer_size = new_buffer_size;
+ buffer->used_size += size;
+}
+
+void
+buffer_free (struct buffer *buffer)
+{
+ if (!buffer)
+ return;
+
+ free (buffer->buffer);
+ buffer->buffer = NULL;
+ buffer->buffer_size = 0;
+ buffer->used_size = 0;
+}
+
+void
+buffer_init (struct buffer *buffer)
+{
+ memset (buffer, 0, sizeof (*buffer));
+}
+
+char*
+buffer_finish (struct buffer *buffer)
+{
+ char *ret = buffer->buffer;
+ buffer->buffer = NULL;
+ buffer->buffer_size = 0;
+ buffer->used_size = 0;
+ return ret;
+}
+
+void
+buffer_xml_printf (struct buffer *buffer, const char *format, ...)
+{
+ va_list ap;
+ const char *f;
+ const char *prev;
+ int percent = 0;
+
+ va_start (ap, format);
+
+ prev = format;
+ for (f = format; *f; f++)
+ {
+ if (percent)
+ {
+ switch (*f)
+ {
+ case 's':
+ {
+ char *p;
+ char *a = va_arg (ap, char *);
+ buffer_grow (buffer, prev, f - prev - 1);
+ p = xml_escape_text (a);
+ buffer_grow_str (buffer, p);
+ free (p);
+ prev = f + 1;
+ }
+ break;
+ }
+ percent = 0;
+ }
+ else if (*f == '%')
+ percent = 1;
+ }
+
+ buffer_grow_str (buffer, prev);
+ va_end (ap);
+}