You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.8 KiB
84 lines
2.8 KiB
# 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
|
|
"""Command for specifying a partial or complete state for the program to enter
|
|
during execution.
|
|
"""
|
|
|
|
from itertools import chain
|
|
|
|
from dex.command.CommandBase import CommandBase
|
|
from dex.dextIR import ProgramState, SourceLocation, StackFrame, DextIR
|
|
|
|
def frame_from_dict(source: dict) -> StackFrame:
|
|
if 'location' in source:
|
|
assert isinstance(source['location'], dict)
|
|
source['location'] = SourceLocation(**source['location'])
|
|
return StackFrame(**source)
|
|
|
|
def state_from_dict(source: dict) -> ProgramState:
|
|
if 'frames' in source:
|
|
assert isinstance(source['frames'], list)
|
|
source['frames'] = list(map(frame_from_dict, source['frames']))
|
|
return ProgramState(**source)
|
|
|
|
class DexExpectProgramState(CommandBase):
|
|
"""Expect to see a given program `state` a certain numer of `times`.
|
|
|
|
DexExpectProgramState(state [,**times])
|
|
|
|
See Commands.md for more info.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
if len(args) != 1:
|
|
raise TypeError('expected exactly one unnamed arg')
|
|
|
|
self.program_state_text = str(args[0])
|
|
|
|
self.expected_program_state = state_from_dict(args[0])
|
|
|
|
self.times = kwargs.pop('times', -1)
|
|
if kwargs:
|
|
raise TypeError('unexpected named args: {}'.format(
|
|
', '.join(kwargs)))
|
|
|
|
# Step indices at which the expected program state was encountered.
|
|
self.encounters = []
|
|
|
|
super(DexExpectProgramState, self).__init__()
|
|
|
|
@staticmethod
|
|
def get_name():
|
|
return __class__.__name__
|
|
|
|
def get_watches(self):
|
|
frame_expects = chain.from_iterable(frame.watches
|
|
for frame in self.expected_program_state.frames)
|
|
return set(frame_expects)
|
|
|
|
def eval(self, step_collection: DextIR) -> bool:
|
|
for step in step_collection.steps:
|
|
if self.expected_program_state.match(step.program_state):
|
|
self.encounters.append(step.step_index)
|
|
|
|
return self.times < 0 < len(self.encounters) or len(self.encounters) == self.times
|
|
|
|
def has_labels(self):
|
|
return len(self.get_label_args()) > 0
|
|
|
|
def get_label_args(self):
|
|
return [frame.location.lineno
|
|
for frame in self.expected_program_state.frames
|
|
if frame.location and
|
|
isinstance(frame.location.lineno, str)]
|
|
|
|
def resolve_label(self, label_line__pair):
|
|
label, line = label_line__pair
|
|
for frame in self.expected_program_state.frames:
|
|
if frame.location and frame.location.lineno == label:
|
|
frame.location.lineno = line
|