<filename>debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DefaultController.py
# 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
"""Default class for controlling debuggers."""

from itertools import chain
import os
import time

from dex.debugger.DebuggerControllers.DebuggerControllerBase import DebuggerControllerBase
from dex.debugger.DebuggerControllers.ControllerHelpers import in_source_file, update_step_watches
from dex.utils.Exceptions import DebuggerException, LoadDebuggerException

class DefaultController(DebuggerControllerBase):
    def __init__(self, context, step_collection):
        self.context = context
        self.step_collection = step_collection
        self.source_files = self.context.options.source_files
        self.watches = set()
        self.step_index = 0

    def _break_point_all_lines(self):
        for s in self.context.options.source_files:
            with open(s, 'r') as fp:
                num_lines = len(fp.readlines())
            for line in range(1, num_lines + 1):
                try:
                   self.debugger.add_breakpoint(s, line)
                except DebuggerException:
                   raise LoadDebuggerException(DebuggerException.msg)

    def _run_debugger_custom(self):
        self.step_collection.debugger = self.debugger.debugger_info
        self._break_point_all_lines()
        self.debugger.launch()

        for command_obj in chain.from_iterable(self.step_collection.commands.values()):
            self.watches.update(command_obj.get_watches())

        max_steps = self.context.options.max_steps
        for _ in range(max_steps):
            while self.debugger.is_running:
                pass

            if self.debugger.is_finished:
                break

            self.step_index += 1
            step_info = self.debugger.get_step_info(self.watches, self.step_index)

            if step_info.current_frame:
                update_step_watches(step_info, self.watches, self.step_collection.commands)
                self.step_collection.new_step(self.context, step_info)

            if in_source_file(self.source_files, step_info):
                self.debugger.step()
            else:
                self.debugger.go()

            time.sleep(self.context.options.pause_between_steps)
        else:
            raise DebuggerException(
                'maximum number of steps reached ({})'.format(max_steps))
