/* 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
- Free Software Foundation, Inc.
+ Copyright (C) 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007 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"
-#if HAVE_TERMINAL_H
#include "terminal.h"
-#endif
#include <stdio.h>
#include <string.h>
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
+#if HAVE_SYS_FILE_H
#include <sys/file.h>
+#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
+#if HAVE_SIGNAL_H
#include <signal.h>
+#endif
+#if HAVE_FCNTL_H
#include <fcntl.h>
+#endif
#include <sys/time.h>
+#if HAVE_UNISTD_H
#include <unistd.h>
+#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#include <sys/stat.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
#if USE_WIN32API
#include <winsock.h>
typedef int socklen_t;
#endif
+#if USE_WIN32API
+# define INVALID_DESCRIPTOR INVALID_SOCKET
+#else
+# define INVALID_DESCRIPTOR -1
+#endif
+
/* A cache entry for a successfully looked-up symbol. */
struct sym_cache
{
int remote_debug = 0;
struct ui_file *gdb_stdlog;
-static int remote_desc;
+static int remote_desc = INVALID_DESCRIPTOR;
/* FIXME headerize? */
extern int using_threads;
extern int debug_threads;
+#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)
+#endif
+
/* Open a connection to a remote debugger.
NAME is the filename used for communication. */
#if defined(F_SETFL) && defined (FASYNC)
int save_fcntl_flags;
#endif
-
- if (!strchr (name, ':'))
+ char *port_str;
+
+ port_str = strchr (name, ':');
+ if (port_str == NULL)
{
#ifdef USE_WIN32API
error ("Only <host>:<port> is supported on this platform.");
#else
- remote_desc = open (name, O_RDWR);
+ struct stat statbuf;
+
+ if (stat (name, &statbuf) == 0
+ && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)))
+ remote_desc = open (name, O_RDWR);
+ else
+ {
+ errno = EINVAL;
+ remote_desc = -1;
+ }
+
if (remote_desc < 0)
perror_with_name ("Could not open remote device");
|| listen (tmp_desc, 1))
perror_with_name ("Can't bind address");
+ /* If port is zero, a random port will be selected, and the
+ fprintf below needs to know what port was selected. */
+ if (port == 0)
+ {
+ socklen_t len = sizeof (sockaddr);
+ if (getsockname (tmp_desc, (struct sockaddr *) &sockaddr, &len) < 0
+ || len < sizeof (sockaddr))
+ perror_with_name ("Can't determine port");
+ port = ntohs (sockaddr.sin_port);
+ }
+
fprintf (stderr, "Listening on port %d\n", port);
fflush (stderr);
/* 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. */
return i;
}
-static void
+void
decode_address (CORE_ADDR *addrp, const char *start, int len)
{
CORE_ADDR addr;
*addrp = addr;
}
+const char *
+decode_address_to_semicolon (CORE_ADDR *addrp, const char *start)
+{
+ const char *end;
+
+ end = start;
+ while (*end != '\0' && *end != ';')
+ end++;
+
+ decode_address (addrp, start, end - start);
+
+ if (*end == ';')
+ end++;
+ return end;
+}
+
/* Convert number NIB to a hex digit. */
static int
return output_index;
}
+/* Look for a sequence of characters which can be run-length encoded.
+ If there are any, update *CSUM and *P. Otherwise, output the
+ single character. Return the number of characters consumed. */
+
+static int
+try_rle (char *buf, int remaining, unsigned char *csum, char **p)
+{
+ int n;
+
+ /* Always output the character. */
+ *csum += buf[0];
+ *(*p)++ = buf[0];
+
+ /* Don't go past '~'. */
+ if (remaining > 97)
+ remaining = 97;
+
+ for (n = 1; n < remaining; n++)
+ if (buf[n] != buf[0])
+ break;
+
+ /* N is the index of the first character not the same as buf[0].
+ buf[0] is counted twice, so by decrementing N, we get the number
+ of characters the RLE sequence will replace. */
+ n--;
+
+ if (n < 3)
+ return 1;
+
+ /* Skip the frame characters. The manual says to skip '+' and '-'
+ also, but there's no reason to. Unfortunately these two unusable
+ characters double the encoded length of a four byte zero
+ value. */
+ while (n + 29 == '$' || n + 29 == '#')
+ n--;
+
+ *csum += '*';
+ *(*p)++ = '*';
+ *csum += n + 29;
+ *(*p)++ = n + 29;
+
+ return n + 1;
+}
+
/* Send a packet to the remote machine, with error checking.
The data of the packet is in BUF, and the length of the
packet is in CNT. Returns >= 0 on success, -1 otherwise. */
p = buf2;
*p++ = '$';
- for (i = 0; i < cnt; i++)
- {
- csum += buf[i];
- *p++ = buf[i];
- }
+ for (i = 0; i < cnt;)
+ i += try_rle (buf + i, cnt - i, &csum, &p);
+
*p++ = '#';
*p++ = tohex ((csum >> 4) & 0xf);
*p++ = tohex (csum & 0xf);
{
int cc;
- if (send (remote_desc, buf2, p - buf2, 0) != p - buf2)
+ if (write (remote_desc, buf2, p - buf2) != p - buf2)
{
perror ("putpkt(write)");
+ free (buf2);
return -1;
}
fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
fflush (stderr);
}
- cc = recv (remote_desc, buf3, 1, 0);
+ cc = read (remote_desc, buf3, 1);
if (remote_debug)
{
fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
/* Check for an input interrupt while we're here. */
if (buf3[0] == '\003')
- (*the_target->send_signal) (SIGINT);
+ (*the_target->request_interrupt) ();
}
while (buf3[0] != '+');
return putpkt_binary (buf, strlen (buf));
}
-#ifndef USE_WIN32API
-
/* Come here when we get an input interrupt from the remote side. This
interrupt should only be active while we are waiting for the child to do
something. About the only thing that should come through is a ^C, which
- will cause us to send a SIGINT to the child. */
+ will cause us to request child interruption. */
static void
input_interrupt (int unused)
{
int cc;
char c = 0;
-
- cc = recv (remote_desc, &c, 1, 0);
+
+ cc = read (remote_desc, &c, 1);
if (cc != 1 || c != '\003')
{
cc, c, c);
return;
}
-
- (*the_target->send_signal) (SIGINT);
+
+ (*the_target->request_interrupt) ();
}
}
-#endif
+
+/* Check if the remote side sent us an interrupt request (^C). */
+void
+check_remote_input_interrupt_request (void)
+{
+ /* This function may be called before establishing communications,
+ therefore we need to validate the remote descriptor. */
+
+ if (remote_desc == INVALID_DESCRIPTOR)
+ return;
+
+ input_interrupt (0);
+}
/* 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
if (bufcnt-- > 0)
return *bufp++;
- bufcnt = recv (remote_desc, buf, sizeof (buf), 0);
+ bufcnt = read (remote_desc, buf, sizeof (buf));
if (bufcnt <= 0)
{
fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
(c1 << 4) + c2, csum, buf);
- send (remote_desc, "-", 1, 0);
+ write (remote_desc, "-", 1);
}
if (remote_debug)
fflush (stderr);
}
- send (remote_desc, "+", 1, 0);
+ write (remote_desc, "+", 1);
if (remote_debug)
{
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;
+}
+
/* 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 = malloc (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;
}
return 1;
}
+
+void
+monitor_output (const char *msg)
+{
+ char *buf = malloc (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 = malloc (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;
+}