+int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+{
+ gdb_connection_t *gdb_connection = connection->priv;
+ gdb_service_t *gdb_service = connection->service->priv;
+ int result;
+
+ /* if flash programming disabled - send a empty reply */
+
+ if (gdb_flash_program == 0)
+ {
+ gdb_put_packet(connection, "", 0);
+ return ERROR_OK;
+ }
+
+ if (strstr(packet, "vFlashErase:"))
+ {
+ unsigned long addr;
+ unsigned long length;
+
+ char *parse = packet + 12;
+ if (*parse == '\0')
+ {
+ ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ addr = strtoul(parse, &parse, 16);
+
+ if (*(parse++) != ',' || *parse == '\0')
+ {
+ ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ length = strtoul(parse, &parse, 16);
+
+ if (*parse != '\0')
+ {
+ ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ /* assume all sectors need erasing - stops any problems
+ * when flash_write is called multiple times */
+ flash_set_dirty();
+
+ /* perform any target specific operations before the erase */
+ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
+
+ /* perform erase */
+ if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
+ {
+ /* GDB doesn't evaluate the actual error number returned,
+ * treat a failed erase as an I/O error
+ */
+ gdb_send_error(connection, EIO);
+ ERROR("flash_erase returned %i", result);
+ }
+ else
+ gdb_put_packet(connection, "OK", 2);
+
+ return ERROR_OK;
+ }
+
+ if (strstr(packet, "vFlashWrite:"))
+ {
+ unsigned long addr;
+ unsigned long length;
+ char *parse = packet + 12;
+
+ if (*parse == '\0')
+ {
+ ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+ addr = strtoul(parse, &parse, 16);
+ if (*(parse++) != ':')
+ {
+ ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+ length = packet_size - (parse - packet);
+
+ /* create a new image if there isn't already one */
+ if (gdb_connection->vflash_image == NULL)
+ {
+ gdb_connection->vflash_image = malloc(sizeof(image_t));
+ image_open(gdb_connection->vflash_image, "", "build");
+ }
+
+ /* create new section with content from packet buffer */
+ image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);
+
+ gdb_put_packet(connection, "OK", 2);
+
+ return ERROR_OK;
+ }
+
+ if (!strcmp(packet, "vFlashDone"))
+ {
+ u32 written;
+ char *error_str;
+
+ /* process the flashing buffer. No need to erase as GDB
+ * always issues a vFlashErase first. */
+ if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, &error_str, NULL, 0)) != ERROR_OK)
+ {
+ if (result == ERROR_FLASH_DST_OUT_OF_BANK)
+ gdb_put_packet(connection, "E.memtype", 9);
+ else
+ gdb_send_error(connection, EIO);
+
+ if (error_str)
+ {
+ ERROR("flash writing failed: %s", error_str);
+ free(error_str);
+ }
+ }
+ else
+ {
+ DEBUG("wrote %u bytes from vFlash image to flash", written);
+ gdb_put_packet(connection, "OK", 2);
+ }
+
+ image_close(gdb_connection->vflash_image);
+ free(gdb_connection->vflash_image);
+ gdb_connection->vflash_image = NULL;
+
+ return ERROR_OK;
+ }
+
+ gdb_put_packet(connection, "", 0);
+ return ERROR_OK;
+}
+
+int gdb_detach(connection_t *connection, target_t *target)
+{
+ switch( detach_mode )
+ {
+ case GDB_DETACH_RESUME:
+ target->type->resume(target, 1, 0, 1, 0);
+ break;
+
+ case GDB_DETACH_RESET:
+ target_process_reset(connection->cmd_ctx);
+ break;
+
+ case GDB_DETACH_HALT:
+ target->type->halt(target);
+ break;
+
+ case GDB_DETACH_NOTHING:
+ break;
+ }
+
+ gdb_put_packet(connection, "OK", 2);
+
+ return ERROR_OK;
+}
+
+static void gdb_log_callback(void *priv, const char *file, int line,
+ const char *function, const char *format, va_list args)
+{
+ connection_t *connection = priv;
+ gdb_connection_t *gdb_con = connection->priv;
+
+ if (gdb_con->busy)
+ {
+ /* do not reply this using the O packet */
+ return;
+ }
+
+ char *t = allocPrintf(format, args);
+ if (t == NULL)
+ return;
+
+ gdb_output_con(connection, t);
+
+ free(t);
+}
+
+int gdb_input_inner(connection_t *connection)