all repos — mgba @ bf595be5c3fda6c84a9b7468b3bcce812596b355

mGBA Game Boy Advance Emulator

src/platform/python/mgba/debugger.py (view raw)

  1# Copyright (c) 2013-2017 Jeffrey Pfau
  2#
  3# This Source Code Form is subject to the terms of the Mozilla Public
  4# License, v. 2.0. If a copy of the MPL was not distributed with this
  5# file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6from ._pylib import ffi, lib  # pylint: disable=no-name-in-module
  7from .core import IRunner, ICoreOwner, Core
  8import sys
  9
 10
 11class DebuggerCoreOwner(ICoreOwner):
 12    def __init__(self, debugger):
 13        self.debugger = debugger
 14        self.was_paused = False
 15
 16    def claim(self):
 17        if self.debugger.isRunning():
 18            self.was_paused = True
 19            self.debugger.pause()
 20        return self.debugger._core
 21
 22    def release(self):
 23        if self.was_paused:
 24            self.debugger.unpause()
 25
 26
 27class NativeDebugger(IRunner):
 28    WATCHPOINT_WRITE = lib.WATCHPOINT_WRITE
 29    WATCHPOINT_READ = lib.WATCHPOINT_READ
 30    WATCHPOINT_RW = lib.WATCHPOINT_RW
 31
 32    BREAKPOINT_HARDWARE = lib.BREAKPOINT_HARDWARE
 33    BREAKPOINT_SOFTWARE = lib.BREAKPOINT_SOFTWARE
 34
 35    ENTER_MANUAL = lib.DEBUGGER_ENTER_MANUAL
 36    ENTER_ATTACHED = lib.DEBUGGER_ENTER_ATTACHED
 37    ENTER_BREAKPOINT = lib.DEBUGGER_ENTER_BREAKPOINT
 38    ENTER_WATCHPOINT = lib.DEBUGGER_ENTER_WATCHPOINT
 39    ENTER_ILLEGAL_OP = lib.DEBUGGER_ENTER_ILLEGAL_OP
 40
 41    def __init__(self, native):
 42        self._native = native
 43        self._cbs = []
 44        self._core = Core._detect(native.core)
 45        self._core._load()
 46
 47    def pause(self):
 48        lib.mDebuggerEnter(self._native, lib.DEBUGGER_ENTER_MANUAL, ffi.NULL)
 49
 50    def unpause(self):
 51        self._native.state = lib.DEBUGGER_RUNNING
 52
 53    @property
 54    def running(self):
 55        return self._native.state == lib.DEBUGGER_RUNNING
 56
 57    @property
 58    def paused(self):
 59        return self._native.state in (lib.DEBUGGER_PAUSED, lib.DEBUGGER_CUSTOM)
 60
 61    def use_core(self):
 62        return DebuggerCoreOwner(self)
 63
 64    def set_breakpoint(self, address):
 65        if not self._native.platform.setBreakpoint:
 66            raise RuntimeError("Platform does not support breakpoints")
 67        self._native.platform.setBreakpoint(self._native.platform, address)
 68
 69    def clear_breakpoint(self, address):
 70        if not self._native.platform.setBreakpoint:
 71            raise RuntimeError("Platform does not support breakpoints")
 72        self._native.platform.clearBreakpoint(self._native.platform, address)
 73
 74    def set_watchpoint(self, address):
 75        if not self._native.platform.setWatchpoint:
 76            raise RuntimeError("Platform does not support watchpoints")
 77        self._native.platform.setWatchpoint(self._native.platform, address)
 78
 79    def clear_watchpoint(self, address):
 80        if not self._native.platform.clearWatchpoint:
 81            raise RuntimeError("Platform does not support watchpoints")
 82        self._native.platform.clearWatchpoint(self._native.platform, address)
 83
 84    def add_callback(self, callback):
 85        self._cbs.append(callback)
 86
 87
 88class CLIBackend(object):
 89    def __init__(self, backend):
 90        self.backend = backend
 91
 92    def write(self, string):
 93        self.backend.printf(string)
 94
 95
 96class CLIDebugger(NativeDebugger):
 97    def __init__(self, native):
 98        super(CLIDebugger, self).__init__(native)
 99        self._cli = ffi.cast("struct CLIDebugger*", native)
100
101    def printf(self, message, *args, **kwargs):
102        message = message.format(*args, **kwargs)
103        self._cli.backend.printf(ffi.new("char []", b"%s"), ffi.new("char []", message.encode('utf-8')))
104
105    def install_print(self):
106        sys.stdout = CLIBackend(self)