+ else if (strstr(packet, "qCRC:"))
+ {
+ if (packet_size > 5)
+ {
+ int retval;
+ char gdb_reply[10];
+ char *separator;
+ u32 checksum;
+ u32 addr = 0;
+ u32 len = 0;
+
+ /* skip command character */
+ packet += 5;
+
+ addr = strtoul(packet, &separator, 16);
+
+ if (*separator != ',')
+ {
+ LOG_ERROR("incomplete read memory packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ len = strtoul(separator + 1, NULL, 16);
+
+ retval = target_checksum_memory(target, addr, len, &checksum);
+
+ if (retval == ERROR_OK)
+ {
+ snprintf(gdb_reply, 10, "C%8.8x", checksum);
+ gdb_put_packet(connection, gdb_reply, 9);
+ }
+ else
+ {
+ if ((retval = gdb_error(connection, retval)) != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+ }
+ }
+ else if (strstr(packet, "qSupported"))
+ {
+ /* we currently support packet size and qXfer:memory-map:read (if enabled)
+ * disable qXfer:features:read for the moment */
+ int retval = ERROR_OK;
+ char *buffer = NULL;
+ int pos = 0;
+ int size = 0;
+
+ xml_printf(&retval, &buffer, &pos, &size,
+ "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+",
+ (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1)&&(flash_get_bank_count()>0)) ? '+' : '-');
+
+ if (retval != ERROR_OK)
+ {
+ gdb_send_error(connection, 01);
+ return ERROR_OK;
+ }
+
+ gdb_put_packet(connection, buffer, strlen(buffer));
+ free(buffer);
+
+ return ERROR_OK;
+ }
+ else if (strstr(packet, "qXfer:memory-map:read::")&&(flash_get_bank_count()>0))
+ {
+ /* We get away with only specifying flash here. Regions that are not
+ * specified are treated as if we provided no memory map(if not we
+ * could detect the holes and mark them as RAM).
+ * Normally we only execute this code once, but no big deal if we
+ * have to regenerate it a couple of times. */
+
+ flash_bank_t *p;
+ char *xml = NULL;
+ int size = 0;
+ int pos = 0;
+ int retval = ERROR_OK;
+
+ int offset;
+ int length;
+ char *separator;
+ int blocksize;
+
+ /* skip command character */
+ packet += 23;
+
+ offset = strtoul(packet, &separator, 16);
+ length = strtoul(separator + 1, &separator, 16);
+
+ xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");
+
+ /*
+ sort banks in ascending order, we need to make non-flash memory be ram(or rather
+ read/write) by default for GDB.
+ GDB does not have a concept of non-cacheable read/write memory.
+ */
+ flash_bank_t **banks=malloc(sizeof(flash_bank_t *)*flash_get_bank_count());
+ int i;
+
+ for (i=0; i<flash_get_bank_count(); i++)
+ {
+ p = get_flash_bank_by_num(i);
+ if (p == NULL)
+ {
+ free(banks);
+ retval = ERROR_FAIL;
+ gdb_send_error(connection, retval);
+ return retval;
+ }
+ banks[i]=p;
+ }
+
+ qsort(banks, flash_get_bank_count(), sizeof(flash_bank_t *), compare_bank);
+
+ u32 ram_start=0;
+ for (i=0; i<flash_get_bank_count(); i++)
+ {
+ p = banks[i];
+
+ if (ram_start<p->base)
+ {
+ xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"0x%x\" length=\"0x%x\"/>\n",
+ ram_start, p->base-ram_start);
+ }
+
+ /* if device has uneven sector sizes, eg. str7, lpc
+ * we pass the smallest sector size to gdb memory map */
+ blocksize = gdb_calc_blocksize(p);
+
+ xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \
+ "<property name=\"blocksize\">0x%x</property>\n" \
+ "</memory>\n", \
+ p->base, p->size, blocksize);
+ ram_start=p->base+p->size;
+ }
+ if (ram_start!=0)
+ {
+ xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"0x%x\" length=\"0x%x\"/>\n",
+ ram_start, 0-ram_start);
+ } else
+ {
+ /* a flash chip could be at the very end of the 32 bit address space, in which case
+ ram_start will be precisely 0 */
+ }
+
+ free(banks);
+ banks = NULL;
+
+ xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");
+
+ if (retval != ERROR_OK)
+ {
+ gdb_send_error(connection, retval);
+ return retval;
+ }
+
+ if (offset + length > pos)
+ {
+ length = pos - offset;
+ }
+
+ char *t = malloc(length + 1);
+ t[0] = 'l';
+ memcpy(t + 1, xml + offset, length);
+ gdb_put_packet(connection, t, length + 1);
+
+ free(t);
+ free(xml);
+ return ERROR_OK;
+ }
+ else if (strstr(packet, "qXfer:features:read:"))
+ {
+ char *xml = NULL;
+ int size = 0;
+ int pos = 0;
+ int retval = ERROR_OK;
+
+ int offset;
+ unsigned int length;
+ char *annex;
+
+ /* skip command character */
+ packet += 20;
+
+ if (decode_xfer_read(packet, &annex, &offset, &length) < 0)
+ {
+ gdb_send_error(connection, 01);
+ return ERROR_OK;
+ }
+
+ if (strcmp(annex, "target.xml") != 0)
+ {
+ gdb_send_error(connection, 01);
+ return ERROR_OK;
+ }
+
+ xml_printf(&retval, &xml, &pos, &size, \
+ "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");
+
+ if (retval != ERROR_OK)
+ {
+ gdb_send_error(connection, retval);
+ return retval;
+ }
+
+ gdb_put_packet(connection, xml, strlen(xml));
+
+ free(xml);
+ return ERROR_OK;
+ }
+ else if (strstr(packet, "QStartNoAckMode"))
+ {
+ gdb_connection->noack_mode = 1;
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+ }
+
+ gdb_put_packet(connection, "", 0);
+ return ERROR_OK;
+}
+
+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')
+ {
+ LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ addr = strtoul(parse, &parse, 16);
+
+ if (*(parse++) != ',' || *parse == '\0')
+ {
+ LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ length = strtoul(parse, &parse, 16);
+
+ if (*parse != '\0')
+ {
+ LOG_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_FLASH_ERASE_START);
+ result = flash_erase_address_range(gdb_service->target, addr, length );
+ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_END);
+
+ /* perform erase */
+ if (result != 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);
+ LOG_ERROR("flash_erase returned %i", result);
+ }
+ else
+ gdb_put_packet(connection, "OK", 2);
+
+ return ERROR_OK;
+ }
+
+ if (strstr(packet, "vFlashWrite:"))
+ {
+ int retval;
+ unsigned long addr;
+ unsigned long length;
+ char *parse = packet + 12;
+
+ if (*parse == '\0')
+ {
+ LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+ addr = strtoul(parse, &parse, 16);
+ if (*(parse++) != ':')
+ {
+ LOG_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 */
+ if((retval = image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse)) != ERROR_OK)
+ {
+ return retval;
+ }
+
+ gdb_put_packet(connection, "OK", 2);
+
+ return ERROR_OK;
+ }
+
+ if (!strcmp(packet, "vFlashDone"))
+ {
+ u32 written;
+
+ /* process the flashing buffer. No need to erase as GDB
+ * always issues a vFlashErase first. */
+ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_START);
+ result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0);
+ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END);
+ if ( result != ERROR_OK)
+ {
+ if (result == ERROR_FLASH_DST_OUT_OF_BANK)
+ gdb_put_packet(connection, "E.memtype", 9);
+ else
+ gdb_send_error(connection, EIO);
+ }
+ else
+ {
+ LOG_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_handle_event( target, TARGET_EVENT_OLD_pre_resume );
+ target_resume(target, 1, 0, 1, 0);
+ break;
+
+ case GDB_DETACH_RESET:
+ /* FIX?? make this configurable?? */
+ target_process_reset(connection->cmd_ctx, RESET_HALT);
+ break;
+
+ case GDB_DETACH_HALT:
+ target_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 *string)
+{
+ connection_t *connection = priv;
+ gdb_connection_t *gdb_con = connection->priv;
+
+ if (gdb_con->busy)
+ {
+ /* do not reply this using the O packet */
+ return;
+ }
+
+ gdb_output_con(connection, string);
+}
+
+/* Do not allocate this on the stack */
+char gdb_packet_buffer[GDB_BUFFER_SIZE];
+
+static void gdb_sig_halted(connection_t *connection)
+{
+ char sig_reply[4];
+ snprintf(sig_reply, 4, "T%2.2x", 2);
+ gdb_put_packet(connection, sig_reply, 3);
+
+}
+
+int gdb_input_inner(connection_t *connection)