示例#1
0
文件: target.c 项目: lu-zero/valgrind
static
void remove_thread_if_not_in_vg_threads (struct inferior_list_entry *inf)
{
  struct thread_info *thread = get_thread (inf);
  if (!VG_(lwpid_to_vgtid)(thread_to_gdb_id(thread))) {
     dlog(1, "removing gdb ptid %s\n", 
          image_ptid(thread_to_gdb_id(thread)));
     remove_thread (thread);
  }
}
示例#2
0
static void
lynx_resume (struct thread_resume *resume_info, size_t n)
{
  ptid_t ptid = resume_info[0].thread;
  const int request
    = (resume_info[0].kind == resume_step
       ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP)
       : PTRACE_CONT);
  const int signal = resume_info[0].sig;

  /* If given a minus_one_ptid, then try using the current_process'
     private->last_wait_event_ptid.  On most LynxOS versions,
     using any of the process' thread works well enough, but
     LynxOS 178 is a little more sensitive, and triggers some
     unexpected signals (Eg SIG61) when we resume the inferior
     using a different thread.  */
  if (ptid_equal (ptid, minus_one_ptid))
    ptid = current_process()->priv->last_wait_event_ptid;

  /* The ptid might still be minus_one_ptid; this can happen between
     the moment we create the inferior or attach to a process, and
     the moment we resume its execution for the first time.  It is
     fine to use the current_thread's ptid in those cases.  */
  if (ptid_equal (ptid, minus_one_ptid))
    ptid = thread_to_gdb_id (current_thread);

  regcache_invalidate ();

  errno = 0;
  lynx_ptrace (request, ptid, 1, signal, 0);
  if (errno)
    perror_with_name ("ptrace");
}
示例#3
0
static void
lynx_request_interrupt (void)
{
  ptid_t inferior_ptid = thread_to_gdb_id (get_first_thread ());

  kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
}
static void
nto_store_registers (struct regcache *regcache, int regno)
{
  procfs_greg greg;
  int err;
  ptid_t ptid;

  TRACE ("%s (regno:%d)\n", __func__, regno);

  if (current_inferior == NULL)
    {
      TRACE ("current_inferior is NULL\n");
      return;
    }
  ptid = thread_to_gdb_id (current_inferior);
  if (!nto_set_thread (ptid))
    return;

  memset (&greg, 0, sizeof (greg));
  for  (regno = 0; regno != the_low_target.num_regs; ++regno)
    {
      const unsigned int regoffset
	= the_low_target.register_offset (regno);
      collect_register (regcache, regno, ((char *)&greg) + regoffset);
    }
  err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg),
		0);
  if (err != EOK)
    TRACE ("Error: setting registers.\n");
}
static int
nto_stopped_by_watchpoint (void)
{
  int ret = 0;

  TRACE ("%s\n", __func__);
  if (nto_inferior.ctl_fd != -1 && current_inferior != NULL)
    {
      ptid_t ptid;

      ptid = thread_to_gdb_id (current_inferior);
      if (nto_set_thread (ptid))
	{
	  const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR
				| _DEBUG_FLAG_TRACE_MODIFY;
	  procfs_status status;
	  int err;

	  err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
			sizeof (status), 0);
	  if (err == EOK && (status.flags & watchmask))
	    ret = 1;
	}
    }
  TRACE ("%s: %s\n", __func__, ret ? "yes" : "no");
  return ret;
}
示例#6
0
static int
lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
{
  /* On LynxOS, memory reads needs to be performed in chunks the size
     of int types, and they should also be aligned accordingly.  */
  int buf;
  const int xfer_size = sizeof (buf);
  CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);

  while (addr < memaddr + len)
    {
      int skip = 0;
      int truncate = 0;

      errno = 0;
      if (addr < memaddr)
        skip = memaddr - addr;
      if (addr + xfer_size > memaddr + len)
        truncate = addr + xfer_size - memaddr - len;
      buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0);
      if (errno)
        return errno;
      memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip,
              xfer_size - skip - truncate);
      addr += xfer_size;
    }

  return 0;
}
示例#7
0
static void
lynx_store_registers (struct regcache *regcache, int regno)
{
  struct lynx_regset_info *regset = lynx_target_regsets;
  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);

  lynx_debug ("lynx_store_registers (regno = %d)", regno);

  while (regset->size >= 0)
    {
      char *buf;
      int res;

      buf = xmalloc (regset->size);
      res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
      if (res == 0)
        {
	  /* Then overlay our cached registers on that.  */
	  regset->fill_function (regcache, buf);
	  /* Only now do we write the register set.  */
	  res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf,
			     0, 0);
        }
      if (res < 0)
        perror ("ptrace");
      free (buf);
      regset++;
    }
}
示例#8
0
static void
lynx_resume (struct thread_resume *resume_info, size_t n)
{
  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
  /* FIXME: Assume for now that n == 1.  */
  const int request = (resume_info[0].kind == resume_step
                       ? PTRACE_SINGLESTEP : PTRACE_CONT);
  const int signal = resume_info[0].sig;
  int ret;

  regcache_invalidate ();
  ret = lynx_ptrace (request, inferior_ptid, 1, signal, 0);
}
示例#9
0
static void
nto_fetch_registers (struct regcache *regcache, int regno)
{
  int regsize;
  procfs_greg greg;
  ptid_t ptid;

  TRACE ("%s (regno=%d)\n", __func__, regno);
  if (regno >= the_low_target.num_regs)
    return;

  if (current_inferior == NULL)
    {
      TRACE ("current_inferior is NULL\n");
      return;
    }
  ptid = thread_to_gdb_id (current_inferior);
  if (!nto_set_thread (ptid))
    return;

  if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg),
	      &regsize) == EOK)
    {
      if (regno == -1) /* All registers. */
	{
	  for (regno = 0; regno != the_low_target.num_regs; ++regno)
	    {
	      const unsigned int registeroffset
		= the_low_target.register_offset (regno);
	      supply_register (regcache, regno,
			       ((char *)&greg) + registeroffset);
	    }
	}
      else
	{
	  const unsigned int registeroffset
	    = the_low_target.register_offset (regno);
	  if (registeroffset == -1)
	    return;
	  supply_register (regcache, regno, ((char *)&greg) + registeroffset);
	}
    }
  else
    TRACE ("ERROR reading registers from inferior.\n");
}
示例#10
0
static void
lynx_fetch_registers (struct regcache *regcache, int regno)
{
  struct lynx_regset_info *regset = lynx_target_regsets;
  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);

  lynx_debug ("lynx_fetch_registers (regno = %d)", regno);

  while (regset->size >= 0)
    {
      char *buf;
      int res;

      buf = xmalloc (regset->size);
      res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
      if (res < 0)
        perror ("ptrace");
      regset->store_function (regcache, buf);
      free (buf);
      regset++;
    }
}
示例#11
0
static int
lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
{
  /* On LynxOS, memory writes needs to be performed in chunks the size
     of int types, and they should also be aligned accordingly.  */
  int buf;
  const int xfer_size = sizeof (buf);
  CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);

  while (addr < memaddr + len)
    {
      int skip = 0;
      int truncate = 0;

      if (addr < memaddr)
        skip = memaddr - addr;
      if (addr + xfer_size > memaddr + len)
        truncate = addr + xfer_size - memaddr - len;
      if (skip > 0 || truncate > 0)
	{
	  /* We need to read the memory at this address in order to preserve
	     the data that we are not overwriting.  */
	  lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
	  if (errno)
	    return errno;
	}
      memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
              xfer_size - skip - truncate);
      errno = 0;
      lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0);
      if (errno)
        return errno;
      addr += xfer_size;
    }

  return 0;
}
static CORE_ADDR
nto_stopped_data_address (void)
{
  CORE_ADDR ret = (CORE_ADDR)0;

  TRACE ("%s\n", __func__);
  if (nto_inferior.ctl_fd != -1 && current_inferior != NULL)
    {
      ptid_t ptid;

      ptid = thread_to_gdb_id (current_inferior);

      if (nto_set_thread (ptid))
	{
	  procfs_status status;

	  if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
		      sizeof (status), 0) == EOK)
	    ret = status.ip;
	}
    }
  TRACE ("%s: 0x%08lx\n", __func__, ret);
  return ret;
}
示例#13
0
/* Handle all of the extended 'q' packets.  */
void
handle_query (char *own_buf, int *new_packet_len_p)
{
  static struct inferior_list_entry *thread_ptr;

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

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

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

      /* 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;
    }

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

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

      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;

      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.  */
    }

  /* Otherwise we didn't know what packet it was.  Say we didn't
     understand it.  */
  own_buf[0] = 0;
}
示例#14
0
文件: server.c 项目: gxliu/bdm-osbdm
/* 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)
    {
      thread_ptr = all_threads.head;
      if (thread_ptr == NULL)
        strcpy (own_buf, "unset");
      else
        sprintf (own_buf, "QC%x",
	  thread_to_gdb_id ((struct thread_info *)thread_ptr));
      return;
    }

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

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

  if (strcmp ("qfThreadInfo", own_buf) == 0)
    {
      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)
    {
      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;
      
      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;

      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;

      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;

      /* 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;

      /* Check for support.  */
      document = get_features_xml ("target.xml");
      if (document == NULL)
	{
	  own_buf[0] = '\0';
	  return;
	}

      /* 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;

      /* 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", PBUFSIZ - 1);
#if !defined (NO_PASS_SIGNALS)
	strcat (own_buf, ";QPassSignals+", PBUFSIZ - 1);
#endif
#if !defined (NO_LIBRARIES)
      /* 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+");
#endif
      strcat (own_buf, ";qXfer:memory map: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+");

      if (get_features_xml ("target.xml") != NULL)
	strcat (own_buf, ";qXfer:features:read+");

      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;

      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 % 1) != 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
	{
          int ok = 0;
	  if (the_target->commands)
            ok = (*the_target->commands) (mon, len);
          else
              monitor_output ("Unknown monitor command.\n\n");
          if (!ok)
            {
              monitor_show_help ();
              write_enn (own_buf);
            }
	}

      free (mon);
      return;
    }

  /* Otherwise we didn't know what packet it was.  Say we didn't
     understand it.  */
  own_buf[0] = 0;
}
示例#15
0
文件: server.c 项目: Zekom/valgrind
/* Handle all of the extended 'q' packets.  */
static
void handle_query (char *arg_own_buf, int *new_packet_len_p)
{
   static struct inferior_list_entry *thread_ptr;

   /* qRcmd, monitor command handling.  */
   if (strncmp ("qRcmd,", arg_own_buf, 6) == 0) {
      char *p = arg_own_buf + 6;
      int cmdlen = strlen(p)/2;
      char cmd[cmdlen+1];
      
      if (unhexify (cmd, p, cmdlen) != cmdlen) {
         write_enn (arg_own_buf);
         return;
      }
      cmd[cmdlen] = '\0';
       
      if (handle_gdb_monitor_command (cmd)) {
         /* In case the command is from a standalone vgdb,
            connection will be closed soon => flush the output. */
         VG_(message_flush) ();
         write_ok (arg_own_buf);
         return;
      } else {
         /* cmd not recognised */
         VG_(gdb_printf) 
            ("command '%s' not recognised\n"
             "In gdb,     try 'monitor help'\n"
             "In a shell, try 'vgdb help'\n",
             cmd);
         write_ok (arg_own_buf);
         return;
      }
   }

   /* provide some valgrind specific info in return to qThreadExtraInfo. */
   if (strncmp ("qThreadExtraInfo,", arg_own_buf, 17) == 0) {
      unsigned long gdb_id;
      struct thread_info *ti;
      ThreadState *tst;
      char status[100];
      
      gdb_id = strtoul (&arg_own_buf[17], NULL, 16);
      ti = gdb_id_to_thread (gdb_id);
      if (ti != NULL) {
         tst = (ThreadState *) inferior_target_data (ti);
         /* Additional info is the tid and the thread status. */
         VG_(snprintf) (status, sizeof(status), "tid %d %s",
                        tst->tid, 
                        VG_(name_of_ThreadStatus)(tst->status));
         hexify (arg_own_buf, status, strlen(status));
         return;
      } else {
         write_enn (arg_own_buf);
         return;
      }
   }
   
   if (strcmp ("qAttached", arg_own_buf) == 0) {
      /* tell gdb to always detach, never kill the process */
      arg_own_buf[0] = '1';
      arg_own_buf[1] = 0;
      return;
   }

   if (strcmp ("qSymbol::", arg_own_buf) == 0) {
      /* We have no symbol to read. */
      write_ok (arg_own_buf);
      return;
   }

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

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

   if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL
        && strncmp ("qXfer:features:read:", arg_own_buf, 20) == 0) {
      CORE_ADDR ofs;
      unsigned int len, doc_len;
      const char *annex = NULL;
      // First, the annex is extracted from the packet received.
      // Then, it is replaced by the corresponding file name.
      int fd;

      /* Grab the annex, offset, and length.  */
      if (decode_xfer_read (arg_own_buf + 20, &annex, &ofs, &len) < 0) {
         strcpy (arg_own_buf, "E00");
         return;
      }
      
      if (strcmp (annex, "target.xml") == 0) {
         annex = valgrind_target_xml(VG_(clo_vgdb_shadow_registers));
         if (annex != NULL && VG_(clo_vgdb_shadow_registers)) {
            /* Ensure the shadow registers are initialized. */
            initialize_shadow_low(True);
         }
         if (annex == NULL) {
            strcpy (arg_own_buf, "E00");
            return;
         }
      }

      {
         char doc[VG_(strlen)(VG_(libdir)) + 1 + VG_(strlen)(annex) + 1];
         struct vg_stat stat_doc;
         char toread[len];
         int len_read;

         VG_(sprintf)(doc, "%s/%s", VG_(libdir), annex);
         fd = VG_(fd_open) (doc, VKI_O_RDONLY, 0);
         if (fd == -1) {
            strcpy (arg_own_buf, "E00");
            return;
         }
         if (VG_(fstat) (fd, &stat_doc) != 0) {
            VG_(close) (fd);
            strcpy (arg_own_buf, "E00");
            return;
         }
         doc_len = stat_doc.size;
         
         if (len > PBUFSIZ - POVERHSIZ)
            len = PBUFSIZ - POVERHSIZ;

         if (ofs > doc_len) {
            write_enn (arg_own_buf);
            VG_(close) (fd);
            return;
         }
         VG_(lseek) (fd, ofs, VKI_SEEK_SET);
         len_read = VG_(read) (fd, toread, len);
         *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)toread,
                                                   len_read, ofs + len_read < doc_len);
         VG_(close) (fd);
         return;
      }
   }

   if (strncmp ("qXfer:auxv:read:", arg_own_buf, 16) == 0) {
      unsigned char *data;
      int n;
      CORE_ADDR ofs;
      unsigned int len;
      const char *annex;

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

      if (len > PBUFSIZ - 2)
         len = PBUFSIZ - 2;
      data = malloc (len);

      {
         UWord *client_auxv = VG_(client_auxv);
         unsigned int client_auxv_len = 0;
         while (*client_auxv != 0) {
            dlog(4, "auxv %lld %llx\n",
                 (ULong)*client_auxv,
                 (ULong)*(client_auxv+1));
            client_auxv++;
            client_auxv++;
            client_auxv_len += 2 * sizeof(UWord);
         }
         client_auxv_len += 2 * sizeof(UWord);
         dlog(4, "auxv len %d\n", client_auxv_len);

         if (ofs >= client_auxv_len)
            n = -1;
         else {
            n = client_auxv_len - ofs;
            VG_(memcpy) (data, (unsigned char *) VG_(client_auxv), n);
         }
      }

      if (n < 0)
         write_enn (arg_own_buf);
      else if (n > len)
         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1);
      else
         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0);
      
      free (data);
      
      return;
   }


   /* Protocol features query.  */
   if (strncmp ("qSupported", arg_own_buf, 10) == 0
       && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) {
      VG_(sprintf) (arg_own_buf, "PacketSize=%x", PBUFSIZ - 1);
      /* Note: max packet size including frame and checksum, but without
         trailing null byte, which is not sent/received. */
      
      strcat (arg_own_buf, ";QStartNoAckMode+");
      strcat (arg_own_buf, ";QPassSignals+");
      if (VG_(client_auxv))
         strcat (arg_own_buf, ";qXfer:auxv:read+");

      if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL) {
         strcat (arg_own_buf, ";qXfer:features:read+");
         /* if a new gdb connects to us, we have to reset the register
            set to the normal register sets to allow this new gdb to
            decide to use or not the shadow registers.
            
            Note that the reset is only done for gdb that are sending
            qSupported packets. If a user first connected with a recent
            gdb using shadow registers and then with a very old gdb
            that does not use qSupported packet, then the old gdb will
            not properly connect. */
         initialize_shadow_low(False);
      }
      return;
   }

   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   arg_own_buf[0] = 0;
}
示例#16
0
/* Handle all of the extended 'q' packets.  */
void
handle_query (char *own_buf)
{
  static struct inferior_list_entry *thread_ptr;

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

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

  if (strcmp ("qfThreadInfo", own_buf) == 0)
    {
      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)
    {
      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_auxv != NULL
      && strncmp ("qPart:auxv:read::", own_buf, 17) == 0)
    {
      unsigned char data[(PBUFSIZ - 1) / 2];
      CORE_ADDR ofs;
      unsigned int len;
      int n;
      decode_m_packet (&own_buf[17], &ofs, &len); /* "OFS,LEN" */
      if (len > sizeof data)
	len = sizeof data;
      n = (*the_target->read_auxv) (ofs, data, len);
      if (n == 0)
	write_ok (own_buf);
      else if (n < 0)
	write_enn (own_buf);
      else
	convert_int_to_ascii (data, own_buf, n);
      return;
    }

  /* Otherwise we didn't know what packet it was.  Say we didn't
     understand it.  */
  own_buf[0] = 0;
}
示例#17
0
static ptid_t
lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options)
{
  int pid;
  int ret;
  int wstat;
  ptid_t new_ptid;

  if (ptid_equal (ptid, minus_one_ptid))
    pid = lynx_ptid_get_pid (thread_to_gdb_id (current_thread));
  else
    pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));

retry:

  ret = lynx_waitpid (pid, &wstat);
  new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
  find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid;

  /* If this is a new thread, then add it now.  The reason why we do
     this here instead of when handling new-thread events is because
     we need to add the thread associated to the "main" thread - even
     for non-threaded applications where the new-thread events are not
     generated.  */
  if (!find_thread_ptid (new_ptid))
    {
      lynx_debug ("New thread: (pid = %d, tid = %d)",
		  lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid));
      add_thread (new_ptid, NULL);
    }

  if (WIFSTOPPED (wstat))
    {
      status->kind = TARGET_WAITKIND_STOPPED;
      status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat));
      lynx_debug ("process stopped with signal: %d",
                  status->value.integer);
    }
  else if (WIFEXITED (wstat))
    {
      status->kind = TARGET_WAITKIND_EXITED;
      status->value.integer = WEXITSTATUS (wstat);
      lynx_debug ("process exited with code: %d", status->value.integer);
    }
  else if (WIFSIGNALED (wstat))
    {
      status->kind = TARGET_WAITKIND_SIGNALLED;
      status->value.integer = gdb_signal_from_host (WTERMSIG (wstat));
      lynx_debug ("process terminated with code: %d",
                  status->value.integer);
    }
  else
    {
      /* Not sure what happened if we get here, or whether we can
	 in fact get here.  But if we do, handle the event the best
	 we can.  */
      status->kind = TARGET_WAITKIND_STOPPED;
      status->value.integer = gdb_signal_from_host (0);
      lynx_debug ("unknown event ????");
    }

  /* SIGTRAP events are generated for situations other than single-step/
     breakpoint events (Eg. new-thread events).  Handle those other types
     of events, and resume the execution if necessary.  */
  if (status->kind == TARGET_WAITKIND_STOPPED
      && status->value.integer == GDB_SIGNAL_TRAP)
    {
      const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0);

      lynx_debug ("(realsig = %d)", realsig);
      switch (realsig)
	{
	  case SIGNEWTHREAD:
	    /* We just added the new thread above.  No need to do anything
	       further.  Just resume the execution again.  */
	    lynx_continue (new_ptid);
	    goto retry;

	  case SIGTHREADEXIT:
	    remove_thread (find_thread_ptid (new_ptid));
	    lynx_continue (new_ptid);
	    goto retry;
	}
    }

  return new_ptid;
}
示例#18
0
文件: server.c 项目: drorgl/valgrind
/* Handle all of the extended 'q' packets.  */
static
void handle_query (char *arg_own_buf, int *new_packet_len_p)
{
   static struct inferior_list_entry *thread_ptr;

   /* thread local storage query */
   if (strncmp ("qGetTLSAddr:", arg_own_buf, 12) == 0) {
      char *from, *to;
      char *end = arg_own_buf + strlen(arg_own_buf);
      unsigned long gdb_id;
      CORE_ADDR lm;
      CORE_ADDR offset;
      struct thread_info *ti;
      
      from = arg_own_buf + 12;
      to = strchr(from, ',');
      *to = 0;
      gdb_id = strtoul (from, NULL, 16);
      from = to + 1;
      to = strchr(from, ',');
      decode_address (&offset, from, to - from);
      from = to + 1;
      to = end;
      decode_address (&lm, from, to - from);
      dlog(2, "qGetTLSAddr thread %lu offset %p lm %p\n", 
           gdb_id, (void*)offset, (void*)lm);

      ti = gdb_id_to_thread (gdb_id);
      if (ti != NULL) {
         ThreadState *tst;
         Addr tls_addr;

         tst = (ThreadState *) inferior_target_data (ti);
         if (valgrind_get_tls_addr(tst, offset, lm, &tls_addr)) {
            VG_(sprintf) (arg_own_buf, "%lx", tls_addr);
            return;
         }
         // else we will report we do not support qGetTLSAddr
      } else {
         write_enn (arg_own_buf);
         return;
      }
   }
   
   /* qRcmd, monitor command handling.  */
   if (strncmp ("qRcmd,", arg_own_buf, 6) == 0) {
      char *p = arg_own_buf + 6;
      int cmdlen = strlen(p)/2;
      char cmd[cmdlen+1];
      
      if (unhexify (cmd, p, cmdlen) != cmdlen) {
         write_enn (arg_own_buf);
         return;
      }
      cmd[cmdlen] = '\0';
       
      if (handle_gdb_monitor_command (cmd)) {
         write_ok (arg_own_buf);
         return;
      } else {
         /* cmd not recognised */
         VG_(gdb_printf) 
            ("command '%s' not recognised\n"
             "In gdb,     try 'monitor help'\n"
             "In a shell, try 'vgdb help'\n",
             cmd);
         write_ok (arg_own_buf);
         return;
      }
   }

   /* provide some valgrind specific info in return to qThreadExtraInfo. */
   if (strncmp ("qThreadExtraInfo,", arg_own_buf, 17) == 0) {
      unsigned long gdb_id;
      struct thread_info *ti;
      ThreadState *tst;
      
      gdb_id = strtoul (&arg_own_buf[17], NULL, 16);
      ti = gdb_id_to_thread (gdb_id);
      if (ti != NULL) {
         tst = (ThreadState *) inferior_target_data (ti);
         /* Additional info is the tid, the thread status and the thread's
            name, if any. */
         SizeT len = strlen(VG_(name_of_ThreadStatus)(tst->status)) + 20;
         if (tst->thread_name) len += strlen(tst->thread_name);
         /* As the string will be hexified and copied into own_buf we need
            to limit the length to avoid buffer overflow. */
         if (len * 2 > (PBUFSIZ + POVERHSIZ))
            len = (PBUFSIZ + POVERHSIZ) / 2;
         char status[len];
         if (tst->thread_name) {
            VG_(snprintf) (status, sizeof(status), "tid %d %s %s",
                           tst->tid, 
                           VG_(name_of_ThreadStatus)(tst->status),
                           tst->thread_name);
         } else {
            VG_(snprintf) (status, sizeof(status), "tid %d %s",
                           tst->tid, 
                           VG_(name_of_ThreadStatus)(tst->status));
         }
         hexify (arg_own_buf, status, strlen(status));
         return;
      } else {
         write_enn (arg_own_buf);
         return;
      }
   }

   if (strcmp ("qAttached", arg_own_buf) == 0) {
      /* tell gdb to always detach, never kill the process */
      arg_own_buf[0] = '1';
      arg_own_buf[1] = 0;
      return;
   }

   if (strcmp ("qSymbol::", arg_own_buf) == 0) {
      /* We have no symbol to read. */
      write_ok (arg_own_buf);
      return;
   }

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

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

   if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL
        && strncmp ("qXfer:features:read:", arg_own_buf, 20) == 0) {
      CORE_ADDR ofs;
      unsigned int len, doc_len;
      const char *annex = NULL;
      // First, the annex is extracted from the packet received.
      // Then, it is replaced by the corresponding file name.
      int fd;

      /* Grab the annex, offset, and length.  */
      if (decode_xfer_read (arg_own_buf + 20, &annex, &ofs, &len) < 0) {
         strcpy (arg_own_buf, "E00");
         return;
      }
      
      if (strcmp (annex, "target.xml") == 0) {
         annex = valgrind_target_xml(VG_(clo_vgdb_shadow_registers));
         if (annex != NULL && VG_(clo_vgdb_shadow_registers)) {
            /* Ensure the shadow registers are initialized. */
            initialize_shadow_low(True);
         }
         if (annex == NULL) {
            strcpy (arg_own_buf, "E00");
            return;
         }
      }

      {
         char doc[VG_(strlen)(VG_(libdir)) + 1 + VG_(strlen)(annex) + 1];
         struct vg_stat stat_doc;
         char toread[len];
         int len_read;

         VG_(sprintf)(doc, "%s/%s", VG_(libdir), annex);
         fd = VG_(fd_open) (doc, VKI_O_RDONLY, 0);
         if (fd == -1) {
            strcpy (arg_own_buf, "E00");
            return;
         }
         if (VG_(fstat) (fd, &stat_doc) != 0) {
            VG_(close) (fd);
            strcpy (arg_own_buf, "E00");
            return;
         }
         doc_len = stat_doc.size;
         
         if (len > PBUFSIZ - POVERHSIZ)
            len = PBUFSIZ - POVERHSIZ;

         if (ofs > doc_len) {
            write_enn (arg_own_buf);
            VG_(close) (fd);
            return;
         }
         VG_(lseek) (fd, ofs, VKI_SEEK_SET);
         len_read = VG_(read) (fd, toread, len);
         *new_packet_len_p = write_qxfer_response (arg_own_buf,
                                                   (unsigned char *)toread,
                                                   len_read,
                                                   ofs + len_read < doc_len);
         VG_(close) (fd);
         return;
      }
   }

   if (strncmp ("qXfer:auxv:read:", arg_own_buf, 16) == 0) {
      unsigned char *data;
      int n;
      CORE_ADDR ofs;
      unsigned int len;
      const char *annex;

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

      if (len > PBUFSIZ - POVERHSIZ)
         len = PBUFSIZ - POVERHSIZ;
      data = malloc (len);

      {
         UWord *client_auxv = VG_(client_auxv);
         unsigned int client_auxv_len = 0;
         while (*client_auxv != 0) {
            dlog(4, "auxv %lld %llx\n",
                 (ULong)*client_auxv,
                 (ULong)*(client_auxv+1));
            client_auxv++;
            client_auxv++;
            client_auxv_len += 2 * sizeof(UWord);
         }
         client_auxv_len += 2 * sizeof(UWord);
         dlog(4, "auxv len %d\n", client_auxv_len);

         if (ofs >= client_auxv_len)
            n = -1;
         else {
            n = client_auxv_len - ofs;
            VG_(memcpy) (data, (unsigned char *) VG_(client_auxv), n);
         }
      }

      if (n < 0)
         write_enn (arg_own_buf);
      else if (n > len)
         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1);
      else
         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0);
      
      free (data);
      
      return;
   }

   if (strncmp ("qXfer:exec-file:read:", arg_own_buf, 21) == 0) {
      unsigned char *data;
      int n;
      CORE_ADDR ofs;
      unsigned int len;
      const char *annex;
      unsigned long pid;
      const HChar *name;

      /* grab the annex, offset and length.  */
      if (decode_xfer_read (arg_own_buf + 21, &annex, &ofs, &len) < 0) {
         strcpy (arg_own_buf, "E00");
         return;
      }
      
      /* Reject any annex with invalid/unexpected pid */
      if (strlen(annex) > 0)
         pid = strtoul (annex, NULL, 16);
      else
         pid = 0;
      if ((int)pid != VG_(getpid)() && pid != 0) {
         VG_(sprintf) (arg_own_buf, 
                       "E.Valgrind gdbserver pid is %d."
                       " Cannot give info for pid %d",
                       VG_(getpid)(), (int) pid);
         return;
      }

      if (len > PBUFSIZ - 2)
         len = PBUFSIZ - 2;
      data = malloc (len);

      if (!VG_(resolve_filename)(VG_(cl_exec_fd), &name)) {
         VG_(sprintf) (arg_own_buf, 
                       "E.Valgrind gdbserver could not"
                       " resolve pid %d exec filename.",
                       VG_(getpid)());
         return;
      }

      if (ofs >= strlen(name))
         n = -1;
      else {
         n = strlen(name) - ofs;
         VG_(memcpy) (data, name, n);
      }

      if (n < 0)
         write_enn (arg_own_buf);
      else if (n > len)
         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1);
      else
         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0);
      
      free (data);
      
      return;
   }

   if (strncmp ("qXfer:siginfo:read:", arg_own_buf, 19) == 0) {
      vki_siginfo_t info;
      int n;
      CORE_ADDR ofs;
      unsigned int len;
      const char *annex;

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

      gdbserver_pending_signal_to_report(&info);

      if (ofs >= sizeof(info))
         n = -1;
      else
         n = sizeof(info) - ofs;

      if (n < 0)
         write_enn (arg_own_buf);
      else if (n > len)
         *new_packet_len_p = write_qxfer_response (arg_own_buf, 
                                                   (unsigned char *)&info,
                                                   len, 1);
      else
         *new_packet_len_p = write_qxfer_response (arg_own_buf, 
                                                   (unsigned char *)&info,
                                                   n, 0);
      
      return;
   }

   /* Protocol features query.  */
   if (strncmp ("qSupported", arg_own_buf, 10) == 0
       && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) {
      VG_(sprintf) (arg_own_buf, "PacketSize=%x", PBUFSIZ - 1);
      /* Note: max packet size including frame and checksum, but without
         trailing null byte, which is not sent/received. */

      strcat (arg_own_buf, ";QStartNoAckMode+");
      strcat (arg_own_buf, ";QPassSignals+");
      if (VG_(client_auxv))
         strcat (arg_own_buf, ";qXfer:auxv:read+");

      if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL) {
         strcat (arg_own_buf, ";qXfer:features:read+");
         /* if a new gdb connects to us, we have to reset the register
            set to the normal register sets to allow this new gdb to
            decide to use or not the shadow registers.
            
            Note that the reset is only done for gdb that are sending
            qSupported packets. If a user first connected with a recent
            gdb using shadow registers and then with a very old gdb
            that does not use qSupported packet, then the old gdb will
            not properly connect. */
         initialize_shadow_low(False);
      }
      strcat (arg_own_buf, ";qXfer:exec-file:read+");
      strcat (arg_own_buf, ";qXfer:siginfo:read+");
      return;
   }

   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   arg_own_buf[0] = 0;
}