From: "Alex Bennée" <alex.bennee@linaro.org>
To: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
Cc: kwolf@redhat.com, wrampazz@redhat.com, ehabkost@redhat.com,
mtosatti@redhat.com, qemu-devel@nongnu.org, armbru@redhat.com,
stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com,
mreitz@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com,
rth@twiddle.net
Subject: Re: [PATCH v3 15/15] tests/acceptance: add reverse debugging test
Date: Tue, 08 Sep 2020 14:01:24 +0100 [thread overview]
Message-ID: <87tuw8pgm3.fsf@linaro.org> (raw)
In-Reply-To: <159903463379.28509.561479052940546124.stgit@pasha-ThinkPad-X280>
Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> writes:
> From: Pavel Dovgalyuk <Pavel.Dovgaluk@gmail.com>
>
> This is a test for GDB reverse debugging commands: reverse step and reverse continue.
> Every test in this suite consists of two phases: record and replay.
> Recording saves the execution of some instructions and makes an initial
> VM snapshot to allow reverse execution.
> Replay saves the order of the first instructions and then checks that they
> are executed backwards in the correct order.
> After that the execution is replayed to the end, and reverse continue
> command is checked by setting several breakpoints, and asserting
> that the execution is stopped at the last of them.
>
> Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
> ---
> MAINTAINERS | 1
> tests/acceptance/reverse_debugging.py | 203 +++++++++++++++++++++++++++++++++
> 2 files changed, 204 insertions(+)
> create mode 100644 tests/acceptance/reverse_debugging.py
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e49af700c9..76450f1bdf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2644,6 +2644,7 @@ F: include/sysemu/replay.h
> F: docs/replay.txt
> F: stubs/replay.c
> F: tests/acceptance/replay_kernel.py
> +F: tests/acceptance/reverse_debugging.py
> F: qapi/replay.json
>
> IOVA Tree
> diff --git a/tests/acceptance/reverse_debugging.py b/tests/acceptance/reverse_debugging.py
> new file mode 100644
> index 0000000000..dda42e1c1a
> --- /dev/null
> +++ b/tests/acceptance/reverse_debugging.py
> @@ -0,0 +1,203 @@
> +# Reverse debugging test
> +#
> +# Copyright (c) 2020 ISP RAS
> +#
> +# Author:
> +# Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
> +#
> +# 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
> +
> +from avocado_qemu import BUILD_DIR
> +from avocado.utils import gdb
> +from avocado.utils import process
> +from avocado.utils.path import find_command
> +from boot_linux_console import LinuxKernelTest
> +
> +class ReverseDebugging(LinuxKernelTest):
> + """
> + Test GDB reverse debugging commands: reverse step and reverse continue.
> + Recording saves the execution of some instructions and makes an initial
> + VM snapshot to allow reverse execution.
> + Replay saves the order of the first instructions and then checks that they
> + are executed backwards in the correct order.
> + After that the execution is replayed to the end, and reverse continue
> + command is checked by setting several breakpoints, and asserting
> + 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):
> + logger = logging.getLogger('replay')
> + vm = self.get_vm()
> + vm.set_console()
> + if record:
> + logger.info('recording the execution...')
> + mode = 'record'
> + else:
> + logger.info('replaying the execution...')
> + mode = 'replay'
> + vm.add_args('-s', '-S')
> + vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s,rrsnapshot=init' %
> + (shift, mode, replay_path),
> + '-net', 'none')
> + vm.add_args('-drive', 'file=%s,if=none' % image_path)
> + if args:
> + vm.add_args(*args)
> + vm.launch()
> + 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)
These seem a little hacky. Can't we issue normal gdb commands. In the
SVE tests I use:
frame = gdb.selected_frame()
for i in range(0, 32):
rname = "z%d" % (i)
zreg = frame.read_register(rname)
which works with the symbolic name and doesn't need endian tricks to
sort it out.
> +
> + 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;')
Hmm so these are packet commands? Can't we access via the python API? Clebber?
> +
> + @staticmethod
> + def vm_get_icount(vm):
> + return vm.qmp('query-replay')['return']['icount']
> +
> + def reverse_debugging(self, shift=7, args=None):
> + logger = logging.getLogger('replay')
> +
> + # create qcow2 for snapshots
> + logger.info('creating qcow2 image for VM snapshots')
> + image_path = os.path.join(self.workdir, 'disk.qcow2')
> + qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
> + if not os.path.exists(qemu_img):
> + qemu_img = find_command('qemu-img', False)
> + if qemu_img is False:
> + self.cancel('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)
> +
> + replay_path = os.path.join(self.workdir, 'replay.bin')
> +
> + # record the log
> + vm = self.run_vm(True, shift, args, replay_path, image_path)
> + while self.vm_get_icount(vm) <= self.STEPS:
> + pass
> + last_icount = self.vm_get_icount(vm)
> + vm.shutdown()
> +
> + logger.info("recorded log with %s+ steps" % last_icount)
> +
> + # replay and run debug commands
> + vm = self.run_vm(False, shift, args, replay_path, image_path)
> + logger.info('connecting to gdbstub')
> + g = gdb.GDBRemote('127.0.0.1', 1234, 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:
> + self.fail('Reverse step is not supported by QEMU')
> + if b'ReverseContinue+' not in r:
> + self.fail('Reverse continue is not supported by QEMU')
> +
> + logger.info('stepping forward')
> + steps = []
> + # record first instruction addresses
> + for _ in range(self.STEPS):
> + pc = self.get_pc(g)
> + logger.info('saving position %x' % pc)
> + steps.append(pc)
> + self.gdb_step(g)
> +
> + # 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)
> +
> + logger.info('seeking to the end (icount %s)' % (last_icount - 1))
> + vm.qmp('replay-break', icount=last_icount - 1)
> + # continue - will return after pausing
> + g.cmd(b'c', b'T02thread:01;')
> +
> + logger.info('setting breakpoints')
> + for addr in steps:
> + # hardware breakpoint at addr with len=1
> + g.cmd(b'Z1,%x,1' % addr, b'OK')
> +
> + 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;')
> +
> + # assume that none of the first instructions is executed again
> + # breaking the order of the breakpoints
> + self.check_pc(g, steps[-1])
> + logger.info('successfully reached %x' % steps[-1])
> +
> + logger.info('exitting gdb and qemu')
> + vm.shutdown()
> +
> +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
> +
> + def test_x86_64_pc(self):
> + """
> + :avocado: tags=arch:x86_64
> + :avocado: tags=machine:pc
> + """
> + # start with BIOS only
> + self.reverse_debugging()
> +
> +class ReverseDebugging_AArch64(ReverseDebugging):
> + REG_PC = 32
> +
> + def test_aarch64_virt(self):
> + """
> + :avocado: tags=arch:aarch64
> + :avocado: tags=machine:virt
> + :avocado: tags=cpu:cortex-a53
> + """
> + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
> + '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
> + '/vmlinuz')
> + kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
> + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
> +
> + self.reverse_debugging(
> + args=('-kernel', kernel_path, '-cpu', 'cortex-a53'))
Quibbles aside it's excellent to have a test that exercises the
functionality.
--
Alex Bennée
prev parent reply other threads:[~2020-09-08 13:02 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-02 8:15 [PATCH v3 00/15] Reverse debugging Pavel Dovgalyuk
2020-09-02 8:15 ` [PATCH v3 01/15] replay: don't record interrupt poll Pavel Dovgalyuk
2020-09-07 10:17 ` Alex Bennée
2020-09-02 8:15 ` [PATCH v3 02/15] replay: provide an accessor for rr filename Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 03/15] qcow2: introduce icount field for snapshots Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 04/15] migration: " Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 05/15] iotests: update snapshot test for new output format Pavel Dovgalyuk
2020-09-07 15:26 ` Alex Bennée
2020-09-07 15:41 ` Pavel Dovgalyuk
2020-09-07 16:00 ` Alex Bennée
2020-09-07 16:05 ` Pavel Dovgalyuk
2020-09-08 13:10 ` Eric Blake
2020-09-02 8:16 ` [PATCH v3 06/15] qapi: introduce replay.json for record/replay-related stuff Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 07/15] replay: introduce info hmp/qmp command Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 08/15] replay: introduce breakpoint at the specified step Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 09/15] replay: implement replay-seek command Pavel Dovgalyuk
2020-09-07 12:45 ` Alex Bennée
2020-09-07 13:32 ` Pavel Dovgalyuk
2020-09-07 12:58 ` Alex Bennée
2020-09-07 13:27 ` Pavel Dovgalyuk
2020-09-07 14:59 ` Alex Bennée
2020-09-07 15:46 ` Pavel Dovgalyuk
2020-09-07 16:25 ` Alex Bennée
2020-09-08 7:44 ` Pavel Dovgalyuk
2020-09-08 9:13 ` Alex Bennée
2020-09-08 10:57 ` Pavel Dovgalyuk
2020-09-08 11:10 ` Alex Bennée
2020-09-08 12:15 ` Pavel Dovgalyuk
2020-09-08 10:54 ` Pavel Dovgalyuk
2020-09-02 8:16 ` [PATCH v3 10/15] replay: flush rr queue before loading the vmstate Pavel Dovgalyuk
2020-09-07 13:37 ` Alex Bennée
2020-09-02 8:16 ` [PATCH v3 11/15] gdbstub: add reverse step support in replay mode Pavel Dovgalyuk
2020-09-07 16:30 ` Alex Bennée
2020-09-08 11:16 ` Alex Bennée
2020-09-02 8:16 ` [PATCH v3 12/15] gdbstub: add reverse continue " Pavel Dovgalyuk
2020-09-02 8:17 ` [PATCH v3 13/15] replay: describe reverse debugging in docs/replay.txt Pavel Dovgalyuk
2020-09-08 11:27 ` Alex Bennée
2020-09-08 12:57 ` Pavel Dovgalyuk
2020-09-02 8:17 ` [PATCH v3 14/15] tests: bump avocado version Pavel Dovgalyuk
2020-09-02 17:02 ` Willian Rampazzo
2020-09-04 21:39 ` Cleber Rosa
2020-09-02 8:17 ` [PATCH v3 15/15] tests/acceptance: add reverse debugging test Pavel Dovgalyuk
2020-09-08 13:01 ` Alex Bennée [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87tuw8pgm3.fsf@linaro.org \
--to=alex.bennee@linaro.org \
--cc=armbru@redhat.com \
--cc=crosa@redhat.com \
--cc=ehabkost@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=mtosatti@redhat.com \
--cc=pavel.dovgalyuk@ispras.ru \
--cc=pbonzini@redhat.com \
--cc=philmd@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=rth@twiddle.net \
--cc=stefanha@redhat.com \
--cc=wrampazz@redhat.com \
--cc=zhiwei_liu@c-sky.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.