Example #1
0
static void
handle_unlink (char *own_buf)
{
  char filename[PATH_MAX];
  char *p;
  int ret;

  p = own_buf + strlen ("vFile:unlink:");

  if (require_filename (&p, filename)
      || require_end (p))
    {
      hostio_packet_error (own_buf);
      return;
    }

  ret = unlink (filename);

  if (ret == -1)
    {
      hostio_error (own_buf);
      return;
    }

  hostio_reply (own_buf, ret);
}
Example #2
0
static void
handle_unlink (char *own_buf)
{
  char filename[HOSTIO_PATH_MAX];
  char *p;
  int ret;

  p = own_buf + strlen ("vFile:unlink:");

  if (require_filename (&p, filename)
      || require_end (p))
    {
      hostio_packet_error (own_buf);
      return;
    }

  if (hostio_fs_pid != 0 && the_target->multifs_unlink != NULL)
    ret = the_target->multifs_unlink (hostio_fs_pid, filename);
  else
    ret = unlink (filename);

  if (ret == -1)
    {
      hostio_error (own_buf);
      return;
    }

  hostio_reply (own_buf, ret);
}
Example #3
0
static void
handle_setfs (char *own_buf)
{
  char *p;
  int pid;

  /* If the target doesn't have any of the in-filesystem-of methods
     then there's no point in GDB sending "vFile:setfs:" packets.  We
     reply with an empty packet (i.e. we pretend we don't understand
     "vFile:setfs:") and that should stop GDB sending any more.  */
  if (the_target->multifs_open == NULL
      && the_target->multifs_unlink == NULL
      && the_target->multifs_readlink == NULL)
    {
      own_buf[0] = '\0';
      return;
    }

  p = own_buf + strlen ("vFile:setfs:");

  if (require_int (&p, &pid)
      || pid < 0
      || require_end (p))
    {
      hostio_packet_error (own_buf);
      return;
    }

  hostio_fs_pid = pid;

  hostio_reply (own_buf, 0);
}
Example #4
0
static void
handle_close (char *own_buf)
{
  int fd, ret;
  char *p;
  struct fd_list **open_fd_p, *old_fd;

  p = own_buf + strlen ("vFile:close:");

  if (require_int (&p, &fd)
      || require_valid_fd (fd)
      || require_end (p))
    {
      hostio_packet_error (own_buf);
      return;
    }

  ret = close (fd);

  if (ret == -1)
    {
      hostio_error (own_buf);
      return;
    }

  open_fd_p = &open_fds;
  while (*open_fd_p && (*open_fd_p)->fd != fd)
    open_fd_p = &(*open_fd_p)->next;

  old_fd = *open_fd_p;
  *open_fd_p = (*open_fd_p)->next;
  free (old_fd);

  hostio_reply (own_buf, ret);
}
Example #5
0
static void
handle_open (char *own_buf)
{
  char filename[HOSTIO_PATH_MAX];
  char *p;
  int fileio_flags, fileio_mode, flags, fd;
  mode_t mode;
  struct fd_list *new_fd;

  p = own_buf + strlen ("vFile:open:");

  if (require_filename (&p, filename)
      || require_comma (&p)
      || require_int (&p, &fileio_flags)
      || require_comma (&p)
      || require_int (&p, &fileio_mode)
      || require_end (p)
      || fileio_to_host_openflags (fileio_flags, &flags)
      || fileio_to_host_mode (fileio_mode, &mode))
    {
      hostio_packet_error (own_buf);
      return;
    }

  /* We do not need to convert MODE, since the fileio protocol
     uses the standard values.  */
  if (hostio_fs_pid != 0 && the_target->multifs_open != NULL)
    fd = the_target->multifs_open (hostio_fs_pid, filename,
				   flags, mode);
  else
    fd = open (filename, flags, mode);

  if (fd == -1)
    {
      hostio_error (own_buf);
      return;
    }

  /* Record the new file descriptor.  */
  new_fd = xmalloc (sizeof (struct fd_list));
  new_fd->fd = fd;
  new_fd->next = open_fds;
  open_fds = new_fd;

  hostio_reply (own_buf, fd);
}
Example #6
0
static void
handle_pwrite (char *own_buf, int packet_len)
{
  int fd, ret, len, offset;
  char *p, *data;

  p = own_buf + strlen ("vFile:pwrite:");

  if (require_int (&p, &fd)
      || require_comma (&p)
      || require_valid_fd (fd)
      || require_int (&p, &offset)
      || require_comma (&p)
      || require_data (p, packet_len - (p - own_buf), &data, &len))
    {
      hostio_packet_error (own_buf);
      return;
    }

#ifdef HAVE_PWRITE
  ret = pwrite (fd, data, len, offset);
#else
  ret = -1;
#endif
  /* If we have no pwrite or it failed for this file, use lseek/write.  */
  if (ret == -1)
    {
      ret = lseek (fd, offset, SEEK_SET);
      if (ret != -1)
	ret = write (fd, data, len);
    }

  if (ret == -1)
    {
      hostio_error (own_buf);
      free (data);
      return;
    }

  hostio_reply (own_buf, ret);
  free (data);
}
Example #7
0
static void
handle_open (char *own_buf)
{
  char filename[PATH_MAX];
  char *p;
  int fileio_flags, mode, flags, fd;
  struct fd_list *new_fd;

  p = own_buf + strlen ("vFile:open:");

  if (require_filename (&p, filename)
      || require_comma (&p)
      || require_int (&p, &fileio_flags)
      || require_comma (&p)
      || require_int (&p, &mode)
      || require_end (p)
      || fileio_open_flags_to_host (fileio_flags, &flags))
    {
      hostio_packet_error (own_buf);
      return;
    }

  /* We do not need to convert MODE, since the fileio protocol
     uses the standard values.  */
  fd = open (filename, flags, mode);

  if (fd == -1)
    {
      hostio_error (own_buf);
      return;
    }

  /* Record the new file descriptor.  */
  new_fd = xmalloc (sizeof (struct fd_list));
  new_fd->fd = fd;
  new_fd->next = open_fds;
  open_fds = new_fd;

  hostio_reply (own_buf, fd);
}
Example #8
0
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{
	int size;
	bool single_step = false;

	/* GDB protocol main loop */
	while(1) {
		SET_IDLE_STATE(1);
		size = gdb_getpacket(pbuf, BUF_SIZE);
		SET_IDLE_STATE(0);
		switch(pbuf[0]) {
		/* Implementation of these is mandatory! */
		case 'g': { /* 'g': Read general registers */
			ERROR_IF_NO_TARGET();
			uint8_t arm_regs[target_regs_size(cur_target)];
			target_regs_read(cur_target, arm_regs);
			gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
			              sizeof(arm_regs) * 2);
			break;
			}
		case 'm': {	/* 'm addr,len': Read len bytes from addr */
			uint32_t addr, len;
			ERROR_IF_NO_TARGET();
			sscanf(pbuf, "m%" SCNx32 ",%" SCNx32, &addr, &len);
			if (len > sizeof(pbuf) / 2) {
				gdb_putpacketz("E02");
				break;
			}
			DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
			uint8_t mem[len];
			if (target_mem_read(cur_target, mem, addr, len))
				gdb_putpacketz("E01");
			else
				gdb_putpacket(hexify(pbuf, mem, len), len*2);
			break;
			}
		case 'G': {	/* 'G XX': Write general registers */
			ERROR_IF_NO_TARGET();
			uint8_t arm_regs[target_regs_size(cur_target)];
			unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
			target_regs_write(cur_target, arm_regs);
			gdb_putpacketz("OK");
			break;
			}
		case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
			uint32_t addr, len;
			int hex;
			ERROR_IF_NO_TARGET();
			sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
			if (len > (unsigned)(size - hex) / 2) {
				gdb_putpacketz("E02");
				break;
			}
			DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
			uint8_t mem[len];
			unhexify(mem, pbuf + hex, len);
			if (target_mem_write(cur_target, addr, mem, len))
				gdb_putpacketz("E01");
			else
				gdb_putpacketz("OK");
			break;
			}
		case 's':	/* 's [addr]': Single step [start at addr] */
			single_step = true;
			/* fall through */
		case 'c':	/* 'c [addr]': Continue [at addr] */
			if(!cur_target) {
				gdb_putpacketz("X1D");
				break;
			}

			target_halt_resume(cur_target, single_step);
			SET_RUN_STATE(1);
			single_step = false;
			/* fall through */
		case '?': {	/* '?': Request reason for target halt */
			/* This packet isn't documented as being mandatory,
			 * but GDB doesn't work without it. */
			target_addr watch;
			enum target_halt_reason reason;

			if(!cur_target) {
				/* Report "target exited" if no target */
				gdb_putpacketz("W00");
				break;
			}

			/* Wait for target halt */
			while(!(reason = target_halt_poll(cur_target, &watch))) {
				unsigned char c = gdb_if_getchar_to(0);
				if((c == '\x03') || (c == '\x04')) {
					target_halt_request(cur_target);
				}
			}
			SET_RUN_STATE(0);

			/* Translate reason to GDB signal */
			switch (reason) {
			case TARGET_HALT_ERROR:
				gdb_putpacket_f("X%02X", GDB_SIGLOST);
				morse("TARGET LOST.", true);
				break;
			case TARGET_HALT_REQUEST:
				gdb_putpacket_f("T%02X", GDB_SIGINT);
				break;
			case TARGET_HALT_WATCHPOINT:
				gdb_putpacket_f("T%02Xwatch:%08X;", GDB_SIGTRAP, watch);
				break;
			case TARGET_HALT_FAULT:
				gdb_putpacket_f("T%02X", GDB_SIGSEGV);
				break;
			default:
				gdb_putpacket_f("T%02X", GDB_SIGTRAP);
			}
			break;
			}
		case 'F':	/* Semihosting call finished */
			if (in_syscall) {
				return hostio_reply(tc, pbuf, size);
			} else {
				DEBUG("*** F packet when not in syscall! '%s'\n", pbuf);
				gdb_putpacketz("");
			}
			break;

		/* Optional GDB packet support */
		case '!':	/* Enable Extended GDB Protocol. */
			/* This doesn't do anything, we support the extended
			 * protocol anyway, but GDB will never send us a 'R'
			 * packet unless we answer 'OK' here.
			 */
			gdb_putpacketz("OK");
			break;

		case 0x04:
		case 'D':	/* GDB 'detach' command. */
			if(cur_target)
				target_detach(cur_target);
			last_target = cur_target;
			cur_target = NULL;
			gdb_putpacketz("OK");
			break;

		case 'k':	/* Kill the target */
			if(cur_target) {
				target_reset(cur_target);
				target_detach(cur_target);
				last_target = cur_target;
				cur_target = NULL;
			}
			break;

		case 'r':	/* Reset the target system */
		case 'R':	/* Restart the target program */
			if(cur_target)
				target_reset(cur_target);
			else if(last_target) {
				cur_target = target_attach(last_target,
						           &gdb_controller);
				target_reset(cur_target);
			}
			break;

		case 'X': { /* 'X addr,len:XX': Write binary data to addr */
			uint32_t addr, len;
			int bin;
			ERROR_IF_NO_TARGET();
			sscanf(pbuf, "X%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &bin);
			if (len > (unsigned)(size - bin)) {
				gdb_putpacketz("E02");
				break;
			}
			DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
			if (target_mem_write(cur_target, addr, pbuf+bin, len))
				gdb_putpacketz("E01");
			else
				gdb_putpacketz("OK");
			break;
			}

		case 'q':	/* General query packet */
			handle_q_packet(pbuf, size);
			break;

		case 'v':	/* General query packet */
			handle_v_packet(pbuf, size);
			break;

		/* These packet implement hardware break-/watchpoints */
		case 'Z':	/* Z type,addr,len: Set breakpoint packet */
		case 'z':	/* z type,addr,len: Clear breakpoint packet */
			ERROR_IF_NO_TARGET();
			handle_z_packet(pbuf, size);
			break;

		default: 	/* Packet not implemented */
			DEBUG("*** Unsupported packet: %s\n", pbuf);
			gdb_putpacketz("");
		}
	}
}