final updates for 9.0 (testing, gdbstub):
- fix the over rebuilding of test VMs - support Xfer:siginfo:read in gdbstub - fix double close() in gdbstub -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmXxkb0ACgkQ+9DbCVqe KkSw9wf+K+3kJYaZ2unEFku3Y6f4Z9XkrZCsFQFVNIJQgpYVc6peQyLUB1pZwzZc yoQhmTIgej16iRZc7gEcJhFl2zlX2vulE/m+wiaR0Chv3E2r510AGn4aWl+GLB9+ /WduHaz1NobPW4JWaarxespa84Re8QZQgqkHX4nwYd++FW63E4uxydL4F1nmSNca eTA6RwS48h4wqPzHBX72hYTRUnYrDUSSGCGUDzK3NHumuPi+AQ77GLRMO0MTYFfy hWriapogCmghY+Xtn++eUIwDyh1CCnUT6Ntf5Qj06bZ+f6eaTwINM8QWhj9mxYX+ 5/F5Q4JJDqRPYw/hF4wYXRsiZxTYFw== =BOWW -----END PGP SIGNATURE----- Merge tag 'pull-maintainer-final-130324-1' of https://gitlab.com/stsquad/qemu into staging final updates for 9.0 (testing, gdbstub): - fix the over rebuilding of test VMs - support Xfer:siginfo:read in gdbstub - fix double close() in gdbstub # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmXxkb0ACgkQ+9DbCVqe # KkSw9wf+K+3kJYaZ2unEFku3Y6f4Z9XkrZCsFQFVNIJQgpYVc6peQyLUB1pZwzZc # yoQhmTIgej16iRZc7gEcJhFl2zlX2vulE/m+wiaR0Chv3E2r510AGn4aWl+GLB9+ # /WduHaz1NobPW4JWaarxespa84Re8QZQgqkHX4nwYd++FW63E4uxydL4F1nmSNca # eTA6RwS48h4wqPzHBX72hYTRUnYrDUSSGCGUDzK3NHumuPi+AQ77GLRMO0MTYFfy # hWriapogCmghY+Xtn++eUIwDyh1CCnUT6Ntf5Qj06bZ+f6eaTwINM8QWhj9mxYX+ # 5/F5Q4JJDqRPYw/hF4wYXRsiZxTYFw== # =BOWW # -----END PGP SIGNATURE----- # gpg: Signature made Wed 13 Mar 2024 11:45:01 GMT # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full] # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * tag 'pull-maintainer-final-130324-1' of https://gitlab.com/stsquad/qemu: gdbstub: Fix double close() of the follow-fork-mode socket tests/tcg: Add multiarch test for Xfer:siginfo:read stub gdbstub: Add Xfer:siginfo:read stub gdbstub: Save target's siginfo linux-user: Move tswap_siginfo out of target code gdbstub: Rename back gdb_handlesig tests/vm: ensure we build everything by default Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ba49d760eb
@ -606,7 +606,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (gdbstub) {
|
if (gdbstub) {
|
||||||
gdbserver_start(gdbstub);
|
gdbserver_start(gdbstub);
|
||||||
gdb_handlesig(cpu, 0);
|
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
cpu_loop(env);
|
cpu_loop(env);
|
||||||
/* never exits */
|
/* never exits */
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
#include "hw/core/tcg-cpu-ops.h"
|
#include "hw/core/tcg-cpu-ops.h"
|
||||||
#include "host-signal.h"
|
#include "host-signal.h"
|
||||||
|
|
||||||
|
/* target_siginfo_t must fit in gdbstub's siginfo save area. */
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(target_siginfo_t) > MAX_SIGINFO_LENGTH);
|
||||||
|
|
||||||
static struct target_sigaction sigact_table[TARGET_NSIG];
|
static struct target_sigaction sigact_table[TARGET_NSIG];
|
||||||
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
|
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
|
||||||
static void target_to_host_sigset_internal(sigset_t *d,
|
static void target_to_host_sigset_internal(sigset_t *d,
|
||||||
@ -889,7 +892,7 @@ static void handle_pending_signal(CPUArchState *env, int sig,
|
|||||||
|
|
||||||
k->pending = 0;
|
k->pending = 0;
|
||||||
|
|
||||||
sig = gdb_handlesig(cpu, sig);
|
sig = gdb_handlesig(cpu, sig, NULL, &k->info, sizeof(k->info));
|
||||||
if (!sig) {
|
if (!sig) {
|
||||||
sa = NULL;
|
sa = NULL;
|
||||||
handler = TARGET_SIG_IGN;
|
handler = TARGET_SIG_IGN;
|
||||||
|
@ -1664,6 +1664,8 @@ static void handle_query_supported(GArray *params, void *user_ctx)
|
|||||||
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
|
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
|
||||||
}
|
}
|
||||||
g_string_append(gdbserver_state.str_buf, ";QCatchSyscalls+");
|
g_string_append(gdbserver_state.str_buf, ";QCatchSyscalls+");
|
||||||
|
|
||||||
|
g_string_append(gdbserver_state.str_buf, ";qXfer:siginfo:read+");
|
||||||
#endif
|
#endif
|
||||||
g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
|
g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
|
||||||
#endif
|
#endif
|
||||||
@ -1818,6 +1820,12 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
|||||||
.cmd_startswith = 1,
|
.cmd_startswith = 1,
|
||||||
.schema = "l,l0"
|
.schema = "l,l0"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.handler = gdb_handle_query_xfer_siginfo,
|
||||||
|
.cmd = "Xfer:siginfo:read::",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "l,l0"
|
||||||
|
},
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
.handler = gdb_handle_query_xfer_exec_file,
|
.handler = gdb_handle_query_xfer_exec_file,
|
||||||
|
@ -190,6 +190,7 @@ typedef union GdbCmdVariant {
|
|||||||
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
|
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
|
||||||
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
||||||
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
||||||
|
void gdb_handle_query_xfer_siginfo(GArray *params, void *user_ctx); /*user */
|
||||||
void gdb_handle_v_file_open(GArray *params, void *user_ctx); /* user */
|
void gdb_handle_v_file_open(GArray *params, void *user_ctx); /* user */
|
||||||
void gdb_handle_v_file_close(GArray *params, void *user_ctx); /* user */
|
void gdb_handle_v_file_close(GArray *params, void *user_ctx); /* user */
|
||||||
void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
|
void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
|
||||||
|
@ -95,6 +95,8 @@ typedef struct {
|
|||||||
enum GDBForkState fork_state;
|
enum GDBForkState fork_state;
|
||||||
int fork_sockets[2];
|
int fork_sockets[2];
|
||||||
pid_t fork_peer_pid, fork_peer_tid;
|
pid_t fork_peer_pid, fork_peer_tid;
|
||||||
|
uint8_t siginfo[MAX_SIGINFO_LENGTH];
|
||||||
|
unsigned long siginfo_len;
|
||||||
} GDBUserState;
|
} GDBUserState;
|
||||||
|
|
||||||
static GDBUserState gdbserver_user_state;
|
static GDBUserState gdbserver_user_state;
|
||||||
@ -190,7 +192,8 @@ void gdb_qemu_exit(int code)
|
|||||||
exit(code);
|
exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gdb_handlesig_reason(CPUState *cpu, int sig, const char *reason)
|
int gdb_handlesig(CPUState *cpu, int sig, const char *reason, void *siginfo,
|
||||||
|
int siginfo_len)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int n;
|
int n;
|
||||||
@ -199,6 +202,18 @@ int gdb_handlesig_reason(CPUState *cpu, int sig, const char *reason)
|
|||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (siginfo) {
|
||||||
|
/*
|
||||||
|
* Save target-specific siginfo.
|
||||||
|
*
|
||||||
|
* siginfo size, i.e. siginfo_len, is asserted at compile-time to fit in
|
||||||
|
* gdbserver_user_state.siginfo, usually in the source file calling
|
||||||
|
* gdb_handlesig. See, for instance, {linux,bsd}-user/signal.c.
|
||||||
|
*/
|
||||||
|
memcpy(gdbserver_user_state.siginfo, siginfo, siginfo_len);
|
||||||
|
gdbserver_user_state.siginfo_len = siginfo_len;
|
||||||
|
}
|
||||||
|
|
||||||
/* disable single step if it was enabled */
|
/* disable single step if it was enabled */
|
||||||
cpu_single_step(cpu, 0);
|
cpu_single_step(cpu, 0);
|
||||||
tb_flush(cpu);
|
tb_flush(cpu);
|
||||||
@ -502,6 +517,7 @@ void gdbserver_fork_end(CPUState *cpu, pid_t pid)
|
|||||||
switch (gdbserver_user_state.fork_state) {
|
switch (gdbserver_user_state.fork_state) {
|
||||||
case GDB_FORK_ENABLED:
|
case GDB_FORK_ENABLED:
|
||||||
if (gdbserver_user_state.running_state) {
|
if (gdbserver_user_state.running_state) {
|
||||||
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QEMU_FALLTHROUGH;
|
QEMU_FALLTHROUGH;
|
||||||
@ -527,7 +543,6 @@ void gdbserver_fork_end(CPUState *cpu, pid_t pid)
|
|||||||
gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
|
gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
|
||||||
break;
|
break;
|
||||||
case GDB_FORK_ENABLE:
|
case GDB_FORK_ENABLE:
|
||||||
close(fd);
|
|
||||||
gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
|
gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
|
||||||
break;
|
break;
|
||||||
case GDB_FORK_DISABLE:
|
case GDB_FORK_DISABLE:
|
||||||
@ -542,7 +557,6 @@ void gdbserver_fork_end(CPUState *cpu, pid_t pid)
|
|||||||
if (write(fd, &b, 1) != 1) {
|
if (write(fd, &b, 1) != 1) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
|
gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
|
||||||
break;
|
break;
|
||||||
case GDB_FORK_DISABLING:
|
case GDB_FORK_DISABLING:
|
||||||
@ -746,7 +760,7 @@ void gdb_breakpoint_remove_all(CPUState *cs)
|
|||||||
void gdb_syscall_handling(const char *syscall_packet)
|
void gdb_syscall_handling(const char *syscall_packet)
|
||||||
{
|
{
|
||||||
gdb_put_packet(syscall_packet);
|
gdb_put_packet(syscall_packet);
|
||||||
gdb_handlesig(gdbserver_state.c_cpu, 0);
|
gdb_handlesig(gdbserver_state.c_cpu, 0, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool should_catch_syscall(int num)
|
static bool should_catch_syscall(int num)
|
||||||
@ -764,7 +778,7 @@ void gdb_syscall_entry(CPUState *cs, int num)
|
|||||||
{
|
{
|
||||||
if (should_catch_syscall(num)) {
|
if (should_catch_syscall(num)) {
|
||||||
g_autofree char *reason = g_strdup_printf("syscall_entry:%x;", num);
|
g_autofree char *reason = g_strdup_printf("syscall_entry:%x;", num);
|
||||||
gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
|
gdb_handlesig(cs, gdb_target_sigtrap(), reason, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,7 +786,7 @@ void gdb_syscall_return(CPUState *cs, int num)
|
|||||||
{
|
{
|
||||||
if (should_catch_syscall(num)) {
|
if (should_catch_syscall(num)) {
|
||||||
g_autofree char *reason = g_strdup_printf("syscall_return:%x;", num);
|
g_autofree char *reason = g_strdup_printf("syscall_return:%x;", num);
|
||||||
gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
|
gdb_handlesig(cs, gdb_target_sigtrap(), reason, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,3 +851,26 @@ void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
|
|||||||
err:
|
err:
|
||||||
gdb_put_packet("E00");
|
gdb_put_packet("E00");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gdb_handle_query_xfer_siginfo(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
unsigned long offset, len;
|
||||||
|
uint8_t *siginfo_offset;
|
||||||
|
|
||||||
|
offset = get_param(params, 0)->val_ul;
|
||||||
|
len = get_param(params, 1)->val_ul;
|
||||||
|
|
||||||
|
if (offset + len > gdbserver_user_state.siginfo_len) {
|
||||||
|
/* Invalid offset and/or requested length. */
|
||||||
|
gdb_put_packet("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
siginfo_offset = (uint8_t *)gdbserver_user_state.siginfo + offset;
|
||||||
|
|
||||||
|
/* Reply */
|
||||||
|
g_string_assign(gdbserver_state.str_buf, "l");
|
||||||
|
gdb_memtox(gdbserver_state.str_buf, (const char *)siginfo_offset, len);
|
||||||
|
gdb_put_packet_binary(gdbserver_state.str_buf->str,
|
||||||
|
gdbserver_state.str_buf->len, true);
|
||||||
|
}
|
||||||
|
@ -9,11 +9,15 @@
|
|||||||
#ifndef GDBSTUB_USER_H
|
#ifndef GDBSTUB_USER_H
|
||||||
#define GDBSTUB_USER_H
|
#define GDBSTUB_USER_H
|
||||||
|
|
||||||
|
#define MAX_SIGINFO_LENGTH 128
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_handlesig_reason() - yield control to gdb
|
* gdb_handlesig() - yield control to gdb
|
||||||
* @cpu: CPU
|
* @cpu: CPU
|
||||||
* @sig: if non-zero, the signal number which caused us to stop
|
* @sig: if non-zero, the signal number which caused us to stop
|
||||||
* @reason: stop reason for stop reply packet or NULL
|
* @reason: stop reason for stop reply packet or NULL
|
||||||
|
* @siginfo: target-specific siginfo struct
|
||||||
|
* @siginfo_len: target-specific siginfo struct length
|
||||||
*
|
*
|
||||||
* This function yields control to gdb, when a user-mode-only target
|
* This function yields control to gdb, when a user-mode-only target
|
||||||
* needs to stop execution. If @sig is non-zero, then we will send a
|
* needs to stop execution. If @sig is non-zero, then we will send a
|
||||||
@ -25,18 +29,7 @@
|
|||||||
* or 0 if no signal should be delivered, ie the signal that caused
|
* or 0 if no signal should be delivered, ie the signal that caused
|
||||||
* us to stop should be ignored.
|
* us to stop should be ignored.
|
||||||
*/
|
*/
|
||||||
int gdb_handlesig_reason(CPUState *, int, const char *);
|
int gdb_handlesig(CPUState *, int, const char *, void *, int);
|
||||||
|
|
||||||
/**
|
|
||||||
* gdb_handlesig() - yield control to gdb
|
|
||||||
* @cpu CPU
|
|
||||||
* @sig: if non-zero, the signal number which caused us to stop
|
|
||||||
* @see gdb_handlesig_reason()
|
|
||||||
*/
|
|
||||||
static inline int gdb_handlesig(CPUState *cpu, int sig)
|
|
||||||
{
|
|
||||||
return gdb_handlesig_reason(cpu, sig, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_signalled() - inform remote gdb of sig exit
|
* gdb_signalled() - inform remote gdb of sig exit
|
||||||
|
@ -670,7 +670,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
|||||||
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
|
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
|
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
|
||||||
env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
|
env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
__put_user(0, &frame->uc.tuc_flags);
|
__put_user(0, &frame->uc.tuc_flags);
|
||||||
__put_user(0, &frame->uc.tuc_link);
|
__put_user(0, &frame->uc.tuc_link);
|
||||||
|
@ -357,7 +357,7 @@ void setup_rt_frame(int usig, struct target_sigaction *ka,
|
|||||||
|
|
||||||
info_addr = frame_addr + offsetof(struct rt_sigframe, info);
|
info_addr = frame_addr + offsetof(struct rt_sigframe, info);
|
||||||
uc_addr = frame_addr + offsetof(struct rt_sigframe, sig.uc);
|
uc_addr = frame_addr + offsetof(struct rt_sigframe, sig.uc);
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
setup_sigframe(&frame->sig.uc, set, env);
|
setup_sigframe(&frame->sig.uc, set, env);
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
}
|
}
|
||||||
|
|
||||||
setup_ucontext(&frame->uc, env, set);
|
setup_ucontext(&frame->uc, env, set);
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
/*
|
/*
|
||||||
* The on-stack signal trampoline is no longer executed;
|
* The on-stack signal trampoline is no longer executed;
|
||||||
* however, the libgcc signal frame unwinding code checks
|
* however, the libgcc signal frame unwinding code checks
|
||||||
|
@ -127,7 +127,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
frame->uc.tuc_flags = 0;
|
frame->uc.tuc_flags = 0;
|
||||||
frame->uc.tuc_link = 0;
|
frame->uc.tuc_link = 0;
|
||||||
|
|
||||||
|
@ -430,7 +430,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||||||
setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
|
setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
|
||||||
frame_addr + offsetof(struct sigframe, fpstate));
|
frame_addr + offsetof(struct sigframe, fpstate));
|
||||||
|
|
||||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
for (i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||||
__put_user(set->sig[i], &frame->extramask[i - 1]);
|
__put_user(set->sig[i], &frame->extramask[i - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +490,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
__put_user(addr, &frame->puc);
|
__put_user(addr, &frame->puc);
|
||||||
#endif
|
#endif
|
||||||
if (ka->sa_flags & TARGET_SA_SIGINFO) {
|
if (ka->sa_flags & TARGET_SA_SIGINFO) {
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
@ -504,7 +504,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
|
setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
|
||||||
set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
|
set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
|
||||||
|
|
||||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||||
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr);
|
extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->rs_info, info);
|
frame->rs_info = *info;
|
||||||
|
|
||||||
__put_user(0, &frame->rs_uc.tuc_flags);
|
__put_user(0, &frame->rs_uc.tuc_flags);
|
||||||
__put_user(0, &frame->rs_uc.tuc_link);
|
__put_user(0, &frame->rs_uc.tuc_link);
|
||||||
|
@ -295,7 +295,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
|
uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
|
||||||
__put_user(uc_addr, &frame->puc);
|
__put_user(uc_addr, &frame->puc);
|
||||||
|
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
/* Create the ucontext */
|
/* Create the ucontext */
|
||||||
|
|
||||||
@ -307,7 +307,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
if (err)
|
if (err)
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
|
||||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||||
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,7 +1018,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
gdbstub);
|
gdbstub);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
gdb_handlesig(cpu, 0);
|
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SEMIHOSTING
|
#ifdef CONFIG_SEMIHOSTING
|
||||||
|
@ -147,7 +147,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
__put_user(0, &frame->uc.tuc_flags);
|
__put_user(0, &frame->uc.tuc_flags);
|
||||||
__put_user(0, &frame->uc.tuc_link);
|
__put_user(0, &frame->uc.tuc_link);
|
||||||
|
@ -303,7 +303,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->rs_info, info);
|
frame->rs_info = *info;
|
||||||
|
|
||||||
__put_user(0, &frame->rs_uc.tuc_flags);
|
__put_user(0, &frame->rs_uc.tuc_flags);
|
||||||
__put_user(0, &frame->rs_uc.tuc_link);
|
__put_user(0, &frame->rs_uc.tuc_link);
|
||||||
@ -311,7 +311,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
|
|
||||||
setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
|
setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
|
||||||
|
|
||||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||||
__put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
|
__put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
__put_user(0, &frame->uc.tuc_flags);
|
__put_user(0, &frame->uc.tuc_flags);
|
||||||
|
@ -103,7 +103,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ka->sa_flags & SA_SIGINFO) {
|
if (ka->sa_flags & SA_SIGINFO) {
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
}
|
}
|
||||||
|
|
||||||
__put_user(0, &frame->uc.tuc_flags);
|
__put_user(0, &frame->uc.tuc_flags);
|
||||||
|
@ -493,7 +493,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
|
if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
|
||||||
tswap_siginfo(&rt_sf->info, info);
|
rt_sf->info = *info;
|
||||||
|
|
||||||
__put_user(0, &rt_sf->uc.tuc_flags);
|
__put_user(0, &rt_sf->uc.tuc_flags);
|
||||||
__put_user(0, &rt_sf->uc.tuc_link);
|
__put_user(0, &rt_sf->uc.tuc_link);
|
||||||
@ -502,7 +502,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
__put_user(h2g (&rt_sf->uc.tuc_mcontext),
|
__put_user(h2g (&rt_sf->uc.tuc_mcontext),
|
||||||
&rt_sf->uc.tuc_regs);
|
&rt_sf->uc.tuc_regs);
|
||||||
#endif
|
#endif
|
||||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||||
__put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
|
__put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
}
|
}
|
||||||
|
|
||||||
setup_ucontext(&frame->uc, env, set);
|
setup_ucontext(&frame->uc, env, set);
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
env->pc = ka->_sa_handler;
|
env->pc = ka->_sa_handler;
|
||||||
env->gpr[xSP] = frame_addr;
|
env->gpr[xSP] = frame_addr;
|
||||||
|
@ -267,7 +267,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create siginfo on the signal stack. */
|
/* Create siginfo on the signal stack. */
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
/* Create ucontext on the signal stack. */
|
/* Create ucontext on the signal stack. */
|
||||||
uc_flags = 0;
|
uc_flags = 0;
|
||||||
|
@ -233,7 +233,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
}
|
}
|
||||||
|
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
__put_user(0, &frame->uc.tuc_flags);
|
__put_user(0, &frame->uc.tuc_flags);
|
||||||
|
@ -43,8 +43,6 @@ void host_to_target_sigset_internal(target_sigset_t *d,
|
|||||||
const sigset_t *s);
|
const sigset_t *s);
|
||||||
void target_to_host_sigset_internal(sigset_t *d,
|
void target_to_host_sigset_internal(sigset_t *d,
|
||||||
const target_sigset_t *s);
|
const target_sigset_t *s);
|
||||||
void tswap_siginfo(target_siginfo_t *tinfo,
|
|
||||||
const target_siginfo_t *info);
|
|
||||||
void set_sigmask(const sigset_t *set);
|
void set_sigmask(const sigset_t *set);
|
||||||
void force_sig(int sig);
|
void force_sig(int sig);
|
||||||
void force_sigsegv(int oldsig);
|
void force_sigsegv(int oldsig);
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
#include "user/safe-syscall.h"
|
#include "user/safe-syscall.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
|
|
||||||
|
/* target_siginfo_t must fit in gdbstub's siginfo save area. */
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(target_siginfo_t) > MAX_SIGINFO_LENGTH);
|
||||||
|
|
||||||
static struct target_sigaction sigact_table[TARGET_NSIG];
|
static struct target_sigaction sigact_table[TARGET_NSIG];
|
||||||
|
|
||||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||||
@ -409,8 +412,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
|
|||||||
tinfo->si_code = deposit32(si_code, 16, 16, si_type);
|
tinfo->si_code = deposit32(si_code, 16, 16, si_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tswap_siginfo(target_siginfo_t *tinfo,
|
static void tswap_siginfo(target_siginfo_t *tinfo,
|
||||||
const target_siginfo_t *info)
|
const target_siginfo_t *info)
|
||||||
{
|
{
|
||||||
int si_type = extract32(info->si_code, 16, 16);
|
int si_type = extract32(info->si_code, 16, 16);
|
||||||
int si_code = sextract32(info->si_code, 0, 16);
|
int si_code = sextract32(info->si_code, 0, 16);
|
||||||
@ -1178,7 +1181,13 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
|
|||||||
/* dequeue signal */
|
/* dequeue signal */
|
||||||
k->pending = 0;
|
k->pending = 0;
|
||||||
|
|
||||||
sig = gdb_handlesig(cpu, sig);
|
/*
|
||||||
|
* Writes out siginfo values byteswapped, accordingly to the target. It also
|
||||||
|
* cleans the si_type from si_code making it correct for the target.
|
||||||
|
*/
|
||||||
|
tswap_siginfo(&k->info, &k->info);
|
||||||
|
|
||||||
|
sig = gdb_handlesig(cpu, sig, NULL, &k->info, sizeof(k->info));
|
||||||
if (!sig) {
|
if (!sig) {
|
||||||
sa = NULL;
|
sa = NULL;
|
||||||
handler = TARGET_SIG_IGN;
|
handler = TARGET_SIG_IGN;
|
||||||
|
@ -333,7 +333,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
|
|
||||||
__put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */
|
__put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */
|
||||||
|
|
||||||
tswap_siginfo(&sf->info, info);
|
sf->info = *info;
|
||||||
tswap_sigset(&sf->mask, set);
|
tswap_sigset(&sf->mask, set);
|
||||||
target_save_altstack(&sf->stack, env);
|
target_save_altstack(&sf->stack, env);
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ka->sa_flags & SA_SIGINFO) {
|
if (ka->sa_flags & SA_SIGINFO) {
|
||||||
tswap_siginfo(&frame->info, info);
|
frame->info = *info;
|
||||||
}
|
}
|
||||||
|
|
||||||
__put_user(0, &frame->uc.tuc_flags);
|
__put_user(0, &frame->uc.tuc_flags);
|
||||||
|
@ -71,6 +71,13 @@ run-gdbstub-qxfer-auxv-read: sha1
|
|||||||
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
|
||||||
basic gdbstub qXfer:auxv:read support)
|
basic gdbstub qXfer:auxv:read support)
|
||||||
|
|
||||||
|
run-gdbstub-qxfer-siginfo-read: segfault
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(GDB) \
|
||||||
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
|
--bin "$< -s" --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-siginfo-read.py, \
|
||||||
|
basic gdbstub qXfer:siginfo:read support)
|
||||||
|
|
||||||
run-gdbstub-proc-mappings: sha1
|
run-gdbstub-proc-mappings: sha1
|
||||||
$(call run-test, $@, $(GDB_SCRIPT) \
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
--gdb $(GDB) \
|
--gdb $(GDB) \
|
||||||
@ -128,7 +135,8 @@ EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
|
|||||||
run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
|
run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
|
||||||
run-gdbstub-registers run-gdbstub-prot-none \
|
run-gdbstub-registers run-gdbstub-prot-none \
|
||||||
run-gdbstub-catch-syscalls run-gdbstub-follow-fork-mode-child \
|
run-gdbstub-catch-syscalls run-gdbstub-follow-fork-mode-child \
|
||||||
run-gdbstub-follow-fork-mode-parent
|
run-gdbstub-follow-fork-mode-parent \
|
||||||
|
run-gdbstub-qxfer-siginfo-read
|
||||||
|
|
||||||
# ARM Compatible Semi Hosting Tests
|
# ARM Compatible Semi Hosting Tests
|
||||||
#
|
#
|
||||||
|
26
tests/tcg/multiarch/gdbstub/test-qxfer-siginfo-read.py
Normal file
26
tests/tcg/multiarch/gdbstub/test-qxfer-siginfo-read.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
#
|
||||||
|
# Test gdbstub Xfer:siginfo:read stub.
|
||||||
|
#
|
||||||
|
# The test runs a binary that causes a SIGSEGV and then looks for additional
|
||||||
|
# info about the signal through printing GDB's '$_siginfo' special variable,
|
||||||
|
# which sends a Xfer:siginfo:read query to the gdbstub.
|
||||||
|
#
|
||||||
|
# The binary causes a SIGSEGV at dereferencing a pointer with value 0xdeadbeef,
|
||||||
|
# so the test looks for and checks if this address is correctly reported by the
|
||||||
|
# gdbstub.
|
||||||
|
#
|
||||||
|
# This is launched via tests/guest-debug/run-test.py
|
||||||
|
#
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
from test_gdbstub import main, report
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"Run through the test"
|
||||||
|
|
||||||
|
gdb.execute("continue", False, True)
|
||||||
|
resp = gdb.execute("print/x $_siginfo", False, True)
|
||||||
|
report(resp.find("si_addr = 0xdeadbeef"), "Found fault address.")
|
||||||
|
|
||||||
|
main(run_test)
|
14
tests/tcg/multiarch/segfault.c
Normal file
14
tests/tcg/multiarch/segfault.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Cause a segfault for testing purposes. */
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int *ptr = (void *)0xdeadbeef;
|
||||||
|
|
||||||
|
if (argc == 2 && strcmp(argv[1], "-s") == 0) {
|
||||||
|
/* Cause segfault. */
|
||||||
|
printf("%d\n", *ptr);
|
||||||
|
}
|
||||||
|
}
|
@ -606,7 +606,7 @@ def parse_args(vmcls):
|
|||||||
parser.add_argument("--build-qemu",
|
parser.add_argument("--build-qemu",
|
||||||
help="build QEMU from source in guest")
|
help="build QEMU from source in guest")
|
||||||
parser.add_argument("--build-target",
|
parser.add_argument("--build-target",
|
||||||
help="QEMU build target", default="check")
|
help="QEMU build target", default="all check")
|
||||||
parser.add_argument("--build-path", default=None,
|
parser.add_argument("--build-path", default=None,
|
||||||
help="Path of build directory, "\
|
help="Path of build directory, "\
|
||||||
"for using build tree QEMU binary. ")
|
"for using build tree QEMU binary. ")
|
||||||
|
Loading…
Reference in New Issue
Block a user