+static int gdb_chr_can_receive(void *opaque)
+{
+ /* We can handle an arbitrarily large amount of data.
+ Pick the maximum packet size, which is as good as anything. */
+ return MAX_PACKET_LENGTH;
+}
+
+static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ gdb_read_byte(gdbserver_state, buf[i]);
+ }
+}
+
+static void gdb_chr_event(void *opaque, int event)
+{
+ switch (event) {
+ case CHR_EVENT_RESET:
+ vm_stop(EXCP_INTERRUPT);
+ gdb_has_xml = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static void gdb_monitor_output(GDBState *s, const char *msg, int len)
+{
+ char buf[MAX_PACKET_LENGTH];
+
+ buf[0] = 'O';
+ if (len > (MAX_PACKET_LENGTH/2) - 1)
+ len = (MAX_PACKET_LENGTH/2) - 1;
+ memtohex(buf + 1, (uint8_t *)msg, len);
+ put_packet(s, buf);
+}
+
+static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ const char *p = (const char *)buf;
+ int max_sz;
+
+ max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
+ for (;;) {
+ if (len <= max_sz) {
+ gdb_monitor_output(gdbserver_state, p, len);
+ break;
+ }
+ gdb_monitor_output(gdbserver_state, p, max_sz);
+ p += max_sz;
+ len -= max_sz;
+ }
+ return len;
+}
+
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+ if (vm_running)
+ vm_stop(EXCP_INTERRUPT);
+}
+#endif
+
+int gdbserver_start(const char *device)
+{
+ GDBState *s;
+ char gdbstub_device_name[128];
+ CharDriverState *chr = NULL;
+ CharDriverState *mon_chr;
+
+ if (!device)
+ return -1;
+ if (strcmp(device, "none") != 0) {
+ if (strstart(device, "tcp:", NULL)) {
+ /* enforce required TCP attributes */
+ snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+ "%s,nowait,nodelay,server", device);
+ device = gdbstub_device_name;
+ }
+#ifndef _WIN32
+ else if (strcmp(device, "stdio") == 0) {
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = gdb_sigterm_handler;
+ sigaction(SIGINT, &act, NULL);
+ }