Exemplo n.º 1
0
 def launch(self):
     self._process = self._target.LaunchSimple(None, None, os.getcwd())
     if not self._process or self._process.GetNumThreads() == 0:
         raise DebuggerException('could not launch process')
     if self._process.GetNumThreads() != 1:
         raise DebuggerException('multiple threads not supported')
     self._thread = self._process.GetThreadAtIndex(0)
     assert self._thread, (self._process, self._thread)
Exemplo n.º 2
0
 def add_conditional_breakpoint(self, file_, line, condition):
     bp = self._target.BreakpointCreateByLocation(file_, line)
     if bp:
         bp.SetCondition(condition)
     else:
         raise DebuggerException(
               'could not add breakpoint [{}:{}]'.format(file_, line))
Exemplo n.º 3
0
    def start(self):
        self.steps.clear_steps()
        self.launch()

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

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

            if self.is_finished:
                break

            self.step_index += 1
            step_info = self.get_step_info()

            if step_info.current_frame:
                self._update_step_watches(step_info)
                self.steps.new_step(self.context, step_info)

            if self.in_source_file(step_info):
                self.step()
            else:
                self.go()

            time.sleep(self.context.options.pause_between_steps)
        else:
            raise DebuggerException(
                'maximum number of steps reached ({})'.format(max_steps))
Exemplo n.º 4
0
def run_debugger_subprocess(debugger_controller, working_dir_path):
    with NamedTemporaryFile(
            dir=working_dir_path, delete=False, mode='wb') as fp:
        pickle.dump(debugger_controller, fp, protocol=pickle.HIGHEST_PROTOCOL)
        controller_path = fp.name

    dexter_py = os.path.basename(sys.argv[0])
    if not os.path.isfile(dexter_py):
        dexter_py = os.path.join(get_root_directory(), '..', dexter_py)
    assert os.path.isfile(dexter_py)

    with NamedTemporaryFile(dir=working_dir_path) as fp:
        args = [
            sys.executable,
            dexter_py,
            'run-debugger-internal-',
            controller_path,
            '--working-directory={}'.format(working_dir_path),
            '--unittest=off',
            '--indent-timer-level={}'.format(Timer.indent + 2)
        ]
        try:
            with Timer('running external debugger process'):
                subprocess.check_call(args)
        except subprocess.CalledProcessError as e:
            raise DebuggerException(e)

    with open(controller_path, 'rb') as fp:
        debugger_controller = pickle.load(fp)

    return debugger_controller
Exemplo n.º 5
0
 def _build_bp_ranges(self):
     commands = self.step_collection.commands
     self._bp_ranges = []
     try:
         limit_commands = commands['DexLimitSteps']
         for lc in limit_commands:
             bpr = BreakpointRange(
               lc.expression,
               lc.path,
               lc.from_line,
               lc.to_line,
               lc.values,
               lc.hit_count,
               False)
             self._bp_ranges.append(bpr)
     except KeyError:
         raise DebuggerException('Missing DexLimitSteps commands, cannot conditionally step.')
     if 'DexFinishTest' in commands:
         finish_commands = commands['DexFinishTest']
         for ic in finish_commands:
             bpr = BreakpointRange(
               ic.expression,
               ic.path,
               ic.on_line,
               ic.on_line,
               ic.values,
               ic.hit_count + 1,
               True)
             self._bp_ranges.append(bpr)
Exemplo n.º 6
0
    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))
Exemplo n.º 7
0
def get_debugger_steps(context):
    step_collection = empty_debugger_steps(context)

    with Timer('parsing commands'):
        try:
            step_collection.commands = _get_command_infos(context)
        except CommandParseError as e:
            msg = 'parser error: <d>{}({}):</> {}\n{}\n{}\n'.format(
                e.filename, e.lineno, e.info, e.src, e.caret)
            raise DebuggerException(msg)

    with NamedTemporaryFile(dir=context.working_directory.path,
                            delete=False) as fp:
        pickle.dump(step_collection, fp, protocol=pickle.HIGHEST_PROTOCOL)
        steps_path = fp.name

    with NamedTemporaryFile(dir=context.working_directory.path,
                            delete=False,
                            mode='wb') as fp:
        pickle.dump(context.options, fp, protocol=pickle.HIGHEST_PROTOCOL)
        options_path = fp.name

    dexter_py = sys.argv[0]
    if not os.path.isfile(dexter_py):
        dexter_py = os.path.join(get_root_directory(), '..', dexter_py)
    assert os.path.isfile(dexter_py)

    with NamedTemporaryFile(dir=context.working_directory.path) as fp:
        args = [
            sys.executable, dexter_py, 'run-debugger-internal-', steps_path,
            options_path, '--working-directory',
            context.working_directory.path, '--unittest=off',
            '--indent-timer-level={}'.format(Timer.indent + 2)
        ]
        try:
            with Timer('running external debugger process'):
                subprocess.check_call(args)
        except subprocess.CalledProcessError as e:
            raise DebuggerException(e)

    with open(steps_path, 'rb') as fp:
        step_collection = pickle.load(fp)

    return step_collection
Exemplo n.º 8
0
    def _run_debugger_custom(self, cmdline):
        # TODO: Add conditional and unconditional breakpoint support to dbgeng.
        if self.debugger.get_name() == 'dbgeng':
            raise DebuggerException('DexLimitSteps commands are not supported by dbgeng')

        self.step_collection.clear_steps()
        self._set_leading_bps()

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

        self.debugger.launch(cmdline)
        time.sleep(self._pause_between_steps)

        exit_desired = False

        while not self.debugger.is_finished:
            while self.debugger.is_running:
                pass

            step_info = self.debugger.get_step_info(self._watches, self._step_index)
            if step_info.current_frame:
                self._step_index += 1
                update_step_watches(step_info, self._watches, self.step_collection.commands)
                self.step_collection.new_step(self.context, step_info)

            bp_to_delete = []
            for bp_id in self.debugger.get_triggered_breakpoint_ids():
                try:
                    # See if this is one of our leading breakpoints.
                    bpr = self._leading_bp_handles[bp_id]
                except KeyError:
                    # This is a trailing bp. Mark it for removal.
                    bp_to_delete.append(bp_id)
                    continue

                bpr.add_hit()
                if bpr.should_be_removed():
                    if bpr.finish_on_remove:
                        exit_desired = True
                    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
                # final line.
                for line in range(bpr.range_from + 1, bpr.range_to + 1):
                    self.debugger.add_breakpoint(bpr.path, line)

            # Remove any trailing or expired leading breakpoints we just hit.
            self.debugger.delete_breakpoints(bp_to_delete)

            if exit_desired:
                break
            self.debugger.go()
            time.sleep(self._pause_between_steps)
Exemplo n.º 9
0
 def _add_conditional_breakpoint(self, file_, line, condition):
     bp = self._target.BreakpointCreateByLocation(file_, line)
     if not bp:
         raise DebuggerException('could not add breakpoint [{}:{}]'.format(
             file_, line))
     id = bp.GetID()
     if condition:
         bp.SetCondition(condition)
         assert id not in self._breakpoint_conditions
         self._breakpoint_conditions[id] = condition
     return id
Exemplo n.º 10
0
    def _run_debugger_custom(self):
        # TODO: Add conditional and unconditional breakpoint support to dbgeng.
        if self.debugger.get_name() == 'dbgeng':
            raise DebuggerException(
                'DexLimitSteps commands are not supported by dbgeng')

        self.step_collection.clear_steps()
        self._set_conditional_bps()

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

        self.debugger.launch()
        time.sleep(self._pause_between_steps)
        while not self.debugger.is_finished:
            while self.debugger.is_running:
                pass

            step_info = self.debugger.get_step_info(self._watches,
                                                    self._step_index)
            if step_info.current_frame:
                self._step_index += 1
                update_step_watches(step_info, self._watches,
                                    self.step_collection.commands)
                self.step_collection.new_step(self.context, step_info)

            bp_to_delete = []
            for bp_id in self.debugger.get_triggered_breakpoint_ids():
                try:
                    # See if this is one of our conditional breakpoints.
                    cbp = self._conditional_bp_handles[bp_id]
                except KeyError:
                    # This is an unconditional bp. Mark it for removal.
                    bp_to_delete.append(bp_id)
                    continue
                # We have triggered a breakpoint with a condition. Check that
                # the condition has been met.
                if self._conditional_met(cbp):
                    # Add a range of unconditional breakpoints covering the
                    # lines requested in the DexLimitSteps command. Ignore
                    # first line as that's the conditional bp we just hit and
                    # include the final line.
                    for line in range(cbp.range_from + 1, cbp.range_to + 1):
                        self.debugger.add_breakpoint(cbp.path, line)

            # Remove any unconditional breakpoints we just hit.
            for bp_id in bp_to_delete:
                self.debugger.delete_breakpoint(bp_id)

            self.debugger.go()
            time.sleep(self._pause_between_steps)
Exemplo n.º 11
0
 def _build_conditional_bp_ranges(self):
     commands = self.step_collection.commands
     self._conditional_bp_ranges = []
     try:
         limit_commands = commands['DexLimitSteps']
         for lc in limit_commands:
             conditional_bp = ConditionalBpRange(lc.expression, lc.path,
                                                 lc.from_line, lc.to_line,
                                                 lc.values)
             self._conditional_bp_ranges.append(conditional_bp)
     except KeyError:
         raise DebuggerException(
             'Missing DexLimitSteps commands, cannot conditionally step.')
Exemplo n.º 12
0
def get_command_infos(source_files):
    with Timer('parsing commands'):
        try:
            commands = _find_all_commands(source_files)
            command_infos = OrderedDict()
            for command_type in commands:
                for command in commands[command_type].values():
                    if command_type not in command_infos:
                        command_infos[command_type] = []
                    command_infos[command_type].append(command)
            return OrderedDict(command_infos)
        except CommandParseError as e:
            msg = 'parser error: <d>{}({}):</> {}\n{}\n{}\n'.format(
                e.filename, e.lineno, e.info, e.src, e.caret)
            raise DebuggerException(msg)
    def _run_debugger_custom(self):
        # TODO: Add conditional and unconditional breakpoint support to dbgeng.
        if self.debugger.get_name() == 'dbgeng':
            raise DebuggerException(
                'DexLimitSteps commands are not supported by dbgeng')

        self.step_collection.clear_steps()
        self._set_conditional_bps()

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

        self.debugger.launch()
        time.sleep(self._pause_between_steps)
        while not self.debugger.is_finished:
            while self.debugger.is_running:
                pass

            step_info = self.debugger.get_step_info(self._watches,
                                                    self._step_index)
            if step_info.current_frame:
                self._step_index += 1
                update_step_watches(step_info, self._watches,
                                    self.step_collection.commands)
                self.step_collection.new_step(self.context, step_info)

                loc = step_info.current_location
                conditional_bp_key = (loc.path, loc.lineno)
                if conditional_bp_key in self._path_and_line_to_conditional_bp:

                    conditional_bps = self._path_and_line_to_conditional_bp[
                        conditional_bp_key]
                    for cbp in conditional_bps:
                        if self._conditional_met(cbp):
                            # Unconditional range should ignore first line as that's the
                            # conditional bp we just hit and should be inclusive of final line
                            for line in range(cbp.range_from + 1,
                                              cbp.range_to + 1):
                                self.debugger.add_conditional_breakpoint(
                                    cbp.path, line, condition='')

            # Clear any uncondtional break points at this loc.
            self.debugger.delete_conditional_breakpoint(file_=loc.path,
                                                        line=loc.lineno,
                                                        condition='')
            self.debugger.go()
            time.sleep(self._pause_between_steps)
Exemplo n.º 14
0
 def add_breakpoint(self, file_, line):
     if not self._target.BreakpointCreateByLocation(file_, line):
         raise DebuggerException(
             'could not add breakpoint [{}:{}]'.format(file_, line))
Exemplo n.º 15
0
 def _add_breakpoint(self, file_, line):
     bp = self._target.BreakpointCreateByLocation(file_, line)
     if not bp:
         raise DebuggerException('could not add breakpoint [{}:{}]'.format(
             file_, line))
     return bp.GetID()