aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Borneo <borneo.antonio@gmail.com>2020-10-15 14:45:27 +0200
committerAntonio Borneo <borneo.antonio@gmail.com>2020-11-04 17:37:59 +0000
commite2e8a5f467e8e35618ce4fbf16b8da4e682d8258 (patch)
tree5b200e7d3b599606143b36149f64182775759565
parent360b2c27012f3f787382bee9ce0b4e4707b22dc3 (diff)
downloadriscv-openocd-e2e8a5f467e8e35618ce4fbf16b8da4e682d8258.zip
riscv-openocd-e2e8a5f467e8e35618ce4fbf16b8da4e682d8258.tar.gz
riscv-openocd-e2e8a5f467e8e35618ce4fbf16b8da4e682d8258.tar.bz2
gdb_server: allow multiple GDB connections to selected targets
The default way of working is to have a single GDB attached to one target, so OpenOCD accepts only one connection to the GDB port of each targets and rejects any further connection. There are some barely safe use cases in which it could get useful having a second GDB connection to the same target. One such use case is while using GDB as a 'non-intrusive memory inspector', as explained in the OpenOCD documentation. One GDB can be left running an infinite loop to dump some memory area, or even analysing the content, while keeping a second GDB ready for user interaction or spot memory check. Add a target configure option to specify the maximum number of GDB connections allowed for that target, keeping the default to 1. Change-Id: I4985a602e61588df0b527d2f2aa5b955c93e125e Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/5865 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
-rw-r--r--doc/openocd.texi13
-rw-r--r--src/server/gdb_server.c2
-rw-r--r--src/target/target.c28
-rw-r--r--src/target/target.h2
4 files changed, 40 insertions, 5 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index ca10f8c..e6a1467 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -4694,6 +4694,11 @@ possible values of the parameter @var{number}, which are not only numeric values
Use this option to override, for this target only, the global parameter set with
command @command{gdb_port}.
@xref{gdb_port,,command gdb_port}.
+
+@item @code{-gdb-max-connections} @var{number} -- EXPERIMENTAL: set the maximum
+number of GDB connections that are allowed for the target. Default is 1.
+A negative value for @var{number} means unlimited connections.
+See @xref{gdbmeminspect,,Using GDB as a non-intrusive memory inspector}.
@end itemize
@end deffn
@@ -10606,7 +10611,13 @@ of a running target. Do not use GDB commands @command{continue},
and GDB would require stopping the target to get the prompt back.
Do not use this mode under an IDE like Eclipse as it caches values of
-previously shown varibles.
+previously shown variables.
+
+It's also possible to connect more than one GDB to the same target by the
+target's configuration option @code{-gdb-max-connections}. This allows, for
+example, one GDB to run a script that continuously polls a set of variables
+while other GDB can be used interactively. Be extremely careful in this case,
+because the two GDB can easily get out-of-sync.
@section RTOS Support
@cindex RTOS Support
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 1a209a7..c96be10 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -3508,7 +3508,7 @@ static int gdb_target_start(struct target *target, const char *port)
target->gdb_service = gdb_service;
ret = add_service("gdb",
- port, 1, &gdb_new_connection, &gdb_input,
+ port, target->gdb_max_connections, &gdb_new_connection, &gdb_input,
&gdb_connection_closed, gdb_service);
/* initialize all targets gdb service with the same pointer */
{
diff --git a/src/target/target.c b/src/target/target.c
index 53d3e82..9443f6c 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -1263,10 +1263,10 @@ int target_get_gdb_reg_list_noread(struct target *target,
bool target_supports_gdb_connection(struct target *target)
{
/*
- * based on current code, we can simply exclude all the targets that
- * don't provide get_gdb_reg_list; this could change with new targets.
+ * exclude all the targets that don't provide get_gdb_reg_list
+ * or that have explicit gdb_max_connection == 0
*/
- return !!target->type->get_gdb_reg_list;
+ return !!target->type->get_gdb_reg_list && !!target->gdb_max_connections;
}
int target_step(struct target *target,
@@ -4652,6 +4652,7 @@ enum target_cfg_param {
TCFG_RTOS,
TCFG_DEFER_EXAMINE,
TCFG_GDB_PORT,
+ TCFG_GDB_MAX_CONNECTIONS,
};
static Jim_Nvp nvp_config_opts[] = {
@@ -4668,6 +4669,7 @@ static Jim_Nvp nvp_config_opts[] = {
{ .name = "-rtos", .value = TCFG_RTOS },
{ .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE },
{ .name = "-gdb-port", .value = TCFG_GDB_PORT },
+ { .name = "-gdb-max-connections", .value = TCFG_GDB_MAX_CONNECTIONS },
{ .name = NULL, .value = -1 }
};
@@ -4975,6 +4977,25 @@ no_params:
Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1);
/* loop for more */
break;
+
+ case TCFG_GDB_MAX_CONNECTIONS:
+ if (goi->isconfigure) {
+ struct command_context *cmd_ctx = current_command_context(goi->interp);
+ if (cmd_ctx->mode != COMMAND_CONFIG) {
+ Jim_SetResultString(goi->interp, "-gdb-max-conenctions must be configured before 'init'", -1);
+ return JIM_ERR;
+ }
+
+ e = Jim_GetOpt_Wide(goi, &w);
+ if (e != JIM_OK)
+ return e;
+ target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w;
+ } else {
+ if (goi->argc != 0)
+ goto no_params;
+ }
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections));
+ break;
}
} /* while (goi->argc) */
@@ -5555,6 +5576,7 @@ static int target_create(Jim_GetOptInfo *goi)
target->rtos_auto_detect = false;
target->gdb_port_override = NULL;
+ target->gdb_max_connections = 1;
/* Do the rest as "configure" options */
goi->isconfigure = 1;
diff --git a/src/target/target.h b/src/target/target.h
index 9589b53..ee0bdfb 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -211,6 +211,8 @@ struct target {
char *gdb_port_override; /* target-specific override for gdb_port */
+ int gdb_max_connections; /* max number of simultaneous gdb connections */
+
/* The semihosting information, extracted from the target. */
struct semihosting *semihosting;
};