[PATCH v2 00/14] maintainer updates for 9.0 pre-PR (docker, plugin tests, deprecation, elf, semihosting, gdbstub)

A fairly random collection of fixes in this tree. I've still got a report of openbsd rebuilding which is confusing me (something triggers it but calling again works as expected). v2 - added Ilya's vm-build and gdbstub patches Everything is reviewed now so baring objections I intend to post the PR on Friday afternoon. Alex. Alex Bennée (2): docs: mark CRIS support as deprecated Revert "hw/elf_ops: Ignore loadable segments with zero size" Fabiano Rosas (1): tests/docker: Add sqlite3 module to openSUSE Leap container Ilya Leoshkevich (9): tests/vm: Set UseDNS=no in the sshd configuration tests/vm/freebsd: Reload the sshd configuration test-util-filemonitor: Adapt to the FreeBSD inotify rename semantics meson: Link with libinotify on FreeBSD gdbstub: Expose TARGET_SIGTRAP in a target-agnostic way gdbstub: Allow specifying a reason in stop packets gdbstub: Add syscall entry/return hooks gdbstub: Implement catching syscalls tests/tcg: Add the syscall catchpoint gdbstub test Paolo Bonzini (2): configure: run plugin TCG tests again kconfig: use "select" to enable semihosting docs/about/deprecated.rst | 8 ++ configure | 3 + configs/devices/m68k-softmmu/default.mak | 2 - configs/devices/mips-softmmu/common.mak | 3 - configs/devices/nios2-softmmu/default.mak | 2 - configs/devices/riscv32-softmmu/default.mak | 2 - configs/devices/riscv64-softmmu/default.mak | 2 - configs/devices/xtensa-softmmu/default.mak | 2 - meson.build | 23 +++- gdbstub/internals.h | 2 + include/gdbstub/user.h | 29 ++++- include/hw/elf_ops.h | 75 ++++++------- include/user/syscall-trace.h | 7 +- gdbstub/gdbstub.c | 9 ++ gdbstub/user-target.c | 5 + gdbstub/user.c | 104 +++++++++++++++++- tests/tcg/multiarch/catch-syscalls.c | 51 +++++++++ tests/unit/test-util-filemonitor.c | 8 ++ target/m68k/Kconfig | 1 + target/mips/Kconfig | 1 + target/nios2/Kconfig | 1 + target/riscv/Kconfig | 2 + target/xtensa/Kconfig | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/lcitool/mappings.yml | 4 + tests/lcitool/projects/qemu.yml | 1 + tests/tcg/multiarch/Makefile.target | 10 +- tests/tcg/multiarch/gdbstub/catch-syscalls.py | 53 +++++++++ tests/vm/basevm.py | 2 + tests/vm/freebsd | 1 + util/meson.build | 6 +- 31 files changed, 358 insertions(+), 63 deletions(-) create mode 100644 tests/tcg/multiarch/catch-syscalls.c create mode 100644 tests/tcg/multiarch/gdbstub/catch-syscalls.py -- 2.39.2

From: Fabiano Rosas <farosas@suse.de> Avocado needs sqlite3: Failed to load plugin from module "avocado.plugins.journal": ImportError("Module 'sqlite3' is not installed. Use: sudo zypper install python311 to install it")
From 'zypper info python311': "This package supplies rich command line features provided by readline, and sqlite3 support for the interpreter core, thus forming a so called "extended" runtime."
Include the appropriate package in the lcitool mappings which will guarantee the dockerfile gets properly updated when lcitool is run. Also include the updated dockerfile. Signed-off-by: Fabiano Rosas <farosas@suse.de> Suggested-by: Andrea Bolognani <abologna@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20240117164227.32143-1-farosas@suse.de> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/lcitool/mappings.yml | 4 ++++ tests/lcitool/projects/qemu.yml | 1 + 3 files changed, 6 insertions(+) diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index dc0e36ce488..cf753383a45 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -90,6 +90,7 @@ RUN zypper update -y && \ pcre-devel-static \ pipewire-devel \ pkgconfig \ + python311 \ python311-base \ python311-pip \ python311-setuptools \ diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml index 0b908882f1d..407c03301bf 100644 --- a/tests/lcitool/mappings.yml +++ b/tests/lcitool/mappings.yml @@ -59,6 +59,10 @@ mappings: CentOSStream8: OpenSUSELeap15: + python3-sqlite3: + CentOSStream8: python38 + OpenSUSELeap15: python311 + python3-tomli: # test using tomllib apk: diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index 82092c9f175..149b15de57b 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -97,6 +97,7 @@ packages: - python3-pip - python3-sphinx - python3-sphinx-rtd-theme + - python3-sqlite3 - python3-tomli - python3-venv - rpm2cpio -- 2.39.2

This might be premature but while streamlining the avocado tests I realised the only tests we have are "check-tcg" ones. The ageing fedora-cris-cross image works well enough for developers but can't be used in CI as we need supported build platforms to build QEMU. Does this mean the writing is on the wall for this architecture? Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Cc: Rabin Vincent <rabinv@axis.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-Id: <20230925144854.1872513-5-alex.bennee@linaro.org> --- docs/about/deprecated.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index d4492b94604..82922476d72 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -183,6 +183,14 @@ Nios II CPU (since 8.2) The Nios II architecture is orphan. The ``nios2`` guest CPU support is deprecated and will be removed in a future version of QEMU. +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 ------------------------ -- 2.39.2

From: Paolo Bonzini <pbonzini@redhat.com> Commit 39fb3cfc28b ("configure: clean up plugin option handling", 2023-10-18) dropped the CONFIG_PLUGIN line from tests/tcg/config-host.mak, due to confusion caused by the shadowing of $config_host_mak. However, TCG tests were still expecting it. Oops. Put it back, in the meanwhile the shadowing is gone so it's clear that it goes in the tests/tcg configuration. Cc: <alex.bennee@linaro.org> Fixes: 39fb3cfc28b ("configure: clean up plugin option handling", 2023-10-18) Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20240124115332.612162-1-pbonzini@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure b/configure index 3d8e24ae011..ff058d6c486 100755 --- a/configure +++ b/configure @@ -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 -- 2.39.2

This regressed qemu-system-xtensa: TEST test_load_store on xtensa qemu-system-xtensa: Some ROM regions are overlapping These ROM regions might have been loaded by direct user request or by default. They could be BIOS/firmware images, a guest kernel, initrd or some other file loaded into guest memory. Check whether you intended to load all this guest code, and whether it has been built to load to the correct addresses. The following two regions overlap (in the memory address space): test_load_store ELF program header segment 1 (addresses 0x0000000000001000 - 0x0000000000001f26) test_load_store ELF program header segment 2 (addresses 0x0000000000001ab8 - 0x0000000000001ab8) make[1]: *** [Makefile:187: run-test_load_store] Error 1 This reverts commit 62570f1434160d356311e1c217537e24a4ac85cd. Message-Id: <20240201122835.1712347-5-alex.bennee@linaro.org> Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/hw/elf_ops.h | 75 +++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 3e966ddd5a1..9c35d1b9da6 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -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); - - /* - * 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); + /* 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; + + 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; + } + } } } -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> make vm-build-freebsd sometimes fails with "Connection timed out during banner exchange". The client strace shows: 13:59:30 write(3, "SSH-2.0-OpenSSH_9.3\r\n", 21) = 21 13:59:30 getpid() = 252655 13:59:30 poll([{fd=3, events=POLLIN}], 1, 5000) = 1 ([{fd=3, revents=POLLIN}]) 13:59:32 read(3, "S", 1) = 1 13:59:32 poll([{fd=3, events=POLLIN}], 1, 3625) = 1 ([{fd=3, revents=POLLIN}]) 13:59:32 read(3, "S", 1) = 1 13:59:32 poll([{fd=3, events=POLLIN}], 1, 3625) = 1 ([{fd=3, revents=POLLIN}]) 13:59:32 read(3, "H", 1) = 1 There is a 2s delay during connection, and ConnectTimeout is set to 1. Raising it makes the issue go away, but we can do better. The server truss shows: 888: 27.811414714 socket(PF_INET,SOCK_DGRAM|SOCK_CLOEXEC,0) = 5 (0x5) 888: 27.811765030 connect(5,{ AF_INET 10.0.2.3:53 },16) = 0 (0x0) 888: 27.812166941 sendto(5,"\^Z/\^A\0\0\^A\0\0\0\0\0\0\^A2"...,39,0,NULL,0) = 39 (0x27) 888: 29.363970743 poll({ 5/POLLRDNORM },1,5000) = 1 (0x1) So the delay is due to a DNS query. Disable DNS queries in the server config. Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240206002344.12372-2-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/vm/basevm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 61725b83254..c0d62c08031 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -423,6 +423,8 @@ def console_ssh_init(self, prompt, user, pw): def console_sshd_config(self, prompt): self.console_wait(prompt) self.console_send("echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config\n") + self.console_wait(prompt) + self.console_send("echo 'UseDNS no' >> /etc/ssh/sshd_config\n") for var in self.envvars: self.console_wait(prompt) self.console_send("echo 'AcceptEnv %s' >> /etc/ssh/sshd_config\n" % var) -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> After console_sshd_config(), the SSH server needs to be nudged to pick up the new configs. The scripts for the other BSD flavors already do this with a reboot, but a simple reload is sufficient. Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240206002344.12372-3-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/vm/freebsd | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/vm/freebsd b/tests/vm/freebsd index b581bd17fb7..1247f40a385 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -108,6 +108,7 @@ class FreeBSDVM(basevm.BaseVM): prompt = "root@freebsd:~ #" self.console_ssh_init(prompt, "root", self._config["root_pass"]) self.console_sshd_config(prompt) + self.console_wait_send(prompt, "service sshd reload\n") # setup virtio-blk #1 (tarfile) self.console_wait(prompt) -- 2.39.2

On Wed, Feb 7, 2024 at 9:38 AM Alex Bennée <alex.bennee@linaro.org> wrote:
From: Ilya Leoshkevich <iii@linux.ibm.com>
After console_sshd_config(), the SSH server needs to be nudged to pick up the new configs. The scripts for the other BSD flavors already do this with a reboot, but a simple reload is sufficient.
Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240206002344.12372-3-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/vm/freebsd | 1 + 1 file changed, 1 insertion(+)
Reviewed-by: Warner Losh <imp@bsdimp.com>
diff --git a/tests/vm/freebsd b/tests/vm/freebsd index b581bd17fb7..1247f40a385 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -108,6 +108,7 @@ class FreeBSDVM(basevm.BaseVM): prompt = "root@freebsd:~ #" self.console_ssh_init(prompt, "root", self._config["root_pass"]) self.console_sshd_config(prompt) + self.console_wait_send(prompt, "service sshd reload\n")
# setup virtio-blk #1 (tarfile) self.console_wait(prompt) -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> Unlike on Linux, on FreeBSD renaming a file when the destination already exists results in an IN_DELETE event for that existing file: $ FILEMONITOR_DEBUG=1 build/tests/unit/test-util-filemonitor Rename /tmp/test-util-filemonitor-K13LI2/fish/one.txt -> /tmp/test-util-filemonitor-K13LI2/two.txt Event id=200000000 event=2 file=one.txt Queue event id 200000000 event 2 file one.txt Queue event id 100000000 event 2 file two.txt Queue event id 100000002 event 2 file two.txt Queue event id 100000000 event 0 file two.txt Queue event id 100000002 event 0 file two.txt Event id=100000000 event=0 file=two.txt Expected event 0 but got 2 This difference in behavior is not expected to break the real users, so teach the test to accept it. Suggested-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240206002344.12372-4-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/unit/test-util-filemonitor.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/unit/test-util-filemonitor.c b/tests/unit/test-util-filemonitor.c index a22de275955..02e67fc96ac 100644 --- a/tests/unit/test-util-filemonitor.c +++ b/tests/unit/test-util-filemonitor.c @@ -360,6 +360,14 @@ test_file_monitor_events(void) { .type = QFILE_MONITOR_TEST_OP_EVENT, .filesrc = "one.txt", .watchid = &watch4, .eventid = QFILE_MONITOR_EVENT_DELETED }, +#ifdef __FreeBSD__ + { .type = QFILE_MONITOR_TEST_OP_EVENT, + .filesrc = "two.txt", .watchid = &watch0, + .eventid = QFILE_MONITOR_EVENT_DELETED }, + { .type = QFILE_MONITOR_TEST_OP_EVENT, + .filesrc = "two.txt", .watchid = &watch2, + .eventid = QFILE_MONITOR_EVENT_DELETED }, +#endif { .type = QFILE_MONITOR_TEST_OP_EVENT, .filesrc = "two.txt", .watchid = &watch0, .eventid = QFILE_MONITOR_EVENT_CREATED }, -- 2.39.2

On Wed, Feb 7, 2024 at 9:38 AM Alex Bennée <alex.bennee@linaro.org> wrote:
From: Ilya Leoshkevich <iii@linux.ibm.com>
Unlike on Linux, on FreeBSD renaming a file when the destination already exists results in an IN_DELETE event for that existing file:
$ FILEMONITOR_DEBUG=1 build/tests/unit/test-util-filemonitor Rename /tmp/test-util-filemonitor-K13LI2/fish/one.txt -> /tmp/test-util-filemonitor-K13LI2/two.txt Event id=200000000 event=2 file=one.txt Queue event id 200000000 event 2 file one.txt Queue event id 100000000 event 2 file two.txt Queue event id 100000002 event 2 file two.txt Queue event id 100000000 event 0 file two.txt Queue event id 100000002 event 0 file two.txt Event id=100000000 event=0 file=two.txt Expected event 0 but got 2
This difference in behavior is not expected to break the real users, so teach the test to accept it.
Reviewed-by: Warner Losh <imp@bsdimp.com> Suggested-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240206002344.12372-4-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/unit/test-util-filemonitor.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/tests/unit/test-util-filemonitor.c b/tests/unit/test-util-filemonitor.c index a22de275955..02e67fc96ac 100644 --- a/tests/unit/test-util-filemonitor.c +++ b/tests/unit/test-util-filemonitor.c @@ -360,6 +360,14 @@ test_file_monitor_events(void) { .type = QFILE_MONITOR_TEST_OP_EVENT, .filesrc = "one.txt", .watchid = &watch4, .eventid = QFILE_MONITOR_EVENT_DELETED }, +#ifdef __FreeBSD__ + { .type = QFILE_MONITOR_TEST_OP_EVENT, + .filesrc = "two.txt", .watchid = &watch0, + .eventid = QFILE_MONITOR_EVENT_DELETED }, + { .type = QFILE_MONITOR_TEST_OP_EVENT, + .filesrc = "two.txt", .watchid = &watch2, + .eventid = QFILE_MONITOR_EVENT_DELETED }, +#endif { .type = QFILE_MONITOR_TEST_OP_EVENT, .filesrc = "two.txt", .watchid = &watch0, .eventid = QFILE_MONITOR_EVENT_CREATED }, -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> make vm-build-freebsd fails with: ld: error: undefined symbol: inotify_init1 >>> referenced by filemonitor-inotify.c:183 (../src/util/filemonitor-inotify.c:183) >>> util_filemonitor-inotify.c.o:(qemu_file_monitor_new) in archive libqemuutil.a On FreeBSD the inotify functions are defined in libinotify.so. Add it to the dependencies. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-Id: <20240206002344.12372-5-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- meson.build | 23 +++++++++++++++++++---- util/meson.build | 6 +++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index b5d6dc94a83..e5d6f2d057e 100644 --- a/meson.build +++ b/meson.build @@ -2384,6 +2384,22 @@ else endif config_host_data.set('CONFIG_ASAN_IFACE_FIBER', have_asan_fiber) +have_inotify_init = cc.has_header_symbol('sys/inotify.h', 'inotify_init') +have_inotify_init1 = cc.has_header_symbol('sys/inotify.h', 'inotify_init1') +inotify = not_found +if (have_inotify_init or have_inotify_init1) and host_os == 'freebsd' + # libinotify-kqueue + inotify = cc.find_library('inotify') + if have_inotify_init + have_inotify_init = inotify.found() + endif + if have_inotify_init1 + have_inotify_init1 = inotify.found() + endif +endif +config_host_data.set('CONFIG_INOTIFY', have_inotify_init) +config_host_data.set('CONFIG_INOTIFY1', have_inotify_init1) + # has_header_symbol config_host_data.set('CONFIG_BLKZONED', cc.has_header_symbol('linux/blkzoned.h', 'BLKOPENZONE')) @@ -2400,10 +2416,6 @@ config_host_data.set('CONFIG_FIEMAP', config_host_data.set('CONFIG_GETRANDOM', cc.has_function('getrandom') and cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK')) -config_host_data.set('CONFIG_INOTIFY', - cc.has_header_symbol('sys/inotify.h', 'inotify_init')) -config_host_data.set('CONFIG_INOTIFY1', - cc.has_header_symbol('sys/inotify.h', 'inotify_init1')) config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK', cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK')) config_host_data.set('CONFIG_RTNETLINK', @@ -4407,6 +4419,9 @@ summary_info += {'libudev': libudev} summary_info += {'FUSE lseek': fuse_lseek.found()} summary_info += {'selinux': selinux} summary_info += {'libdw': libdw} +if host_os == 'freebsd' + summary_info += {'libinotify-kqueue': inotify} +endif summary(summary_info, bool_yn: true, section: 'Dependencies') if host_arch == 'unknown' diff --git a/util/meson.build b/util/meson.build index af3bf5692d8..0ef9886be04 100644 --- a/util/meson.build +++ b/util/meson.build @@ -104,7 +104,11 @@ if have_block util_ss.add(files('throttle.c')) util_ss.add(files('timed-average.c')) if config_host_data.get('CONFIG_INOTIFY1') - util_ss.add(files('filemonitor-inotify.c')) + freebsd_dep = [] + if host_os == 'freebsd' + freebsd_dep = inotify + endif + util_ss.add(files('filemonitor-inotify.c'), freebsd_dep) else util_ss.add(files('filemonitor-stub.c')) endif -- 2.39.2

On Wed, Feb 7, 2024 at 9:38 AM Alex Bennée <alex.bennee@linaro.org> wrote:
From: Ilya Leoshkevich <iii@linux.ibm.com>
make vm-build-freebsd fails with:
ld: error: undefined symbol: inotify_init1 >>> referenced by filemonitor-inotify.c:183 (../src/util/filemonitor-inotify.c:183) >>> util_filemonitor-inotify.c.o:(qemu_file_monitor_new) in archive libqemuutil.a
On FreeBSD the inotify functions are defined in libinotify.so. Add it to the dependencies.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-Id: <20240206002344.12372-5-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- meson.build | 23 +++++++++++++++++++---- util/meson.build | 6 +++++- 2 files changed, 24 insertions(+), 5 deletions(-)
Reviewed-by: Warner Losh <imp@bsdimp.com>
diff --git a/meson.build b/meson.build index b5d6dc94a83..e5d6f2d057e 100644 --- a/meson.build +++ b/meson.build @@ -2384,6 +2384,22 @@ else endif config_host_data.set('CONFIG_ASAN_IFACE_FIBER', have_asan_fiber)
+have_inotify_init = cc.has_header_symbol('sys/inotify.h', 'inotify_init') +have_inotify_init1 = cc.has_header_symbol('sys/inotify.h', 'inotify_init1') +inotify = not_found +if (have_inotify_init or have_inotify_init1) and host_os == 'freebsd' + # libinotify-kqueue + inotify = cc.find_library('inotify') + if have_inotify_init + have_inotify_init = inotify.found() + endif + if have_inotify_init1 + have_inotify_init1 = inotify.found() + endif +endif +config_host_data.set('CONFIG_INOTIFY', have_inotify_init) +config_host_data.set('CONFIG_INOTIFY1', have_inotify_init1) + # has_header_symbol config_host_data.set('CONFIG_BLKZONED', cc.has_header_symbol('linux/blkzoned.h', 'BLKOPENZONE')) @@ -2400,10 +2416,6 @@ config_host_data.set('CONFIG_FIEMAP', config_host_data.set('CONFIG_GETRANDOM', cc.has_function('getrandom') and cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK')) -config_host_data.set('CONFIG_INOTIFY', - cc.has_header_symbol('sys/inotify.h', 'inotify_init')) -config_host_data.set('CONFIG_INOTIFY1', - cc.has_header_symbol('sys/inotify.h', 'inotify_init1')) config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK', cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK')) config_host_data.set('CONFIG_RTNETLINK', @@ -4407,6 +4419,9 @@ summary_info += {'libudev': libudev} summary_info += {'FUSE lseek': fuse_lseek.found()} summary_info += {'selinux': selinux} summary_info += {'libdw': libdw} +if host_os == 'freebsd' + summary_info += {'libinotify-kqueue': inotify} +endif summary(summary_info, bool_yn: true, section: 'Dependencies')
if host_arch == 'unknown' diff --git a/util/meson.build b/util/meson.build index af3bf5692d8..0ef9886be04 100644 --- a/util/meson.build +++ b/util/meson.build @@ -104,7 +104,11 @@ if have_block util_ss.add(files('throttle.c')) util_ss.add(files('timed-average.c')) if config_host_data.get('CONFIG_INOTIFY1') - util_ss.add(files('filemonitor-inotify.c')) + freebsd_dep = [] + if host_os == 'freebsd' + freebsd_dep = inotify + endif + util_ss.add(files('filemonitor-inotify.c'), freebsd_dep) else util_ss.add(files('filemonitor-stub.c')) endif -- 2.39.2

From: Paolo Bonzini <pbonzini@redhat.com> Just like all other dependencies, these can be expressed in Kconfig files rather than in the default configurations. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-Id: <20240201122835.1712347-6-alex.bennee@linaro.org> Message-Id: <20240129115809.1039924-1-pbonzini@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configs/devices/m68k-softmmu/default.mak | 2 -- configs/devices/mips-softmmu/common.mak | 3 --- configs/devices/nios2-softmmu/default.mak | 2 -- configs/devices/riscv32-softmmu/default.mak | 2 -- configs/devices/riscv64-softmmu/default.mak | 2 -- configs/devices/xtensa-softmmu/default.mak | 2 -- target/m68k/Kconfig | 1 + target/mips/Kconfig | 1 + target/nios2/Kconfig | 1 + target/riscv/Kconfig | 2 ++ target/xtensa/Kconfig | 1 + 11 files changed, 6 insertions(+), 13 deletions(-) diff --git a/configs/devices/m68k-softmmu/default.mak b/configs/devices/m68k-softmmu/default.mak index 7f8619e4278..8dcaa28ed38 100644 --- a/configs/devices/m68k-softmmu/default.mak +++ b/configs/devices/m68k-softmmu/default.mak @@ -1,7 +1,5 @@ # Default configuration for m68k-softmmu -CONFIG_SEMIHOSTING=y - # Boards: # CONFIG_AN5206=y diff --git a/configs/devices/mips-softmmu/common.mak b/configs/devices/mips-softmmu/common.mak index 7da99327a77..1a853841b27 100644 --- a/configs/devices/mips-softmmu/common.mak +++ b/configs/devices/mips-softmmu/common.mak @@ -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 diff --git a/configs/devices/nios2-softmmu/default.mak b/configs/devices/nios2-softmmu/default.mak index 1bc4082ea99..e130d024e62 100644 --- a/configs/devices/nios2-softmmu/default.mak +++ b/configs/devices/nios2-softmmu/default.mak @@ -1,7 +1,5 @@ # Default configuration for nios2-softmmu -CONFIG_SEMIHOSTING=y - # Boards: # CONFIG_NIOS2_10M50=y diff --git a/configs/devices/riscv32-softmmu/default.mak b/configs/devices/riscv32-softmmu/default.mak index d847bd5692e..94a236c9c25 100644 --- a/configs/devices/riscv32-softmmu/default.mak +++ b/configs/devices/riscv32-softmmu/default.mak @@ -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: # diff --git a/configs/devices/riscv64-softmmu/default.mak b/configs/devices/riscv64-softmmu/default.mak index bc69301fa4a..3f680594484 100644 --- a/configs/devices/riscv64-softmmu/default.mak +++ b/configs/devices/riscv64-softmmu/default.mak @@ -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: # diff --git a/configs/devices/xtensa-softmmu/default.mak b/configs/devices/xtensa-softmmu/default.mak index 4fe1bf00c94..49e4c9da88c 100644 --- a/configs/devices/xtensa-softmmu/default.mak +++ b/configs/devices/xtensa-softmmu/default.mak @@ -1,7 +1,5 @@ # Default configuration for Xtensa -CONFIG_SEMIHOSTING=y - # Boards: # CONFIG_XTENSA_SIM=y diff --git a/target/m68k/Kconfig b/target/m68k/Kconfig index 23debad519a..9eae71486ff 100644 --- a/target/m68k/Kconfig +++ b/target/m68k/Kconfig @@ -1,2 +1,3 @@ config M68K bool + select SEMIHOSTING diff --git a/target/mips/Kconfig b/target/mips/Kconfig index 6adf1453548..eb19c94c7d4 100644 --- a/target/mips/Kconfig +++ b/target/mips/Kconfig @@ -1,5 +1,6 @@ config MIPS bool + select SEMIHOSTING config MIPS64 bool diff --git a/target/nios2/Kconfig b/target/nios2/Kconfig index 1529ab8950d..c65550c861a 100644 --- a/target/nios2/Kconfig +++ b/target/nios2/Kconfig @@ -1,2 +1,3 @@ config NIOS2 bool + select SEMIHOSTING diff --git a/target/riscv/Kconfig b/target/riscv/Kconfig index b9e5932f13f..adb7de3f37d 100644 --- a/target/riscv/Kconfig +++ b/target/riscv/Kconfig @@ -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() diff --git a/target/xtensa/Kconfig b/target/xtensa/Kconfig index a3c8dc7f6d7..5e46049262d 100644 --- a/target/xtensa/Kconfig +++ b/target/xtensa/Kconfig @@ -1,2 +1,3 @@ config XTENSA bool + select SEMIHOSTING -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> The upcoming syscall catchpoint support needs to send SIGTRAP stop packets to GDB. Being able to compile this support only once for all targets is a good thing, and it requires hiding TARGET_SIGTRAP behind a function call. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240202152506.279476-2-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/internals.h | 1 + gdbstub/user-target.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/gdbstub/internals.h b/gdbstub/internals.h index 5c0c725e54c..aeb0d9b5377 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -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); diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c index c4bba4c72c7..b7d4c37cd81 100644 --- a/gdbstub/user-target.c +++ b/gdbstub/user-target.c @@ -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; +} -- 2.39.2

On 7/2/24 17:38, Alex Bennée wrote:
From: Ilya Leoshkevich <iii@linux.ibm.com>
The upcoming syscall catchpoint support needs to send SIGTRAP stop packets to GDB. Being able to compile this support only once for all targets is a good thing, and it requires hiding TARGET_SIGTRAP behind a function call.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240202152506.279476-2-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/internals.h | 1 + gdbstub/user-target.c | 5 +++++ 2 files changed, 6 insertions(+)
diff --git a/gdbstub/internals.h b/gdbstub/internals.h index 5c0c725e54c..aeb0d9b5377 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -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);
diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c index c4bba4c72c7..b7d4c37cd81 100644 --- a/gdbstub/user-target.c +++ b/gdbstub/user-target.c @@ -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; +}
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

From: Ilya Leoshkevich <iii@linux.ibm.com> The upcoming syscall catchpoint support needs to send stop packets with an associated reason to GDB. Add an extra parameter to gdb_handlesig() for that, and rename it to gdb_handlesig_reason(). Provide a compatibility wrapper with an old name. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240202152506.279476-3-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/gdbstub/user.h | 16 ++++++++++++++-- gdbstub/user.c | 5 ++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/gdbstub/user.h b/include/gdbstub/user.h index d392e510c59..1fc43e04af5 100644 --- a/include/gdbstub/user.h +++ b/include/gdbstub/user.h @@ -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 diff --git a/gdbstub/user.c b/gdbstub/user.c index dbe1d9b8875..63edca131ab 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -121,7 +121,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 +141,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; } -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> The upcoming syscall catchpoint support needs to get control on syscall entry and return. Provide the necessary hooks for that, which are no-ops for now. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240202152506.279476-4-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/gdbstub/user.h | 13 +++++++++++++ include/user/syscall-trace.h | 7 +++++-- gdbstub/user.c | 8 ++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/gdbstub/user.h b/include/gdbstub/user.h index 1fc43e04af5..68b6534130c 100644 --- a/include/gdbstub/user.h +++ b/include/gdbstub/user.h @@ -51,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 */ diff --git a/include/user/syscall-trace.h b/include/user/syscall-trace.h index 557f881a79b..b48b2b2d0ae 100644 --- a/include/user/syscall-trace.h +++ b/include/user/syscall-trace.h @@ -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); } diff --git a/gdbstub/user.c b/gdbstub/user.c index 63edca131ab..2ba01c17faf 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -502,3 +502,11 @@ void gdb_syscall_handling(const char *syscall_packet) gdb_put_packet(syscall_packet); gdb_handlesig(gdbserver_state.c_cpu, 0); } + +void gdb_syscall_entry(CPUState *cs, int num) +{ +} + +void gdb_syscall_return(CPUState *cs, int num) +{ +} -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> GDB supports stopping on syscall entry and exit using the "catch syscall" command. It relies on 3 packets, which are currently not supported by QEMU: * qSupported:QCatchSyscalls+ [1] * QCatchSyscalls: [2] * T05syscall_entry: and T05syscall_return: [3] Implement generation and handling of these packets. [1] https://sourceware.org/gdb/current/onlinedocs/gdb.html/General-Query-Packets... [2] https://sourceware.org/gdb/current/onlinedocs/gdb.html/General-Query-Packets... [3] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Stop-Reply-Packets.ht... Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240202152506.279476-5-iii@linux.ibm.com> [AJB: GString -> g_strdup_printf] Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/internals.h | 1 + gdbstub/gdbstub.c | 9 +++++ gdbstub/user.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/gdbstub/internals.h b/gdbstub/internals.h index aeb0d9b5377..56b7c13b750 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -195,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 */ diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 46d752bbc2c..7e73e916bdc 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -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) diff --git a/gdbstub/user.c b/gdbstub/user.c index 2ba01c17faf..14918d1a217 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -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; @@ -503,10 +513,91 @@ void gdb_syscall_handling(const char *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 = ¶m[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"); } -- 2.39.2

From: Ilya Leoshkevich <iii@linux.ibm.com> Check that adding/removing syscall catchpoints works. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240202152506.279476-6-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/tcg/multiarch/catch-syscalls.c | 51 ++++++++++++++++++ tests/tcg/multiarch/Makefile.target | 10 +++- tests/tcg/multiarch/gdbstub/catch-syscalls.py | 53 +++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/multiarch/catch-syscalls.c create mode 100644 tests/tcg/multiarch/gdbstub/catch-syscalls.py diff --git a/tests/tcg/multiarch/catch-syscalls.c b/tests/tcg/multiarch/catch-syscalls.c new file mode 100644 index 00000000000..d1ff1936a7a --- /dev/null +++ b/tests/tcg/multiarch/catch-syscalls.c @@ -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; +} diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 315a2e13588..e10951a8016 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -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 # diff --git a/tests/tcg/multiarch/gdbstub/catch-syscalls.py b/tests/tcg/multiarch/gdbstub/catch-syscalls.py new file mode 100644 index 00000000000..ccce35902fb --- /dev/null +++ b/tests/tcg/multiarch/gdbstub/catch-syscalls.py @@ -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) -- 2.39.2
participants (3)
-
Alex Bennée
-
Philippe Mathieu-Daudé
-
Warner Losh