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_CALLBACK)
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)