mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-29 05:13:54 -06:00
system: propagate Error to gdbserver_start (and other device setups)
This started as a clean-up to properly pass a Error handler to the gdbserver_start so we could do the right thing for command line and HMP invocations. Now that we have cleaned up foreach_device_config_or_exit() in earlier patches we can further simplify by it by passing &error_fatal instead of checking the return value. Having a return value is still useful for HMP though so tweak the return to use a simple bool instead. Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Acked-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20250116160306.1709518-11-alex.bennee@linaro.org>
This commit is contained in:
parent
05cdd648a8
commit
c0e6b8b798
7 changed files with 62 additions and 59 deletions
|
@ -628,7 +628,7 @@ int main(int argc, char **argv)
|
||||||
target_cpu_init(env, regs);
|
target_cpu_init(env, regs);
|
||||||
|
|
||||||
if (gdbstub) {
|
if (gdbstub) {
|
||||||
gdbserver_start(gdbstub);
|
gdbserver_start(gdbstub, &error_fatal);
|
||||||
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
cpu_loop(env);
|
cpu_loop(env);
|
||||||
|
|
|
@ -330,26 +330,27 @@ static void create_processes(GDBState *s)
|
||||||
gdb_create_default_process(s);
|
gdb_create_default_process(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gdbserver_start(const char *device)
|
bool gdbserver_start(const char *device, Error **errp)
|
||||||
{
|
{
|
||||||
Chardev *chr = NULL;
|
Chardev *chr = NULL;
|
||||||
Chardev *mon_chr;
|
Chardev *mon_chr;
|
||||||
g_autoptr(GString) cs = g_string_new(device);
|
g_autoptr(GString) cs = g_string_new(device);
|
||||||
|
|
||||||
if (!first_cpu) {
|
if (!first_cpu) {
|
||||||
error_report("gdbstub: meaningless to attach gdb to a "
|
error_setg(errp, "gdbstub: meaningless to attach gdb to a "
|
||||||
"machine without any CPU.");
|
"machine without any CPU.");
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gdb_supports_guest_debug()) {
|
if (!gdb_supports_guest_debug()) {
|
||||||
error_report("gdbstub: current accelerator doesn't "
|
error_setg(errp, "gdbstub: current accelerator doesn't "
|
||||||
"support guest debugging");
|
"support guest debugging");
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs->len == 0) {
|
if (cs->len == 0) {
|
||||||
return -1;
|
error_setg(errp, "gdbstub: missing connection string");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_gdbstub_op_start(cs->str);
|
trace_gdbstub_op_start(cs->str);
|
||||||
|
@ -374,7 +375,8 @@ int gdbserver_start(const char *device)
|
||||||
*/
|
*/
|
||||||
chr = qemu_chr_new_noreplay("gdb", cs->str, true, NULL);
|
chr = qemu_chr_new_noreplay("gdb", cs->str, true, NULL);
|
||||||
if (!chr) {
|
if (!chr) {
|
||||||
return -1;
|
error_setg(errp, "gdbstub: couldn't create chardev");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +408,7 @@ int gdbserver_start(const char *device)
|
||||||
gdbserver_system_state.mon_chr = mon_chr;
|
gdbserver_system_state.mon_chr = mon_chr;
|
||||||
gdb_syscall_reset();
|
gdb_syscall_reset();
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
#include "exec/hwaddr.h"
|
#include "exec/hwaddr.h"
|
||||||
#include "exec/tb-flush.h"
|
#include "exec/tb-flush.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
@ -372,14 +373,14 @@ static bool gdb_accept_tcp(int gdb_fd)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdbserver_open_port(int port)
|
static int gdbserver_open_port(int port, Error **errp)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sockaddr;
|
struct sockaddr_in sockaddr;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
|
|
||||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("socket");
|
error_setg_errno(errp, errno, "Failed to create socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
qemu_set_cloexec(fd);
|
qemu_set_cloexec(fd);
|
||||||
|
@ -391,13 +392,13 @@ static int gdbserver_open_port(int port)
|
||||||
sockaddr.sin_addr.s_addr = 0;
|
sockaddr.sin_addr.s_addr = 0;
|
||||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
perror("bind");
|
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ret = listen(fd, 1);
|
ret = listen(fd, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
perror("listen");
|
error_setg_errno(errp, errno, "Failed to listen to socket");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -405,31 +406,32 @@ static int gdbserver_open_port(int port)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gdbserver_start(const char *port_or_path)
|
bool gdbserver_start(const char *port_or_path, Error **errp)
|
||||||
{
|
{
|
||||||
int port = g_ascii_strtoull(port_or_path, NULL, 10);
|
int port = g_ascii_strtoull(port_or_path, NULL, 10);
|
||||||
int gdb_fd;
|
int gdb_fd;
|
||||||
|
|
||||||
if (port > 0) {
|
if (port > 0) {
|
||||||
gdb_fd = gdbserver_open_port(port);
|
gdb_fd = gdbserver_open_port(port, errp);
|
||||||
} else {
|
} else {
|
||||||
gdb_fd = gdbserver_open_socket(port_or_path);
|
gdb_fd = gdbserver_open_socket(port_or_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gdb_fd < 0) {
|
if (gdb_fd < 0) {
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port > 0 && gdb_accept_tcp(gdb_fd)) {
|
if (port > 0 && gdb_accept_tcp(gdb_fd)) {
|
||||||
return 0;
|
return true;
|
||||||
} else if (gdb_accept_socket(gdb_fd)) {
|
} else if (gdb_accept_socket(gdb_fd)) {
|
||||||
gdbserver_user_state.socket_path = g_strdup(port_or_path);
|
gdbserver_user_state.socket_path = g_strdup(port_or_path);
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gone wrong */
|
/* gone wrong */
|
||||||
close(gdb_fd);
|
close(gdb_fd);
|
||||||
return -1;
|
error_setg(errp, "gdbstub: failed to accept connection");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdbserver_fork_start(void)
|
void gdbserver_fork_start(void)
|
||||||
|
|
|
@ -49,12 +49,18 @@ void gdb_unregister_coprocessor_all(CPUState *cpu);
|
||||||
/**
|
/**
|
||||||
* gdbserver_start: start the gdb server
|
* gdbserver_start: start the gdb server
|
||||||
* @port_or_device: connection spec for gdb
|
* @port_or_device: connection spec for gdb
|
||||||
|
* @errp: error handle
|
||||||
*
|
*
|
||||||
* For CONFIG_USER this is either a tcp port or a path to a fifo. For
|
* For CONFIG_USER this is either a tcp port or a path to a fifo. For
|
||||||
* system emulation you can use a full chardev spec for your gdbserver
|
* system emulation you can use a full chardev spec for your gdbserver
|
||||||
* port.
|
* port.
|
||||||
|
*
|
||||||
|
* The error handle should be either &error_fatal (for start-up) or
|
||||||
|
* &error_warn (for QMP/HMP initiated sessions).
|
||||||
|
*
|
||||||
|
* Returns true when server successfully started.
|
||||||
*/
|
*/
|
||||||
int gdbserver_start(const char *port_or_device);
|
bool gdbserver_start(const char *port_or_device, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
|
* gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
|
||||||
|
|
|
@ -1023,11 +1023,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
target_cpu_copy_regs(env, regs);
|
target_cpu_copy_regs(env, regs);
|
||||||
|
|
||||||
if (gdbstub) {
|
if (gdbstub) {
|
||||||
if (gdbserver_start(gdbstub) < 0) {
|
gdbserver_start(gdbstub, &error_fatal);
|
||||||
fprintf(stderr, "qemu: could not open gdbserver on %s\n",
|
|
||||||
gdbstub);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,7 @@ void hmp_gdbserver(Monitor *mon, const QDict *qdict)
|
||||||
device = "tcp::" DEFAULT_GDBSTUB_PORT;
|
device = "tcp::" DEFAULT_GDBSTUB_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gdbserver_start(device) < 0) {
|
if (!gdbserver_start(device, &error_warn)) {
|
||||||
monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
|
monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
|
||||||
device);
|
device);
|
||||||
} else if (strcmp(device, "none") == 0) {
|
} else if (strcmp(device, "none") == 0) {
|
||||||
|
|
59
system/vl.c
59
system/vl.c
|
@ -811,15 +811,15 @@ static void configure_msg(QemuOpts *opts)
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* USB devices */
|
/* USB devices */
|
||||||
|
|
||||||
static int usb_parse(const char *cmdline)
|
static bool usb_parse(const char *cmdline, Error **errp)
|
||||||
{
|
{
|
||||||
g_assert(machine_usb(current_machine));
|
g_assert(machine_usb(current_machine));
|
||||||
|
|
||||||
if (!usbdevice_create(cmdline)) {
|
if (!usbdevice_create(cmdline)) {
|
||||||
error_report("could not add USB device '%s'", cmdline);
|
error_setg(errp, "could not add USB device '%s'", cmdline);
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
|
@ -1298,24 +1298,21 @@ static void add_device_config(int type, const char *cmdline)
|
||||||
* @type: device_config type
|
* @type: device_config type
|
||||||
* @func: device specific config function, returning pass/fail
|
* @func: device specific config function, returning pass/fail
|
||||||
*
|
*
|
||||||
* Any failure is fatal and we exit with an error message.
|
* @func is called with the &error_fatal handler so device specific
|
||||||
|
* error messages can be reported on failure.
|
||||||
*/
|
*/
|
||||||
static void foreach_device_config_or_exit(int type,
|
static void foreach_device_config_or_exit(int type,
|
||||||
int (*func)(const char *cmdline))
|
bool (*func)(const char *cmdline,
|
||||||
|
Error **errp))
|
||||||
{
|
{
|
||||||
struct device_config *conf;
|
struct device_config *conf;
|
||||||
int rc;
|
|
||||||
|
|
||||||
QTAILQ_FOREACH(conf, &device_configs, next) {
|
QTAILQ_FOREACH(conf, &device_configs, next) {
|
||||||
if (conf->type != type)
|
if (conf->type != type)
|
||||||
continue;
|
continue;
|
||||||
loc_push_restore(&conf->loc);
|
loc_push_restore(&conf->loc);
|
||||||
rc = func(conf->cmdline);
|
func(conf->cmdline, &error_fatal);
|
||||||
loc_pop(&conf->loc);
|
loc_pop(&conf->loc);
|
||||||
if (rc) {
|
|
||||||
error_setg(&error_fatal, "failed to configure: %s", conf->cmdline);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1446,7 +1443,7 @@ static void qemu_create_default_devices(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int serial_parse(const char *devname)
|
static bool serial_parse(const char *devname, Error **errp)
|
||||||
{
|
{
|
||||||
int index = num_serial_hds;
|
int index = num_serial_hds;
|
||||||
|
|
||||||
|
@ -1461,13 +1458,13 @@ static int serial_parse(const char *devname)
|
||||||
|
|
||||||
serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
|
serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
|
||||||
if (!serial_hds[index]) {
|
if (!serial_hds[index]) {
|
||||||
error_report("could not connect serial device"
|
error_setg(errp, "could not connect serial device"
|
||||||
" to character backend '%s'", devname);
|
" to character backend '%s'", devname);
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
num_serial_hds++;
|
num_serial_hds++;
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *serial_hd(int i)
|
Chardev *serial_hd(int i)
|
||||||
|
@ -1479,44 +1476,44 @@ Chardev *serial_hd(int i)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parallel_parse(const char *devname)
|
static bool parallel_parse(const char *devname, Error **errp)
|
||||||
{
|
{
|
||||||
static int index = 0;
|
static int index = 0;
|
||||||
char label[32];
|
char label[32];
|
||||||
|
|
||||||
if (strcmp(devname, "none") == 0)
|
if (strcmp(devname, "none") == 0)
|
||||||
return 0;
|
return true;
|
||||||
if (index == MAX_PARALLEL_PORTS) {
|
if (index == MAX_PARALLEL_PORTS) {
|
||||||
error_report("too many parallel ports");
|
error_setg(errp, "too many parallel ports");
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
snprintf(label, sizeof(label), "parallel%d", index);
|
snprintf(label, sizeof(label), "parallel%d", index);
|
||||||
parallel_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
|
parallel_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
|
||||||
if (!parallel_hds[index]) {
|
if (!parallel_hds[index]) {
|
||||||
error_report("could not connect parallel device"
|
error_setg(errp, "could not connect parallel device"
|
||||||
" to character backend '%s'", devname);
|
" to character backend '%s'", devname);
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debugcon_parse(const char *devname)
|
static bool debugcon_parse(const char *devname, Error **errp)
|
||||||
{
|
{
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
|
|
||||||
if (!qemu_chr_new_mux_mon("debugcon", devname, NULL)) {
|
if (!qemu_chr_new_mux_mon("debugcon", devname, NULL)) {
|
||||||
error_report("invalid character backend '%s'", devname);
|
error_setg(errp, "invalid character backend '%s'", devname);
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);
|
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);
|
||||||
if (!opts) {
|
if (!opts) {
|
||||||
error_report("already have a debugcon device");
|
error_setg(errp, "already have a debugcon device");
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
qemu_opt_set(opts, "driver", "isa-debugcon", &error_abort);
|
qemu_opt_set(opts, "driver", "isa-debugcon", &error_abort);
|
||||||
qemu_opt_set(opts, "chardev", "debugcon", &error_abort);
|
qemu_opt_set(opts, "chardev", "debugcon", &error_abort);
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint machine_class_cmp(gconstpointer a, gconstpointer b)
|
static gint machine_class_cmp(gconstpointer a, gconstpointer b)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue