From nobody Sun Sep 28 17:04:53 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1758863914; cv=none; d=zohomail.com; s=zohoarc; b=VHWYTePrX6zpxBmYtj9P75q4ssuL/gmU+feus/ZYO47uxTqzUD7vtbajDEKn4E2LOMFvrRV9M59rs+7z1f7OvK8DxEa9eumipBfihB/DfwNWzYS92akFxifJTVNBwu7UeEiBVqUDugGJNNlMUYhO45vvWAKLtNq4mvS39S7HzC4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1758863914; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=YK36azP6oOgCQtElb4HgeO0m9NeDE6FMPmb4sfTtQPg=; b=XS/Y8JvSI5hVgCTzSQErkWEZPpG+CmdeJID4JkYIvbVTfz5PmNVpg90b02NYeWioUDP51vve7PxKI8EQVnaOrKCPLNb9XTl6DMbTXGjzUWIdG+m7jDr8nrsU+HzTbRxkJcwOkkJY1+pQZW2BWlaDuTrV7aG0nTnI5yQP6QChSFY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17588639143071005.2912392334146; Thu, 25 Sep 2025 22:18:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1v20p9-0004sx-VT; Fri, 26 Sep 2025 01:16:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1v20p4-0004pb-5G for qemu-devel@nongnu.org; Fri, 26 Sep 2025 01:16:46 -0400 Received: from mail-pg1-x52c.google.com ([2607:f8b0:4864:20::52c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1v20ov-00061p-3x for qemu-devel@nongnu.org; Fri, 26 Sep 2025 01:16:45 -0400 Received: by mail-pg1-x52c.google.com with SMTP id 41be03b00d2f7-b555b0fb839so1298381a12.3 for ; Thu, 25 Sep 2025 22:16:32 -0700 (PDT) Received: from gromero0.. (189-47-45-49.dsl.telesp.net.br. [189.47.45.49]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-27ed672a51fsm42160085ad.63.2025.09.25.22.16.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Sep 2025 22:16:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1758863788; x=1759468588; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YK36azP6oOgCQtElb4HgeO0m9NeDE6FMPmb4sfTtQPg=; b=mMx6BhwK82iQYoLM10RuvAfgG6/HPnlNFbQCDFL+EhxuaMICIL+8JPU9HeY7Onhr96 2uOIV9F5bmRPL7Syo88tR7dYfoaCW5G6HCWpP95Hdlh8RQImZW5aU/f2c72lpnB5FbDV wsppa6O1urII/x1JzBhrJw8qmBVdzvDM5qHvvuX4UpdUNMos6aTeym/57Uj8IyDXkad3 3+waMFZcPLzfoSiBgeZbUDY/JI1cmGqKYiKz2ZufXexpiJd2yJlM4IwwPOhTSIN/9rJc YoBzmEAmYULB7Wao6k0EMGPmm1vPVTKEC8OXicntVzOEI6ShR+kWdRLJai6Z3w/G7crb /qYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1758863788; x=1759468588; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=YK36azP6oOgCQtElb4HgeO0m9NeDE6FMPmb4sfTtQPg=; b=sfE4TKjOPdbUEyi7EkZfkjuyTOVgK/UxfK7ySNIb/3VtSCNc6Ia1ynqPFnjacrP0+o h0jCioOQKbNBqP7vR5WFnhsNRXqt5lEQZSUkAz2OQzcXfwkZTKuFk9XTa7mLKpVDguoW 5LgYh2TdL94zkI5cHcbCz13pdu9OdKYyPdz4yKn4JaRW6+/g0qTtcEWY2uLYN30ZeQaO wEtujvI9lkRt7FKlGoEw8+RsgIDlxVvOn1CeTA+7dkh0x750Ra0BsfDEjbxvraty/uKL ddalvX3gU4ZpF8TW18+XAhgLvkg99JuyQvkaTxA71pkUE9hqbTwWzWtjjkFVIRwl4QiG Z2ww== X-Gm-Message-State: AOJu0YxiYOfNq+YD8mlzos50n7DxP3wqyOFHowtXymC0Ike1Xm88UohT wT/F4LdT4aQtsY+9h+fDPB/tjnGHjA27uTIxjzxCqx/S5yVFcrDg4svWZnGHBYwfvKZ7N0M3s1L Yfb8/ X-Gm-Gg: ASbGncsWRnbEX6Dq9y7ySCLAuIBqPIw0Fy4Xu0XxPogf+A3bDBjomOhyTL+YEneY4G0 E1xKS7A9plJTmMFmbzl7MRfbazXLZgEy9LChL5PpefRLwyDEaWzsnM2jwP/CQbxuFZC6Va9u3do arU6QYmS3ZxYPvKCU2/HLohS9Uia0FB15vlZuwct0uZvfAoyaMmk9pk+LCpdE5cm6NcRB+IuD70 8fjyVgw2UwP3s19ca4brABmL0xxIr57udqWpg+IrwEQWUdflRRDMiB0HgJgSQfXam8u3RjX6sDV h/OnpyATB5gq+HfGgB2qHtCQTApPvzhqM/WXXE/prabs52Re+agxMEKLcvDIIwFG06pX2YO70cT FFvOU0wwYCUglxHb3MIKCg2EZWGIwwmXTYvMKJL5g7puM/XPSRMlD/kr1o8pdQcbuiW7n X-Google-Smtp-Source: AGHT+IH+Q9C1XpS4cbBUrNuuddIisnUeD8gMNtxRGplXbkIoZXsBEjwQDoZv+BMrrmtBKAJrXYVjRg== X-Received: by 2002:a17:903:3c26:b0:264:ede2:683d with SMTP id d9443c01a7336-27ed4adb732mr60136045ad.56.1758863788431; Thu, 25 Sep 2025 22:16:28 -0700 (PDT) From: Gustavo Romero To: qemu-devel@nongnu.org, alex.bennee@linaro.org, thuth@redhat.com, berrange@redhat.com Cc: qemu-arm@nongnu.org, gustavo.romero@linaro.org, manos.pitsidianakis@linaro.org, peter.maydell@linaro.org Subject: [PATCH v4 8/9] tests/functional: Adapt reverse_debugging to run w/o Avocado Date: Fri, 26 Sep 2025 05:15:41 +0000 Message-Id: <20250926051542.104432-9-gustavo.romero@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250926051542.104432-1-gustavo.romero@linaro.org> References: <20250926051542.104432-1-gustavo.romero@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::52c; envelope-from=gustavo.romero@linaro.org; helo=mail-pg1-x52c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1758863916862116600 Content-Type: text/plain; charset="utf-8" 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's 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=3D1 is set in the test environment, before running 'make check-functional' or 'meson test [...]'. Signed-off-by: Gustavo Romero --- tests/functional/reverse_debugging.py | 127 +++++++++++++------------- 1 file changed, 61 insertions(+), 66 deletions(-) diff --git a/tests/functional/reverse_debugging.py b/tests/functional/rever= se_debugging.py index 7fd8c7607f..4e4200dd48 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 pygdbmi.constants import GdbTimeoutError from subprocess import check_output =20 -from qemu_test import LinuxKernelTest, get_qemu_img +from qemu_test import LinuxKernelTest, get_qemu_img, GDB, skipIfMissingEnv from qemu_test.ports import Ports =20 =20 @@ -29,9 +33,7 @@ class ReverseDebugging(LinuxKernelTest): that the execution is stopped at the last of them. """ =20 - timeout =3D 10 STEPS =3D 10 - endian_is_le =3D True =20 def run_vm(self, record, shift, args, replay_path, image_path, port): logger =3D logging.getLogger('replay') @@ -53,49 +55,11 @@ def run_vm(self, record, shift, args, replay_path, imag= e_path, port): vm.launch() return vm =20 - @staticmethod - def get_reg_le(g, reg): - res =3D g.cmd(b'p%x' % reg) - num =3D 0 - for i in range(len(res))[-2::-2]: - num =3D 0x100 * num + int(res[i:i + 2], 16) - return num - - @staticmethod - def get_reg_be(g, reg): - res =3D 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 =3D self.get_pc(g) - if pc !=3D 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;') - @staticmethod def vm_get_icount(vm): return vm.qmp('query-replay')['return']['icount'] =20 def reverse_debugging(self, shift=3D7, args=3DNone): - from avocado.utils import gdb - logger =3D logging.getLogger('replay') =20 # create qcow2 for snapshots @@ -124,68 +88,99 @@ def reverse_debugging(self, shift=3D7, args=3DNone): with Ports() as ports: port =3D ports.find_free_port() vm =3D self.run_vm(False, shift, args, replay_path, image_path= , port) - logger.info('connecting to gdbstub') - g =3D gdb.GDBRemote('127.0.0.1', port, False, False) - g.connect() - r =3D 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, last_icount) + logger.info('Test passed.') + except GdbTimeoutError: + self.fail("Connection to gdbstub timeouted...") + + @skipIfMissingEnv("QEMU_TEST_GDB") + def reverse_debugging_run(self, vm, port, last_icount): + logger =3D logging.getLogger('replay') + + gdb_cmd =3D os.getenv('QEMU_TEST_GDB') + gdb =3D GDB(gdb_cmd) + + gdb.cli("set debug remote 1") + + c =3D 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 =3D 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') =20 + gdb.cli("set debug remote 0") + logger.info('stepping forward') steps =3D [] # record first instruction addresses for _ in range(self.STEPS): - pc =3D self.get_pc(g) + pc =3D gdb.cli("print $pc").get_addr() logger.info('saving position %x' % pc) steps.append(pc) - self.gdb_step(g) + gdb.cli("stepi") =20 # 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 =3D gdb.cli("print $pc").get_addr() + if pc !=3D addr: + logger.info('Invalid PC (read %x instead of %x)' % (pc, ad= dr)) + self.fail('Reverse stepping failed!') =20 # 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 =3D gdb.cli("print $pc").get_addr() + if pc !=3D addr: + logger.info('Invalid PC (read %x instead of %x)' % (pc, ad= dr)) + self.fail('Forward stepping failed!') + gdb.cli("stepi") =20 # set breakpoints for the instructions just stepped over logger.info('setting breakpoints') for addr in steps: - # hardware breakpoint at addr with len=3D1 - g.cmd(b'Z1,%x,1' % addr, b'OK') + gdb.cli(f"break *{hex(addr)}") =20 # this may hit a breakpoint if first instructions are executed # again logger.info('continuing execution') vm.qmp('replay-break', icount=3Dlast_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 SIGI= NT, + # or by re-executing one of the breakpoints and gdb stops at a + # breakpoint. + gdb.cli("continue") + + pc =3D gdb.cli("print $pc").get_addr() if self.vm_get_icount(vm) =3D=3D 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))) + (pc, self.vm_get_icount(vm))) =20 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") =20 # assume that none of the first instructions is executed again # breaking the order of the breakpoints - self.check_pc(g, steps[-1]) + pc =3D gdb.cli("print $pc").get_addr() + if pc !=3D steps[-1]: + self.fail("'reverse-continue' did not hit the first PC in reve= rse order!") + logger.info('successfully reached %x' % steps[-1]) =20 logger.info('exiting gdb and qemu') + gdb.exit() vm.shutdown() --=20 2.34.1