1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus-core - api/debugger.c * |
3 | * Mupen64Plus homepage: https://mupen64plus.org/ * |
4 | * Copyright (C) 2009 Richard Goedeken * |
5 | * * |
6 | * This program is free software; you can redistribute it and/or modify * |
7 | * it under the terms of the GNU General Public License as published by * |
8 | * the Free Software Foundation; either version 2 of the License, or * |
9 | * (at your option) any later version. * |
10 | * * |
11 | * This program is distributed in the hope that it will be useful, * |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
14 | * GNU General Public License for more details. * |
15 | * * |
16 | * You should have received a copy of the GNU General Public License * |
17 | * along with this program; if not, write to the * |
18 | * Free Software Foundation, Inc., * |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
20 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
21 | |
22 | /* This file contains the Core debugger functions which will be exported |
23 | * outside of the core library. |
24 | */ |
25 | |
26 | #include <stdlib.h> |
27 | |
28 | #define M64P_CORE_PROTOTYPES 1 |
29 | #include "callbacks.h" |
30 | #include "debugger.h" |
31 | #include "debugger/dbg_breakpoints.h" |
32 | #include "debugger/dbg_debugger.h" |
33 | #include "debugger/dbg_decoder.h" |
34 | #include "debugger/dbg_memory.h" |
35 | #include "device/device.h" |
36 | #include "device/memory/memory.h" |
37 | #include "device/r4300/r4300_core.h" |
38 | #include "device/r4300/tlb.h" |
39 | #include "m64p_debugger.h" |
40 | #include "m64p_types.h" |
41 | #include "main/main.h" |
42 | |
43 | unsigned int op; |
44 | |
45 | /* local variables */ |
46 | static void (*callback_ui_init)(void) = NULL; |
47 | static void (*callback_ui_update)(unsigned int) = NULL; |
48 | static void (*callback_ui_vi)(void) = NULL; |
49 | |
50 | static void (*callback_core_compare)(unsigned int) = NULL; |
51 | static void (*callback_core_data_sync)(int, void *) = NULL; |
52 | |
53 | /* global Functions for use by the Core */ |
54 | |
55 | int DebuggerCallbacksAreSet(void) |
56 | { |
57 | if (callback_ui_init != NULL && callback_ui_update != NULL && callback_ui_vi != NULL) |
58 | return 1; |
59 | else |
60 | return 0; |
61 | } |
62 | |
63 | void DebuggerCallback(eDbgCallbackType type, unsigned int param) |
64 | { |
65 | if (type == DEBUG_UI_INIT) |
66 | { |
67 | if (callback_ui_init != NULL) |
68 | (*callback_ui_init)(); |
69 | } |
70 | else if (type == DEBUG_UI_UPDATE) |
71 | { |
72 | if (callback_ui_update != NULL) |
73 | (*callback_ui_update)(param); |
74 | } |
75 | else if (type == DEBUG_UI_VI) |
76 | { |
77 | if (callback_ui_vi != NULL) |
78 | (*callback_ui_vi)(); |
79 | } |
80 | } |
81 | |
82 | void CoreCompareCallback(void) |
83 | { |
84 | if (callback_core_compare != NULL) |
85 | (*callback_core_compare)(op); |
86 | } |
87 | |
88 | void CoreCompareDataSync(int length, void *ptr) |
89 | { |
90 | if (callback_core_data_sync != NULL) |
91 | (*callback_core_data_sync)(length, ptr); |
92 | } |
93 | |
94 | /* exported functions for use by the front-end User Interface */ |
95 | |
96 | EXPORT m64p_error CALL DebugSetCoreCompare(void (*dbg_core_compare)(unsigned int), void (*dbg_core_data_sync)(int, void *)) |
97 | { |
98 | callback_core_compare = dbg_core_compare; |
99 | callback_core_data_sync = dbg_core_data_sync; |
100 | return M64ERR_SUCCESS; |
101 | } |
102 | |
103 | EXPORT m64p_error CALL DebugSetCallbacks(void (*dbg_frontend_init)(void), void (*dbg_frontend_update)(unsigned int pc), void (*dbg_frontend_vi)(void)) |
104 | { |
105 | #ifdef DBG |
106 | callback_ui_init = dbg_frontend_init; |
107 | callback_ui_update = dbg_frontend_update; |
108 | callback_ui_vi = dbg_frontend_vi; |
109 | return M64ERR_SUCCESS; |
110 | #else |
111 | return M64ERR_UNSUPPORTED; |
112 | #endif |
113 | } |
114 | |
115 | EXPORT m64p_error CALL DebugSetRunState(m64p_dbg_runstate runstate) |
116 | { |
117 | #ifdef DBG |
118 | g_dbg_runstate = runstate; /* in debugger/debugger.c */ |
119 | if (runstate == M64P_DBG_RUNSTATE_RUNNING) |
120 | { |
121 | /* clear out last breakpoint state when resuming */ |
122 | breakpointFlag = 0; |
123 | breakpointAccessed = 0; |
124 | } |
125 | return M64ERR_SUCCESS; |
126 | #else |
127 | return M64ERR_UNSUPPORTED; |
128 | #endif |
129 | } |
130 | |
131 | EXPORT int CALL DebugGetState(m64p_dbg_state statenum) |
132 | { |
133 | #ifdef DBG |
134 | switch (statenum) |
135 | { |
136 | case M64P_DBG_RUN_STATE: |
137 | return g_dbg_runstate; |
138 | case M64P_DBG_PREVIOUS_PC: |
139 | return previousPC; |
140 | case M64P_DBG_NUM_BREAKPOINTS: |
141 | return g_NumBreakpoints; |
142 | case M64P_DBG_CPU_DYNACORE: |
143 | return get_r4300_emumode(&g_dev.r4300); |
144 | case M64P_DBG_CPU_NEXT_INTERRUPT: |
145 | return *r4300_cp0_next_interrupt(&g_dev.r4300.cp0); |
146 | default: |
147 | DebugMessage(M64MSG_WARNING, "Bug: invalid m64p_dbg_state input in DebugGetState()" ); |
148 | return 0; |
149 | } |
150 | return 0; |
151 | #else |
152 | DebugMessage(M64MSG_ERROR, "Bug: DebugGetState() called, but Debugger not supported in Core library" ); |
153 | return 0; |
154 | #endif |
155 | } |
156 | |
157 | EXPORT m64p_error CALL DebugStep(void) |
158 | { |
159 | #ifdef DBG |
160 | if (!g_DebuggerActive) |
161 | return M64ERR_INVALID_STATE; |
162 | debugger_step(); /* in debugger/debugger.c */ |
163 | return M64ERR_SUCCESS; |
164 | #else |
165 | return M64ERR_UNSUPPORTED; |
166 | #endif |
167 | } |
168 | |
169 | EXPORT void CALL DebugDecodeOp(unsigned int instruction, char *op, char *args, int pc) |
170 | { |
171 | #ifdef DBG |
172 | r4300_decode_op(instruction, op, args, pc); |
173 | #else |
174 | DebugMessage(M64MSG_ERROR, "Bug: DebugDecodeOp() called, but Debugger not supported in Core library" ); |
175 | #endif |
176 | } |
177 | |
178 | EXPORT void * CALL DebugMemGetRecompInfo(m64p_dbg_mem_info recomp_type, unsigned int address, int index) |
179 | { |
180 | #ifdef DBG |
181 | struct r4300_core* r4300 = &g_dev.r4300; |
182 | |
183 | switch (recomp_type) |
184 | { |
185 | case M64P_DBG_RECOMP_OPCODE: |
186 | return get_recompiled_opcode(r4300, address, index); |
187 | case M64P_DBG_RECOMP_ARGS: |
188 | return get_recompiled_args(r4300, address, index); |
189 | case M64P_DBG_RECOMP_ADDR: |
190 | return get_recompiled_addr(r4300, address, index); |
191 | default: |
192 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetRecompInfo() called with invalid m64p_dbg_mem_info" ); |
193 | return NULL; |
194 | } |
195 | #else |
196 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetRecompInfo() called, but Debugger not supported in Core library" ); |
197 | return NULL; |
198 | #endif |
199 | } |
200 | |
201 | EXPORT int CALL DebugMemGetMemInfo(m64p_dbg_mem_info mem_info_type, unsigned int address) |
202 | { |
203 | #ifdef DBG |
204 | struct device* dev = &g_dev; |
205 | struct r4300_core* r4300 = &dev->r4300; |
206 | |
207 | switch (mem_info_type) |
208 | { |
209 | case M64P_DBG_MEM_TYPE: |
210 | return get_memory_type(&dev->mem, address); |
211 | case M64P_DBG_MEM_FLAGS: |
212 | return get_memory_flags(dev, address); |
213 | case M64P_DBG_MEM_HAS_RECOMPILED: |
214 | return get_has_recompiled(r4300, address); |
215 | case M64P_DBG_MEM_NUM_RECOMPILED: |
216 | return get_num_recompiled(r4300, address); |
217 | default: |
218 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetMemInfo() called with invalid m64p_dbg_mem_info" ); |
219 | return 0; |
220 | } |
221 | #else |
222 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetMemInfo() called, but Debugger not supported in Core library" ); |
223 | return 0; |
224 | #endif |
225 | } |
226 | |
227 | EXPORT void * CALL DebugMemGetPointer(m64p_dbg_memptr_type mem_ptr_type) |
228 | { |
229 | switch (mem_ptr_type) |
230 | { |
231 | case M64P_DBG_PTR_RDRAM: |
232 | return g_dev.rdram.dram; |
233 | case M64P_DBG_PTR_PI_REG: |
234 | return g_dev.pi.regs; |
235 | case M64P_DBG_PTR_SI_REG: |
236 | return g_dev.si.regs; |
237 | case M64P_DBG_PTR_VI_REG: |
238 | return g_dev.vi.regs; |
239 | case M64P_DBG_PTR_RI_REG: |
240 | return g_dev.ri.regs; |
241 | case M64P_DBG_PTR_AI_REG: |
242 | return g_dev.ai.regs; |
243 | default: |
244 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetPointer() called with invalid m64p_dbg_memptr_type" ); |
245 | return NULL; |
246 | } |
247 | } |
248 | |
249 | EXPORT unsigned long long CALL DebugMemRead64(unsigned int address) |
250 | { |
251 | #ifdef DBG |
252 | struct device* dev = &g_dev; |
253 | |
254 | if ((address & 3) == 0) |
255 | return read_memory_64(dev, address); |
256 | else |
257 | return read_memory_64_unaligned(dev, address); |
258 | #else |
259 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead64() called, but Debugger not supported in Core library" ); |
260 | return 0LL; |
261 | #endif |
262 | } |
263 | |
264 | EXPORT unsigned int CALL DebugMemRead32(unsigned int address) |
265 | { |
266 | #ifdef DBG |
267 | struct device* dev = &g_dev; |
268 | |
269 | if ((address & 3) == 0) |
270 | return read_memory_32(dev, address); |
271 | else |
272 | return read_memory_32_unaligned(dev, address); |
273 | #else |
274 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead32() called, but Debugger not supported in Core library" ); |
275 | return 0; |
276 | #endif |
277 | } |
278 | |
279 | EXPORT unsigned short CALL DebugMemRead16(unsigned int address) |
280 | { |
281 | #ifdef DBG |
282 | struct device* dev = &g_dev; |
283 | |
284 | return read_memory_16(dev, address); |
285 | #else |
286 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead16() called, but Debugger not supported in Core library" ); |
287 | return 0; |
288 | #endif |
289 | } |
290 | |
291 | EXPORT unsigned char CALL DebugMemRead8(unsigned int address) |
292 | { |
293 | #ifdef DBG |
294 | struct device* dev = &g_dev; |
295 | |
296 | return read_memory_8(dev, address); |
297 | #else |
298 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead8() called, but Debugger not supported in Core library" ); |
299 | return 0; |
300 | #endif |
301 | } |
302 | |
303 | EXPORT void CALL DebugMemWrite64(unsigned int address, unsigned long long value) |
304 | { |
305 | #ifdef DBG |
306 | struct device* dev = &g_dev; |
307 | |
308 | if ((address & 3) == 0) |
309 | write_memory_64(dev, address, value); |
310 | else |
311 | write_memory_64_unaligned(dev, address, value); |
312 | #else |
313 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite64() called, but Debugger not supported in Core library" ); |
314 | #endif |
315 | } |
316 | |
317 | EXPORT void CALL DebugMemWrite32(unsigned int address, unsigned int value) |
318 | { |
319 | #ifdef DBG |
320 | struct device* dev = &g_dev; |
321 | |
322 | if ((address & 3) == 0) |
323 | write_memory_32(dev, address, value); |
324 | else |
325 | write_memory_32_unaligned(dev, address, value); |
326 | #else |
327 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite32() called, but Debugger not supported in Core library" ); |
328 | #endif |
329 | } |
330 | |
331 | EXPORT void CALL DebugMemWrite16(unsigned int address, unsigned short value) |
332 | { |
333 | #ifdef DBG |
334 | struct device* dev = &g_dev; |
335 | |
336 | write_memory_16(dev, address, value); |
337 | #else |
338 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite16() called, but Debugger not supported in Core library" ); |
339 | #endif |
340 | } |
341 | |
342 | EXPORT void CALL DebugMemWrite8(unsigned int address, unsigned char value) |
343 | { |
344 | #ifdef DBG |
345 | struct device* dev = &g_dev; |
346 | |
347 | write_memory_8(dev, address, value); |
348 | #else |
349 | DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite8() called, but Debugger not supported in Core library" ); |
350 | #endif |
351 | } |
352 | |
353 | EXPORT void * CALL DebugGetCPUDataPtr(m64p_dbg_cpu_data cpu_data_type) |
354 | { |
355 | struct device* dev = &g_dev; |
356 | struct r4300_core* r4300 = &dev->r4300; |
357 | |
358 | cp1_reg *cp1_regs = r4300_cp1_regs(&r4300->cp1); |
359 | switch (cpu_data_type) |
360 | { |
361 | case M64P_CPU_PC: |
362 | return r4300_pc(r4300); |
363 | case M64P_CPU_REG_REG: |
364 | return r4300_regs(r4300); |
365 | case M64P_CPU_REG_HI: |
366 | return r4300_mult_hi(r4300); |
367 | case M64P_CPU_REG_LO: |
368 | return r4300_mult_lo(r4300); |
369 | case M64P_CPU_REG_COP0: |
370 | return r4300_cp0_regs(&r4300->cp0); |
371 | case M64P_CPU_REG_COP1_DOUBLE_PTR: |
372 | return r4300_cp1_regs_double(&r4300->cp1); |
373 | case M64P_CPU_REG_COP1_SIMPLE_PTR: |
374 | return r4300_cp1_regs_simple(&r4300->cp1); |
375 | case M64P_CPU_REG_COP1_FGR_64: |
376 | return &cp1_regs->dword; |
377 | case M64P_CPU_TLB: |
378 | return r4300->cp0.tlb.entries; |
379 | default: |
380 | DebugMessage(M64MSG_ERROR, "Bug: DebugGetCPUDataPtr() called with invalid input m64p_dbg_cpu_data" ); |
381 | return NULL; |
382 | } |
383 | } |
384 | |
385 | EXPORT int CALL DebugBreakpointLookup(unsigned int address, unsigned int size, unsigned int flags) |
386 | { |
387 | #ifdef DBG |
388 | return lookup_breakpoint(address, size, flags); |
389 | #else |
390 | DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointLookup() called, but Debugger not supported in Core library" ); |
391 | return -1; |
392 | #endif |
393 | } |
394 | |
395 | EXPORT int CALL DebugBreakpointCommand(m64p_dbg_bkp_command command, unsigned int index, m64p_breakpoint *bkp) |
396 | { |
397 | #ifdef DBG |
398 | struct memory* mem = &g_dev.mem; |
399 | |
400 | switch (command) |
401 | { |
402 | case M64P_BKP_CMD_ADD_ADDR: |
403 | return add_breakpoint(mem, index); |
404 | case M64P_BKP_CMD_ADD_STRUCT: |
405 | return add_breakpoint_struct(mem, bkp); |
406 | case M64P_BKP_CMD_REPLACE: |
407 | replace_breakpoint_num(mem, index, bkp); |
408 | return 0; |
409 | case M64P_BKP_CMD_REMOVE_ADDR: |
410 | remove_breakpoint_by_address(mem, index); |
411 | return 0; |
412 | case M64P_BKP_CMD_REMOVE_IDX: |
413 | remove_breakpoint_by_num(mem, index); |
414 | return 0; |
415 | case M64P_BKP_CMD_ENABLE: |
416 | enable_breakpoint(mem, index); |
417 | return 0; |
418 | case M64P_BKP_CMD_DISABLE: |
419 | disable_breakpoint(mem, index); |
420 | return 0; |
421 | case M64P_BKP_CMD_CHECK: |
422 | return check_breakpoints(index); |
423 | default: |
424 | DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointCommand() called with invalid input m64p_dbg_bkp_command" ); |
425 | return -1; |
426 | } |
427 | #else |
428 | DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointCommand() called, but Debugger not supported in Core library" ); |
429 | return -1; |
430 | #endif |
431 | } |
432 | |
433 | EXPORT void CALL DebugBreakpointTriggeredBy(uint32_t *flags, uint32_t *accessed) |
434 | { |
435 | #ifdef DBG |
436 | *flags = breakpointFlag; |
437 | *accessed = breakpointAccessed; |
438 | #else |
439 | DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointTriggeredBy() called, but Debugger not supported in Core library" ); |
440 | #endif |
441 | } |
442 | |
443 | EXPORT uint32_t CALL DebugVirtualToPhysical(uint32_t address) |
444 | { |
445 | #ifdef DBG |
446 | struct device* dev = &g_dev; |
447 | struct r4300_core* r4300 = &dev->r4300; |
448 | |
449 | if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { |
450 | address = virtual_to_physical_address(r4300, address, 0); |
451 | if (address == 0) { |
452 | return 0; |
453 | } |
454 | } |
455 | |
456 | address &= UINT32_C(0x1fffffff); |
457 | return address; |
458 | #else |
459 | DebugMessage(M64MSG_ERROR, "Bug: DebugVirtualToPhysical() called, but Debugger not supported in Core library" ); |
460 | return address; |
461 | #endif |
462 | } |
463 | |