[Dexter] Add timeout options

Adds a pair of options for Dexter that allow the user to specify a
timeout duration. These options are:

* --timeout-total: Times out if the total run-time of the debugger session
  exceeds <timeout-total> seconds.
* --timeout-breakpoint: Times out if the time without hitting a
  breakpoint exceeds <timeout-breakpoint> seconds.

Reviewed By: Orlando

Differential Revision: https://reviews.llvm.org/D145063
This commit is contained in:
Stephen Tozer
2023-03-01 13:05:11 +00:00
parent 893ce5759f
commit ee5617dc71
4 changed files with 82 additions and 6 deletions

View File

@@ -16,6 +16,7 @@ from dex.debugger.DebuggerControllers.ControllerHelpers import in_source_file, u
from dex.debugger.DebuggerControllers.DebuggerControllerBase import DebuggerControllerBase
from dex.debugger.DebuggerBase import DebuggerBase
from dex.utils.Exceptions import DebuggerException
from dex.utils.Timeout import Timeout
class BreakpointRange:
@@ -140,10 +141,26 @@ class ConditionalController(DebuggerControllerBase):
time.sleep(self._pause_between_steps)
exit_desired = False
timed_out = False
total_timeout = Timeout(self.context.options.timeout_total)
while not self.debugger.is_finished:
while self.debugger.is_running:
pass
breakpoint_timeout = Timeout(self.context.options.timeout_breakpoint)
while self.debugger.is_running and not timed_out:
# Check to see whether we've timed out while we're waiting.
if total_timeout.timed_out():
self.context.logger.error('Debugger session has been '
f'running for {total_timeout.elapsed}s, timeout reached!')
timed_out = True
if breakpoint_timeout.timed_out():
self.context.logger.error(f'Debugger session has not '
f'hit a breakpoint for {breakpoint_timeout.elapsed}s, timeout '
'reached!')
timed_out = True
if timed_out:
break
step_info = self.debugger.get_step_info(self._watches, self._step_index)
if step_info.current_frame:

View File

@@ -13,6 +13,7 @@ import time
from dex.debugger.DebuggerControllers.DebuggerControllerBase import DebuggerControllerBase
from dex.debugger.DebuggerControllers.ControllerHelpers import in_source_file, update_step_watches
from dex.utils.Exceptions import DebuggerException, LoadDebuggerException
from dex.utils.Timeout import Timeout
class EarlyExitCondition(object):
def __init__(self, on_line, hit_count, expression, values):
@@ -81,12 +82,25 @@ class DefaultController(DebuggerControllerBase):
self.watches.update(command_obj.get_watches())
early_exit_conditions = self._get_early_exit_conditions()
timed_out = False
total_timeout = Timeout(self.context.options.timeout_total)
max_steps = self.context.options.max_steps
for _ in range(max_steps):
while self.debugger.is_running:
pass
if self.debugger.is_finished:
breakpoint_timeout = Timeout(self.context.options.timeout_breakpoint)
while self.debugger.is_running and not timed_out:
# Check to see whether we've timed out while we're waiting.
if total_timeout.timed_out():
self.context.logger.error('Debugger session has been '
f'running for {total_timeout.elapsed}s, timeout reached!')
timed_out = True
if breakpoint_timeout.timed_out():
self.context.logger.error(f'Debugger session has not '
f'hit a breakpoint for {breakpoint_timeout.elapsed}s, timeout '
'reached!')
timed_out = True
if timed_out or self.debugger.is_finished:
break
self.step_index += 1

View File

@@ -121,7 +121,21 @@ def add_debugger_tool_arguments(parser, context, defaults):
default='',
help='command line arguments for the test program, in addition to any '
'provided by DexCommandLine')
parser.add_argument(
'--timeout-total',
metavar='<seconds>',
type=float,
default=0.0,
help='if >0, debugger session will automatically exit after '
'running for <timeout-total> seconds')
parser.add_argument(
'--timeout-breakpoint',
metavar='<seconds>',
type=float,
default=0.0,
help='if >0, debugger session will automatically exit after '
'waiting <timeout-breakpoint> seconds without hitting a '
'breakpoint')
def handle_debugger_tool_base_options(context, defaults): # noqa
options = context.options

View File

@@ -0,0 +1,31 @@
# DExTer : Debugging Experience Tester
# ~~~~~~ ~ ~~ ~ ~~
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Utility class to check for timeouts. Timer starts when the object is initialized,
and can be checked by calling timed_out(). Passing a timeout value of 0.0 or less
means a timeout will never be triggered, i.e. timed_out() will always return False.
"""
import time
class Timeout(object):
def __init__(self, duration: float):
self.start = self.now
self.duration = duration
def timed_out(self):
if self.duration <= 0.0:
return False
return self.elapsed > self.duration
@property
def elapsed(self):
return self.now - self.start
@property
def now(self):
return time.time()