all repos — mgba @ 5a6ee3aadc2abce53f03416a2da3f5c14bb03d75

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
  7from .core import IRunner, ICoreOwner, Core
  8import io
  9import sys
 10
 11class DebuggerCoreOwner(ICoreOwner):
 12    def __init__(self, debugger):
 13        self.debugger = debugger
 14        self.wasPaused = False
 15
 16    def claim(self):
 17        if self.debugger.isRunning():
 18            self.wasPaused = True
 19            self.debugger.pause()
 20        return self.debugger._core
 21
 22    def release(self):
 23        if self.wasPaused:
 24            self.debugger.unpause()
 25
 26class NativeDebugger(IRunner):
 27    WATCHPOINT_WRITE = lib.WATCHPOINT_WRITE
 28    WATCHPOINT_READ = lib.WATCHPOINT_READ
 29    WATCHPOINT_RW = lib.WATCHPOINT_RW
 30
 31    BREAKPOINT_HARDWARE = lib.BREAKPOINT_HARDWARE
 32    BREAKPOINT_SOFTWARE = lib.BREAKPOINT_SOFTWARE
 33
 34    ENTER_MANUAL = lib.DEBUGGER_ENTER_MANUAL
 35    ENTER_ATTACHED = lib.DEBUGGER_ENTER_ATTACHED
 36    ENTER_BREAKPOINT = lib.DEBUGGER_ENTER_BREAKPOINT
 37    ENTER_WATCHPOINT = lib.DEBUGGER_ENTER_WATCHPOINT
 38    ENTER_ILLEGAL_OP = lib.DEBUGGER_ENTER_ILLEGAL_OP
 39
 40    def __init__(self, native):
 41        self._native = native
 42        self._cbs = []
 43        self._core = Core._detect(native.core)
 44        self._core._load()
 45
 46    def pause(self):
 47        lib.mDebuggerEnter(self._native, lib.DEBUGGER_ENTER_MANUAL, ffi.NULL)
 48
 49    def unpause(self):
 50        self._native.state = lib.DEBUGGER_RUNNING
 51
 52    def isRunning(self):
 53        return self._native.state == lib.DEBUGGER_RUNNING
 54
 55    def isPaused(self):
 56        return self._native.state in (lib.DEBUGGER_PAUSED, lib.DEBUGGER_CUSTOM)
 57
 58    def useCore(self):
 59        return DebuggerCoreOwner(self)
 60
 61    def setBreakpoint(self, address):
 62        if not self._native.platform.setBreakpoint:
 63            raise RuntimeError("Platform does not support breakpoints")
 64        self._native.platform.setBreakpoint(self._native.platform, address)
 65
 66    def clearBreakpoint(self, address):
 67        if not self._native.platform.setBreakpoint:
 68            raise RuntimeError("Platform does not support breakpoints")
 69        self._native.platform.clearBreakpoint(self._native.platform, address)
 70
 71    def setWatchpoint(self, address):
 72        if not self._native.platform.setWatchpoint:
 73            raise RuntimeError("Platform does not support watchpoints")
 74        self._native.platform.setWatchpoint(self._native.platform, address)
 75
 76    def clearWatchpoint(self, address):
 77        if not self._native.platform.clearWatchpoint:
 78            raise RuntimeError("Platform does not support watchpoints")
 79        self._native.platform.clearWatchpoint(self._native.platform, address)
 80
 81    def addCallback(self, cb):
 82        self._cbs.append(cb)
 83
 84class CLIBackend(object):
 85    def __init__(self, backend):
 86        self.backend = backend
 87
 88    def write(self, string):
 89        self.backend.printf(string)
 90
 91class CLIDebugger(NativeDebugger):
 92    def __init__(self, native):
 93        super(CLIDebugger, self).__init__(native)
 94        self._cli = ffi.cast("struct CLIDebugger*", native)
 95
 96    def printf(self, message, *args, **kwargs):
 97        message = message.format(*args, **kwargs)
 98        self._cli.backend.printf(ffi.new("char []", b"%s"), ffi.new("char []", message.encode('utf-8')))
 99
100    def installPrint(self):
101        sys.stdout = CLIBackend(self)