From 547d94ffc62a96736953c35c94c7916181805895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:41 +0100 Subject: [PATCH 01/17] .gitpublish: use origin/master as default base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is very much the result of my recent fat finger but I think it's safer to assume that origin/master points to a recent commit (or at least a commit a given branch is based on) than master. Acked-by: Stefan Hajnoczi Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-2-alex.bennee@linaro.org> --- .gitpublish | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitpublish b/.gitpublish index a13f8c7c0e..a3adb21ffa 100644 --- a/.gitpublish +++ b/.gitpublish @@ -4,48 +4,48 @@ # See https://github.com/stefanha/git-publish for more information # [gitpublishprofile "default"] -base = master +base = origin/master to = qemu-devel@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "rfc"] -base = master +base = origin/master prefix = RFC PATCH to = qemu-devel@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "stable"] -base = master +base = origin/master to = qemu-devel@nongnu.org cc = qemu-stable@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "trivial"] -base = master +base = origin/master to = qemu-devel@nongnu.org cc = qemu-trivial@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "block"] -base = master +base = origin/master to = qemu-devel@nongnu.org cc = qemu-block@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "arm"] -base = master +base = origin/master to = qemu-devel@nongnu.org cc = qemu-arm@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "s390"] -base = master +base = origin/master to = qemu-devel@nongnu.org cc = qemu-s390@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null [gitpublishprofile "ppc"] -base = master +base = origin/master to = qemu-devel@nongnu.org cc = qemu-ppc@nongnu.org cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null From 43a1c177426ff1babb863b3c45281fbc9f47f130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:42 +0100 Subject: [PATCH 02/17] .gitmodules: restore qemu-project mirror of u-boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this change also reference the upstream repo. Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-3-alex.bennee@linaro.org> --- .gitmodules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index e27dfe8c2c..e51abe6525 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,7 +15,8 @@ url = https://gitlab.com/qemu-project/qemu-palcode.git [submodule "roms/u-boot"] path = roms/u-boot - url = https://gitlab.com/qemu-project-mirrors/u-boot.git + # upstream is https://github.com/u-boot/u-boot + url = https://gitlab.com/qemu-project/u-boot.git [submodule "roms/skiboot"] path = roms/skiboot url = https://gitlab.com/qemu-project/skiboot.git From 88091789f0d6234d9050c1c7a2dfc2515044ece0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:43 +0100 Subject: [PATCH 03/17] .gitmodules: restore qemu-project mirror of u-boot-sam460ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this change also reference the upstream repo. Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-4-alex.bennee@linaro.org> --- .gitmodules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index e51abe6525..c307216d17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,7 +28,8 @@ url = https://gitlab.com/qemu-project/seabios-hppa.git [submodule "roms/u-boot-sam460ex"] path = roms/u-boot-sam460ex - url = https://gitlab.com/qemu-project-mirrors/u-boot-sam460ex.git + # upstream is https://github.com/zbalaton/u-boot-sam460ex + url = https://gitlab.com/qemu-project/u-boot-sam460ex.git [submodule "roms/edk2"] path = roms/edk2 url = https://gitlab.com/qemu-project/edk2.git From 3d8c04b0eee35b7345c34c5265bb0478fcfc90ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:44 +0100 Subject: [PATCH 04/17] tests/lcitool: drop 64 bit guests from i686 cross build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With only TCG available we can't support 64 bit guests on a 32 bit host. Fixes: 5c27baf9519 (docs/about/deprecated: Deprecate 32-bit x86 hosts for system emulation) Reviewed-by: Marc-André Lureau Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-5-alex.bennee@linaro.org> --- tests/docker/dockerfiles/debian-i686-cross.docker | 2 +- tests/lcitool/refresh | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/docker/dockerfiles/debian-i686-cross.docker b/tests/docker/dockerfiles/debian-i686-cross.docker index 4e8b3a8293..2998764065 100644 --- a/tests/docker/dockerfiles/debian-i686-cross.docker +++ b/tests/docker/dockerfiles/debian-i686-cross.docker @@ -178,7 +178,7 @@ ENV ABI "i686-linux-gnu" ENV MESON_OPTS "--cross-file=i686-linux-gnu" ENV RUST_TARGET "i686-unknown-linux-gnu" ENV QEMU_CONFIGURE_OPTS --cross-prefix=i686-linux-gnu- -ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user +ENV DEF_TARGET_LIST i386-softmmu,i386-linux-user # As a final step configure the user (if env is defined) ARG USER ARG UID diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 645959318a..185a47cebe 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -216,8 +216,6 @@ try: generate_dockerfile("debian-i686-cross", "debian-13", cross="i686", trailer=cross_build("i686-linux-gnu-", - "x86_64-softmmu," - "x86_64-linux-user," "i386-softmmu,i386-linux-user")) # mips no longer supported in debian-13 From 07a58aac21c80c3b74b2955ea9f9ba02070be75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:45 +0100 Subject: [PATCH 05/17] tests/lcitool: bump custom runner packages to Ubuntu 24.04 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In anticipation of new runners lets move to a newer Ubuntu LTS. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-6-alex.bennee@linaro.org> --- scripts/ci/setup/gitlab-runner.yml | 2 +- scripts/ci/setup/ubuntu/build-environment.yml | 12 ++++++------ ...tu-2204-aarch64.yaml => ubuntu-2404-aarch64.yaml} | 4 +++- ...ubuntu-2204-s390x.yaml => ubuntu-2404-s390x.yaml} | 4 +++- tests/lcitool/refresh | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) rename scripts/ci/setup/ubuntu/{ubuntu-2204-aarch64.yaml => ubuntu-2404-aarch64.yaml} (96%) rename scripts/ci/setup/ubuntu/{ubuntu-2204-s390x.yaml => ubuntu-2404-s390x.yaml} (96%) diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml index 57e7faebf1..7350f6cff4 100644 --- a/scripts/ci/setup/gitlab-runner.yml +++ b/scripts/ci/setup/gitlab-runner.yml @@ -103,7 +103,7 @@ when: - ansible_facts['distribution'] == 'Ubuntu' - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '22.04' + - ansible_facts['distribution_version'] == '24.04' - name: Install the gitlab-runner service using its own functionality command: "/usr/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner" diff --git a/scripts/ci/setup/ubuntu/build-environment.yml b/scripts/ci/setup/ubuntu/build-environment.yml index 56b51609e3..6042750cb4 100644 --- a/scripts/ci/setup/ubuntu/build-environment.yml +++ b/scripts/ci/setup/ubuntu/build-environment.yml @@ -35,19 +35,19 @@ # the package lists are updated by "make lcitool-refresh" - name: Include package lists based on OS and architecture include_vars: - file: "ubuntu-2204-{{ ansible_facts['architecture'] }}.yaml" + file: "ubuntu-2404-{{ ansible_facts['architecture'] }}.yaml" when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_version'] == '22.04' + - ansible_facts['distribution_version'] == '24.04' - - name: Install packages for QEMU on Ubuntu 22.04 + - name: Install packages for QEMU on Ubuntu 24.04 package: name: "{{ packages }}" when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_version'] == '22.04' + - ansible_facts['distribution_version'] == '24.04' - - name: Install armhf cross-compile packages to build QEMU on AArch64 Ubuntu 22.04 + - name: Install armhf cross-compile packages to build QEMU on AArch64 Ubuntu 24.04 package: name: - binutils-arm-linux-gnueabihf @@ -62,6 +62,6 @@ - zlib1g-dev:armhf when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_version'] == '22.04' + - ansible_facts['distribution_version'] == '24.04' - ansible_facts['architecture'] == 'aarch64' diff --git a/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml similarity index 96% rename from scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml rename to scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml index 2ca4a5392f..ce632d9710 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml @@ -1,12 +1,13 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool variables --host-arch aarch64 ubuntu-2204 qemu +# $ lcitool variables --host-arch aarch64 ubuntu-2404 qemu # # https://gitlab.com/libvirt/libvirt-ci packages: - bash - bc + - bindgen - bison - bsdextrautils - bzip2 @@ -92,6 +93,7 @@ packages: - libvdeplug-dev - libvirglrenderer-dev - libvte-2.91-dev + - libxdp-dev - libxen-dev - libzstd-dev - llvm diff --git a/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml similarity index 96% rename from scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml rename to scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml index 7198fbbcbb..f45f75c960 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml @@ -1,12 +1,13 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool variables --host-arch s390x ubuntu-2204 qemu +# $ lcitool variables --host-arch s390x ubuntu-2404 qemu # # https://gitlab.com/libvirt/libvirt-ci packages: - bash - bc + - bindgen - bison - bsdextrautils - bzip2 @@ -91,6 +92,7 @@ packages: - libvdeplug-dev - libvirglrenderer-dev - libvte-2.91-dev + - libxdp-dev - libzstd-dev - llvm - locales diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 185a47cebe..056cfb6e9d 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -270,8 +270,8 @@ try: # # Ansible package lists # - generate_yaml("ubuntu", "ubuntu-2204", "aarch64") - generate_yaml("ubuntu", "ubuntu-2204", "s390x") + generate_yaml("ubuntu", "ubuntu-2404", "aarch64") + generate_yaml("ubuntu", "ubuntu-2404", "s390x") sys.exit(0) From eafc5f69e621725dcdcedcc1955d820af7abfc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:46 +0100 Subject: [PATCH 06/17] gitlab: move custom runners to Ubuntu 24.04 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-7-alex.bennee@linaro.org> --- .gitlab-ci.d/custom-runners.yml | 6 ++-- ...4-aarch32.yml => ubuntu-24.04-aarch32.yml} | 8 ++--- ...4-aarch64.yml => ubuntu-24.04-aarch64.yml} | 32 +++++++++---------- ...22.04-s390x.yml => ubuntu-24.04-s390x.yml} | 28 ++++++++-------- 4 files changed, 37 insertions(+), 37 deletions(-) rename .gitlab-ci.d/custom-runners/{ubuntu-22.04-aarch32.yml => ubuntu-24.04-aarch32.yml} (78%) rename .gitlab-ci.d/custom-runners/{ubuntu-22.04-aarch64.yml => ubuntu-24.04-aarch64.yml} (89%) rename .gitlab-ci.d/custom-runners/{ubuntu-22.04-s390x.yml => ubuntu-24.04-s390x.yml} (88%) diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 2d493f70f7..3eb8216d57 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -29,6 +29,6 @@ junit: build/meson-logs/*.junit.xml include: - - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml' - - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml' - - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml' + - local: '/.gitlab-ci.d/custom-runners/ubuntu-24.04-s390x.yml' + - local: '/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml' + - local: '/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch32.yml' diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch32.yml similarity index 78% rename from .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml rename to .gitlab-ci.d/custom-runners/ubuntu-24.04-aarch32.yml index 8727687e2b..75029c9187 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch32.yml @@ -1,13 +1,13 @@ -# All ubuntu-22.04 jobs should run successfully in an environment +# All ubuntu-24.04 jobs should run successfully in an environment # setup by the scripts/ci/setup/ubuntu/build-environment.yml task -# "Install basic packages to build QEMU on Ubuntu 22.04" +# "Install basic packages to build QEMU on Ubuntu 24.04" -ubuntu-22.04-aarch32-all: +ubuntu-24.04-aarch32-all: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch32 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml similarity index 89% rename from .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml rename to .gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml index ca2f140471..d26c7827f4 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml @@ -1,13 +1,13 @@ -# All ubuntu-22.04 jobs should run successfully in an environment +# All ubuntu-24.04 jobs should run successfully in an environment # setup by the scripts/ci/setup/ubuntu/build-environment.yml task -# "Install basic packages to build QEMU on Ubuntu 22.04" +# "Install basic packages to build QEMU on Ubuntu 24.04" -ubuntu-22.04-aarch64-all-linux-static: +ubuntu-24.04-aarch64-all-linux-static: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -23,12 +23,12 @@ ubuntu-22.04-aarch64-all-linux-static: - make check-tcg - make --output-sync -j`nproc --ignore=40` check -ubuntu-22.04-aarch64-all: +ubuntu-24.04-aarch64-all: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -45,12 +45,12 @@ ubuntu-22.04-aarch64-all: - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check -ubuntu-22.04-aarch64-without-defaults: +ubuntu-24.04-aarch64-without-defaults: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -67,12 +67,12 @@ ubuntu-22.04-aarch64-without-defaults: - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check -ubuntu-22.04-aarch64-alldbg: +ubuntu-24.04-aarch64-alldbg: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -86,12 +86,12 @@ ubuntu-22.04-aarch64-alldbg: - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check -ubuntu-22.04-aarch64-clang: +ubuntu-24.04-aarch64-clang: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -108,11 +108,11 @@ ubuntu-22.04-aarch64-clang: - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check -ubuntu-22.04-aarch64-tci: +ubuntu-24.04-aarch64-tci: needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -128,12 +128,12 @@ ubuntu-22.04-aarch64-tci: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` -ubuntu-22.04-aarch64-notcg: +ubuntu-24.04-aarch64-notcg: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml b/.gitlab-ci.d/custom-runners/ubuntu-24.04-s390x.yml similarity index 88% rename from .gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml rename to .gitlab-ci.d/custom-runners/ubuntu-24.04-s390x.yml index e62ff1763f..45dbee1788 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-24.04-s390x.yml @@ -1,13 +1,13 @@ -# All ubuntu-22.04 jobs should run successfully in an environment +# All ubuntu-24.04 jobs should run successfully in an environment # setup by the scripts/ci/setup/ubuntu/build-environment.yml task -# "Install basic packages to build QEMU on Ubuntu 22.04" +# "Install basic packages to build QEMU on Ubuntu 24.04" -ubuntu-22.04-s390x-all-linux: +ubuntu-24.04-s390x-all-linux: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - s390x rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -21,12 +21,12 @@ ubuntu-22.04-s390x-all-linux: - make --output-sync check-tcg - make --output-sync -j`nproc` check -ubuntu-22.04-s390x-all-system: +ubuntu-24.04-s390x-all-system: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - s390x timeout: 75m rules: @@ -42,12 +42,12 @@ ubuntu-22.04-s390x-all-system: - make --output-sync -j`nproc` - make --output-sync -j`nproc` check -ubuntu-22.04-s390x-alldbg: +ubuntu-24.04-s390x-alldbg: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - s390x rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -65,12 +65,12 @@ ubuntu-22.04-s390x-alldbg: - make --output-sync -j`nproc` - make --output-sync -j`nproc` check -ubuntu-22.04-s390x-clang: +ubuntu-24.04-s390x-clang: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - s390x rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -87,11 +87,11 @@ ubuntu-22.04-s390x-clang: - make --output-sync -j`nproc` - make --output-sync -j`nproc` check -ubuntu-22.04-s390x-tci: +ubuntu-24.04-s390x-tci: needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - s390x rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -107,12 +107,12 @@ ubuntu-22.04-s390x-tci: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` -ubuntu-22.04-s390x-notcg: +ubuntu-24.04-s390x-notcg: extends: .custom_runner_template needs: [] stage: build tags: - - ubuntu_22.04 + - ubuntu_24.04 - s390x rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' From 1f3a37ae1c170114ae2730176b4a8cba73abb620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Oct 2025 18:09:47 +0100 Subject: [PATCH 07/17] scripts/ci: use recommended registration command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The registration-token method is being deprecated: https://docs.gitlab.com/ci/runners/new_creation_workflow/ As a result we can drop a bunch of the descriptive stuff as that is entered on the web UI. We don't need a secondary runner if we just create one with both aarch64 and aarch32 tags. Signed-off-by: Alex Bennée Message-ID: <20251001170947.2769296-8-alex.bennee@linaro.org> --- scripts/ci/setup/gitlab-runner.yml | 12 ++---------- scripts/ci/setup/vars.yml.template | 5 +++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml index 7350f6cff4..7025935487 100644 --- a/scripts/ci/setup/gitlab-runner.yml +++ b/scripts/ci/setup/gitlab-runner.yml @@ -16,7 +16,7 @@ tasks: - debug: msg: 'Checking for a valid GitLab registration token' - failed_when: "gitlab_runner_registration_token == 'PLEASE_PROVIDE_A_VALID_TOKEN'" + failed_when: "gitlab_runner_authentication_token == 'PLEASE_PROVIDE_A_VALID_TOKEN'" - name: Create a group for the gitlab-runner service group: @@ -95,15 +95,7 @@ # Register Runners - name: Register the gitlab-runner - command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" - - # The secondary runner will still run under the single gitlab-runner service - - name: Register secondary gitlab-runner - command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list aarch32,{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '24.04' + command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --token {{ gitlab_runner_authentication_token }} --executor shell" - name: Install the gitlab-runner service using its own functionality command: "/usr/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner" diff --git a/scripts/ci/setup/vars.yml.template b/scripts/ci/setup/vars.yml.template index 4b355fb80f..e9ddc05f3b 100644 --- a/scripts/ci/setup/vars.yml.template +++ b/scripts/ci/setup/vars.yml.template @@ -6,5 +6,6 @@ ansible_to_gitlab_arch: x86_64: amd64 aarch64: arm64 s390x: s390x -# A unique token made available by GitLab to your project for registering runners -gitlab_runner_registration_token: PLEASE_PROVIDE_A_VALID_TOKEN +# A unique token made obtained from GitLab for each runner +# see: https://gitlab.com/PROJECT/REPO/-/runners/new +gitlab_runner_authentication_token: PLEASE_PROVIDE_A_VALID_TOKEN From 75b1786996c422878d09bd12f166004a7d32e459 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:12 +0000 Subject: [PATCH 08/17] tests/functional: Re-activate the check-venv target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add check-venv target as a dependency for the functional tests. This causes Python modules listed in pythondeps.toml, under the testdeps group, to be installed when 'make check-functional{-}' is executed to prepare and run the functional tests. Suggested-by: Thomas Huth Reviewed-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-2-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- tests/Makefile.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 62a4fc8ed3..e47ef4d45c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -105,11 +105,11 @@ check-venv: $(TESTS_VENV_TOKEN) FUNCTIONAL_TARGETS=$(patsubst %-softmmu,check-functional-%, $(filter %-softmmu,$(TARGETS))) .PHONY: $(FUNCTIONAL_TARGETS) -$(FUNCTIONAL_TARGETS): +$(FUNCTIONAL_TARGETS): check-venv @$(MAKE) SPEED=thorough $(subst -functional,-func,$@) .PHONY: check-functional -check-functional: +check-functional: check-venv @$(NINJA) precache-functional @QEMU_TEST_NO_DOWNLOAD=1 $(MAKE) SPEED=thorough check-func check-func-quick From c8f24e1b95430759f79223dc75c66fa7ec3ef2ee Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:13 +0000 Subject: [PATCH 09/17] python: Install pygdbmi in meson's venv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upcoming changes in the reverse_debugging functional test to remove Avocado as a dependency will require pygdbmi for interacting with GDB, so install it in meson's venv (located in the build dir's pyvenv/). Reviewed-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-3-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- pythondeps.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pythondeps.toml b/pythondeps.toml index 16fb2a989c..98e99e7900 100644 --- a/pythondeps.toml +++ b/pythondeps.toml @@ -33,3 +33,4 @@ sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.2.2" } [testdeps] qemu.qmp = { accepted = ">=0.0.3", installed = "0.0.3" } +pygdbmi = { accepted = ">=0.11.0.0", installed = "0.11.0.0" } From b46b3818cf8d838991b15f20d3cb747b71ce040e Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:14 +0000 Subject: [PATCH 10/17] tests/functional: Provide GDB to the functional tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The probe of GDB is done in 'configure' and the full path is passed to meson.build via the -Dgdb=option. Meson then can pass the location of GDB to the functional tests via an environment variable: QEMU_TEST_GDB. Signed-off-by: Thomas Huth Reviewed-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-4-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- configure | 2 ++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 2 ++ tests/functional/meson.build | 6 ++++++ 4 files changed, 12 insertions(+) diff --git a/configure b/configure index 78445cbb4b..21d1679f58 100755 --- a/configure +++ b/configure @@ -2003,6 +2003,8 @@ if test "$skip_meson" = no; then test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" test "$plugins" = yes && meson_option_add "-Dplugins=true" test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg" + test -n "$gdb_bin" && meson_option_add "-Dgdb=$gdb_bin" + run_meson() { NINJA=$ninja $meson setup "$@" "$PWD" "$source_path" } diff --git a/meson_options.txt b/meson_options.txt index fff1521e58..5bb41bcbc4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -36,6 +36,8 @@ option('trace_file', type: 'string', value: 'trace', option('coroutine_backend', type: 'combo', choices: ['ucontext', 'sigaltstack', 'windows', 'wasm', 'auto'], value: 'auto', description: 'coroutine backend to use') +option('gdb', type: 'string', value: '', + description: 'Path to GDB') # Everything else can be set via --enable/--disable-* option # on the configure script command line. After adding an option diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 0ebe6bc52a..f4bd21220e 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -58,6 +58,7 @@ meson_options_help() { printf "%s\n" ' --enable-ubsan enable undefined behaviour sanitizer' printf "%s\n" ' --firmwarepath=VALUES search PATH for firmware files [share/qemu-' printf "%s\n" ' firmware]' + printf "%s\n" ' --gdb=VALUE Path to GDB' printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' printf "%s\n" ' --includedir=VALUE Header file directory [include]' printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for' @@ -323,6 +324,7 @@ _meson_option_parse() { --disable-fuzzing) printf "%s" -Dfuzzing=false ;; --enable-gcrypt) printf "%s" -Dgcrypt=enabled ;; --disable-gcrypt) printf "%s" -Dgcrypt=disabled ;; + --gdb=*) quote_sh "-Dgdb=$2" ;; --enable-gettext) printf "%s" -Dgettext=enabled ;; --disable-gettext) printf "%s" -Dgettext=disabled ;; --enable-gio) printf "%s" -Dgio=enabled ;; diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 2a0c5aa141..725630d308 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -77,6 +77,12 @@ foreach speed : ['quick', 'thorough'] test_env.set('PYTHONPATH', meson.project_source_root() / 'python:' + meson.current_source_dir()) + # Define the GDB environment variable if gdb is available. + gdb = get_option('gdb') + if gdb != '' + test_env.set('QEMU_TEST_GDB', gdb) + endif + foreach test : target_tests testname = '@0@-@1@'.format(target_base, test) if fs.exists('generic' / 'test_' + test + '.py') From aa7b1b726a0009c9147d9e2f64e0f6e82d4394af Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:15 +0000 Subject: [PATCH 11/17] tests/functional: Add GDB class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add GDB class, which provides methods to run GDB commands and capture their output. The GDB class is a wrapper around the pygdbmi module and interacts with GDB via GDB's machine interface (MI). Acked-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-5-gustavo.romero@linaro.org> [AJB: trimmed excess license text] Signed-off-by: Alex Bennée --- tests/functional/qemu_test/__init__.py | 1 + tests/functional/qemu_test/gdb.py | 86 ++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/functional/qemu_test/gdb.py diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 6e666a059f..60d19891bf 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -18,3 +18,4 @@ from .decorators import skipIfMissingCommands, skipIfNotMachine, \ skipIfMissingImports, skipIfOperatingSystem, skipLockedMemoryTest from .archive import archive_extract from .uncompress import uncompress +from .gdb import GDB diff --git a/tests/functional/qemu_test/gdb.py b/tests/functional/qemu_test/gdb.py new file mode 100644 index 0000000000..558d476a68 --- /dev/null +++ b/tests/functional/qemu_test/gdb.py @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# A simple interface module built around pygdbmi for handling GDB commands. +# +# Copyright (c) 2025 Linaro Limited +# +# Author: +# Gustavo Romero +# + +import re + + +class GDB: + """Provides methods to run and capture GDB command output.""" + + + def __init__(self, gdb_path, echo=True, suffix='# ', prompt="$ "): + from pygdbmi.gdbcontroller import GdbController + from pygdbmi.constants import GdbTimeoutError + type(self).TimeoutError = GdbTimeoutError + + gdb_cmd = [gdb_path, "-q", "--interpreter=mi2"] + self.gdbmi = GdbController(gdb_cmd) + self.echo = echo + self.suffix = suffix + self.prompt = prompt + self.response = None + self.cmd_output = None + + + def get_payload(self, response, kind): + output = [] + for o in response: + # Unpack payloads of the same type. + _type, _, payload, *_ = o.values() + if _type == kind: + output += [payload] + + # Some output lines do not end with \n but begin with it, + # so remove the leading \n and merge them with the next line + # that ends with \n. + lines = [line.lstrip('\n') for line in output] + lines = "".join(lines) + lines = lines.splitlines(keepends=True) + + return lines + + + def cli(self, cmd, timeout=32.0): + self.response = self.gdbmi.write(cmd, timeout_sec=timeout) + self.cmd_output = self.get_payload(self.response, kind="console") + if self.echo: + print(self.suffix + self.prompt + cmd) + + if len(self.cmd_output) > 0: + cmd_output = self.suffix.join(self.cmd_output) + print(self.suffix + cmd_output, end="") + + return self + + + def get_addr(self): + address_pattern = r"0x[0-9A-Fa-f]+" + cmd_output = "".join(self.cmd_output) # Concat output lines. + + match = re.search(address_pattern, cmd_output) + + return int(match[0], 16) if match else None + + + def get_log(self): + r = self.get_payload(self.response, kind="log") + r = "".join(r) + + return r + + + def get_console(self): + r = "".join(self.cmd_output) + + return r + + + def exit(self): + self.gdbmi.exit() From a0ad64c390b19242ae1d246d1ccfff77dcc752a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 3 Oct 2025 14:18:16 +0000 Subject: [PATCH 12/17] tests/functional: replace avocado process with subprocess MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The standard python subprocess.check_call method is better than avocado.utils.process as it doesn't require stuffing all args into a single string. Signed-off-by: Daniel P. Berrangé Reviewed-by: Alex Bennée Reviewed-by: Thomas Huth Message-ID: <20251003141820.85278-6-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- tests/functional/reverse_debugging.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/functional/reverse_debugging.py b/tests/functional/reverse_debugging.py index f9a1d395f1..a7ff47cb90 100644 --- a/tests/functional/reverse_debugging.py +++ b/tests/functional/reverse_debugging.py @@ -11,6 +11,7 @@ # later. See the COPYING file in the top-level directory. import os import logging +from subprocess import check_output from qemu_test import LinuxKernelTest, get_qemu_img from qemu_test.ports import Ports @@ -100,7 +101,6 @@ class ReverseDebugging(LinuxKernelTest): def reverse_debugging(self, shift=7, args=None): from avocado.utils import gdb - from avocado.utils import process logger = logging.getLogger('replay') @@ -111,8 +111,9 @@ class ReverseDebugging(LinuxKernelTest): if qemu_img is None: self.skipTest('Could not find "qemu-img", which is required to ' 'create the temporary qcow2 image') - cmd = '%s create -f qcow2 %s 128M' % (qemu_img, image_path) - process.run(cmd) + out = check_output([qemu_img, 'create', '-f', 'qcow2', image_path, '128M'], + encoding='utf8') + logger.info("qemu-img: %s" % out) replay_path = os.path.join(self.workdir, 'replay.bin') From db205774d1b2dc8e3a0e925f090a5b2f59b9bb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 3 Oct 2025 14:18:17 +0000 Subject: [PATCH 13/17] tests/functional: drop datadrainer class in reverse debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reverse debugging test uses the avocado datadrainer class to create a background thread that reads from the console socket and dumps it via python logger. Most tests log console output as a side effect of doing calls to match strings, but this test never tries to match anything. This isn't critical, so just drop the functionality. Signed-off-by: Daniel P. Berrangé Reviewed-by: Alex Bennée Reviewed-by: Thomas Huth Message-ID: <20251003141820.85278-7-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- tests/functional/reverse_debugging.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/functional/reverse_debugging.py b/tests/functional/reverse_debugging.py index a7ff47cb90..7fd8c7607f 100644 --- a/tests/functional/reverse_debugging.py +++ b/tests/functional/reverse_debugging.py @@ -34,8 +34,6 @@ class ReverseDebugging(LinuxKernelTest): endian_is_le = True def run_vm(self, record, shift, args, replay_path, image_path, port): - from avocado.utils import datadrainer - logger = logging.getLogger('replay') vm = self.get_vm(name='record' if record else 'replay') vm.set_console() @@ -53,10 +51,6 @@ class ReverseDebugging(LinuxKernelTest): if args: vm.add_args(*args) vm.launch() - console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(), - logger=self.log.getChild('console'), - stop_check=(lambda : not vm.is_running())) - console_drainer.start() return vm @staticmethod From fb8f35949384c3a00ef56528cb43e851c95268e6 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:18 +0000 Subject: [PATCH 14/17] tests/functional: Add decorator to skip test on missing env vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a decorator to skip tests on missing env variable(s). Multiple variable names can be provided and if one or more of them are not set in the test environment the test is skipped and the missing vars are printed out. Reviewed-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-8-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- tests/functional/qemu_test/__init__.py | 3 ++- tests/functional/qemu_test/decorators.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 60d19891bf..320193591b 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -15,7 +15,8 @@ from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest from .linuxkernel import LinuxKernelTest from .decorators import skipIfMissingCommands, skipIfNotMachine, \ skipFlakyTest, skipUntrustedTest, skipBigDataTest, skipSlowTest, \ - skipIfMissingImports, skipIfOperatingSystem, skipLockedMemoryTest + skipIfMissingImports, skipIfOperatingSystem, skipLockedMemoryTest, \ + skipIfMissingEnv from .archive import archive_extract from .uncompress import uncompress from .gdb import GDB diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py index c0d1567b14..b239295804 100644 --- a/tests/functional/qemu_test/decorators.py +++ b/tests/functional/qemu_test/decorators.py @@ -11,6 +11,24 @@ from unittest import skipIf, skipUnless from .cmd import which ''' +Decorator to skip execution of a test if the provided +environment variables are not set. +Example: + + @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1") +''' +def skipIfMissingEnv(*vars_): + missing_vars = [] + for var in vars_: + if os.getenv(var) == None: + missing_vars.append(var) + + has_vars = True if len(missing_vars) == 0 else False + + return skipUnless(has_vars, f"Missing env var(s): {', '.join(missing_vars)}") + +''' + Decorator to skip execution of a test if the list of command binaries is not available in $PATH. Example: From bddce216192122c51ff7fef171a16af9da514b61 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:19 +0000 Subject: [PATCH 15/17] tests/functional: Adapt reverse_debugging to run w/o Avocado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit removes Avocado as a dependency for running the reverse_debugging test. The main benefit, beyond eliminating an extra dependency, is that there is no longer any need to handle GDB packets manually. This removes the need for ad-hoc functions dealing with endianness and arch-specific register numbers, making the test easier to read. The timeout variable is also removed, since Meson now manages timeouts automatically. reverse_debugging now uses the pygdbmi module to interact with GDB, if it is available in the test environment, otherwise the test is skipped. GDB is detect via the QEMU_TEST_GDB env. variable. This commit also significantly improves the output for the test and now prints all the GDB commands used in sequence. It also adds some clarifications to existing comments, for example, clarifying that once the replay-break is reached, a SIGINT is captured in GDB. reverse_debugging is kept "skipped" for aarch64, ppc64, and x86_64, so won't run unless QEMU_TEST_FLAKY_TESTS=1 is set in the test environment, before running 'make check-functional' or 'meson test [...]'. Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-9-gustavo.romero@linaro.org> [AJB: it is and broke long line] Signed-off-by: Alex Bennée Tested-by: Thomas Huth --- tests/functional/reverse_debugging.py | 139 ++++++++++++++------------ 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/tests/functional/reverse_debugging.py b/tests/functional/reverse_debugging.py index 7fd8c7607f..68cfcb3985 100644 --- a/tests/functional/reverse_debugging.py +++ b/tests/functional/reverse_debugging.py @@ -1,19 +1,23 @@ -# Reverse debugging test -# # SPDX-License-Identifier: GPL-2.0-or-later # +# Reverse debugging test +# # Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited # # Author: # Pavel Dovgalyuk +# Gustavo Romero (Run without Avocado) # # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -import os + import logging +import os from subprocess import check_output -from qemu_test import LinuxKernelTest, get_qemu_img +from qemu_test import LinuxKernelTest, get_qemu_img, GDB, \ + skipIfMissingEnv, skipIfMissingImports from qemu_test.ports import Ports @@ -29,9 +33,7 @@ class ReverseDebugging(LinuxKernelTest): that the execution is stopped at the last of them. """ - timeout = 10 STEPS = 10 - endian_is_le = True def run_vm(self, record, shift, args, replay_path, image_path, port): logger = logging.getLogger('replay') @@ -54,47 +56,17 @@ class ReverseDebugging(LinuxKernelTest): return vm @staticmethod - def get_reg_le(g, reg): - res = g.cmd(b'p%x' % reg) - num = 0 - for i in range(len(res))[-2::-2]: - num = 0x100 * num + int(res[i:i + 2], 16) - return num - - @staticmethod - def get_reg_be(g, reg): - res = g.cmd(b'p%x' % reg) - return int(res, 16) - - def get_reg(self, g, reg): - # value may be encoded in BE or LE order - if self.endian_is_le: - return self.get_reg_le(g, reg) - else: - return self.get_reg_be(g, reg) - - def get_pc(self, g): - return self.get_reg(g, self.REG_PC) - - def check_pc(self, g, addr): - pc = self.get_pc(g) - if pc != addr: - self.fail('Invalid PC (read %x instead of %x)' % (pc, addr)) - - @staticmethod - def gdb_step(g): - g.cmd(b's', b'T05thread:01;') - - @staticmethod - def gdb_bstep(g): - g.cmd(b'bs', b'T05thread:01;') + def get_pc(gdb: GDB): + return gdb.cli("print $pc").get_addr() @staticmethod def vm_get_icount(vm): return vm.qmp('query-replay')['return']['icount'] - def reverse_debugging(self, shift=7, args=None): - from avocado.utils import gdb + @skipIfMissingImports("pygdbmi") # Required by GDB class + @skipIfMissingEnv("QEMU_TEST_GDB") + def reverse_debugging(self, gdb_arch, shift=7, args=None): + from qemu_test import GDB logger = logging.getLogger('replay') @@ -124,68 +96,107 @@ class ReverseDebugging(LinuxKernelTest): with Ports() as ports: port = ports.find_free_port() vm = self.run_vm(False, shift, args, replay_path, image_path, port) - logger.info('connecting to gdbstub') - g = gdb.GDBRemote('127.0.0.1', port, False, False) - g.connect() - r = g.cmd(b'qSupported') - if b'qXfer:features:read+' in r: - g.cmd(b'qXfer:features:read:target.xml:0,ffb') - if b'ReverseStep+' not in r: + + try: + logger.info('Connecting to gdbstub...') + self.reverse_debugging_run(vm, port, gdb_arch, last_icount) + logger.info('Test passed.') + except GDB.TimeoutError: + # Convert a GDB timeout exception into a unittest failure exception. + raise self.failureException("Timeout while connecting to or " + "communicating with gdbstub...") from None + except Exception: + # Re-throw exceptions from unittest, like the ones caused by fail(), + # skipTest(), etc. + raise + + def reverse_debugging_run(self, vm, port, gdb_arch, last_icount): + logger = logging.getLogger('replay') + + gdb_cmd = os.getenv('QEMU_TEST_GDB') + gdb = GDB(gdb_cmd) + + r = gdb.cli("set architecture").get_log() + if gdb_arch not in r: + self.skipTest(f"GDB does not support arch '{gdb_arch}'") + + gdb.cli("set debug remote 1") + + c = gdb.cli(f"target remote localhost:{port}").get_console() + if not f"Remote debugging using localhost:{port}" in c: + self.fail("Could not connect to gdbstub!") + + # Remote debug messages are in 'log' payloads. + r = gdb.get_log() + if 'ReverseStep+' not in r: self.fail('Reverse step is not supported by QEMU') - if b'ReverseContinue+' not in r: + if 'ReverseContinue+' not in r: self.fail('Reverse continue is not supported by QEMU') + gdb.cli("set debug remote 0") + logger.info('stepping forward') steps = [] # record first instruction addresses for _ in range(self.STEPS): - pc = self.get_pc(g) + pc = self.get_pc(gdb) logger.info('saving position %x' % pc) steps.append(pc) - self.gdb_step(g) + gdb.cli("stepi") # visit the recorded instruction in reverse order logger.info('stepping backward') for addr in steps[::-1]: - self.gdb_bstep(g) - self.check_pc(g, addr) logger.info('found position %x' % addr) + gdb.cli("reverse-stepi") + pc = self.get_pc(gdb) + if pc != addr: + logger.info('Invalid PC (read %x instead of %x)' % (pc, addr)) + self.fail('Reverse stepping failed!') # visit the recorded instruction in forward order logger.info('stepping forward') for addr in steps: - self.check_pc(g, addr) - self.gdb_step(g) logger.info('found position %x' % addr) + pc = self.get_pc(gdb) + if pc != addr: + logger.info('Invalid PC (read %x instead of %x)' % (pc, addr)) + self.fail('Forward stepping failed!') + gdb.cli("stepi") # set breakpoints for the instructions just stepped over logger.info('setting breakpoints') for addr in steps: - # hardware breakpoint at addr with len=1 - g.cmd(b'Z1,%x,1' % addr, b'OK') + gdb.cli(f"break *{hex(addr)}") # this may hit a breakpoint if first instructions are executed # again logger.info('continuing execution') vm.qmp('replay-break', icount=last_icount - 1) # continue - will return after pausing - # This could stop at the end and get a T02 return, or by - # re-executing one of the breakpoints and get a T05 return. - g.cmd(b'c') + # This can stop at the end of the replay-break and gdb gets a SIGINT, + # or by re-executing one of the breakpoints and gdb stops at a + # breakpoint. + gdb.cli("continue") + if self.vm_get_icount(vm) == last_icount - 1: logger.info('reached the end (icount %s)' % (last_icount - 1)) else: logger.info('hit a breakpoint again at %x (icount %s)' % - (self.get_pc(g), self.vm_get_icount(vm))) + (self.get_pc(gdb), self.vm_get_icount(vm))) logger.info('running reverse continue to reach %x' % steps[-1]) # reverse continue - will return after stopping at the breakpoint - g.cmd(b'bc', b'T05thread:01;') + gdb.cli("reverse-continue") # assume that none of the first instructions is executed again # breaking the order of the breakpoints - self.check_pc(g, steps[-1]) + pc = self.get_pc(gdb) + if pc != steps[-1]: + self.fail("'reverse-continue' did not hit the first PC in reverse order!") + logger.info('successfully reached %x' % steps[-1]) logger.info('exiting gdb and qemu') + gdb.exit() vm.shutdown() From 4d3eb329ccf34da76b0b7822eecaaacc6e6fe646 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 3 Oct 2025 14:18:20 +0000 Subject: [PATCH 16/17] tests/functional: Adapt arches to reverse_debugging w/o Avocado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reverse_debugging no longer depends on Avocado, so remove the import checks for Avocado, the per-arch endianness tweaks, and the per-arch register settings. All of these are now handled in the ReverseDebugging class, automatically. Reviewed-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Signed-off-by: Gustavo Romero Message-ID: <20251003141820.85278-10-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée --- tests/functional/aarch64/test_reverse_debug.py | 11 +++++------ tests/functional/ppc64/test_reverse_debug.py | 15 ++++++--------- tests/functional/x86_64/test_reverse_debug.py | 15 +++++---------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/tests/functional/aarch64/test_reverse_debug.py b/tests/functional/aarch64/test_reverse_debug.py index 8bc91ccfde..906f10aec5 100755 --- a/tests/functional/aarch64/test_reverse_debug.py +++ b/tests/functional/aarch64/test_reverse_debug.py @@ -2,25 +2,24 @@ # # SPDX-License-Identifier: GPL-2.0-or-later # -# Reverse debugging test +# Reverse debugging test for aarch64 # # Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited # # Author: # Pavel Dovgalyuk +# Gustavo Romero (Run without Avocado) # # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -from qemu_test import Asset, skipIfMissingImports, skipFlakyTest +from qemu_test import Asset, skipFlakyTest from reverse_debugging import ReverseDebugging -@skipIfMissingImports('avocado.utils') class ReverseDebugging_AArch64(ReverseDebugging): - REG_PC = 32 - ASSET_KERNEL = Asset( ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'), @@ -31,7 +30,7 @@ class ReverseDebugging_AArch64(ReverseDebugging): self.set_machine('virt') self.cpu = 'cortex-a53' kernel_path = self.ASSET_KERNEL.fetch() - self.reverse_debugging(args=('-kernel', kernel_path)) + self.reverse_debugging(gdb_arch='aarch64', args=('-kernel', kernel_path)) if __name__ == '__main__': diff --git a/tests/functional/ppc64/test_reverse_debug.py b/tests/functional/ppc64/test_reverse_debug.py index 5931adef5a..69551fb84d 100755 --- a/tests/functional/ppc64/test_reverse_debug.py +++ b/tests/functional/ppc64/test_reverse_debug.py @@ -2,39 +2,36 @@ # # SPDX-License-Identifier: GPL-2.0-or-later # -# Reverse debugging test +# Reverse debugging test for ppc64 # # Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited # # Author: # Pavel Dovgalyuk +# Gustavo Romero (Run without Avocado) # # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -from qemu_test import skipIfMissingImports, skipFlakyTest +from qemu_test import skipFlakyTest from reverse_debugging import ReverseDebugging -@skipIfMissingImports('avocado.utils') class ReverseDebugging_ppc64(ReverseDebugging): - REG_PC = 0x40 - @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") def test_ppc64_pseries(self): self.set_machine('pseries') # SLOF branches back to its entry point, which causes this test # to take the 'hit a breakpoint again' path. That's not a problem, # just slightly different than the other machines. - self.endian_is_le = False - self.reverse_debugging() + self.reverse_debugging(gdb_arch='powerpc:common64') @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") def test_ppc64_powernv(self): self.set_machine('powernv') - self.endian_is_le = False - self.reverse_debugging() + self.reverse_debugging(gdb_arch='powerpc:common64') if __name__ == '__main__': diff --git a/tests/functional/x86_64/test_reverse_debug.py b/tests/functional/x86_64/test_reverse_debug.py index d713e91e14..2b31ae8724 100755 --- a/tests/functional/x86_64/test_reverse_debug.py +++ b/tests/functional/x86_64/test_reverse_debug.py @@ -2,34 +2,29 @@ # # SPDX-License-Identifier: GPL-2.0-or-later # -# Reverse debugging test +# Reverse debugging test for x86_64 # # Copyright (c) 2020 ISP RAS +# Copyright (c) 2025 Linaro Limited # # Author: # Pavel Dovgalyuk +# Gustavo Romero (Run without Avocado) # # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -from qemu_test import skipIfMissingImports, skipFlakyTest +from qemu_test import skipFlakyTest from reverse_debugging import ReverseDebugging -@skipIfMissingImports('avocado.utils') class ReverseDebugging_X86_64(ReverseDebugging): - REG_PC = 0x10 - REG_CS = 0x12 - def get_pc(self, g): - return self.get_reg_le(g, self.REG_PC) \ - + self.get_reg_le(g, self.REG_CS) * 0x10 - @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2922") def test_x86_64_pc(self): self.set_machine('pc') # start with BIOS only - self.reverse_debugging() + self.reverse_debugging(gdb_arch='x86-64') if __name__ == '__main__': From 41f8f2be27736192bab29aa38380c9ebaae810fa Mon Sep 17 00:00:00 2001 From: Vladimir Lukianov <1844144@gmail.com> Date: Tue, 3 Jun 2025 14:54:59 +0200 Subject: [PATCH 17/17] record/replay: fix race condition on test_aarch64_reverse_debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures EVENT_INSTRUCTION written to replay.bin before EVENT_SHUTDOWN_HOST_QMP Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2921 Signed-off-by: Vladimir Lukianov <1844144@gmail.com> Message-ID: <20250603125459.17688-1-1844144@gmail.com> [AJB: fix re-base file mode] Signed-off-by: Alex Bennée --- replay/replay.c | 2 ++ tests/functional/aarch64/test_reverse_debug.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/replay/replay.c b/replay/replay.c index a3e24c967a..b2121788c1 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -263,6 +263,8 @@ bool replay_has_interrupt(void) void replay_shutdown_request(ShutdownCause cause) { + replay_save_instructions(); + if (replay_mode == REPLAY_MODE_RECORD) { g_assert(replay_mutex_locked()); replay_put_event(EVENT_SHUTDOWN + cause); diff --git a/tests/functional/aarch64/test_reverse_debug.py b/tests/functional/aarch64/test_reverse_debug.py index 906f10aec5..ec3348c96d 100755 --- a/tests/functional/aarch64/test_reverse_debug.py +++ b/tests/functional/aarch64/test_reverse_debug.py @@ -25,7 +25,6 @@ class ReverseDebugging_AArch64(ReverseDebugging): 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'), '7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7') - @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2921") def test_aarch64_virt(self): self.set_machine('virt') self.cpu = 'cortex-a53'