+
+ if (gdb_ctx->num_params < 3) {
+ put_packet(gdb_ctx->s, "E22");
+ return;
+ }
+
+ process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
+ cc = CPU_GET_CLASS(gdb_ctx->s->g_cpu);
+ if (!cc->gdb_core_xml_file) {
+ put_packet(gdb_ctx->s, "");
+ return;
+ }
+
+ gdb_has_xml = true;
+ p = gdb_ctx->params[0].data;
+ xml = get_feature_xml(gdb_ctx->s, p, &p, process);
+ if (!xml) {
+ put_packet(gdb_ctx->s, "E00");
+ return;
+ }
+
+ addr = gdb_ctx->params[1].val_ul;
+ len = gdb_ctx->params[2].val_ul;
+ total_len = strlen(xml);
+ if (addr > total_len) {
+ put_packet(gdb_ctx->s, "E00");
+ return;
+ }
+
+ if (len > (MAX_PACKET_LENGTH - 5) / 2) {
+ len = (MAX_PACKET_LENGTH - 5) / 2;
+ }
+
+ if (len < total_len - addr) {
+ gdb_ctx->str_buf[0] = 'm';
+ len = memtox(gdb_ctx->str_buf + 1, xml + addr, len);
+ } else {
+ gdb_ctx->str_buf[0] = 'l';
+ len = memtox(gdb_ctx->str_buf + 1, xml + addr, total_len - addr);
+ }
+
+ put_packet_binary(gdb_ctx->s, gdb_ctx->str_buf, len + 1, true);
+}
+
+static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ put_packet(gdb_ctx->s, GDB_ATTACHED);
+}
+
+static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "sstepbits;sstep");
+#ifndef CONFIG_USER_ONLY
+ pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";PhyMemMode");
+#endif
+ put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
+ void *user_ctx)
+{
+ snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", phy_memory_mode);
+ put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ if (!gdb_ctx->num_params) {
+ put_packet(gdb_ctx->s, "E22");
+ return;
+ }
+
+ if (!gdb_ctx->params[0].val_ul) {
+ phy_memory_mode = 0;
+ } else {
+ phy_memory_mode = 1;
+ }
+ put_packet(gdb_ctx->s, "OK");
+}
+#endif
+
+static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
+ /* Order is important if has same prefix */
+ {
+ .handler = handle_query_qemu_sstepbits,
+ .cmd = "qemu.sstepbits",
+ },
+ {
+ .handler = handle_query_qemu_sstep,
+ .cmd = "qemu.sstep",
+ },
+ {
+ .handler = handle_set_qemu_sstep,
+ .cmd = "qemu.sstep=",
+ .cmd_startswith = 1,
+ .schema = "l0"
+ },
+};
+
+static GdbCmdParseEntry gdb_gen_query_table[] = {
+ {
+ .handler = handle_query_curr_tid,
+ .cmd = "C",
+ },
+ {
+ .handler = handle_query_threads,
+ .cmd = "sThreadInfo",
+ },
+ {
+ .handler = handle_query_first_threads,
+ .cmd = "fThreadInfo",
+ },
+ {
+ .handler = handle_query_thread_extra,
+ .cmd = "ThreadExtraInfo,",
+ .cmd_startswith = 1,
+ .schema = "t0"
+ },
+#ifdef CONFIG_USER_ONLY
+ {
+ .handler = handle_query_offsets,
+ .cmd = "Offsets",
+ },
+#else
+ {
+ .handler = handle_query_rcmd,
+ .cmd = "Rcmd,",
+ .cmd_startswith = 1,
+ .schema = "s0"
+ },
+#endif
+ {
+ .handler = handle_query_supported,
+ .cmd = "Supported:",
+ .cmd_startswith = 1,
+ .schema = "s0"
+ },
+ {
+ .handler = handle_query_supported,
+ .cmd = "Supported",
+ .schema = "s0"
+ },
+ {
+ .handler = handle_query_xfer_features,
+ .cmd = "Xfer:features:read:",
+ .cmd_startswith = 1,
+ .schema = "s:l,l0"
+ },
+ {
+ .handler = handle_query_attached,
+ .cmd = "Attached:",
+ .cmd_startswith = 1
+ },
+ {
+ .handler = handle_query_attached,
+ .cmd = "Attached",
+ },
+ {
+ .handler = handle_query_qemu_supported,
+ .cmd = "qemu.Supported",
+ },
+#ifndef CONFIG_USER_ONLY
+ {
+ .handler = handle_query_qemu_phy_mem_mode,
+ .cmd = "qemu.PhyMemMode",
+ },
+#endif
+};
+
+static GdbCmdParseEntry gdb_gen_set_table[] = {
+ /* Order is important if has same prefix */
+ {
+ .handler = handle_set_qemu_sstep,
+ .cmd = "qemu.sstep:",
+ .cmd_startswith = 1,
+ .schema = "l0"
+ },
+#ifndef CONFIG_USER_ONLY
+ {
+ .handler = handle_set_qemu_phy_mem_mode,
+ .cmd = "qemu.PhyMemMode:",
+ .cmd_startswith = 1,
+ .schema = "l0"
+ },
+#endif
+};
+
+static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ if (!gdb_ctx->num_params) {
+ return;
+ }
+
+ if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ gdb_gen_query_set_common_table,
+ ARRAY_SIZE(gdb_gen_query_set_common_table))) {
+ return;
+ }
+
+ if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ gdb_gen_query_table,
+ ARRAY_SIZE(gdb_gen_query_table))) {
+ put_packet(gdb_ctx->s, "");
+ }
+}
+
+static void handle_gen_set(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ if (!gdb_ctx->num_params) {
+ return;
+ }
+
+ if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ gdb_gen_query_set_common_table,
+ ARRAY_SIZE(gdb_gen_query_set_common_table))) {
+ return;
+ }
+
+ if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ gdb_gen_set_table,
+ ARRAY_SIZE(gdb_gen_set_table))) {
+ put_packet(gdb_ctx->s, "");
+ }
+}
+
+static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
+{