+ extern const char *const xml_builtin[][2];
+ size_t len;
+ int i;
+ const char *name;
+ static char target_xml[1024];
+
+ len = 0;
+ while (p[len] && p[len] != ':')
+ len++;
+ *newp = p + len;
+
+ name = NULL;
+ if (strncmp(p, "target.xml", len) == 0) {
+ /* Generate the XML description for this CPU. */
+ if (!target_xml[0]) {
+ GDBRegisterState *r;
+
+ snprintf(target_xml, sizeof(target_xml),
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+ "<target>"
+ "<xi:include href=\"%s\"/>",
+ GDB_CORE_XML);
+
+ for (r = first_cpu->gdb_regs; r; r = r->next) {
+ strcat(target_xml, "<xi:include href=\"");
+ strcat(target_xml, r->xml);
+ strcat(target_xml, "\"/>");
+ }
+ strcat(target_xml, "</target>");
+ }
+ return target_xml;
+ }
+ for (i = 0; ; i++) {
+ name = xml_builtin[i][0];
+ if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len))
+ break;
+ }
+ return name ? xml_builtin[i][1] : NULL;
+}
+#endif
+
+static int gdb_read_register(CPUState *env, uint8_t *mem_buf, int reg)
+{
+ GDBRegisterState *r;
+
+ if (reg < NUM_CORE_REGS)
+ return cpu_gdb_read_register(env, mem_buf, reg);
+
+ for (r = env->gdb_regs; r; r = r->next) {
+ if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+ return r->get_reg(env, mem_buf, reg - r->base_reg);
+ }
+ }
+ return 0;
+}
+
+static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
+{
+ GDBRegisterState *r;
+
+ if (reg < NUM_CORE_REGS)
+ return cpu_gdb_write_register(env, mem_buf, reg);
+
+ for (r = env->gdb_regs; r; r = r->next) {
+ if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+ return r->set_reg(env, mem_buf, reg - r->base_reg);
+ }
+ }
+ return 0;
+}
+
+/* Register a supplemental set of CPU registers. If g_pos is nonzero it
+ specifies the first register number and these registers are included in
+ a standard "g" packet. Direction is relative to gdb, i.e. get_reg is
+ gdb reading a CPU register, and set_reg is gdb modifying a CPU register.
+ */
+
+void gdb_register_coprocessor(CPUState * env,
+ gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+ int num_regs, const char *xml, int g_pos)
+{
+ GDBRegisterState *s;
+ GDBRegisterState **p;
+ static int last_reg = NUM_CORE_REGS;
+
+ s = (GDBRegisterState *)qemu_mallocz(sizeof(GDBRegisterState));
+ s->base_reg = last_reg;
+ s->num_regs = num_regs;
+ s->get_reg = get_reg;
+ s->set_reg = set_reg;
+ s->xml = xml;
+ p = &env->gdb_regs;
+ while (*p) {
+ /* Check for duplicates. */
+ if (strcmp((*p)->xml, xml) == 0)
+ return;
+ p = &(*p)->next;
+ }
+ /* Add to end of list. */
+ last_reg += num_regs;
+ *p = s;
+ if (g_pos) {
+ if (g_pos != s->base_reg) {
+ fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n"
+ "Expected %d got %d\n", xml, g_pos, s->base_reg);
+ } else {
+ num_g_regs = last_reg;
+ }
+ }
+}
+
+/* GDB breakpoint/watchpoint types */
+#define GDB_BREAKPOINT_SW 0
+#define GDB_BREAKPOINT_HW 1
+#define GDB_WATCHPOINT_WRITE 2
+#define GDB_WATCHPOINT_READ 3
+#define GDB_WATCHPOINT_ACCESS 4
+
+#ifndef CONFIG_USER_ONLY
+static const int xlat_gdb_type[] = {
+ [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE,
+ [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ,
+ [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
+};
+#endif
+
+static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
+{
+ CPUState *env;
+ int err = 0;
+
+ switch (type) {
+ case GDB_BREAKPOINT_SW:
+ case GDB_BREAKPOINT_HW:
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
+ if (err)
+ break;
+ }
+ return err;
+#ifndef CONFIG_USER_ONLY
+ case GDB_WATCHPOINT_WRITE:
+ case GDB_WATCHPOINT_READ:
+ case GDB_WATCHPOINT_ACCESS:
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
+ NULL);
+ if (err)
+ break;
+ }
+ return err;
+#endif
+ default:
+ return -ENOSYS;
+ }
+}
+
+static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
+{
+ CPUState *env;
+ int err = 0;
+
+ switch (type) {
+ case GDB_BREAKPOINT_SW:
+ case GDB_BREAKPOINT_HW:
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ err = cpu_breakpoint_remove(env, addr, BP_GDB);
+ if (err)
+ break;
+ }
+ return err;
+#ifndef CONFIG_USER_ONLY
+ case GDB_WATCHPOINT_WRITE:
+ case GDB_WATCHPOINT_READ:
+ case GDB_WATCHPOINT_ACCESS:
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
+ if (err)
+ break;
+ }
+ return err;
+#endif
+ default:
+ return -ENOSYS;
+ }
+}
+
+static void gdb_breakpoint_remove_all(void)
+{
+ CPUState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_breakpoint_remove_all(env, BP_GDB);
+#ifndef CONFIG_USER_ONLY
+ cpu_watchpoint_remove_all(env, BP_GDB);
+#endif
+ }
+}
+
+static int gdb_handle_packet(GDBState *s, const char *line_buf)
+{
+ CPUState *env;