예제 #1
0
/* Handle all of the extended 'v' packets.  */
void
handle_v_requests (char *own_buf, char *status, int *signal,
		   int packet_len, int *new_packet_len)
{
  if (!disable_packet_vCont)
    {
      if (strncmp (own_buf, "vCont;", 6) == 0)
	{
	  require_running (own_buf);
	  handle_v_cont (own_buf, status, signal);
	  return;
	}

      if (strncmp (own_buf, "vCont?", 6) == 0)
	{
	  strcpy (own_buf, "vCont;c;C;s;S");
	  return;
	}
    }

  if (strncmp (own_buf, "vFile:", 6) == 0
      && handle_vFile (own_buf, packet_len, new_packet_len))
    return;

  if (strncmp (own_buf, "vAttach;", 8) == 0)
    {
      if (target_running ())
	{
	  fprintf (stderr, "Already debugging a process\n");
	  write_enn (own_buf);
	  return;
	}
      handle_v_attach (own_buf, status, signal);
      return;
    }

  if (strncmp (own_buf, "vRun;", 5) == 0)
    {
      if (target_running ())
	{
	  fprintf (stderr, "Already debugging a process\n");
	  write_enn (own_buf);
	  return;
	}
      handle_v_run (own_buf, status, signal);
      return;
    }

  /* Otherwise we didn't know what packet it was.  Say we didn't
     understand it.  */
  own_buf[0] = 0;
  return;
}
예제 #2
0
/* Handle all of the extended 'q' packets.  */
void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
  static struct inferior_list_entry *thread_ptr;

  /* Reply the current thread id.  */
  if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
    {
      require_running (own_buf);
      thread_ptr = all_threads.head;
      sprintf (own_buf, "QC%x",
	       thread_to_gdb_id ((struct thread_info *)thread_ptr));
      return;
    }

  if (strcmp ("qSymbol::", own_buf) == 0)
    {
      if (target_running () && the_target->look_up_symbols != NULL)
	(*the_target->look_up_symbols) ();

      strcpy (own_buf, "OK");
      return;
    }

  if (!disable_packet_qfThreadInfo)
    {
      if (strcmp ("qfThreadInfo", own_buf) == 0)
	{
	  require_running (own_buf);
	  thread_ptr = all_threads.head;
	  sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr));
	  thread_ptr = thread_ptr->next;
	  return;
	}

      if (strcmp ("qsThreadInfo", own_buf) == 0)
	{
	  require_running (own_buf);
	  if (thread_ptr != NULL)
	    {
	      sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr));
	      thread_ptr = thread_ptr->next;
	      return;
	    }
	  else
	    {
	      sprintf (own_buf, "l");
	      return;
	    }
	}
    }

  if (the_target->read_offsets != NULL
      && strcmp ("qOffsets", own_buf) == 0)
    {
      CORE_ADDR text, data;

      require_running (own_buf);
      if (the_target->read_offsets (&text, &data))
	sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX",
		 (long)text, (long)data, (long)data);
      else
	write_enn (own_buf);
      
      return;
    }

  if (the_target->qxfer_spu != NULL
      && strncmp ("qXfer:spu:read:", own_buf, 15) == 0)
    {
      char *annex;
      int n;
      unsigned int len;
      CORE_ADDR ofs;
      unsigned char *spu_buf;

      require_running (own_buf);
      strcpy (own_buf, "E00");
      if (decode_xfer_read (own_buf + 15, &annex, &ofs, &len) < 0)
	  return;
      if (len > PBUFSIZ - 2)
	len = PBUFSIZ - 2;
      spu_buf = malloc (len + 1);
      if (!spu_buf)
        return;

      n = (*the_target->qxfer_spu) (annex, spu_buf, NULL, ofs, len + 1);
      if (n < 0) 
	write_enn (own_buf);
      else if (n > len)
	*new_packet_len_p = write_qxfer_response
			      (own_buf, spu_buf, len, 1);
      else 
	*new_packet_len_p = write_qxfer_response
			      (own_buf, spu_buf, n, 0);

      free (spu_buf);
      return;
    }

  if (the_target->qxfer_spu != NULL
      && strncmp ("qXfer:spu:write:", own_buf, 16) == 0)
    {
      char *annex;
      int n;
      unsigned int len;
      CORE_ADDR ofs;
      unsigned char *spu_buf;

      require_running (own_buf);
      strcpy (own_buf, "E00");
      spu_buf = malloc (packet_len - 15);
      if (!spu_buf)
        return;
      if (decode_xfer_write (own_buf + 16, packet_len - 16, &annex,
			     &ofs, &len, spu_buf) < 0)
	{
	  free (spu_buf);
	  return;
	}

      n = (*the_target->qxfer_spu) 
	(annex, NULL, (unsigned const char *)spu_buf, ofs, len);
      if (n < 0)
	write_enn (own_buf);
      else
	sprintf (own_buf, "%x", n);

      free (spu_buf);
      return;
    }

  if (the_target->read_auxv != NULL
      && strncmp ("qXfer:auxv:read:", own_buf, 16) == 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 + 16, &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);
      n = (*the_target->read_auxv) (ofs, data, 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 (strncmp ("qXfer:features:read:", own_buf, 20) == 0)
    {
      CORE_ADDR ofs;
      unsigned int len, total_len;
      const char *document;
      char *annex;

      require_running (own_buf);

      /* Grab the annex, offset, and length.  */
      if (decode_xfer_read (own_buf + 20, &annex, &ofs, &len) < 0)
	{
	  strcpy (own_buf, "E00");
	  return;
	}

      /* Now grab the correct annex.  */
      document = get_features_xml (annex);
      if (document == NULL)
	{
	  strcpy (own_buf, "E00");
	  return;
	}

      total_len = strlen (document);
      if (len > PBUFSIZ - 2)
	len = PBUFSIZ - 2;

      if (ofs > total_len)
	write_enn (own_buf);
      else if (len < total_len - ofs)
	*new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
						  len, 1);
      else
	*new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
						  total_len - ofs, 0);

      return;
    }

  if (strncmp ("qXfer:libraries:read:", own_buf, 21) == 0)
    {
      CORE_ADDR ofs;
      unsigned int len, total_len;
      char *document, *p;
      struct inferior_list_entry *dll_ptr;
      char *annex;

      require_running (own_buf);

      /* Reject any annex; grab the offset and length.  */
      if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0
	  || annex[0] != '\0')
	{
	  strcpy (own_buf, "E00");
	  return;
	}

      /* Over-estimate the necessary memory.  Assume that every character
	 in the library name must be escaped.  */
      total_len = 64;
      for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
	total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name);

      document = malloc (total_len);
      strcpy (document, "<library-list>\n");
      p = document + strlen (document);

      for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
	{
	  struct dll_info *dll = (struct dll_info *) dll_ptr;
	  char *name;

	  strcpy (p, "  <library name=\"");
	  p = p + strlen (p);
	  name = xml_escape_text (dll->name);
	  strcpy (p, name);
	  free (name);
	  p = p + strlen (p);
	  strcpy (p, "\"><segment address=\"");
	  p = p + strlen (p);
	  sprintf (p, "0x%lx", (long) dll->base_addr);
	  p = p + strlen (p);
	  strcpy (p, "\"/></library>\n");
	  p = p + strlen (p);
	}

      strcpy (p, "</library-list>\n");

      total_len = strlen (document);
      if (len > PBUFSIZ - 2)
	len = PBUFSIZ - 2;

      if (ofs > total_len)
	write_enn (own_buf);
      else if (len < total_len - ofs)
	*new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
						  len, 1);
      else
	*new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
						  total_len - ofs, 0);

      free (document);
      return;
    }

  /* Protocol features query.  */
  if (strncmp ("qSupported", own_buf, 10) == 0
      && (own_buf[10] == ':' || own_buf[10] == '\0'))
    {
      sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);

      /* We do not have any hook to indicate whether the target backend
	 supports qXfer:libraries:read, so always report it.  */
      strcat (own_buf, ";qXfer:libraries:read+");

      if (the_target->read_auxv != NULL)
	strcat (own_buf, ";qXfer:auxv:read+");

      if (the_target->qxfer_spu != NULL)
	strcat (own_buf, ";qXfer:spu:read+;qXfer:spu: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+");
      return;
    }

  /* Thread-local storage support.  */
  if (the_target->get_tls_address != NULL
      && strncmp ("qGetTLSAddr:", own_buf, 12) == 0)
    {
      char *p = own_buf + 12;
      CORE_ADDR parts[3], address = 0;
      int i, err;

      require_running (own_buf);

      for (i = 0; i < 3; i++)
	{
	  char *p2;
	  int len;

	  if (p == NULL)
	    break;

	  p2 = strchr (p, ',');
	  if (p2)
	    {
	      len = p2 - p;
	      p2++;
	    }
	  else
	    {
	      len = strlen (p);
	      p2 = NULL;
	    }

	  decode_address (&parts[i], p, len);
	  p = p2;
	}

      if (p != NULL || i < 3)
	err = 1;
      else
	{
	  struct thread_info *thread = gdb_id_to_thread (parts[0]);

	  if (thread == NULL)
	    err = 2;
	  else
	    err = the_target->get_tls_address (thread, parts[1], parts[2],
					       &address);
	}

      if (err == 0)
	{
	  sprintf (own_buf, "%llx", address);
	  return;
	}
      else if (err > 0)
	{
	  write_enn (own_buf);
	  return;
	}

      /* Otherwise, pretend we do not understand this packet.  */
    }

  /* Handle "monitor" commands.  */
  if (strncmp ("qRcmd,", own_buf, 6) == 0)
    {
      char *mon = malloc (PBUFSIZ);
      int len = strlen (own_buf + 6);

      if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2)
	{
	  write_enn (own_buf);
	  free (mon);
	  return;
	}
      mon[len / 2] = '\0';

      write_ok (own_buf);

      if (strcmp (mon, "set debug 1") == 0)
	{
	  debug_threads = 1;
	  monitor_output ("Debug output enabled.\n");
	}
      else if (strcmp (mon, "set debug 0") == 0)
	{
	  debug_threads = 0;
	  monitor_output ("Debug output disabled.\n");
	}
      else if (strcmp (mon, "set remote-debug 1") == 0)
	{
	  remote_debug = 1;
	  monitor_output ("Protocol debug output enabled.\n");
	}
      else if (strcmp (mon, "set remote-debug 0") == 0)
	{
	  remote_debug = 0;
	  monitor_output ("Protocol debug output disabled.\n");
	}
      else if (strcmp (mon, "help") == 0)
	monitor_show_help ();
      else if (strcmp (mon, "exit") == 0)
	exit_requested = 1;
      else
	{
	  monitor_output ("Unknown monitor command.\n\n");
	  monitor_show_help ();
	  write_enn (own_buf);
	}

      free (mon);
      return;
    }

  if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
    {
      require_running (own_buf);
      handle_search_memory (own_buf, packet_len);
      return;
    }

  /* Otherwise we didn't know what packet it was.  Say we didn't
     understand it.  */
  own_buf[0] = 0;
}
예제 #3
0
int
main (int argc, char *argv[])
{
  char ch, status, *own_buf;
  unsigned char *mem_buf;
  int i = 0;
  int signal;
  unsigned int len;
  CORE_ADDR mem_addr;
  int bad_attach;
  int pid;
  char *arg_end, *port;
  char **next_arg = &argv[1];
  int multi_mode = 0;
  int attach = 0;
  int was_running;

  while (*next_arg != NULL && **next_arg == '-')
    {
      if (strcmp (*next_arg, "--version") == 0)
	{
	  gdbserver_version ();
	  exit (0);
	}
      else if (strcmp (*next_arg, "--help") == 0)
	{
	  gdbserver_usage (stdout);
	  exit (0);
	}
      else if (strcmp (*next_arg, "--attach") == 0)
	attach = 1;
      else if (strcmp (*next_arg, "--multi") == 0)
	multi_mode = 1;
      else if (strcmp (*next_arg, "--wrapper") == 0)
	{
	  next_arg++;

	  wrapper_argv = next_arg;
	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
	    next_arg++;

	  if (next_arg == wrapper_argv || *next_arg == NULL)
	    {
	      gdbserver_usage (stderr);
	      exit (1);
	    }

	  /* Consume the "--".  */
	  *next_arg = NULL;
	}
      else if (strcmp (*next_arg, "--debug") == 0)
	debug_threads = 1;
      else if (strcmp (*next_arg, "--disable-packet") == 0)
	{
	  gdbserver_show_disableable (stdout);
	  exit (0);
	}
      else if (strncmp (*next_arg,
			"--disable-packet=",
			sizeof ("--disable-packet=") - 1) == 0)
	{
	  char *packets, *tok;

	  packets = *next_arg += sizeof ("--disable-packet=") - 1;
	  for (tok = strtok (packets, ",");
	       tok != NULL;
	       tok = strtok (NULL, ","))
	    {
	      if (strcmp ("vCont", tok) == 0)
		disable_packet_vCont = 1;
	      else if (strcmp ("Tthread", tok) == 0)
		disable_packet_Tthread = 1;
	      else if (strcmp ("qC", tok) == 0)
		disable_packet_qC = 1;
	      else if (strcmp ("qfThreadInfo", tok) == 0)
		disable_packet_qfThreadInfo = 1;
	      else if (strcmp ("threads", tok) == 0)
		{
		  disable_packet_vCont = 1;
		  disable_packet_Tthread = 1;
		  disable_packet_qC = 1;
		  disable_packet_qfThreadInfo = 1;
		}
	      else
		{
		  fprintf (stderr, "Don't know how to disable \"%s\".\n\n",
			   tok);
		  gdbserver_show_disableable (stderr);
		  exit (1);
		}
	    }
	}
      else
	{
	  fprintf (stderr, "Unknown argument: %s\n", *next_arg);
	  exit (1);
	}

      next_arg++;
      continue;
    }

  if (setjmp (toplevel))
    {
      fprintf (stderr, "Exiting\n");
      exit (1);
    }

  port = *next_arg;
  next_arg++;
  if (port == NULL || (!attach && !multi_mode && *next_arg == NULL))
    {
      gdbserver_usage (stderr);
      exit (1);
    }

  bad_attach = 0;
  pid = 0;

  /* --attach used to come after PORT, so allow it there for
       compatibility.  */
  if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0)
    {
      attach = 1;
      next_arg++;
    }

  if (attach
      && (*next_arg == NULL
	  || (*next_arg)[0] == '\0'
	  || (pid = strtoul (*next_arg, &arg_end, 0)) == 0
	  || *arg_end != '\0'
	  || next_arg[1] != NULL))
    bad_attach = 1;

  if (bad_attach)
    {
      gdbserver_usage (stderr);
      exit (1);
    }

  initialize_async_io ();
  initialize_low ();

  own_buf = malloc (PBUFSIZ + 1);
  mem_buf = malloc (PBUFSIZ);

  if (pid == 0 && *next_arg != NULL)
    {
      int i, n;

      n = argc - (next_arg - argv);
      program_argv = malloc (sizeof (char *) * (n + 1));
      for (i = 0; i < n; i++)
	program_argv[i] = strdup (next_arg[i]);
      program_argv[i] = NULL;

      /* Wait till we are at first instruction in program.  */
      signal = start_inferior (program_argv, &status);

      /* We are now (hopefully) stopped at the first instruction of
	 the target process.  This assumes that the target process was
	 successfully created.  */
    }
  else if (pid != 0)
    {
      if (attach_inferior (pid, &status, &signal) == -1)
	error ("Attaching not supported on this target");

      /* Otherwise succeeded.  */
    }
  else
    {
      status = 'W';
      signal = 0;
    }

  /* Don't report shared library events on the initial connection,
     even if some libraries are preloaded.  Avoids the "stopped by
     shared library event" notice on gdb side.  */
  dlls_changed = 0;

  if (setjmp (toplevel))
    {
      fprintf (stderr, "Killing inferior\n");
      kill_inferior ();
      exit (1);
    }

  if (status == 'W' || status == 'X')
    was_running = 0;
  else
    was_running = 1;

  if (!was_running && !multi_mode)
    {
      fprintf (stderr, "No program to debug.  GDBserver exiting.\n");
      exit (1);
    }

  while (1)
    {
      noack_mode = 0;
      remote_open (port);

    restart:
      if (setjmp (toplevel) != 0)
	{
	  /* An error occurred.  */
	  if (response_needed)
	    {
	      write_enn (own_buf);
	      putpkt (own_buf);
	    }
	}

      disable_async_io ();
      while (!exit_requested)
	{
	  unsigned char sig;
	  int packet_len;
	  int new_packet_len = -1;

	  response_needed = 0;
	  packet_len = getpkt (own_buf);
	  if (packet_len <= 0)
	    break;
	  response_needed = 1;

	  i = 0;
	  ch = own_buf[i++];
	  switch (ch)
	    {
	    case 'q':
	      handle_query (own_buf, packet_len, &new_packet_len);
	      break;
	    case 'Q':
	      handle_general_set (own_buf);
	      break;
	    case 'D':
	      require_running (own_buf);
	      fprintf (stderr, "Detaching from inferior\n");
	      if (detach_inferior () != 0)
		write_enn (own_buf);
	      else
		{
		  write_ok (own_buf);

		  if (extended_protocol)
		    {
		      /* Treat this like a normal program exit.  */
		      signal = 0;
		      status = 'W';
		    }
		  else
		    {
		      putpkt (own_buf);
		      remote_close ();

		      /* If we are attached, then we can exit.  Otherwise, we
			 need to hang around doing nothing, until the child
			 is gone.  */
		      if (!attached)
			join_inferior ();

		      exit (0);
		    }
		}
	      break;
	    case '!':
	      extended_protocol = 1;
	      write_ok (own_buf);
	      break;
	    case '?':
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'H':
	      if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's')
		{
		  unsigned long gdb_id, thread_id;

		  require_running (own_buf);
		  gdb_id = strtoul (&own_buf[2], NULL, 16);
		  if (gdb_id == 0 || gdb_id == -1)
		    thread_id = gdb_id;
		  else
		    {
		      thread_id = gdb_id_to_thread_id (gdb_id);
		      if (thread_id == 0)
			{
			  write_enn (own_buf);
			  break;
			}
		    }

		  if (own_buf[1] == 'g')
		    {
		      general_thread = thread_id;
		      set_desired_inferior (1);
		    }
		  else if (own_buf[1] == 'c')
		    cont_thread = thread_id;
		  else if (own_buf[1] == 's')
		    step_thread = thread_id;

		  write_ok (own_buf);
		}
	      else
		{
		  /* Silently ignore it so that gdb can extend the protocol
		     without compatibility headaches.  */
		  own_buf[0] = '\0';
		}
	      break;
	    case 'g':
	      require_running (own_buf);
	      set_desired_inferior (1);
	      registers_to_string (own_buf);
	      break;
	    case 'G':
	      require_running (own_buf);
	      set_desired_inferior (1);
	      registers_from_string (&own_buf[1]);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      require_running (own_buf);
	      decode_m_packet (&own_buf[1], &mem_addr, &len);
	      if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
		convert_int_to_ascii (mem_buf, own_buf, len);
	      else
		write_enn (own_buf);
	      break;
	    case 'M':
	      require_running (own_buf);
	      decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
	      if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
		write_ok (own_buf);
	      else
		write_enn (own_buf);
	      break;
	    case 'X':
	      require_running (own_buf);
	      if (decode_X_packet (&own_buf[1], packet_len - 1,
				   &mem_addr, &len, mem_buf) < 0
		  || write_inferior_memory (mem_addr, mem_buf, len) != 0)
		write_enn (own_buf);
	      else
		write_ok (own_buf);
	      break;
	    case 'C':
	      require_running (own_buf);
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      if (target_signal_to_host_p (sig))
		signal = target_signal_to_host (sig);
	      else
		signal = 0;
	      myresume (own_buf, 0, &signal, &status);
	      break;
	    case 'S':
	      require_running (own_buf);
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      if (target_signal_to_host_p (sig))
		signal = target_signal_to_host (sig);
	      else
		signal = 0;
	      myresume (own_buf, 1, &signal, &status);
	      break;
	    case 'c':
	      require_running (own_buf);
	      signal = 0;
	      myresume (own_buf, 0, &signal, &status);
	      break;
	    case 's':
	      require_running (own_buf);
	      signal = 0;
	      myresume (own_buf, 1, &signal, &status);
	      break;
	    case 'Z':
	      {
		char *lenptr;
		char *dataptr;
		CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
		int len = strtol (lenptr + 1, &dataptr, 16);
		char type = own_buf[1];

		if (the_target->insert_watchpoint == NULL
		    || (type < '2' || type > '4'))
		  {
		    /* No watchpoint support or not a watchpoint command;
		       unrecognized either way.  */
		    own_buf[0] = '\0';
		  }
		else
		  {
		    int res;

		    require_running (own_buf);
		    res = (*the_target->insert_watchpoint) (type, addr, len);
		    if (res == 0)
		      write_ok (own_buf);
		    else if (res == 1)
		      /* Unsupported.  */
		      own_buf[0] = '\0';
		    else
		      write_enn (own_buf);
		  }
		break;
	      }
	    case 'z':
	      {
		char *lenptr;
		char *dataptr;
		CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
		int len = strtol (lenptr + 1, &dataptr, 16);
		char type = own_buf[1];

		if (the_target->remove_watchpoint == NULL
		    || (type < '2' || type > '4'))
		  {
		    /* No watchpoint support or not a watchpoint command;
		       unrecognized either way.  */
		    own_buf[0] = '\0';
		  }
		else
		  {
		    int res;

		    require_running (own_buf);
		    res = (*the_target->remove_watchpoint) (type, addr, len);
		    if (res == 0)
		      write_ok (own_buf);
		    else if (res == 1)
		      /* Unsupported.  */
		      own_buf[0] = '\0';
		    else
		      write_enn (own_buf);
		  }
		break;
	      }
	    case 'k':
	      response_needed = 0;
	      if (!target_running ())
		/* The packet we received doesn't make sense - but we
		   can't reply to it, either.  */
		goto restart;

	      fprintf (stderr, "Killing inferior\n");
	      kill_inferior ();

	      /* When using the extended protocol, we wait with no
		 program running.  The traditional protocol will exit
		 instead.  */
	      if (extended_protocol)
		{
		  status = 'X';
		  signal = TARGET_SIGNAL_KILL;
		  was_running = 0;
		  goto restart;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      {
		unsigned long gdb_id, thread_id;

		require_running (own_buf);
		gdb_id = strtoul (&own_buf[1], NULL, 16);
		thread_id = gdb_id_to_thread_id (gdb_id);
		if (thread_id == 0)
		  {
		    write_enn (own_buf);
		    break;
		  }

		if (mythread_alive (thread_id))
		  write_ok (own_buf);
		else
		  write_enn (own_buf);
	      }
	      break;
	    case 'R':
	      response_needed = 0;

	      /* Restarting the inferior is only supported in the
	         extended protocol.  */
	      if (extended_protocol)
		{
		  if (target_running ())
		    kill_inferior ();
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  if (program_argv != NULL)
		    signal = start_inferior (program_argv, &status);
		  else
		    {
		      status = 'X';
		      signal = TARGET_SIGNAL_KILL;
		    }
		  goto restart;
		}
	      else
		{
		  /* It is a request we don't understand.  Respond with an
		     empty packet so that gdb knows that we don't support this
		     request.  */
		  own_buf[0] = '\0';
		  break;
		}
	    case 'v':
	      /* Extended (long) request.  */
	      handle_v_requests (own_buf, &status, &signal,
				 packet_len, &new_packet_len);
	      break;

	    default:
	      /* It is a request we don't understand.  Respond with an
	         empty packet so that gdb knows that we don't support this
	         request.  */
	      own_buf[0] = '\0';
	      break;
	    }

	  if (new_packet_len != -1)
	    putpkt_binary (own_buf, new_packet_len);
	  else
	    putpkt (own_buf);

	  response_needed = 0;

	  if (was_running && (status == 'W' || status == 'X'))
	    {
	      was_running = 0;

	      if (status == 'W')
		fprintf (stderr,
			 "\nChild exited with status %d\n", signal);
	      if (status == 'X')
		fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
			 target_signal_to_host (signal),
			 target_signal_to_name (signal));

	      if (extended_protocol)
		goto restart;
	      else
		{
		  fprintf (stderr, "GDBserver exiting\n");
		  exit (0);
		}
	    }

	  if (status != 'W' && status != 'X')
	    was_running = 1;
	}

      /* If an exit was requested (using the "monitor exit" command),
	 terminate now.  The only other way to get here is for
	 getpkt to fail; close the connection and reopen it at the
	 top of the loop.  */

      if (exit_requested)
	{
	  remote_close ();
	  if (attached && target_running ())
	    detach_inferior ();
	  else if (target_running ())
	    kill_inferior ();
	  exit (0);
	}
      else
	{
	  fprintf (stderr, "Remote side has terminated connection.  "
			   "GDBserver will reopen the connection.\n");
	  remote_close ();
	}
    }
}
예제 #4
0
파일: server.c 프로젝트: mmcx/cegcc
void
gdbserver_main (void)
{
  CORE_ADDR mem_addr;
  char *own_buf;
  unsigned char *mem_buf;
  int i = 0;
  unsigned int len;

  own_buf = malloc (PBUFSIZ + 1);
  mem_buf = malloc (PBUFSIZ);

  while (1)
    {
      remote_open (port);

    restart:
#if 0
      if (setjmp (toplevel) != 0)
	{
	  /* An error occurred.  */
	  if (response_needed)
	    {
	      write_enn (own_buf);
	      putpkt (own_buf);
	    }
	}
#endif

      disable_async_io ();
      while (!exit_requested)
	{
	  unsigned char sig;
	  int packet_len;
	  int new_packet_len = -1;

	  response_needed = 0;
	  packet_len = getpkt (own_buf);
	  if (packet_len <= 0)
	    break;
	  response_needed = 1;

	  i = 0;
	  ch = own_buf[i++];
	  switch (ch)
	    {
	    case 'q':
	      handle_query (own_buf, packet_len, &new_packet_len);
	      break;
	    case 'Q':
	      handle_general_set (own_buf);
	      break;
	    case 'D':
	      require_running (own_buf);
	      fprintf (stderr, "Detaching from inferior\n");
	      if (detach_inferior () != 0)
		write_enn (own_buf);
	      else
		{
		  write_ok (own_buf);

		  if (extended_protocol)
		    {
		      /* Treat this like a normal program exit.  */
		      signal = 0;
		      status = 'W';
		    }
		  else
		    {
		      putpkt (own_buf);
		      remote_close ();

		      /* If we are attached, then we can exit.  Otherwise, we
			 need to hang around doing nothing, until the child
			 is gone.  */
		      if (!attached)
			join_inferior ();

		      exit (0);
		    }
		}
	      break;
	    case '!':
	      extended_protocol = 1;
	      write_ok (own_buf);
	      break;
	    case '?':
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'H':
	      if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's')
		{
		  unsigned long gdb_id, thread_id;

		  require_running (own_buf);
		  gdb_id = strtoul (&own_buf[2], NULL, 16);
		  if (gdb_id == 0 || gdb_id == -1)
		    thread_id = gdb_id;
		  else
		    {
		      thread_id = gdb_id_to_thread_id (gdb_id);
		      if (thread_id == 0)
			{
			  write_enn (own_buf);
			  break;
			}
		    }

		  if (own_buf[1] == 'g')
		    {
		      general_thread = thread_id;
		      set_desired_inferior (1);
		    }
		  else if (own_buf[1] == 'c')
		    cont_thread = thread_id;
		  else if (own_buf[1] == 's')
		    step_thread = thread_id;

		  write_ok (own_buf);
		}
	      else
		{
		  /* Silently ignore it so that gdb can extend the protocol
		     without compatibility headaches.  */
		  own_buf[0] = '\0';
		}
	      break;
	    case 'g':
	      require_running (own_buf);
	      set_desired_inferior (1);
	      registers_to_string (own_buf);
	      break;
	    case 'G':
	      require_running (own_buf);
	      set_desired_inferior (1);
	      registers_from_string (&own_buf[1]);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      require_running (own_buf);
	      decode_m_packet (&own_buf[1], &mem_addr, &len);
	      if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
		convert_int_to_ascii (mem_buf, own_buf, len);
	      else
		write_enn (own_buf);
	      break;
	    case 'M':
	      require_running (own_buf);
	      decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
	      if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
		write_ok (own_buf);
	      else
		write_enn (own_buf);
	      break;
	    case 'X':
	      require_running (own_buf);
	      if (decode_X_packet (&own_buf[1], packet_len - 1,
				   &mem_addr, &len, mem_buf) < 0
		  || write_inferior_memory (mem_addr, mem_buf, len) != 0)
		write_enn (own_buf);
	      else
		write_ok (own_buf);
	      break;
	    case 'C':
	      require_running (own_buf);
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      if (target_signal_to_host_p (sig))
		signal = target_signal_to_host (sig);
	      else
		signal = 0;
	      myresume (own_buf, 0, &signal, &status);
	      break;
	    case 'S':
	      require_running (own_buf);
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      if (target_signal_to_host_p (sig))
		signal = target_signal_to_host (sig);
	      else
		signal = 0;
	      myresume (own_buf, 1, &signal, &status);
	      break;
	    case 'c':
	      require_running (own_buf);
	      signal = 0;
	      myresume (own_buf, 0, &signal, &status);
	      break;
	    case 's':
	      require_running (own_buf);
	      signal = 0;
	      myresume (own_buf, 1, &signal, &status);
	      break;
	    case 'Z':
	      {
		char *lenptr;
		char *dataptr;
		CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
		int len = strtol (lenptr + 1, &dataptr, 16);
		char type = own_buf[1];

		if (the_target->insert_watchpoint == NULL
		    || (type < '2' || type > '4'))
		  {
		    /* No watchpoint support or not a watchpoint command;
		       unrecognized either way.  */
		    own_buf[0] = '\0';
		  }
		else
		  {
		    int res;

		    require_running (own_buf);
		    res = (*the_target->insert_watchpoint) (type, addr, len);
		    if (res == 0)
		      write_ok (own_buf);
		    else if (res == 1)
		      /* Unsupported.  */
		      own_buf[0] = '\0';
		    else
		      write_enn (own_buf);
		  }
		break;
	      }
	    case 'z':
	      {
		char *lenptr;
		char *dataptr;
		CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
		int len = strtol (lenptr + 1, &dataptr, 16);
		char type = own_buf[1];

		if (the_target->remove_watchpoint == NULL
		    || (type < '2' || type > '4'))
		  {
		    /* No watchpoint support or not a watchpoint command;
		       unrecognized either way.  */
		    own_buf[0] = '\0';
		  }
		else
		  {
		    int res;

		    require_running (own_buf);
		    res = (*the_target->remove_watchpoint) (type, addr, len);
		    if (res == 0)
		      write_ok (own_buf);
		    else if (res == 1)
		      /* Unsupported.  */
		      own_buf[0] = '\0';
		    else
		      write_enn (own_buf);
		  }
		break;
	      }
	    case 'k':
	      response_needed = 0;
	      if (!target_running ())
		/* The packet we received doesn't make sense - but we
		   can't reply to it, either.  */
		goto restart;

	      fprintf (stderr, "Killing inferior\n");
	      kill_inferior ();

	      /* When using the extended protocol, we wait with no
		 program running.  The traditional protocol will exit
		 instead.  */
	      if (extended_protocol)
		{
		  status = 'X';
		  signal = TARGET_SIGNAL_KILL;
		  was_running = 0;
		  goto restart;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      {
		unsigned long gdb_id, thread_id;

		require_running (own_buf);
		gdb_id = strtoul (&own_buf[1], NULL, 16);
		thread_id = gdb_id_to_thread_id (gdb_id);
		if (thread_id == 0)
		  {
		    write_enn (own_buf);
		    break;
		  }

		if (mythread_alive (thread_id))
		  write_ok (own_buf);
		else
		  write_enn (own_buf);
	      }
	      break;
	    case 'R':
	      response_needed = 0;

	      /* Restarting the inferior is only supported in the
	         extended protocol.  */
	      if (extended_protocol)
		{
		  if (target_running ())
		    kill_inferior ();
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  if (program_argv != NULL)
		    signal = start_inferior (program_argv, &status);
		  else
		    {
		      status = 'X';
		      signal = TARGET_SIGNAL_KILL;
		    }
		  goto restart;
		}
	      else
		{
		  /* It is a request we don't understand.  Respond with an
		     empty packet so that gdb knows that we don't support this
		     request.  */
		  own_buf[0] = '\0';
		  break;
		}
	    case 'v':
	      /* Extended (long) request.  */
	      handle_v_requests (own_buf, &status, &signal,
				 packet_len, &new_packet_len);
	      break;

	    default:
	      /* It is a request we don't understand.  Respond with an
	         empty packet so that gdb knows that we don't support this
	         request.  */
	      own_buf[0] = '\0';
	      break;
	    }

	  if (new_packet_len != -1)
	    putpkt_binary (own_buf, new_packet_len);
	  else
	    putpkt (own_buf);

	  response_needed = 0;

	  if (was_running && (status == 'W' || status == 'X'))
	    {
	      was_running = 0;

	      if (status == 'W')
		fprintf (stderr,
			 "\nChild exited with status %d\n", signal);
	      if (status == 'X')
		fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
			 target_signal_to_host (signal),
			 target_signal_to_name (signal));

	      if (extended_protocol)
		goto restart;
	      else
		{
		  fprintf (stderr, "GDBserver exiting\n");
		  exit (0);
		}
	    }

	  if (status != 'W' && status != 'X')
	    was_running = 1;
	}

      /* If an exit was requested (using the "monitor exit" command),
	 terminate now.  The only other way to get here is for
	 getpkt to fail; close the connection and reopen it at the
	 top of the loop.  */

      if (exit_requested)
	{
	  remote_close ();
	  if (attached && target_running ())
	    detach_inferior ();
	  else if (target_running ())
	    kill_inferior ();
	  exit (0);
	}
      else
	{
	  fprintf (stderr, "Remote side has terminated connection.  "
			   "GDBserver will reopen the connection.\n");
	  remote_close ();
	}
    }
}