# SPDX-License-Identifier: GPL-2.0-or-later
#
# Reverse debugging test
#
# Copyright (c) 2020 ISP RAS
# Copyright (c) 2025 Linaro Limited
#
# Author:
#  Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
#  Gustavo Romero <gustavo.romero@linaro.org> (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 logging
import os
from subprocess import check_output

from qemu_test import LinuxKernelTest, get_qemu_img, GDB, \
    skipIfMissingEnv, skipIfMissingImports
from qemu_test.ports import Ports


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.
    """

    STEPS = 10

    def run_vm(self, record, shift, args, replay_path, image_path, port):
        vm = self.get_vm(name='record' if record else 'replay')
        vm.set_console()
        if record:
            self.log.info('recording the execution...')
            mode = 'record'
        else:
            self.log.info('replaying the execution...')
            mode = 'replay'
            vm.add_args('-gdb', 'tcp::%d' % port, '-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_pc(gdb: GDB):
        return gdb.cli("print $pc").get_addr()

    @staticmethod
    def vm_get_icount(vm):
        return vm.qmp('query-replay')['return']['icount']

    @skipIfMissingImports("pygdbmi") # Required by GDB class
    @skipIfMissingEnv("QEMU_TEST_GDB")
    def reverse_debugging(self, gdb_arch, shift=7, args=None, big_endian=False):
        from qemu_test import GDB

        self.require_accelerator("tcg")

        # create qcow2 for snapshots
        self.log.info('creating qcow2 image for VM snapshots')
        image_path = os.path.join(self.workdir, 'disk.qcow2')
        qemu_img = get_qemu_img(self)
        if qemu_img is None:
            self.skipTest('Could not find "qemu-img", which is required to '
                          'create the temporary qcow2 image')
        out = check_output([qemu_img, 'create', '-f', 'qcow2', image_path, '128M'],
                           encoding='utf8')
        self.log.info("qemu-img: %s" % out)

        replay_path = os.path.join(self.workdir, 'replay.bin')

        # record the log
        vm = self.run_vm(True, shift, args, replay_path, image_path, -1)
        while self.vm_get_icount(vm) <= self.STEPS:
            pass
        last_icount = self.vm_get_icount(vm)
        vm.shutdown()

        self.log.info("recorded log with %s+ steps" % last_icount)

        # replay and run debug commands
        with Ports() as ports:
            port = ports.find_free_port()
            vm = self.run_vm(False, shift, args, replay_path, image_path, port)

        try:
            self.log.info('Connecting to gdbstub...')
            gdb_cmd = os.getenv('QEMU_TEST_GDB')
            gdb = GDB(gdb_cmd)
            try:
                if big_endian:
                    gdb.cli("set endian big")
                self.reverse_debugging_run(gdb, vm, port, gdb_arch, last_icount)
            finally:
                self.log.info('exiting gdb and qemu')
                gdb.exit()
                vm.shutdown()
            self.log.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, gdb, vm, port, gdb_arch, last_icount):
        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 'ReverseContinue+' not in r:
            self.fail('Reverse continue is not supported by QEMU')

        gdb.cli("set debug remote 0")

        self.log.info('stepping forward')
        steps = []
        # record first instruction addresses
        for _ in range(self.STEPS):
            pc = self.get_pc(gdb)
            self.log.info('saving position %x' % pc)
            steps.append(pc)
            gdb.cli("stepi")

        # visit the recorded instruction in reverse order
        self.log.info('stepping backward')
        for addr in steps[::-1]:
            self.log.info('found position %x' % addr)
            gdb.cli("reverse-stepi")
            pc = self.get_pc(gdb)
            if pc != addr:
                self.log.info('Invalid PC (read %x instead of %x)' % (pc, addr))
                self.fail('Reverse stepping failed!')

        # visit the recorded instruction in forward order
        self.log.info('stepping forward')
        for addr in steps:
            self.log.info('found position %x' % addr)
            pc = self.get_pc(gdb)
            if pc != addr:
                self.log.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
        self.log.info('setting breakpoints')
        for addr in steps:
            gdb.cli(f"break *{hex(addr)}")

        # this may hit a breakpoint if first instructions are executed
        # again
        self.log.info('continuing execution')
        vm.qmp('replay-break', icount=last_icount - 1)
        # continue - will return after pausing
        # 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:
            self.log.info('reached the end (icount %s)' % (last_icount - 1))
        else:
            self.log.info('hit a breakpoint again at %x (icount %s)' %
                        (self.get_pc(gdb), self.vm_get_icount(vm)))

        self.log.info('running reverse continue to reach %x' % steps[-1])
        # reverse continue - will return after stopping at the breakpoint
        gdb.cli("reverse-continue")

        # assume that none of the first instructions is executed again
        # breaking the order of the breakpoints
        pc = self.get_pc(gdb)
        if pc != steps[-1]:
            self.fail("'reverse-continue' did not hit the first PC in reverse order!")

        self.log.info('successfully reached %x' % steps[-1])
