Add the "-semihosting-config" option.

The usual semihosting behaviour is to process the system calls locally and
return; unfortuantelly the initial implementation dinamically changed the
target to GDB during debug sessions, which, for the usual arm-none-eabi-gdb,
is not implemented. The result was that during debug sessions the semihosting
calls were discarded.

This patch adds a configuration variable and an option to set it on the
command line:

    -semihosting-config [enable=on|off,]target=native|gdb|auto

This option enables semihosting and defines where the semihosting calls will
be addressed, to QEMU ('native') or to GDB ('gdb'). The default is auto, which
means 'gdb' during debug sessions and 'native' otherwise.

Signed-off-by: Liviu Ionescu <ilg@livius.net>
Message-id: 1416341957-9796-1-git-send-email-ilg@livius.net
[PMM: moved declaration and definition of semihosting_target to
 gdbstub.h and gdbstub.c to fix build failure on linux-user]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Liviu Ionescu 2014-12-11 12:07:48 +00:00 committed by Peter Maydell
parent 1ecc3a2df1
commit a38bb0792c
4 changed files with 78 additions and 3 deletions

View File

@ -317,6 +317,8 @@ static GDBState *gdbserver_state;
bool gdb_has_xml; bool gdb_has_xml;
int semihosting_target = SEMIHOSTING_TARGET_AUTO;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
/* XXX: This is not thread safe. Do we care? */ /* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1; static int gdbserver_fd = -1;
@ -351,10 +353,19 @@ static enum {
GDB_SYS_DISABLED, GDB_SYS_DISABLED,
} gdb_syscall_mode; } gdb_syscall_mode;
/* If gdb is connected when the first semihosting syscall occurs then use /* Decide if either remote gdb syscalls or native file IO should be used. */
remote gdb syscalls. Otherwise use native file IO. */
int use_gdb_syscalls(void) int use_gdb_syscalls(void)
{ {
if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) {
/* -semihosting-config target=native */
return false;
} else if (semihosting_target == SEMIHOSTING_TARGET_GDB) {
/* -semihosting-config target=gdb */
return true;
}
/* -semihosting-config target=auto */
/* On the first call check if gdb is connected and remember. */
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
: GDB_SYS_DISABLED); : GDB_SYS_DISABLED);

View File

@ -95,4 +95,10 @@ extern bool gdb_has_xml;
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2]; extern const char *const xml_builtin[][2];
/* Command line option defining whether semihosting should go via gdb or not */
extern int semihosting_target;
#define SEMIHOSTING_TARGET_AUTO 0
#define SEMIHOSTING_TARGET_NATIVE 1
#define SEMIHOSTING_TARGET_GDB 2
#endif #endif

View File

@ -3218,7 +3218,17 @@ DEF("semihosting", 0, QEMU_OPTION_semihosting,
STEXI STEXI
@item -semihosting @item -semihosting
@findex -semihosting @findex -semihosting
Semihosting mode (ARM, M68K, Xtensa only). Enable semihosting mode (ARM, M68K, Xtensa only).
ETEXI
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
"-semihosting-config [enable=on|off,]target=native|gdb|auto semihosting configuration\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
STEXI
@item -semihosting-config [enable=on|off,]target=native|gdb|auto
@findex -semihosting-config
Enable semihosting and define where the semihosting calls will be addressed,
to QEMU (@code{native}) or to GDB (@code{gdb}). The default is @code{auto}, which means
@code{gdb} during debug sessions and @code{native} otherwise (ARM, M68K, Xtensa only).
ETEXI ETEXI
DEF("old-param", 0, QEMU_OPTION_old_param, DEF("old-param", 0, QEMU_OPTION_old_param,
"-old-param old param mode\n", QEMU_ARCH_ARM) "-old-param old param mode\n", QEMU_ARCH_ARM)

48
vl.c
View File

@ -554,6 +554,22 @@ static QemuOptsList qemu_icount_opts = {
}, },
}; };
static QemuOptsList qemu_semihosting_config_opts = {
.name = "semihosting-config",
.implied_opt_name = "enable",
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
.desc = {
{
.name = "enable",
.type = QEMU_OPT_BOOL,
}, {
.name = "target",
.type = QEMU_OPT_STRING,
},
{ /* end of list */ }
},
};
/** /**
* Get machine options * Get machine options
* *
@ -2811,6 +2827,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_name_opts); qemu_add_opts(&qemu_name_opts);
qemu_add_opts(&qemu_numa_opts); qemu_add_opts(&qemu_numa_opts);
qemu_add_opts(&qemu_icount_opts); qemu_add_opts(&qemu_icount_opts);
qemu_add_opts(&qemu_semihosting_config_opts);
runstate_init(); runstate_init();
@ -3618,6 +3635,37 @@ int main(int argc, char **argv, char **envp)
break; break;
case QEMU_OPTION_semihosting: case QEMU_OPTION_semihosting:
semihosting_enabled = 1; semihosting_enabled = 1;
semihosting_target = SEMIHOSTING_TARGET_AUTO;
break;
case QEMU_OPTION_semihosting_config:
semihosting_enabled = 1;
opts = qemu_opts_parse(qemu_find_opts("semihosting-config"),
optarg, 0);
if (opts != NULL) {
semihosting_enabled = qemu_opt_get_bool(opts, "enable",
true);
const char *target = qemu_opt_get(opts, "target");
if (target != NULL) {
if (strcmp("native", target) == 0) {
semihosting_target = SEMIHOSTING_TARGET_NATIVE;
} else if (strcmp("gdb", target) == 0) {
semihosting_target = SEMIHOSTING_TARGET_GDB;
} else if (strcmp("auto", target) == 0) {
semihosting_target = SEMIHOSTING_TARGET_AUTO;
} else {
fprintf(stderr, "Unsupported semihosting-config"
" %s\n",
optarg);
exit(1);
}
} else {
semihosting_target = SEMIHOSTING_TARGET_AUTO;
}
} else {
fprintf(stderr, "Unsupported semihosting-config %s\n",
optarg);
exit(1);
}
break; break;
case QEMU_OPTION_tdf: case QEMU_OPTION_tdf:
fprintf(stderr, "Warning: user space PIT time drift fix " fprintf(stderr, "Warning: user space PIT time drift fix "