Index: debuginfo-tests/dexter/Commands.md =================================================================== --- debuginfo-tests/dexter/Commands.md +++ debuginfo-tests/dexter/Commands.md @@ -178,7 +178,7 @@ ---- ## DexLimitSteps DexLimitSteps([expr, *values][, **from_line=1][,**to_line=Max] - [,**on_line]) + [,**on_line][,**hit_count]) Args: expr (str): variable or value to compare. @@ -191,12 +191,15 @@ to_line (int): Define the end of the limited step range. on_line (int): Define a range with length 1 starting and ending on the same line. + hit_count (int): If provided, limit the number of times the command + triggers. ### Description Define a limited stepping range that may be predicated on a condition. When the leading line is stepped on and any condition '(expr) == (values[n])' is true or there are no conditions, set a range of temporary breakpoints within the test -file defined by the range 'from_line' and 'to_line' or 'on_line'. +file defined by the range 'from_line' and 'to_line' or 'on_line'. This only +happens 'hit_count' number of times if the argument is provided. The condition is only evaluated on the line 'from_line' or 'on_line'. If the condition is not true at the start of the range, or that line is never stepped Index: debuginfo-tests/dexter/dex/command/commands/DexLimitSteps.py =================================================================== --- debuginfo-tests/dexter/dex/command/commands/DexLimitSteps.py +++ debuginfo-tests/dexter/dex/command/commands/DexLimitSteps.py @@ -27,6 +27,7 @@ except KeyError: self.from_line = kwargs.pop('from_line', 1) self.to_line = kwargs.pop('to_line', 999999) + self.hit_count = kwargs.pop('hit_count', None) if kwargs: raise TypeError('unexpected named args: {}'.format( ', '.join(kwargs))) Index: debuginfo-tests/dexter/dex/debugger/DebuggerControllers/ConditionalController.py =================================================================== --- debuginfo-tests/dexter/dex/debugger/DebuggerControllers/ConditionalController.py +++ debuginfo-tests/dexter/dex/debugger/DebuggerControllers/ConditionalController.py @@ -31,14 +31,20 @@ Args: expression: None for no conditions, or a str expression to compare against `values`. + + hit_count: None for no limit, or int to set the number of times the + leading breakpoint is triggered before it is removed. """ - def __init__(self, expression: str, path: str, range_from: int, range_to: int, values: list): + def __init__(self, expression: str, path: str, range_from: int, range_to: int, + values: list, hit_count: int): self.expression = expression self.path = path self.range_from = range_from self.range_to = range_to self.conditional_values = values + self.max_hit_count = hit_count + self.current_hit_count = 0 def has_conditions(self): return self.expression != None @@ -51,6 +57,14 @@ conditional_list.append(conditional_expression) return conditional_list + def add_hit(self): + self.current_hit_count += 1 + + def should_be_removed(self): + if self.max_hit_count == None: + return False + return self.current_hit_count >= self.max_hit_count + class ConditionalController(DebuggerControllerBase): def __init__(self, context, step_collection): @@ -76,7 +90,8 @@ lc.path, lc.from_line, lc.to_line, - lc.values) + lc.values, + lc.hit_count) self._bp_ranges.append(bpr) except KeyError: raise DebuggerException('Missing DexLimitSteps commands, cannot conditionally step.') @@ -129,6 +144,11 @@ # This is a trailing bp. Mark it for removal. bp_to_delete.append(bp_id) continue + + bpr.add_hit() + if bpr.should_be_removed(): + bp_to_delete.append(bp_id) + del self._leading_bp_handles[bp_id] # Add a range of trailing breakpoints covering the lines # requested in the DexLimitSteps command. Ignore first line as # that's covered by the leading bp we just hit and include the @@ -136,7 +156,7 @@ for line in range(bpr.range_from + 1, bpr.range_to + 1): self.debugger.add_breakpoint(bpr.path, line) - # Remove any trailing breakpoints we just hit. + # Remove any trailing or expired leading breakpoints we just hit. for bp_id in bp_to_delete: self.debugger.delete_breakpoint(bp_id) Index: debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/hit_count.cpp =================================================================== --- /dev/null +++ debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/hit_count.cpp @@ -0,0 +1,21 @@ +// Purpose: +// Test that \DexLimitSteps keyword argument hit_count correctly limits +// the number of times the command can trigger. +// +// REQUIRES: system-linux +// +// RUN: %dexter_regression_test -- %s | FileCheck %s +// CHECK: hit_count.cpp + +int a; +int main() { + for (int i = 0; i < 4; i++) { + a = i; // DexLabel('check') + } + return 0; +} + +//// Unconditionally limit dexter's view of the program to 'on_line' and check +//// for i=0, i=1. The test will fail if dexter sees any other value for test. +// DexLimitSteps(hit_count=2, on_line=ref('check')) +// DexExpectWatchValue('i', '0', '1')