Ejemplo n.º 1
0
static void do_rmem(const char* line, uint8_t len)
{
  uint16_t size;

  skip_ws(&line, &len);
  if (len != 4) goto on_error;

  if (string_to_uint16(line, &size)) goto on_error;
  if ((mem_addr + size) > DS2433_MEM_SIZE) goto on_error;
  if (ds2433_read_mem(mem_buf, mem_addr, size)) goto on_error;
  mem_addr += size;

  write_ok();
  write_buf(mem_buf, size);
  return ;

 on_error:
  write_ko();
  return ;
}
Ejemplo n.º 2
0
static int
sha_fs_get(struct request *r)
{
	struct sha_fs_request *sp = (struct sha_fs_request *)r->open_data;
	int status = 0;
	blk_SHA_CTX ctx;
	unsigned char digest[20];
	int fd;
	unsigned char chunk[CHUNK_SIZE];
	int nread;

	blob_path(r, r->digest);

	/*
	 *  Open the file to the blob.
	 */
	switch (_open(r, sp->blob_path, &fd)) {
	case 0:
		break;
	case ENOENT:
		return 1;
	default:
		_panic(r, "_open(blob) failed");
	}

	/*
	 *  Tell the client we have the blob.
	 */
	if (write_ok(r)) {
		_error(r, "write_ok() failed");
		goto croak;
	}

	blk_SHA1_Init(&ctx);

	/*
	 *  Read a chunk from the file, write chunk to client,
	 *  update incremental digest.
	 *
	 *  In principle, we ought to first scan the blob file
	 *  before sending "ok" to the requestor.
	 */
	while ((nread = _read(r, fd, chunk, sizeof chunk)) > 0) {
		if (blob_write(r, chunk, nread)) {
			_error(r, "blob_write(blob chunk) failed");
			goto croak;
		}
		/*
		 *  Update the incremental digest.
		 */
		blk_SHA1_Update(&ctx, chunk, nread);
	}
	if (nread < 0)
		_panic(r, "_read(blob) failed");
	/*
	 *  Finalize the digest.
	 */
	blk_SHA1_Final(digest, &ctx);
	/*
	 *  If the calculated digest does NOT match the stored digest,
	 *  then zap the blob from storage and get panicy.
	 *  A corrupt blob is a bad, bad thang.
	 *
	 *  Note: unfortunately we've already deceived the client
	 *        by sending "ok".  Probably need to improve for
	 *	  the special case when the entire blob is read
	 *        in first chunk.
	 */
	if (memcmp(sp->digest, digest, 20)) {
		_error2(r, "PANIC: stored blob doesn't match digest",
								r->digest);
		if (zap_blob(r))
			_panic(r, "zap_blob() failed");
		goto croak;
	}
	goto cleanup;
croak:
	status = -1;
cleanup:
	if (_close(r, &fd))
		_panic(r, "_close(blob) failed");
	return status;
}
Ejemplo n.º 3
0
Archivo: server.c Proyecto: 0mp/freebsd
/* 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_ptr->id);
      thread_ptr = thread_ptr->next;
      return;
    }

  if (strcmp ("qsThreadInfo", own_buf) == 0)
    {
      if (thread_ptr != NULL)
	{
	  sprintf (own_buf, "m%x", thread_ptr->id);
	  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)
    {
      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;
}
Ejemplo n.º 4
0
Archivo: server.c Proyecto: 0mp/freebsd
int
main (int argc, char *argv[])
{
  char ch, status, *own_buf, mem_buf[2000];
  int i = 0;
  unsigned char signal;
  unsigned int len;
  CORE_ADDR mem_addr;
  int bad_attach;
  int pid;
  char *arg_end;

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

  bad_attach = 0;
  pid = 0;
  attached = 0;
  if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
    {
      if (argc == 4
	  && argv[3] != '\0'
	  && (pid = strtoul (argv[3], &arg_end, 10)) != 0
	  && *arg_end == '\0')
	{
	  ;
	}
      else
	bad_attach = 1;
    }

  if (argc < 3 || bad_attach)
    gdbserver_usage();

  initialize_low ();

  own_buf = malloc (PBUFSIZ);

  if (pid == 0)
    {
      /* Wait till we are at first instruction in program.  */
      signal = start_inferior (&argv[2], &status);

      /* We are now stopped at the first instruction of the target process */
    }
  else
    {
      switch (attach_inferior (pid, &status, &signal))
	{
	case -1:
	  error ("Attaching not supported on this target");
	  break;
	default:
	  attached = 1;
	  break;
	}
    }

  while (1)
    {
      remote_open (argv[1]);

    restart:
      setjmp (toplevel);
      while (getpkt (own_buf) > 0)
	{
	  unsigned char sig;
	  i = 0;
	  ch = own_buf[i++];
	  switch (ch)
	    {
	    case 'q':
	      handle_query (own_buf);
	      break;
	    case 'd':
	      remote_debug = !remote_debug;
	      break;
	    case 'D':
	      fprintf (stderr, "Detaching from inferior\n");
	      detach_inferior ();
	      write_ok (own_buf);
	      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)
		{
		  int status, ret;

		  do {
		    ret = waitpid (signal_pid, &status, 0);
		    if (WIFEXITED (status) || WIFSIGNALED (status))
		      break;
		  } while (ret != -1 || errno != ECHILD);
		}

	      exit (0);

	    case '!':
	      if (attached == 0)
		{
		  extended_protocol = 1;
		  prepare_resume_reply (own_buf, status, signal);
		}
	      else
		{
		  /* We can not use the extended protocol if we are
		     attached, because we can not restart the running
		     program.  So return unrecognized.  */
		  own_buf[0] = '\0';
		}
	      break;
	    case '?':
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'H':
	      switch (own_buf[1])
		{
		case 'g':
		  general_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  set_desired_inferior (1);
		  break;
		case 'c':
		  cont_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  break;
		case 's':
		  step_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  break;
		default:
		  /* Silently ignore it so that gdb can extend the protocol
		     without compatibility headaches.  */
		  own_buf[0] = '\0';
		  break;
		}
	      break;
	    case 'g':
	      set_desired_inferior (1);
	      registers_to_string (own_buf);
	      break;
	    case 'G':
	      set_desired_inferior (1);
	      registers_from_string (&own_buf[1]);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      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':
	      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 'C':
	      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;
	      set_desired_inferior (0);
	      myresume (0, signal);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'S':
	      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;
	      set_desired_inferior (0);
	      myresume (1, signal);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'c':
	      set_desired_inferior (0);
	      myresume (0, 0);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 's':
	      set_desired_inferior (0);
	      myresume (1, 0);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'k':
	      fprintf (stderr, "Killing inferior\n");
	      kill_inferior ();
	      /* When using the extended protocol, we start up a new
	         debugging session.   The traditional protocol will
	         exit instead.  */
	      if (extended_protocol)
		{
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      if (mythread_alive (strtol (&own_buf[1], NULL, 16)))
		write_ok (own_buf);
	      else
		write_enn (own_buf);
	      break;
	    case 'R':
	      /* Restarting the inferior is only supported in the
	         extended protocol.  */
	      if (extended_protocol)
		{
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      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);
	      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;
	    }

	  putpkt (own_buf);

	  if (status == 'W')
	    fprintf (stderr,
		     "\nChild exited with status %d\n", signal);
	  if (status == 'X')
	    fprintf (stderr, "\nChild terminated with signal = 0x%x\n",
		     signal);
	  if (status == 'W' || status == 'X')
	    {
	      if (extended_protocol)
		{
		  fprintf (stderr, "Killing inferior\n");
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  fprintf (stderr, "GDBserver exiting\n");
		  exit (0);
		}
	    }
	}

      /* We come here when getpkt fails.

         For the extended remote protocol we exit (and this is the only
         way we gracefully exit!).

         For the traditional remote protocol close the connection,
         and re-open it at the top of the loop.  */
      if (extended_protocol)
	{
	  remote_close ();
	  exit (0);
	}
      else
	{
	  fprintf (stderr, "Remote side has terminated connection.  "
			   "GDBserver will reopen the connection.\n");
	  remote_close ();
	}
    }
}
Ejemplo n.º 5
0
void server_main (void)
{
   static char status;
   static int zignal;

   char ch;
   int i = 0;
   unsigned int len;
   CORE_ADDR mem_addr;

   zignal = valgrind_wait (&status);
   if (VG_MINIMAL_SETJMP(toplevel)) {
      dlog(0, "error caused VG_MINIMAL_LONGJMP to server_main\n");
   }
   while (1) {
      unsigned char sig;
      int packet_len;
      int new_packet_len = -1;
      
      if (resume_reply_packet_needed) {
         /* Send the resume reply to reply to last GDB resume
            request. */
         resume_reply_packet_needed = False;
         prepare_resume_reply (own_buf, status, zignal);
         putpkt (own_buf);
      }

      /* If we our status is terminal (exit or fatal signal) get out
         as quickly as we can. We won't be able to handle any request
         anymore.  */
      if (status == 'W' || status == 'X') {
         return;
      }

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

      i = 0;
      ch = own_buf[i++];
      switch (ch) {
      case 'Q':
         handle_set (own_buf, &new_packet_len);
         break;
      case 'q':
         handle_query (own_buf, &new_packet_len);
         break;
      case 'd':
         /* set/unset debugging is done through valgrind debug level. */
         own_buf[0] = '\0';
         break;
      case 'D':
         reset_valgrind_sink("gdb detaching from process");

         /* When detaching or kill the process, gdb expects to get
            an packet OK back.  Any other output will make gdb
            believes detach did not work. */
         write_ok (own_buf);
         putpkt (own_buf);
         remote_finish (reset_after_error);
         remote_open (VG_(clo_vgdb_prefix));
         myresume (0, 0);
         resume_reply_packet_needed = False;
         return;
      case '!':
         /* We can not use the extended protocol with valgrind,
            because we can not restart the running
            program.  So return unrecognized.  */
         own_buf[0] = '\0';
         break;
      case '?':
         prepare_resume_reply (own_buf, status, zignal);
         break;
      case 'H':
         if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') {
            unsigned long gdb_id, thread_id;
            
            gdb_id = strtoul (&own_buf[2], NULL, 16);
            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':
         set_desired_inferior (1);
         registers_to_string (own_buf);
         break;
      case 'G':
         set_desired_inferior (1);
         registers_from_string (&own_buf[1]);
         write_ok (own_buf);
         break;
      case 'P': {
         int regno;
         char *regbytes;
         Bool mod;
         ThreadState *tst;
         regno = strtol(&own_buf[1], NULL, 16);
         regbytes = strchr(&own_buf[0], '=') + 1;
         set_desired_inferior (1);
         tst = (ThreadState *) inferior_target_data (current_inferior);
         /* Only accept changing registers in "runnable state3.
            In fact, it would be ok to change most of the registers
            except a few "sensitive" registers such as the PC, SP, BP.
            We assume we do not need to very specific here, and that we
            can just refuse all of these. */
         if (tst->status == VgTs_Runnable || tst->status == VgTs_Yielding) {
            supply_register_from_string (regno, regbytes, &mod);
            write_ok (own_buf);
         } else {
            /* at least from gdb 6.6 onwards, an E. error
               reply is shown to the user. So, we do an error
               msg which both is accepted by gdb as an error msg
               and is readable by the user. */
            VG_(sprintf) 
               (own_buf,
"E.\n"
"ERROR changing register %s regno %d\n"
"gdb commands changing registers (pc, sp, ...) (e.g. 'jump',\n"
"set pc, calling from gdb a function in the debugged process, ...)\n"
"can only be accepted if the thread is VgTs_Runnable or VgTs_Yielding state\n"
"Thread status is %s\n",
                find_register_by_number (regno)->name, regno,
                VG_(name_of_ThreadStatus)(tst->status));
            if (VG_(clo_verbosity) > 1)
               VG_(umsg) ("%s\n", own_buf);
         }
         break;            
      }
      case 'm':
         decode_m_packet (&own_buf[1], &mem_addr, &len);
         if (valgrind_read_memory (mem_addr, mem_buf, len) == 0)
            convert_int_to_ascii (mem_buf, own_buf, len);
         else
            write_enn (own_buf);
         break;
      case 'M':
         decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
         if (valgrind_write_memory (mem_addr, mem_buf, len) == 0)
            write_ok (own_buf);
         else
            write_enn (own_buf);
         break;
      case 'X':
         if (decode_X_packet (&own_buf[1], packet_len - 1,
                              &mem_addr, &len, mem_buf) < 0
             || valgrind_write_memory (mem_addr, mem_buf, len) != 0)
            write_enn (own_buf);
         else
            write_ok (own_buf);
         break;
      case 'C':
         convert_ascii_to_int (own_buf + 1, &sig, 1);
         if (target_signal_to_host_p (sig))
            zignal = target_signal_to_host (sig);
         else
            zignal = 0;
         set_desired_inferior (0);
         myresume (0, zignal);
         return; // return control to valgrind
      case 'S':
         convert_ascii_to_int (own_buf + 1, &sig, 1);
         if (target_signal_to_host_p (sig))
            zignal = target_signal_to_host (sig);
         else
            zignal = 0;
         set_desired_inferior (0);
         myresume (1, zignal);
         return; // return control to valgrind
      case 'c':
         set_desired_inferior (0);
         myresume (0, 0);
         return; // return control to valgrind
      case 's':
         set_desired_inferior (0);
         myresume (1, 0);
         return; // return control to valgrind
      case 'Z': {
         char *lenptr;
         char *dataptr;
         CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
         int zlen = strtol (lenptr + 1, &dataptr, 16);
         char type = own_buf[1];
         
         if (type < '0' || type > '4') {
            /* Watchpoint command type unrecognized. */
            own_buf[0] = '\0';
         } else {
            int res;
            
            res = valgrind_insert_watchpoint (type, addr, zlen);
            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 zlen = strtol (lenptr + 1, &dataptr, 16);
         char type = own_buf[1];
         
         if (type < '0' || type > '4') {
            /* Watchpoint command type unrecognized. */
            own_buf[0] = '\0';
         } else {
            int res;
            
            res = valgrind_remove_watchpoint (type, addr, zlen);
            if (res == 0)
               write_ok (own_buf);
            else if (res == 1)
               /* Unsupported.  */
               own_buf[0] = '\0';
            else
               write_enn (own_buf);
         }
         break;
      }
      case 'k':
         kill_request("Gdb request to kill this process\n");
         break;
      case 'T': {
         unsigned long gdb_id, thread_id;
         
         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 (valgrind_thread_alive (thread_id))
            write_ok (own_buf);
         else
            write_enn (own_buf);
         break;
      }
      case 'R':
         /* Restarting the inferior is only supported in the
            extended protocol.
            => 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, &zignal);
         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);
      
      if (status == 'W')
         VG_(umsg) ("\nChild exited with status %d\n", zignal);
      if (status == 'X')
         VG_(umsg) ("\nChild terminated with signal = 0x%x (%s)\n",
                    target_signal_to_host (zignal),
                    target_signal_to_name (zignal));
      if (status == 'W' || status == 'X') {
         VG_(umsg) ("Process exiting\n");
         VG_(exit) (0);
      }
   }

   /* We come here when getpkt fails => close the connection,
      and re-open. Then return control to valgrind.
      We return the control to valgrind as we assume that
      the connection was closed due to vgdb having finished
      to execute a command. */
   if (VG_(clo_verbosity) > 1)
      VG_(umsg) ("Remote side has terminated connection.  "
                 "GDBserver will reopen the connection.\n");
   remote_finish (reset_after_error);
   remote_open (VG_(clo_vgdb_prefix)); 
   myresume (0, 0);
   resume_reply_packet_needed = False;
   return;
}
Ejemplo n.º 6
0
/* 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;
}
Ejemplo n.º 7
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;

  my_stdout = stdout;
  my_stderr = stderr;
  
  myname = argv[0];
  
  if (argc >= 2 && strcmp (argv[1], "--version") == 0)
    {
      gdbserver_version ();
      exit (0);
    }

  if (argc >= 2 && strcmp (argv[1], "--help") == 0)
    {
      gdbserver_usage ();
      exit (0);
    }

  if (setjmp (toplevel))
    {
      warning ("Exiting");
      exit (1);
    }

  bad_attach = 0;
  pid = 0;
  attached = 0;
  if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
    {
      if (argc == 4
	  && argv[3][0] != '\0'
	  && (pid = strtoul (argv[3], &arg_end, 10)) != 0
	  && *arg_end == '\0')
	{
	  ;
	}
      else
	bad_attach = 1;
    }

  if (argc < 3 || bad_attach)
    {
      gdbserver_usage ();
      exit (1);
    }

  if (strcmp (argv[1], "pipe") == 0)
    {
      my_stdout = my_stderr = stderr;
    }

  initialize_low ();

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

  if (pid == 0)
    {
      /* Wait till we are at first instruction in program.  */
      signal = start_inferior (&argv[2], &status);

      /* We are now (hopefully) stopped at the first instruction of
	 the target process.  This assumes that the target process was
	 successfully created.  */

      /* Don't report shared library events on the initial connection,
	 even if some libraries are preloaded.  */
      dlls_changed = 0;
    }
  else
    {
      switch (attach_inferior (pid, &status, &signal))
	{
	case -1:
	  error ("Attaching not supported on this target");
	  break;
	default:
	  attached = 1;
	  break;
	}
    }

  if (setjmp (toplevel))
    {
      warning ("Killing inferior");
      kill_inferior ();
      exit (1);
    }

  if (status == 'W' || status == 'X')
    {
      warning ("No inferior, GDBserver exiting.");
      exit (1);
    }

  while (1)
    {
      remote_open (argv[1]);

    restart:
      if (setjmp (toplevel))
        {
          if (remote_debug)
            printf_filtered ("gdbserver: error returned to main loop\n");
          write_enn (own_buf);
          putpkt (own_buf);
        }
      
      while (1)
	{
	  unsigned char sig;
	  int packet_len;
	  int new_packet_len = -1;

	  packet_len = getpkt (own_buf, PBUFSIZ);
	  if (packet_len <= 0)
	    break;

	  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':
	      warning ("Detaching from inferior");
	      if (detach_inferior () != 0)
		{
		  write_enn (own_buf);
		  putpkt (own_buf);
		}
	      else
		{
		  write_ok (own_buf);
		  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);
		}
	    case '!':
	      if (attached == 0)
		{
		  extended_protocol = 1;
		  prepare_resume_reply (own_buf, status, signal);
		}
	      else
		{
		  /* We can not use the extended protocol if we are
		     attached, because we can not restart the running
		     program.  So return unrecognized.  */
		  own_buf[0] = '\0';
		}
	      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;

		  gdb_id = strtoul (&own_buf[2], NULL, 16);
		  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':
	      set_desired_inferior (1);
	      registers_to_string (own_buf);
	      break;
	    case 'G':
	      set_desired_inferior (1);
	      registers_from_string (&own_buf[1]);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      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':
	      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':
	      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':
	      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;
	      set_desired_inferior (0);
	      myresume (0, signal);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'S':
	      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;
	      set_desired_inferior (0);
	      myresume (1, signal);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'c':
	      set_desired_inferior (0);
	      myresume (0, 0);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 's':
	      set_desired_inferior (0);
	      myresume (1, 0);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'z':
	    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
		    || the_target->remove_watchpoint == NULL
		    || (type < '0' || type > '4'))
		  {
		    /* No watchpoint support or not a watchpoint command;
		       unrecognized either way.  */
		    own_buf[0] = '\0';
		  }
		else
		  {
		    int res;
		    if (ch == 'z')
		      res = (*the_target->remove_watchpoint) (type, addr, len);
		    else
		      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 'k':
	      warning ("Killing inferior");
	      kill_inferior ();
	      /* When using the extended protocol, we start up a new
	         debugging session.   The traditional protocol will
	         exit instead.  */
	      if (extended_protocol)
		{
		  write_ok (own_buf);
		  warning ("GDBserver restarting");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      {
		unsigned long gdb_id, thread_id;

		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':
	      /* Restarting the inferior is only supported in the
	         extended protocol.  */
	      if (extended_protocol)
		{
		  kill_inferior ();
		  write_ok (own_buf);
		  warning ("GDBserver restarting");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      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);
	      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);

	  if (status == 'W')
	    warning ("\nChild exited with status %d", signal);
	  if (status == 'X')
	    warning ("\nChild terminated with signal = 0x%x (%s)",
                        target_signal_to_host (signal),
                        target_signal_to_name (signal));
	  if (status == 'W' || status == 'X')
	    {
	      if (extended_protocol)
		{
		  warning ("Killing inferior");
		  kill_inferior ();
		  write_ok (own_buf);
		  warning ("GDBserver restarting");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  warning ("GDBserver exiting");
		  exit (0);
		}
	    }
	}

      /* We come here when getpkt fails.

         For the extended remote protocol we exit (and this is the only
         way we gracefully exit!).

         For the traditional remote protocol close the connection,
         and re-open it at the top of the loop.  */
      if (extended_protocol)
	{
	  remote_close ();
	  exit (0);
	}
      else
	{
	  warning ("Remote side has terminated connection.  "
                   "GDBserver will reopen the connection.");
	  remote_close ();
	}
    }
}
Ejemplo n.º 8
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)
    {
      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;
}
Ejemplo n.º 9
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 ();
	}
    }
}
Ejemplo n.º 10
0
Archivo: server.c Proyecto: 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 ();
	}
    }
}
Ejemplo n.º 11
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;

  if (argc >= 2 && strcmp (argv[1], "--version") == 0)
    {
      gdbserver_version ();
      exit (0);
    }

  if (argc >= 2 && strcmp (argv[1], "--help") == 0)
    {
      gdbserver_usage ();
      exit (0);
    }

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

  bad_attach = 0;
  pid = 0;
  attached = 0;
  if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
    {
      if (argc == 4
	  && argv[3] != '\0'
	  && (pid = strtoul (argv[3], &arg_end, 10)) != 0
	  && *arg_end == '\0')
	{
	  ;
	}
      else
	bad_attach = 1;
    }

  if (argc < 3 || bad_attach)
    {
      gdbserver_usage ();
      exit (1);
    }

  initialize_low ();

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

  if (pid == 0)
    {
      /* Wait till we are at first instruction in program.  */
      signal = start_inferior (&argv[2], &status);

      /* start_inferior() returns an integer, but the wait
       * function returns an unsigned char.  in the case of
       * of an error, the wait returns -1 which means 255.  */
      if (status == 'W' || status == 'X')
	{
	  fprintf (stderr, "Aborting server; child exited with %i\n", signal);
	  exit (signal);
	}

      /* We are now stopped at the first instruction of the target process */
    }
  else
    {
      switch (attach_inferior (pid, &status, &signal))
	{
	case -1:
	  error ("Attaching not supported on this target");
	  break;
	default:
	  attached = 1;
	  break;
	}
    }

  while (1)
    {
      remote_open (argv[1]);

    restart:
      setjmp (toplevel);
      while (1)
	{
	  unsigned char sig;
	  int packet_len;
	  int new_packet_len = -1;

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

	  i = 0;
	  ch = own_buf[i++];
	  switch (ch)
	    {
	    case 'q':
	      handle_query (own_buf, &new_packet_len);
	      break;
	    case 'd':
	      remote_debug = !remote_debug;
	      break;
#ifndef USE_WIN32API
	    /* Skip "detach" support on mingw32, since we don't have
	       waitpid.  */
	    case 'D':
	      fprintf (stderr, "Detaching from inferior\n");
	      detach_inferior ();
	      write_ok (own_buf);
	      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)
		{
		  int status, ret;

		  do {
		    ret = waitpid (signal_pid, &status, 0);
		    if (WIFEXITED (status) || WIFSIGNALED (status))
		      break;
		  } while (ret != -1 || errno != ECHILD);
		}

	      exit (0);
#endif

	    case '!':
	      if (attached == 0)
		{
		  extended_protocol = 1;
		  prepare_resume_reply (own_buf, status, signal);
		}
	      else
		{
		  /* We can not use the extended protocol if we are
		     attached, because we can not restart the running
		     program.  So return unrecognized.  */
		  own_buf[0] = '\0';
		}
	      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;

		  gdb_id = strtoul (&own_buf[2], NULL, 16);
		  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':
	      set_desired_inferior (1);
	      registers_to_string (own_buf);
	      break;
	    case 'G':
	      set_desired_inferior (1);
	      registers_from_string (&own_buf[1]);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      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':
	      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':
	      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':
	      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;
	      set_desired_inferior (0);
	      myresume (0, signal);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'S':
	      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;
	      set_desired_inferior (0);
	      myresume (1, signal);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'c':
	      set_desired_inferior (0);
	      myresume (0, 0);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 's':
	      set_desired_inferior (0);
	      myresume (1, 0);
	      signal = mywait (&status, 1);
	      prepare_resume_reply (own_buf, status, signal);
	      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;

		    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;

		    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':
	      fprintf (stderr, "Killing inferior\n");
	      kill_inferior ();
	      /* When using the extended protocol, we start up a new
	         debugging session.   The traditional protocol will
	         exit instead.  */
	      if (extended_protocol)
		{
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      {
		unsigned long gdb_id, thread_id;

		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':
	      /* Restarting the inferior is only supported in the
	         extended protocol.  */
	      if (extended_protocol)
		{
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      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);
	      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);

	  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 (status == 'W' || status == 'X')
	    {
	      if (extended_protocol)
		{
		  fprintf (stderr, "Killing inferior\n");
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  fprintf (stderr, "GDBserver exiting\n");
		  exit (0);
		}
	    }
	}

      /* We come here when getpkt fails.

         For the extended remote protocol we exit (and this is the only
         way we gracefully exit!).

         For the traditional remote protocol close the connection,
         and re-open it at the top of the loop.  */
      if (extended_protocol)
	{
	  remote_close ();
	  exit (0);
	}
      else
	{
	  fprintf (stderr, "Remote side has terminated connection.  "
			   "GDBserver will reopen the connection.\n");
	  remote_close ();
	}
    }
}
Ejemplo n.º 12
0
/* 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;
}
Ejemplo n.º 13
0
int
main (int argc, char *argv[])
{
  char ch, status, own_buf[PBUFSIZ], mem_buf[2000];
  int i = 0;
  unsigned char signal;
  unsigned int len;
  CORE_ADDR mem_addr;

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

  if (argc < 3)
    error ("Usage: gdbserver tty prog [args ...]");

  initialize_low ();

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

  /* We are now stopped at the first instruction of the target process */

  while (1)
    {
      remote_open (argv[1]);

    restart:
      setjmp (toplevel);
      while (getpkt (own_buf) > 0)
	{
	  unsigned char sig;
	  i = 0;
	  ch = own_buf[i++];
	  switch (ch)
	    {
	    case 'd':
	      remote_debug = !remote_debug;
	      break;
	    case '!':
	      extended_protocol = 1;
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case '?':
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'H':
	      switch (own_buf[1])
		{
		case 'g':
		  general_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  fetch_inferior_registers (0);
		  break;
		case 'c':
		  cont_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  break;
		default:
		  /* Silently ignore it so that gdb can extend the protocol
		     without compatibility headaches.  */
		  own_buf[0] = '\0';
		  break;
		}
	      break;
	    case 'g':
	      convert_int_to_ascii (registers, own_buf, REGISTER_BYTES);
	      break;
	    case 'G':
	      convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES);
	      store_inferior_registers (-1);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      decode_m_packet (&own_buf[1], &mem_addr, &len);
	      read_inferior_memory (mem_addr, mem_buf, len);
	      convert_int_to_ascii (mem_buf, own_buf, len);
	      break;
	    case 'M':
	      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 'C':
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      myresume (0, sig);
	      signal = mywait (&status);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'S':
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      myresume (1, sig);
	      signal = mywait (&status);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'c':
	      myresume (0, 0);
	      signal = mywait (&status);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 's':
	      myresume (1, 0);
	      signal = mywait (&status);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'k':
	      fprintf (stderr, "Killing inferior\n");
	      kill_inferior ();
	      /* When using the extended protocol, we start up a new
	         debugging session.   The traditional protocol will
	         exit instead.  */
	      if (extended_protocol)
		{
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      if (mythread_alive (strtol (&own_buf[1], NULL, 16)))
		write_ok (own_buf);
	      else
		write_enn (own_buf);
	      break;
	    case 'R':
	      /* Restarting the inferior is only supported in the
	         extended protocol.  */
	      if (extended_protocol)
		{
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      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;
		}
	    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;
	    }

	  putpkt (own_buf);

	  if (status == 'W')
	    fprintf (stderr,
		     "\nChild exited with status %d\n", sig);
	  if (status == 'X')
	    fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig);
	  if (status == 'W' || status == 'X')
	    {
	      if (extended_protocol)
		{
		  fprintf (stderr, "Killing inferior\n");
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  fprintf (stderr, "GDBserver exiting\n");
		  exit (0);
		}
	    }
	}

      /* We come here when getpkt fails.

         For the extended remote protocol we exit (and this is the only
         way we gracefully exit!).

         For the traditional remote protocol close the connection,
         and re-open it at the top of the loop.  */
      if (extended_protocol)
	{
	  remote_close ();
	  exit (0);
	}
      else
	{
	  fprintf (stderr, "Remote side has terminated connection.  GDBserver will reopen the connection.\n");

	  remote_close ();
	}
    }
}