testing, doc and gdbstub updates:

- add sqlite3 to openSUSE image
   - mark CRIS as deprecated
   - re-enable the TCG plugin tests
   - use select for semihosting
   - implement syscall catching in gdbstub
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmXGZtQACgkQ+9DbCVqe
 KkTegAgAg7Kkd0Pa2cgkPfNPYR5yT4hYurjVSfi/69cOpj/Vadsav4WWFsuUiQMI
 FfKWCNDo5lmNcWIPKgC0oeWVwxal4IhqhO8f9lRIYqg9z4bRkZbdsrvh8J52Q6Xh
 Bu9UAEk5KBGrMfEdsAwHnVDg435c7IGdJZnE/iKBK1aKljS5LOiX1J6ZxrqUoMsJ
 keTAcdXyvs/BIz68c87AHrW/HKO9KKLgHA2n7T/l2N5KJdoa3p8La9py+v1SGUh8
 6JlDRYR1H16mITS8tm6ZffPqcOpfHXp7DRquu7obVS5+CVTJ2H9w8TICw56rqMg7
 cVnysNLhdS18cMNKD2Jx3zgd5Nq/cg==
 =deHm
 -----END PGP SIGNATURE-----

Merge tag 'pull-maintainer-updates-090224-1' of https://gitlab.com/stsquad/qemu into staging

testing, doc and gdbstub updates:

  - add sqlite3 to openSUSE image
  - mark CRIS as deprecated
  - re-enable the TCG plugin tests
  - use select for semihosting
  - implement syscall catching in gdbstub

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmXGZtQACgkQ+9DbCVqe
# KkTegAgAg7Kkd0Pa2cgkPfNPYR5yT4hYurjVSfi/69cOpj/Vadsav4WWFsuUiQMI
# FfKWCNDo5lmNcWIPKgC0oeWVwxal4IhqhO8f9lRIYqg9z4bRkZbdsrvh8J52Q6Xh
# Bu9UAEk5KBGrMfEdsAwHnVDg435c7IGdJZnE/iKBK1aKljS5LOiX1J6ZxrqUoMsJ
# keTAcdXyvs/BIz68c87AHrW/HKO9KKLgHA2n7T/l2N5KJdoa3p8La9py+v1SGUh8
# 6JlDRYR1H16mITS8tm6ZffPqcOpfHXp7DRquu7obVS5+CVTJ2H9w8TICw56rqMg7
# cVnysNLhdS18cMNKD2Jx3zgd5Nq/cg==
# =deHm
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 09 Feb 2024 17:54:28 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-updates-090224-1' of https://gitlab.com/stsquad/qemu:
  tests/tcg: Add the syscall catchpoint gdbstub test
  gdbstub: Implement catching syscalls
  gdbstub: Add syscall entry/return hooks
  gdbstub: Allow specifying a reason in stop packets
  gdbstub: Expose TARGET_SIGTRAP in a target-agnostic way
  kconfig: use "select" to enable semihosting
  Revert "hw/elf_ops: Ignore loadable segments with zero size"
  configure: run plugin TCG tests again
  docs: mark CRIS support as deprecated
  tests/docker: Add sqlite3 module to openSUSE Leap container

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-02-12 14:14:10 +00:00
commit 5005aed8a7
26 changed files with 320 additions and 56 deletions

View File

@ -1,7 +1,5 @@
# Default configuration for m68k-softmmu
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_AN5206=y

View File

@ -1,8 +1,5 @@
# Common mips*-softmmu CONFIG defines
# CONFIG_SEMIHOSTING is always required on this architecture
CONFIG_SEMIHOSTING=y
CONFIG_ISA_BUS=y
CONFIG_PCI=y
CONFIG_PCI_DEVICES=y

View File

@ -1,7 +1,5 @@
# Default configuration for nios2-softmmu
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_NIOS2_10M50=y

View File

@ -3,8 +3,6 @@
# Uncomment the following lines to disable these optional devices:
#
#CONFIG_PCI_DEVICES=n
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
# Boards:
#

View File

@ -3,8 +3,6 @@
# Uncomment the following lines to disable these optional devices:
#
#CONFIG_PCI_DEVICES=n
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
# Boards:
#

View File

@ -1,7 +1,5 @@
# Default configuration for Xtensa
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_XTENSA_SIM=y

3
configure vendored
View File

@ -1644,6 +1644,9 @@ fi
mkdir -p tests/tcg
echo "# Automatically generated by configure - do not modify" > tests/tcg/$config_host_mak
echo "SRC_PATH=$source_path" >> tests/tcg/$config_host_mak
if test "$plugins" = "yes" ; then
echo "CONFIG_PLUGIN=y" >> tests/tcg/$config_host_mak
fi
tcg_tests_targets=
for target in $target_list; do

View File

@ -192,6 +192,13 @@ in the QEMU object model anymore. ``power5+``, ``power5+_v2.1``,
an alias, but for consistency these will get removed in a future
release, too. Use ``power5p_v2.1`` and ``power7p_v2.1`` instead.
CRIS CPU architecture (since 9.0)
'''''''''''''''''''''''''''''''''
The CRIS architecture was pulled from Linux in 4.17 and the compiler
is no longer packaged in any distro making it harder to run the
``check-tcg`` tests. Unless we can improve the testing situation there
is a chance the code will bitrot without anyone noticing.
System emulator machines
------------------------

View File

@ -1617,6 +1617,7 @@ static void handle_query_supported(GArray *params, void *user_ctx)
if (gdbserver_state.c_cpu->opaque) {
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
}
g_string_append(gdbserver_state.str_buf, ";QCatchSyscalls+");
#endif
g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
#endif
@ -1810,6 +1811,14 @@ static const GdbCmdParseEntry gdb_gen_set_table[] = {
.schema = "l0"
},
#endif
#if defined(CONFIG_USER_ONLY)
{
.handler = gdb_handle_set_catch_syscalls,
.cmd = "CatchSyscalls:",
.cmd_startswith = 1,
.schema = "s0",
},
#endif
};
static void handle_gen_query(GArray *params, void *user_ctx)

View File

@ -136,6 +136,7 @@ void gdb_append_thread_id(CPUState *cpu, GString *buf);
int gdb_get_cpu_index(CPUState *cpu);
unsigned int gdb_get_max_cpus(void); /* both */
bool gdb_can_reverse(void); /* softmmu, stub for user */
int gdb_target_sigtrap(void); /* user */
void gdb_create_default_process(GDBState *s);
@ -194,6 +195,7 @@ 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_readlink(GArray *params, void *user_ctx); /* user */
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx); /* user */
void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */

View File

@ -418,3 +418,8 @@ void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
ts->bprm->filename + offset);
gdb_put_strbuf();
}
int gdb_target_sigtrap(void)
{
return TARGET_SIGTRAP;
}

View File

@ -10,6 +10,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "qemu/cutils.h"
#include "qemu/sockets.h"
#include "exec/hwaddr.h"
@ -21,11 +22,20 @@
#include "trace.h"
#include "internals.h"
#define GDB_NR_SYSCALLS 1024
typedef unsigned long GDBSyscallsMask[BITS_TO_LONGS(GDB_NR_SYSCALLS)];
/* User-mode specific state */
typedef struct {
int fd;
char *socket_path;
int running_state;
/*
* Store syscalls mask without memory allocation in order to avoid
* implementing synchronization.
*/
bool catch_all_syscalls;
GDBSyscallsMask catch_syscalls_mask;
} GDBUserState;
static GDBUserState gdbserver_user_state;
@ -121,7 +131,7 @@ void gdb_qemu_exit(int code)
exit(code);
}
int gdb_handlesig(CPUState *cpu, int sig)
int gdb_handlesig_reason(CPUState *cpu, int sig, const char *reason)
{
char buf[256];
int n;
@ -141,6 +151,9 @@ int gdb_handlesig(CPUState *cpu, int sig)
"T%02xthread:", gdb_target_signal_to_gdb(sig));
gdb_append_thread_id(cpu, gdbserver_state.str_buf);
g_string_append_c(gdbserver_state.str_buf, ';');
if (reason) {
g_string_append(gdbserver_state.str_buf, reason);
}
gdb_put_strbuf();
gdbserver_state.allow_stop_reply = false;
}
@ -499,3 +512,92 @@ void gdb_syscall_handling(const char *syscall_packet)
gdb_put_packet(syscall_packet);
gdb_handlesig(gdbserver_state.c_cpu, 0);
}
static bool should_catch_syscall(int num)
{
if (gdbserver_user_state.catch_all_syscalls) {
return true;
}
if (num < 0 || num >= GDB_NR_SYSCALLS) {
return false;
}
return test_bit(num, gdbserver_user_state.catch_syscalls_mask);
}
void gdb_syscall_entry(CPUState *cs, int num)
{
if (should_catch_syscall(num)) {
g_autofree char *reason = g_strdup_printf("syscall_entry:%x;", num);
gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
}
}
void gdb_syscall_return(CPUState *cs, int num)
{
if (should_catch_syscall(num)) {
g_autofree char *reason = g_strdup_printf("syscall_return:%x;", num);
gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
}
}
void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
{
const char *param = get_param(params, 0)->data;
GDBSyscallsMask catch_syscalls_mask;
bool catch_all_syscalls;
unsigned int num;
const char *p;
/* "0" means not catching any syscalls. */
if (strcmp(param, "0") == 0) {
gdbserver_user_state.catch_all_syscalls = false;
memset(gdbserver_user_state.catch_syscalls_mask, 0,
sizeof(gdbserver_user_state.catch_syscalls_mask));
gdb_put_packet("OK");
return;
}
/* "1" means catching all syscalls. */
if (strcmp(param, "1") == 0) {
gdbserver_user_state.catch_all_syscalls = true;
gdb_put_packet("OK");
return;
}
/*
* "1;..." means catching only the specified syscalls.
* The syscall list must not be empty.
*/
if (param[0] == '1' && param[1] == ';') {
catch_all_syscalls = false;
memset(catch_syscalls_mask, 0, sizeof(catch_syscalls_mask));
for (p = &param[2];; p++) {
if (qemu_strtoui(p, &p, 16, &num) || (*p && *p != ';')) {
goto err;
}
if (num >= GDB_NR_SYSCALLS) {
/*
* Fall back to reporting all syscalls. Reporting extra
* syscalls is inefficient, but the spec explicitly allows it.
* Keep parsing in case there is a syntax error ahead.
*/
catch_all_syscalls = true;
} else {
set_bit(num, catch_syscalls_mask);
}
if (!*p) {
break;
}
}
gdbserver_user_state.catch_all_syscalls = catch_all_syscalls;
if (!catch_all_syscalls) {
memcpy(gdbserver_user_state.catch_syscalls_mask,
catch_syscalls_mask, sizeof(catch_syscalls_mask));
}
gdb_put_packet("OK");
return;
}
err:
gdb_put_packet("E00");
}

View File

@ -10,9 +10,10 @@
#define GDBSTUB_USER_H
/**
* gdb_handlesig() - yield control to gdb
* gdb_handlesig_reason() - yield control to gdb
* @cpu: CPU
* @sig: if non-zero, the signal number which caused us to stop
* @reason: stop reason for stop reply packet or NULL
*
* 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
@ -24,7 +25,18 @@
* or 0 if no signal should be delivered, ie the signal that caused
* us to stop should be ignored.
*/
int gdb_handlesig(CPUState *, int);
int gdb_handlesig_reason(CPUState *, int, const char *);
/**
* 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
@ -39,5 +51,18 @@ void gdb_signalled(CPUArchState *as, int sig);
*/
void gdbserver_fork(CPUState *cs);
/**
* gdb_syscall_entry() - inform gdb of syscall entry and yield control to it
* @cs: CPU
* @num: syscall number
*/
void gdb_syscall_entry(CPUState *cs, int num);
/**
* gdb_syscall_entry() - inform gdb of syscall return and yield control to it
* @cs: CPU
* @num: syscall number
*/
void gdb_syscall_return(CPUState *cs, int num);
#endif /* GDBSTUB_USER_H */

View File

@ -427,16 +427,6 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
file_size = ph->p_filesz; /* Size of the allocated data */
data_offset = ph->p_offset; /* Offset where the data is located */
/*
* Some ELF files really do have segments of zero size;
* just ignore them rather than trying to set the wrong addr,
* or create empty ROM blobs, because the zero-length blob can
* falsely trigger the overlapping-ROM-blobs check.
*/
if (mem_size == 0) {
continue;
}
if (file_size > 0) {
if (g_mapped_file_get_length(mapped_file) <
file_size + data_offset) {
@ -540,38 +530,45 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
*pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
}
if (load_rom) {
g_autofree char *label =
g_strdup_printf("%s ELF program header segment %d",
name, i);
/* Some ELF files really do have segments of zero size;
* just ignore them rather than trying to create empty
* ROM blobs, because the zero-length blob can falsely
* trigger the overlapping-ROM-blobs check.
*/
if (mem_size != 0) {
if (load_rom) {
g_autofree char *label =
g_strdup_printf("%s ELF program header segment %d",
name, i);
/*
* rom_add_elf_program() takes its own reference to
* 'mapped_file'.
*/
rom_add_elf_program(label, mapped_file, data, file_size,
mem_size, addr, as);
} else {
MemTxResult res;
/*
* rom_add_elf_program() takes its own reference to
* 'mapped_file'.
*/
rom_add_elf_program(label, mapped_file, data, file_size,
mem_size, addr, as);
} else {
MemTxResult res;
res = address_space_write(as ? as : &address_space_memory,
addr, MEMTXATTRS_UNSPECIFIED,
data, file_size);
if (res != MEMTX_OK) {
goto fail;
}
/*
* We need to zero'ify the space that is not copied
* from file
*/
if (file_size < mem_size) {
res = address_space_set(as ? as : &address_space_memory,
addr + file_size, 0,
mem_size - file_size,
MEMTXATTRS_UNSPECIFIED);
res = address_space_write(as ? as : &address_space_memory,
addr, MEMTXATTRS_UNSPECIFIED,
data, file_size);
if (res != MEMTX_OK) {
goto fail;
}
/*
* We need to zero'ify the space that is not copied
* from file
*/
if (file_size < mem_size) {
res = address_space_set(as ? as : &address_space_memory,
addr + file_size, 0,
mem_size - file_size,
MEMTXATTRS_UNSPECIFIED);
if (res != MEMTX_OK) {
goto fail;
}
}
}
}

View File

@ -11,6 +11,7 @@
#define SYSCALL_TRACE_H
#include "exec/user/abitypes.h"
#include "gdbstub/user.h"
#include "qemu/plugin.h"
#include "trace/trace-root.h"
@ -20,7 +21,7 @@
* could potentially unify the -strace code here as well.
*/
static inline void record_syscall_start(void *cpu, int num,
static inline void record_syscall_start(CPUState *cpu, int num,
abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6,
@ -29,11 +30,13 @@ static inline void record_syscall_start(void *cpu, int num,
qemu_plugin_vcpu_syscall(cpu, num,
arg1, arg2, arg3, arg4,
arg5, arg6, arg7, arg8);
gdb_syscall_entry(cpu, num);
}
static inline void record_syscall_return(void *cpu, int num, abi_long ret)
static inline void record_syscall_return(CPUState *cpu, int num, abi_long ret)
{
qemu_plugin_vcpu_syscall_ret(cpu, num, ret);
gdb_syscall_return(cpu, num);
}

View File

@ -1,2 +1,3 @@
config M68K
bool
select SEMIHOSTING

View File

@ -1,5 +1,6 @@
config MIPS
bool
select SEMIHOSTING
config MIPS64
bool

View File

@ -1,2 +1,3 @@
config NIOS2
bool
select SEMIHOSTING

View File

@ -1,5 +1,7 @@
config RISCV32
bool
select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
config RISCV64
bool
select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()

View File

@ -1,2 +1,3 @@
config XTENSA
bool
select SEMIHOSTING

View File

@ -90,6 +90,7 @@ RUN zypper update -y && \
pcre-devel-static \
pipewire-devel \
pkgconfig \
python311 \
python311-base \
python311-pip \
python311-setuptools \

View File

@ -59,6 +59,10 @@ mappings:
CentOSStream8:
OpenSUSELeap15:
python3-sqlite3:
CentOSStream8: python38
OpenSUSELeap15: python311
python3-tomli:
# test using tomllib
apk:

View File

@ -97,6 +97,7 @@ packages:
- python3-pip
- python3-sphinx
- python3-sphinx-rtd-theme
- python3-sqlite3
- python3-tomli
- python3-venv
- rpm2cpio

View File

@ -108,13 +108,21 @@ run-gdbstub-prot-none: prot-none
--bin $< --test $(MULTIARCH_SRC)/gdbstub/prot-none.py, \
accessing PROT_NONE memory)
run-gdbstub-catch-syscalls: catch-syscalls
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(GDB) \
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
--bin $< --test $(MULTIARCH_SRC)/gdbstub/catch-syscalls.py, \
hitting a syscall catchpoint)
else
run-gdbstub-%:
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
endif
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
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
# ARM Compatible Semi Hosting Tests
#

View File

@ -0,0 +1,51 @@
/*
* Test GDB syscall catchpoints.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
const char *catch_syscalls_state = "start";
void end_of_main(void)
{
}
int main(void)
{
int ret = EXIT_FAILURE;
char c0 = 'A', c1;
int fd[2];
catch_syscalls_state = "pipe2";
if (pipe2(fd, 0)) {
goto out;
}
catch_syscalls_state = "write";
if (write(fd[1], &c0, sizeof(c0)) != sizeof(c0)) {
goto out_close;
}
catch_syscalls_state = "read";
if (read(fd[0], &c1, sizeof(c1)) != sizeof(c1)) {
goto out_close;
}
catch_syscalls_state = "check";
if (c0 == c1) {
ret = EXIT_SUCCESS;
}
out_close:
catch_syscalls_state = "close";
close(fd[0]);
close(fd[1]);
out:
catch_syscalls_state = "end";
end_of_main();
return ret;
}

View File

@ -0,0 +1,53 @@
"""Test GDB syscall catchpoints.
SPDX-License-Identifier: GPL-2.0-or-later
"""
from test_gdbstub import main, report
def check_state(expected):
"""Check the catch_syscalls_state value"""
actual = gdb.parse_and_eval("catch_syscalls_state").string()
report(actual == expected, "{} == {}".format(actual, expected))
def run_test():
"""Run through the tests one by one"""
gdb.Breakpoint("main")
gdb.execute("continue")
# Check that GDB stops for pipe2/read calls/returns, but not for write.
gdb.execute("delete")
try:
gdb.execute("catch syscall pipe2 read")
except gdb.error as exc:
exc_str = str(exc)
if "not supported on this architecture" in exc_str:
print("SKIP: {}".format(exc_str))
return
raise
for _ in range(2):
gdb.execute("continue")
check_state("pipe2")
for _ in range(2):
gdb.execute("continue")
check_state("read")
# Check that deletion works.
gdb.execute("delete")
gdb.Breakpoint("end_of_main")
gdb.execute("continue")
check_state("end")
# Check that catch-all works (libc should at least call exit).
gdb.execute("delete")
gdb.execute("catch syscall")
gdb.execute("continue")
gdb.execute("delete")
gdb.execute("continue")
exitcode = int(gdb.parse_and_eval("$_exitcode"))
report(exitcode == 0, "{} == 0".format(exitcode))
main(run_test)