[PATCH 6/7] tests/avocado: reverse-debugging cope with re-executing breakpoints

Nicholas Piggin posted 7 patches 2 years, 6 months ago
Maintainers: Daniel Henrique Barboza <danielhb413@gmail.com>, "Cédric Le Goater" <clg@kaod.org>, David Gibson <david@gibson.dropbear.id.au>, Greg Kurz <groug@kaod.org>, Nicholas Piggin <npiggin@gmail.com>, Harsh Prateek Bora <harshpb@linux.ibm.com>, Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>, Paolo Bonzini <pbonzini@redhat.com>, Cleber Rosa <crosa@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Wainer dos Santos Moschetta <wainersm@redhat.com>, Beraldo Leal <bleal@redhat.com>
[PATCH 6/7] tests/avocado: reverse-debugging cope with re-executing breakpoints
Posted by Nicholas Piggin 2 years, 6 months ago
The reverse-debugging test creates a trace, then replays it and:

1. Steps the first 10 instructions and records their addresses.
2. Steps backward and verifies their addresses match.
3. Runs to (near) the end of the trace.
4. Sets breakpoints on the first 10 instructions.
5. Continues backward and verifies execution stops at the last
   breakpoint.

Step 5 breaks if any of the other 9 breakpoints are re-executed in the
trace after the 10th instruction is run, because those will be
unexpectedly hit when reverse continuing. This situation does arise
with the ppc pseries machine, the SLOF bios branches to its own entry
point.

Permit this breakpoint re-execution by switching steps 4 and 5, so that
the trace will be run to the end *or* the next breakpoint hit.
Reversing from there to the 10th intsruction will not hit another
breakpoint, by definition.

Another step is added between steps 2 and 3, which steps forward over
the first 10 instructions and verifies their addresses, to support this.

Cc: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 tests/avocado/reverse_debugging.py | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/tests/avocado/reverse_debugging.py b/tests/avocado/reverse_debugging.py
index 680c314cfc..7d1a478df1 100644
--- a/tests/avocado/reverse_debugging.py
+++ b/tests/avocado/reverse_debugging.py
@@ -150,16 +150,33 @@ def reverse_debugging(self, shift=7, args=None):
             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;')
+        # 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)
 
+        # 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')
 
+        # 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')
+        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)))
+
         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;')
-- 
2.40.1
Re: [PATCH 6/7] tests/avocado: reverse-debugging cope with re-executing breakpoints
Posted by Pavel Dovgalyuk 2 years, 6 months ago
Reviewed-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>

On 26.07.2023 21:35, Nicholas Piggin wrote:
> The reverse-debugging test creates a trace, then replays it and:
> 
> 1. Steps the first 10 instructions and records their addresses.
> 2. Steps backward and verifies their addresses match.
> 3. Runs to (near) the end of the trace.
> 4. Sets breakpoints on the first 10 instructions.
> 5. Continues backward and verifies execution stops at the last
>     breakpoint.
> 
> Step 5 breaks if any of the other 9 breakpoints are re-executed in the
> trace after the 10th instruction is run, because those will be
> unexpectedly hit when reverse continuing. This situation does arise
> with the ppc pseries machine, the SLOF bios branches to its own entry
> point.
> 
> Permit this breakpoint re-execution by switching steps 4 and 5, so that
> the trace will be run to the end *or* the next breakpoint hit.
> Reversing from there to the 10th intsruction will not hit another
> breakpoint, by definition.
> 
> Another step is added between steps 2 and 3, which steps forward over
> the first 10 instructions and verifies their addresses, to support this.
> 
> Cc: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
>   tests/avocado/reverse_debugging.py | 25 +++++++++++++++++++++----
>   1 file changed, 21 insertions(+), 4 deletions(-)
> 
> diff --git a/tests/avocado/reverse_debugging.py b/tests/avocado/reverse_debugging.py
> index 680c314cfc..7d1a478df1 100644
> --- a/tests/avocado/reverse_debugging.py
> +++ b/tests/avocado/reverse_debugging.py
> @@ -150,16 +150,33 @@ def reverse_debugging(self, shift=7, args=None):
>               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;')
> +        # 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)
>   
> +        # 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')
>   
> +        # 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')
> +        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)))
> +
>           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;')