[dexter] Add hit_count keyword arg to DexLimitSteps

The DexLimitSteps command leading breakpoint will be deleted after triggering
'hit_count' number of times if the argument is provided.

All the lit tests pass on linux (with lldb), and I've tested this on windows
(with vs2017) manually as the lit tests for DexLimitSteps are currently
unsupported on windows.

Reviewed By: StephenTozer, chrisjackson

Differential Revision: https://reviews.llvm.org/D101527
This commit is contained in:
OCHyams
2021-05-21 12:43:13 +01:00
parent 3ae7f7ae0a
commit 469833f418
4 changed files with 50 additions and 5 deletions

View File

@@ -178,7 +178,7 @@ Expect the source line this is found on will never be stepped on to.
----
## 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 @@ Expect the source line this is found on will never be stepped on to.
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

View File

@@ -27,6 +27,7 @@ class DexLimitSteps(CommandBase):
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)))

View File

@@ -31,14 +31,20 @@ class BreakpointRange:
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 @@ class BreakpointRange:
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 @@ class ConditionalController(DebuggerControllerBase):
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 @@ class ConditionalController(DebuggerControllerBase):
# 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 @@ class ConditionalController(DebuggerControllerBase):
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)

View File

@@ -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')