Пример #1
0
void GdbServer::gdb_out(const char *buf) {
  int i = strlen (buf) * 2 + 1;

  char hexdata [i + 1];
  hexdata[0] = 'O';
  hexify (hexdata + 1, (unsigned char*) buf, strlen(buf));
  gdb_putpacket (hexdata, i);
}
Пример #2
0
void GdbServer::gdb_putpacket_f (const char *fmt, ...) {
  va_list ap;
  char *buf;
  int size;

  va_start(ap, fmt);
  size = vasprintf (&buf, (const char*) fmt, ap);
  gdb_putpacket (buf, size);
  free(buf);
  va_end(ap);
}
Пример #3
0
void GdbServer::handle_q_packet (char *packet, int len) {
  unsigned long addr, alen;

  if (!strncmp (packet, "qRcmd,", 6)) {
    int datalen;

    /* calculate size and allocate buffer for command */
    datalen = (len - 6) / 2;
    char data [datalen + 1];
    /* dehexify command */
    unhexify ((unsigned char*) data, (const unsigned char*)packet + 6, datalen);
    data[datalen] = 0; /* add terminating null */

    int c = mon.command (data);
    if (c < 0)
      gdb_putpacketz ("");
    else if (c == 0)
      gdb_putpacketz ("OK");
    else
      gdb_putpacketz ("E");

  } else if (!strncmp (packet, "qSupported", 10)) {
    /* Query supported protocol features */
    gdb_putpacket_f ("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);

  } else if (strncmp (packet, "qXfer:memory-map:read::", 23) == 0) {
    /* Read target XML memory map */
    if ((!target) || (!target->xml_mem_map)) {
      gdb_putpacketz ("E01");
      return;
    }
    handle_q_string_reply (target->xml_mem_map, packet + 23);

  } else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
    /* Read target description */
    if ((!target) || (!target->tdesc)) {
      gdb_putpacketz ("E01");
      return;
    }
    handle_q_string_reply (target->tdesc, packet + 31);
  } else if (sscanf (packet, "qCRC:%08lx,%08lx", &addr, &alen) == 2) {
    if (!target) {
      gdb_putpacketz ("E01");
      return;
    }
    gdb_putpacket_f ("C%lx", target->generic_crc32 (addr, alen));

  } else {      
    debug ("*** Unsupported packet: %s\n", packet);
    gdb_putpacket ("", 0);
  }

}
Пример #4
0
void GdbServer::handle_q_string_reply (const char *str, const char *param) {
  unsigned long addr, len;

  if (sscanf (param, "%08lx,%08lx", &addr, &len) != 2) {
    gdb_putpacketz ("E01");
    return;
  }
  if (addr < strlen (str)) {
    char reply [len+2];
    reply[0] = 'm';
    strncpy (reply + 1, &str [addr], len);
    if (len > strlen (&str [addr]))
      len = strlen (&str [addr]);
    gdb_putpacket (reply, len + 1);
  } else if (addr == strlen (str)) {
    gdb_putpacketz ("l");
  } else
    gdb_putpacketz ("E01");
}
Пример #5
0
void
gdb_main(void)
{
	int size;
	bool single_step = false;
	char last_activity = 0;

	DEBUG("Entring GDB protocol main loop\n");
	/* GDB protocol main loop */
	while(1) {
		SET_IDLE_STATE(1);
		size = gdb_getpacket(pbuf, BUF_SIZE);
		SET_IDLE_STATE(0);
	continue_activity:
		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);
			DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
			uint8_t mem[len];
			target_mem_read(cur_target, mem, addr, len);
			if(target_check_error(cur_target))
				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);
			DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
			uint8_t mem[len];
			unhexify(mem, pbuf + hex, len);
			target_mem_write(cur_target, addr, mem, len);
			if(target_check_error(cur_target))
				gdb_putpacketz("E01");
			else
				gdb_putpacketz("OK");
			break;
			}
		case 's':	/* 's [addr]': Single step [start at addr] */
			single_step = true;
			// Fall through to resume target
		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 to wait for target halt
		case '?': {	/* '?': Request reason for target halt */
			/* This packet isn't documented as being mandatory,
			 * but GDB doesn't work without it. */
			uint32_t watch_addr;
			int sig;

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

			last_activity = pbuf[0];
			/* Wait for target halt */
			while(!(sig = target_halt_wait(cur_target))) {
				unsigned char c = gdb_if_getchar_to(0);
				if((c == '\x03') || (c == '\x04')) {
					target_halt_request(cur_target);
					last_activity = 's';
				}
			}
			SET_RUN_STATE(0);

			/* Negative signal indicates we're in a syscall */
			if (sig < 0)
				break;

			/* Target disappeared */
			if (cur_target == NULL) {
				gdb_putpacket_f("X%02X", sig);
				break;
			}

			/* Report reason for halt */
			if(target_check_hw_wp(cur_target, &watch_addr)) {
				/* Watchpoint hit */
				gdb_putpacket_f("T%02Xwatch:%08X;", sig, watch_addr);
			} else {
				gdb_putpacket_f("T%02X", sig);
			}
			break;
			}
		case 'F': {	/* Semihosting call finished */
			int retcode, errcode, items;
			char c, *p;
			if (pbuf[1] == '-')
				p = &pbuf[2];
			else
				p = &pbuf[1];
			items = sscanf(p, "%x,%x,%c", &retcode, &errcode, &c);
			if (pbuf[1] == '-')
				retcode = -retcode;

			target_hostio_reply(cur_target, retcode, errcode);

			/* if break is requested */
			if (items == 3 && c == 'C') {
				gdb_putpacketz("T02");
				break;
			}

			pbuf[0] = last_activity;
			goto continue_activity;
		}

		/* 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_target_destroy_callback);
				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);
			DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
			target_mem_write(cur_target, addr, pbuf+bin, len);
			if(target_check_error(cur_target))
				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("");
		}
	}
}
Пример #6
0
static void
handle_v_packet(char *packet, int plen)
{
	unsigned long addr, len;
	int bin;
	static uint8_t flash_mode = 0;

	if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
		/* Attach to remote target processor */
		target *t;
		uint32_t i;
		for(t = target_list, i = 1; t; t = t->next, i++)
			if(i == addr) {
				cur_target = target_attach(t,
						gdb_target_destroy_callback);
				break;
			}
		if(cur_target)
			gdb_putpacketz("T05");
		else
			gdb_putpacketz("E01");

	} else if (!strcmp(packet, "vRun;")) {
		/* Run target program. For us (embedded) this means reset. */
		if(cur_target) {
			target_reset(cur_target);
			gdb_putpacketz("T05");
		} else if(last_target) {
			cur_target = target_attach(last_target,
						gdb_target_destroy_callback);

                        /* If we were able to attach to the target again */
                        if (cur_target) {
                        	target_reset(cur_target);
                        	gdb_putpacketz("T05");
                        } else	gdb_putpacketz("E01");

		} else	gdb_putpacketz("E01");

	} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
		/* Erase Flash Memory */
		DEBUG("Flash Erase %08lX %08lX\n", addr, len);
		if(!cur_target) { gdb_putpacketz("EFF"); return; }

		if(!flash_mode) {
			/* Reset target if first flash command! */
			/* This saves us if we're interrupted in IRQ context */
			target_reset(cur_target);
			flash_mode = 1;
		}
		if(target_flash_erase(cur_target, addr, len) == 0)
			gdb_putpacketz("OK");
		else
			gdb_putpacketz("EFF");

	} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
		/* Write Flash Memory */
		len = plen - bin;
		DEBUG("Flash Write %08lX %08lX\n", addr, len);
		if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
			gdb_putpacketz("OK");
		else
			gdb_putpacketz("EFF");

	} else if (!strcmp(packet, "vFlashDone")) {
		/* Commit flash operations. */
		gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
		flash_mode = 0;

	} else {
		DEBUG("*** Unsupported packet: %s\n", packet);
		gdb_putpacket("", 0);
	}
}
Пример #7
0
static void
handle_q_packet(char *packet, int len)
{
	uint32_t addr, alen;

	if(!strncmp(packet, "qRcmd,", 6)) {
		char *data;
		int datalen;

		/* calculate size and allocate buffer for command */
		datalen = (len - 6) / 2;
		data = alloca(datalen+1);
		/* dehexify command */
		unhexify(data, packet+6, datalen);
		data[datalen] = 0;	/* add terminating null */

		int c = command_process(cur_target, data);
		if(c < 0)
			gdb_putpacketz("");
		else if(c == 0)
			gdb_putpacketz("OK");
		else
			gdb_putpacketz("E");

	} else if (!strncmp (packet, "qSupported", 10)) {
		/* Query supported protocol features */
		gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);

	} else if (strncmp (packet, "qXfer:memory-map:read::", 23) == 0) {
		/* Read target XML memory map */
		if((!cur_target) && last_target) {
			/* Attach to last target if detached. */
			cur_target = target_attach(last_target,
						gdb_target_destroy_callback);
		}
		if (!cur_target) {
			gdb_putpacketz("E01");
			return;
		}
		handle_q_string_reply(target_mem_map(cur_target), packet + 23);

	} else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
		/* Read target description */
		if((!cur_target) && last_target) {
			/* Attach to last target if detached. */
			cur_target = target_attach(last_target,
						gdb_target_destroy_callback);
		}
		if (!cur_target) {
			gdb_putpacketz("E01");
			return;
		}
		handle_q_string_reply(target_tdesc(cur_target), packet + 31);
	} else if (sscanf(packet, "qCRC:%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
		if(!cur_target) {
			gdb_putpacketz("E01");
			return;
		}
		gdb_putpacket_f("C%lx", generic_crc32(cur_target, addr, alen));

	} else {
		DEBUG("*** Unsupported packet: %s\n", packet);
		gdb_putpacket("", 0);
	}
}
Пример #8
0
uint32_t GdbServer::Up (char *pbuf, uint32_t plen) {
  debug ("Up::%d:\"%s\"\n", plen, pbuf);
  lock.lock();
  size = plen;
continue_activity:
  switch (pbuf[0]) {
    case 0: {           // Ctrl - C
      debug ("GdbServer::Up Ctrl-C\n");
      target->halt_request ();
      last_activity = 's';
      break;
    }
      /* Implementation of these is mandatory! */
    case 'g': { /* 'g': Read general registers */
      if (!target_check ()) break;
      int rsize = target->get_regs_size();
      debug ("RSIZE = %d\n", rsize);
      uint8_t arm_regs [rsize];
      target->regs_read (arm_regs);
      /* Výstup po blocích délky max. 240 bytů byl vynucen větší déklou dat registrů
       * CortexM4F. Zdá se, že to funguje.
       */
      const int  chunk = 120;
      int block, start = 0;
      for (;;) {
        if (rsize > chunk) block = chunk; 
        else               block = rsize;
        char* tptr =  (char*) hexify (pbuf, (const unsigned char*) arm_regs + start, block);
        gdb_putpacket (tptr , block * 2);
        start += block;
        rsize -= block;
        if (!rsize) break;
      }
      break;
    }
    case 'm': { /* 'm addr,len': Read len bytes from addr */
      unsigned long addr, len;
      if (!target_check ()) break;
      sscanf ((char*)pbuf, "m%08lx,%08lx", &addr, &len);
      debug ("m packet: addr = %08lX, len = %08lX\n", addr, len);
      uint8_t mem[len];
      if ( ( (addr & 3) == 0) && ( (len & 3) == 0))
        target->mem_read_words ((uint32_t*) mem, addr, len);
      else
        target->mem_read_bytes (mem, addr, len);
      if (target->check_error ())
        gdb_putpacketz ("E01");
      else
        gdb_putpacket ((char*)hexify (pbuf, mem, len), len*2);
      break;
    }
    case 'G': { /* 'G XX': Write general registers */
      if (!target_check ()) break;
      int rsize = target->get_regs_size();
      uint8_t arm_regs [rsize];
      unhexify (arm_regs, (unsigned char*) &pbuf[1], rsize);
      target->regs_write (arm_regs);
      gdb_putpacketz ("OK");
      break;
    }
    case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
      unsigned long addr, len;
      int hex;
      if (!target_check ()) break;
      sscanf ((char*)pbuf, "M%08lx,%08lx:%n", &addr, &len, &hex);
      debug ("M packet: addr = %08lX, len = %08lX\n", addr, len);
      uint8_t mem[len];
      unhexify (mem, (unsigned char*)pbuf + hex, len);
      if ( ( (addr & 3) == 0) && ( (len & 3) == 0))
        target->mem_write_words (addr, (const uint32_t*) mem, len);
      else
        target->mem_write_bytes (addr, mem, len);
      if (target->check_error ())
        gdb_putpacketz ("E01");
      else
        gdb_putpacketz ("OK");
      break;
    }
    
    case 's': /* 's [addr]': Single step [start at addr] */
      single_step = true;
      // Fall through to resume target
    case 'c': /* 'c [addr]': Continue [at addr] */
      if (!target) {
        gdb_putpacketz ("X1D");
        break;
      }
      target->halt_resume (single_step);
      single_step = false;
      // Fall through to wait for target halt
    case '?': { /* '?': Request reason for target halt */
      /* This packet isn't documented as being mandatory,
       * but GDB doesn't work without it. */

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

      last_activity = pbuf[0];
      /* Wait for target halt */
      debug("? WAIT HALT\n");
      SetActive ();            // timto se prepne do mainloop, kde ceka na zastaveni
      break;
    }
    case 'F': { /* Semihosting call finished */
      int retcode, errcode, items;
      char c, *p;
      if (pbuf[1] == '-')
        p = (char*) &pbuf[2];
      else
        p = (char*) &pbuf[1];
      items = sscanf (p, "%x,%x,%c", &retcode, &errcode, &c);
      if (pbuf[1] == '-')
        retcode = -retcode;

      target->hostio_reply (retcode, errcode);

      /* if break is requested */
      if (items == 3 && c == 'C') {
        gdb_putpacketz ("T02");
        break;
      }

      pbuf[0] = last_activity;
      goto continue_activity;
    }

    /* 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: // ???
      debug ("CASE 4 packet ???\n");
    case 'D': /* GDB 'detach' command. */
      if (target) {
        if (target->attached) {
          target->detach ();
          target->reset  ();
        }
      }
      gdb_putpacketz ("OK");
      break;

    case 'k': /* Kill the target */
      if (target) {
        target->detach ();
        target->reset  ();
      }
      break;

    case 'r': /* Reset the target system */
    case 'R': /* Restart the target program */
      if (target && target->attach()) {
        target->reset ();
        SetActive ();
      }
      break;

    case 'X': { /* 'X addr,len:XX': Write binary data to addr */
      unsigned long addr, len;
      int bin, icp;
      if (!target_check ()) break;
      sscanf ((char*)pbuf, "X%08lx,%08lx:%n", &addr, &len, &bin);
      // On Cortex-M0 word align param to write_words
      for (icp=0; icp<(int)len; icp++) pbuf[icp] = pbuf[icp + bin];
      
      debug ("X packet: addr = %08lX, len = %08lX\n", addr, len);
      if ( ( (addr & 3) == 0) && ( (len & 3) == 0))
        target->mem_write_words (addr, (const uint32_t*)  pbuf, len);
      else
        target->mem_write_bytes (addr, (unsigned char*) pbuf, len);
      if (target->check_error   ())
        gdb_putpacketz ("E01");
      else
        gdb_putpacketz ("OK");
      break;
    }

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

    case 'v': /* General query packet */
      handle_v_packet ((char*)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 */
      if (!target_check ()) break;
      handle_z_packet ((char*)pbuf, size);
      break;

    default:  /* Packet not implemented */
      debug ("*** Unsupported packet: %s\n", pbuf);
      gdb_putpacketz ("");
  }
  lock.unlock();
  //return BaseLayer::Up (pbuf, plen);
  return plen;
}
Пример #9
0
void GdbServer::gdb_putpacketz (const char *packet) {
  int size = strlen (packet);
  gdb_putpacket (packet, size);
}
Пример #10
0
void GdbServer::handle_v_packet (char *packet, int plen) {
  unsigned long addr, len;
  int bin;
  static uint32_t flash_mode = 0;

  if (sscanf (packet, "vAttach;%08lx", &addr) == 1) {
    /* Attach to remote target processor */
    if (target && target->attach())
      gdb_putpacketz ("T05");
    else
      gdb_putpacketz ("E01");

  } else if (!strcmp (packet, "vRun;")) {
    /* Run target program. For us (embedded) this means reset. */
    if (target && target->attach()) {
        target->reset ();
        SetActive ();
        gdb_putpacketz ("T05");
      }
      else
        gdb_putpacketz ("E01"); 

  } else if (sscanf (packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
    /* Erase Flash Memory */
    debug ("Flash Erase %08lX %08lX\n", addr, len);
    if (!target) {
      gdb_putpacketz ("EFF");
      return;
    }

    if (!flash_mode) {
      /* Reset target if first flash command! */
      /* This saves us if we're interrupted in IRQ context */
      target->reset ();
      flash_mode = 1;
    }
    if (target->flash_erase (addr, len) == 0)
      gdb_putpacketz ("OK");
    else
      gdb_putpacketz ("EFF");

  } else if (sscanf (packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
    /* Write Flash Memory */
    len = plen - bin;
    debug ("Flash Write %08lX %08lX\n", addr, len);
    if (target && target->flash_write (addr, (unsigned char*) packet + bin, len) == 0)
      gdb_putpacketz ("OK");
    else
      gdb_putpacketz ("EFF");

  } else if (!strcmp (packet, "vFlashDone")) {
    /* Commit flash operations. */
    gdb_putpacketz ("OK");
    flash_mode = 0;

  } else {
    debug ("*** Unsupported packet: %s\n", packet);
    gdb_putpacket ("", 0);
  }

}
Пример #11
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("");
		}
	}
}