2009-02-06 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / gdbserver / server.c
index da9d83c402e629c2bd4798b17d017204b01f47d6..416ceb3e33c2cc2a20436d873dc7e72c9385c8b5 100644 (file)
@@ -1,6 +1,6 @@
 /* Main code for remote server for GDB.
    Copyright (C) 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -28,6 +28,9 @@
 #if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
 
 unsigned long cont_thread;
 unsigned long general_thread;
@@ -67,14 +70,6 @@ int terminal_fd;
 /* TERMINAL_FD's original foreground group.  */
 pid_t old_foreground_pgrp;
 
-/* Set if you want to disable optional thread related packets support
-   in gdbserver, for the sake of testing GDB against stubs that don't
-   support them.  */
-int disable_packet_vCont;
-int disable_packet_Tthread;
-int disable_packet_qC;
-int disable_packet_qfThreadInfo;
-
 /* Hand back terminal ownership to the original foreground group.  */
 
 static void
@@ -84,6 +79,14 @@ restore_old_foreground_pgrp (void)
 }
 #endif
 
+/* Set if you want to disable optional thread related packets support
+   in gdbserver, for the sake of testing GDB against stubs that don't
+   support them.  */
+int disable_packet_vCont;
+int disable_packet_Tthread;
+int disable_packet_qC;
+int disable_packet_qfThreadInfo;
+
 static int
 target_running (void)
 {
@@ -267,6 +270,19 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (strcmp (own_buf, "QStartNoAckMode") == 0)
+    {
+      if (remote_debug)
+       {
+         fprintf (stderr, "[noack mode enabled]\n");
+         fflush (stderr);
+       }
+
+      noack_mode = 1;
+      write_ok (own_buf);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -633,6 +649,11 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (len > PBUFSIZ - 2)
        len = PBUFSIZ - 2;
       data = malloc (len + 1);
+      if (data == NULL)
+       {
+         write_enn (own_buf);
+         return;
+       }
       n = (*the_target->read_auxv) (ofs, data, len + 1);
       if (n < 0)
        write_enn (own_buf);
@@ -711,6 +732,11 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
        total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name);
 
       document = malloc (total_len);
+      if (document == NULL)
+       {
+         write_enn (own_buf);
+         return;
+       }
       strcpy (document, "<library-list>\n");
       p = document + strlen (document);
 
@@ -752,6 +778,109 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       return;
     }
 
+  if (the_target->qxfer_osdata != NULL
+      && strncmp ("qXfer:osdata:read:", own_buf, 18) == 0)
+    {
+      char *annex;
+      int n;
+      unsigned int len;
+      CORE_ADDR ofs;
+      unsigned char *workbuf;
+
+      strcpy (own_buf, "E00");
+      if (decode_xfer_read (own_buf + 18, &annex, &ofs, &len) < 0)
+       return;
+      if (len > PBUFSIZ - 2)
+       len = PBUFSIZ - 2;
+      workbuf = malloc (len + 1);
+      if (!workbuf)
+        return;
+
+      n = (*the_target->qxfer_osdata) (annex, workbuf, NULL, ofs, len + 1);
+      if (n < 0)
+       write_enn (own_buf);
+      else if (n > len)
+       *new_packet_len_p = write_qxfer_response
+                             (own_buf, workbuf, len, 1);
+      else
+       *new_packet_len_p = write_qxfer_response
+                             (own_buf, workbuf, n, 0);
+
+      free (workbuf);
+      return;
+    }
+
+  if (the_target->qxfer_siginfo != NULL
+      && strncmp ("qXfer:siginfo:read:", own_buf, 19) == 0)
+    {
+      unsigned char *data;
+      int n;
+      CORE_ADDR ofs;
+      unsigned int len;
+      char *annex;
+
+      require_running (own_buf);
+
+      /* Reject any annex; grab the offset and length.  */
+      if (decode_xfer_read (own_buf + 19, &annex, &ofs, &len) < 0
+         || annex[0] != '\0')
+       {
+         strcpy (own_buf, "E00");
+         return;
+       }
+
+      /* Read one extra byte, as an indicator of whether there is
+        more.  */
+      if (len > PBUFSIZ - 2)
+       len = PBUFSIZ - 2;
+      data = malloc (len + 1);
+      if (!data)
+        return;
+      n = (*the_target->qxfer_siginfo) (annex, data, NULL, ofs, len + 1);
+      if (n < 0)
+       write_enn (own_buf);
+      else if (n > len)
+       *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1);
+      else
+       *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0);
+
+      free (data);
+      return;
+    }
+
+  if (the_target->qxfer_siginfo != NULL
+      && strncmp ("qXfer:siginfo:write:", own_buf, 20) == 0)
+    {
+      char *annex;
+      int n;
+      unsigned int len;
+      CORE_ADDR ofs;
+      unsigned char *data;
+
+      require_running (own_buf);
+
+      strcpy (own_buf, "E00");
+      data = malloc (packet_len - 19);
+      if (!data)
+        return;
+      if (decode_xfer_write (own_buf + 20, packet_len - 20, &annex,
+                            &ofs, &len, data) < 0)
+       {
+         free (data);
+         return;
+       }
+
+      n = (*the_target->qxfer_siginfo)
+       (annex, NULL, (unsigned const char *)data, ofs, len);
+      if (n < 0)
+       write_enn (own_buf);
+      else
+       sprintf (own_buf, "%x", n);
+
+      free (data);
+      return;
+    }
+
   /* Protocol features query.  */
   if (strncmp ("qSupported", own_buf, 10) == 0
       && (own_buf[10] == ':' || own_buf[10] == '\0'))
@@ -768,12 +897,21 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (the_target->qxfer_spu != NULL)
        strcat (own_buf, ";qXfer:spu:read+;qXfer:spu:write+");
 
+      if (the_target->qxfer_siginfo != NULL)
+       strcat (own_buf, ";qXfer:siginfo:read+;qXfer:siginfo:write+");
+
       /* We always report qXfer:features:read, as targets may
         install XML files on a subsequent call to arch_setup.
         If we reported to GDB on startup that we don't support
         qXfer:feature:read at all, we will never be re-queried.  */
       strcat (own_buf, ";qXfer:features:read+");
 
+      if (transport_is_reliable)
+       strcat (own_buf, ";QStartNoAckMode+");
+
+      if (the_target->qxfer_osdata != NULL)
+        strcat (own_buf, ";qXfer:osdata:read+");
+
       return;
     }
 
@@ -844,6 +982,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       char *mon = malloc (PBUFSIZ);
       int len = strlen (own_buf + 6);
 
+      if (mon == NULL)
+       {
+         write_enn (own_buf);
+         return;
+       }
+
       if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2)
        {
          write_enn (own_buf);
@@ -922,6 +1066,8 @@ handle_v_cont (char *own_buf, char *status, int *signal)
      behavior; if no default action is in the list, we'll need the extra
      slot.  */
   resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
+  if (resume_info == NULL)
+    goto err;
 
   default_action.thread = -1;
   default_action.leave_stopped = 1;
@@ -1043,7 +1189,7 @@ handle_v_attach (char *own_buf, char *status, int *signal)
 static int
 handle_v_run (char *own_buf, char *status, int *signal)
 {
-  char *p, **pp, *next_p, **new_argv;
+  char *p, *next_p, **new_argv;
   int i, new_argc;
 
   new_argc = 0;
@@ -1053,7 +1199,13 @@ handle_v_run (char *own_buf, char *status, int *signal)
       new_argc++;
     }
 
-  new_argv = malloc ((new_argc + 2) * sizeof (char *));
+  new_argv = calloc (new_argc + 2, sizeof (char *));
+  if (new_argv == NULL)
+    {
+      write_enn (own_buf);
+      return 0;
+    }
+
   i = 0;
   for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
     {
@@ -1065,7 +1217,8 @@ handle_v_run (char *own_buf, char *status, int *signal)
        new_argv[i] = NULL;
       else
        {
-         new_argv[i] = malloc (1 + (next_p - p) / 2);
+         /* FIXME: Fail request if out of memory instead of dying.  */
+         new_argv[i] = xmalloc (1 + (next_p - p) / 2);
          unhexify (new_argv[i], p, (next_p - p) / 2);
          new_argv[i][(next_p - p) / 2] = '\0';
        }
@@ -1078,22 +1231,27 @@ handle_v_run (char *own_buf, char *status, int *signal)
 
   if (new_argv[0] == NULL)
     {
+      /* GDB didn't specify a program to run.  Use the program from the
+        last run with the new argument list.  */
+
       if (program_argv == NULL)
        {
+         /* FIXME: new_argv memory leak */
          write_enn (own_buf);
          return 0;
        }
 
       new_argv[0] = strdup (program_argv[0]);
+      if (new_argv[0] == NULL)
+       {
+         /* FIXME: new_argv memory leak */
+         write_enn (own_buf);
+         return 0;
+       }         
     }
 
-  /* Free the old argv.  */
-  if (program_argv)
-    {
-      for (pp = program_argv; *pp != NULL; pp++)
-       free (*pp);
-      free (program_argv);
-    }
+  /* Free the old argv and install the new one.  */
+  freeargv (program_argv);
   program_argv = new_argv;
 
   *signal = start_inferior (program_argv, status);
@@ -1198,7 +1356,7 @@ static void
 gdbserver_version (void)
 {
   printf ("GNU gdbserver %s%s\n"
-         "Copyright (C) 2007 Free Software Foundation, Inc.\n"
+         "Copyright (C) 2009 Free Software Foundation, Inc.\n"
          "gdbserver is free software, covered by the GNU General Public License.\n"
          "This gdbserver was configured as \"%s\"\n",
          PKGVERSION, version, host_name);
@@ -1215,9 +1373,10 @@ gdbserver_usage (FILE *stream)
           "HOST:PORT to listen for a TCP connection.\n"
           "\n"
           "Options:\n"
-          "  --debug\t\tEnable debugging output.\n"
-          "  --version\t\tDisplay version information and exit.\n"
-          "  --wrapper WRAPPER --\tRun WRAPPER to start new programs.\n");
+          "  --debug               Enable general debugging output.\n"
+          "  --remote-debug        Enable remote protocol debugging output.\n"
+          "  --version             Display version information and exit.\n"
+          "  --wrapper WRAPPER --  Run WRAPPER to start new programs.\n");
   if (REPORT_BUGS_TO[0] && stream == stdout)
     fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
 }
@@ -1294,6 +1453,8 @@ main (int argc, char *argv[])
        }
       else if (strcmp (*next_arg, "--debug") == 0)
        debug_threads = 1;
+      else if (strcmp (*next_arg, "--remote-debug") == 0)
+       remote_debug = 1;
       else if (strcmp (*next_arg, "--disable-packet") == 0)
        {
          gdbserver_show_disableable (stdout);
@@ -1386,17 +1547,17 @@ main (int argc, char *argv[])
   initialize_async_io ();
   initialize_low ();
 
-  own_buf = malloc (PBUFSIZ + 1);
-  mem_buf = malloc (PBUFSIZ);
+  own_buf = xmalloc (PBUFSIZ + 1);
+  mem_buf = xmalloc (PBUFSIZ);
 
   if (pid == 0 && *next_arg != NULL)
     {
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = malloc (sizeof (char *) * (n + 1));
+      program_argv = xmalloc (sizeof (char *) * (n + 1));
       for (i = 0; i < n; i++)
-       program_argv[i] = strdup (next_arg[i]);
+       program_argv[i] = xstrdup (next_arg[i]);
       program_argv[i] = NULL;
 
       /* Wait till we are at first instruction in program.  */
@@ -1444,6 +1605,7 @@ main (int argc, char *argv[])
 
   while (1)
     {
+      noack_mode = 0;
       remote_open (port);
 
     restart:
This page took 0.042139 seconds and 4 git commands to generate.