brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.5 KiB · 1427084 Raw
140 lines · python
1# DExTer : Debugging Experience Tester2# ~~~~~~   ~         ~~         ~   ~~3#4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5# See https://llvm.org/LICENSE.txt for license information.6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7"""Default class for controlling debuggers."""8 9from itertools import chain10import os11import time12 13from dex.debugger.DebuggerControllers.DebuggerControllerBase import (14    DebuggerControllerBase,15)16from dex.debugger.DebuggerControllers.ControllerHelpers import (17    in_source_file,18    update_step_watches,19)20from dex.utils.Exceptions import DebuggerException, LoadDebuggerException21from dex.utils.Timeout import Timeout22 23 24class EarlyExitCondition(object):25    def __init__(self, on_line, hit_count, expression, values):26        self.on_line = on_line27        self.hit_count = hit_count28        self.expression = expression29        self.values = values30 31 32class DefaultController(DebuggerControllerBase):33    def __init__(self, context, step_collection):34        self.source_files = context.options.source_files35        self.watches = set()36        self.step_index = 037        super(DefaultController, self).__init__(context, step_collection)38 39    def _break_point_all_lines(self):40        for s in self.context.options.source_files:41            with open(s, "r") as fp:42                num_lines = len(fp.readlines())43            for line in range(1, num_lines + 1):44                try:45                    self.debugger.add_breakpoint(s, line)46                except DebuggerException:47                    raise LoadDebuggerException(DebuggerException.msg)48 49    def _get_early_exit_conditions(self):50        commands = self.step_collection.commands51        early_exit_conditions = []52        if "DexFinishTest" in commands:53            finish_commands = commands["DexFinishTest"]54            for fc in finish_commands:55                condition = EarlyExitCondition(56                    on_line=fc.on_line,57                    hit_count=fc.hit_count,58                    expression=fc.expression,59                    values=fc.values,60                )61                early_exit_conditions.append(condition)62        return early_exit_conditions63 64    def _should_exit(self, early_exit_conditions, line_no):65        for condition in early_exit_conditions:66            if condition.on_line == line_no:67                exit_condition_hit = condition.expression is None68                if condition.expression is not None:69                    # For the purposes of consistent behaviour with the70                    # Conditional Controller, check equality in the debugger71                    # rather than in python (as the two can differ).72                    for value in condition.values:73                        expr_val = self.debugger.evaluate_expression(74                            f"({condition.expression}) == ({value})"75                        )76                        if expr_val.value == "true":77                            exit_condition_hit = True78                            break79                if exit_condition_hit:80                    if condition.hit_count <= 0:81                        return True82                    else:83                        condition.hit_count -= 184        return False85 86    def _run_debugger_custom(self, cmdline):87        self.step_collection.debugger = self.debugger.debugger_info88        self._break_point_all_lines()89        self.debugger.launch(cmdline)90        for command_obj in chain.from_iterable(self.step_collection.commands.values()):91            self.watches.update(command_obj.get_watches())92        early_exit_conditions = self._get_early_exit_conditions()93        timed_out = False94        total_timeout = Timeout(self.context.options.timeout_total)95        max_steps = self.context.options.max_steps96        for _ in range(max_steps):97            breakpoint_timeout = Timeout(self.context.options.timeout_breakpoint)98            while self.debugger.is_running and not timed_out:99                # Check to see whether we've timed out while we're waiting.100                if total_timeout.timed_out():101                    self.context.logger.error(102                        "Debugger session has been "103                        f"running for {total_timeout.elapsed}s, timeout reached!"104                    )105                    timed_out = True106                if breakpoint_timeout.timed_out():107                    self.context.logger.error(108                        f"Debugger session has not "109                        f"hit a breakpoint for {breakpoint_timeout.elapsed}s, timeout "110                        "reached!"111                    )112                    timed_out = True113 114            if timed_out or self.debugger.is_finished:115                break116 117            self.step_index += 1118            step_info = self.debugger.get_step_info(self.watches, self.step_index)119 120            if step_info.current_frame:121                update_step_watches(122                    step_info, self.watches, self.step_collection.commands123                )124                self.step_collection.new_step(self.context, step_info)125                if self._should_exit(126                    early_exit_conditions, step_info.current_frame.loc.lineno127                ):128                    break129 130            if in_source_file(self.source_files, step_info):131                self.debugger.step_in()132            else:133                self.debugger.go()134 135            time.sleep(self.context.options.pause_between_steps)136        else:137            raise DebuggerException(138                "maximum number of steps reached ({})".format(max_steps)139            )140