Skip to content

Commit a11117a

Browse files
committed
[dexter] Remove unnecessary double check on conditional breakpoints
Remove the `ConditionalController._conditional_met` method. This was missed in the recent ConditionalController refactor (D98699). We don't need to check that the conditions for a conditional breakpoint have been met because `DebuggerBase.get_triggered_breakpoint_ids` returns the set of ids for breakpoints which have been triggered. To get the "triggered breakpoints" from lldb we use `GetStopReasonDataCount` and `GetStopReasonDataAtIndex`. It seems that these functions count all breakpoints associated with the location which lldb has stopped at, regardless of their condition. i.e. Even if we have two breakpoints at the same source location that have mutually exclusive conditions, both will be found this way when either condition is true. To get around this, we store a map of breakpoint {id: condition} `_breakpoint_conditions` and evaluate the conditions of the triggered breakpoints to filter the set down to those which are unconditional or have a condition which evaluates to true. Essentially we are just moving the condition double check from a general debugger controller into the lldb specific wrapper. This tidy up will help make upcoming patches simpler. Reviewed By: chrisjackson Differential Revision: https://reviews.llvm.org/D101431
1 parent 84306ef commit a11117a

File tree

2 files changed

+51
-28
lines changed

2 files changed

+51
-28
lines changed

debuginfo-tests/dexter/dex/debugger/DebuggerControllers/ConditionalController.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,6 @@ def _set_conditional_bps(self):
7777
cond_expr)
7878
self._conditional_bp_handles[id] = cbp
7979

80-
def _conditional_met(self, cbp):
81-
for cond_expr in cbp.get_conditional_expression_list():
82-
valueIR = self.debugger.evaluate_expression(cond_expr)
83-
if valueIR.type_name == 'bool' and valueIR.value == 'true':
84-
return True
85-
return False
86-
8780
def _run_debugger_custom(self):
8881
# TODO: Add conditional and unconditional breakpoint support to dbgeng.
8982
if self.debugger.get_name() == 'dbgeng':
@@ -116,15 +109,12 @@ def _run_debugger_custom(self):
116109
# This is an unconditional bp. Mark it for removal.
117110
bp_to_delete.append(bp_id)
118111
continue
119-
# We have triggered a breakpoint with a condition. Check that
120-
# the condition has been met.
121-
if self._conditional_met(cbp):
122-
# Add a range of unconditional breakpoints covering the
123-
# lines requested in the DexLimitSteps command. Ignore
124-
# first line as that's the conditional bp we just hit and
125-
# include the final line.
126-
for line in range(cbp.range_from + 1, cbp.range_to + 1):
127-
self.debugger.add_breakpoint(cbp.path, line)
112+
# Add a range of unconditional breakpoints covering the lines
113+
# requested in the DexLimitSteps command. Ignore first line as
114+
# that's the conditional bp we just hit and include the final
115+
# line.
116+
for line in range(cbp.range_from + 1, cbp.range_to + 1):
117+
self.debugger.add_breakpoint(cbp.path, line)
128118

129119
# Remove any unconditional breakpoints we just hit.
130120
for bp_id in bp_to_delete:

debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ def __init__(self, context, *args):
2626
self._target = None
2727
self._process = None
2828
self._thread = None
29+
# Map {id (int): condition (str)} for breakpoints which have a
30+
# condition. See get_triggered_breakpoint_ids usage for more info.
31+
self._breakpoint_conditions = {}
2932
super(LLDB, self).__init__(context, *args)
3033

3134
def _custom_init(self):
@@ -104,37 +107,67 @@ def clear_breakpoints(self):
104107
self._target.DeleteAllBreakpoints()
105108

106109
def _add_breakpoint(self, file_, line):
107-
bp = self._target.BreakpointCreateByLocation(file_, line)
108-
if not bp:
109-
raise DebuggerException(
110-
'could not add breakpoint [{}:{}]'.format(file_, line))
111-
return bp.GetID()
110+
return self._add_conditional_breakpoint(file_, line, None)
112111

113112
def _add_conditional_breakpoint(self, file_, line, condition):
114113
bp = self._target.BreakpointCreateByLocation(file_, line)
115-
if bp:
116-
bp.SetCondition(condition)
117-
else:
114+
if not bp:
118115
raise DebuggerException(
119116
'could not add breakpoint [{}:{}]'.format(file_, line))
120-
return bp.GetID()
117+
id = bp.GetID()
118+
if condition:
119+
bp.SetCondition(condition)
120+
assert id not in self._breakpoint_conditions
121+
self._breakpoint_conditions[id] = condition
122+
return id
123+
124+
def _evaulate_breakpoint_condition(self, id):
125+
"""Evaluate the breakpoint condition and return the result.
126+
127+
Returns True if a conditional breakpoint with the specified id cannot
128+
be found (i.e. assume it is an unconditional breakpoint).
129+
"""
130+
try:
131+
condition = self._breakpoint_conditions[id]
132+
except KeyError:
133+
# This must be an unconditional breakpoint.
134+
return True
135+
valueIR = self.evaluate_expression(condition)
136+
return valueIR.type_name == 'bool' and valueIR.value == 'true'
121137

122138
def get_triggered_breakpoint_ids(self):
123139
# Breakpoints can only have been triggered if we've hit one.
124140
stop_reason = self._translate_stop_reason(self._thread.GetStopReason())
125141
if stop_reason != StopReason.BREAKPOINT:
126142
return []
143+
breakpoint_ids = set()
144+
# When the stop reason is eStopReasonBreakpoint, GetStopReasonDataCount
145+
# counts all breakpoints associated with the location that lldb has
146+
# stopped at, regardless of their condition. I.e. Even if we have two
147+
# breakpoints at the same source location that have mutually exclusive
148+
# conditions, both will be counted by GetStopReasonDataCount when
149+
# either condition is true. Check each breakpoint condition manually to
150+
# filter the list down to breakpoints that have caused this stop.
151+
#
127152
# Breakpoints have two data parts: Breakpoint ID, Location ID. We're
128153
# only interested in the Breakpoint ID so we skip every other item.
129-
return set([self._thread.GetStopReasonDataAtIndex(i)
130-
for i in range(0, self._thread.GetStopReasonDataCount(), 2)])
154+
for i in range(0, self._thread.GetStopReasonDataCount(), 2):
155+
id = self._thread.GetStopReasonDataAtIndex(i)
156+
if self._evaulate_breakpoint_condition(id):
157+
breakpoint_ids.add(id)
158+
return breakpoint_ids
131159

132160
def delete_breakpoint(self, id):
133161
bp = self._target.FindBreakpointByID(id)
134162
if not bp:
135163
# The ID is not valid.
136164
raise KeyError
137-
self._target.BreakpointDelete(bp.GetID())
165+
try:
166+
del self._breakpoint_conditions[id]
167+
except KeyError:
168+
# This must be an unconditional breakpoint.
169+
pass
170+
self._target.BreakpointDelete(id)
138171

139172
def launch(self):
140173
self._process = self._target.LaunchSimple(None, None, os.getcwd())

0 commit comments

Comments
 (0)