/* Pcsx - Pc Psx Emulator * Copyright (C) 1999-2003 Pcsx Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include "psxcommon.h" #include "r3000a.h" #include "debug.h" #include "socket.h" /* PCSX Debug console protocol description, version 1.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Commands number are formatted using %03X (yes) Registers number are formatted using %02X. Breakpoints numbers are formatted using %X All other values are formatted using %08X, unless specified. Client inputs: ~~~~~~~~~~~~~ Basic commands (1xx): -------------------- 100 Sends a dumb message. Will be replied with a 200 reply, followed by the message. 101 Gets PCSX version. 102 Gets protocol version. 103 Gets status 110 Gets PC. 111 [reg] Gets GP register, or all, if no argument. 112 Gets LO/HI registers. 113 [reg] Gets COP0 register, or all, if no argument. 114 [reg] Gets COP2 control register, or all, if no argument. 115 [reg] Gets COP2 data register, or all, if no argument. 119 [pc] Disassemble current PC, or given PC. 121 = Sets a GP register. Will return a 221 message. 122 = Sets LO or HI register. Will return a 222 message. 123 = Sets a COP0 register. Will return a 223 message. 124 = Sets a COP2 control register. Will return a 224 message. 125 = Sets a COP2 data register. Will return a 225 message. 130 @ Dumps a range of memory, of size bytes starting at addr. 140 @ Sets a range of memory, of size bytes starting at addr. Will have to send immediately exactly size bytes afterward. 150 [number] Starts/reset mapping execution flow, or stop it if number = 0 151 [number] Starts/reset mapping read8 flow, or stop it if number = 0 152 [number] Starts/reset mapping read16 flow, or stop it if number = 0 153 [number] Starts/reset mapping read32 flow, or stop it if number = 0 154 [number] Starts/reset mapping write8 flow, or stop it if number = 0 155 [number] Starts/reset mapping write16 flow, or stop it if number = 0 156 [number] Starts/reset mapping write32 flow, or stop it if number = 0 160 [number] Breaks on map exec flow, or stop it if number = 0 161 [number] Breaks on map read8 flow, or stop it if number = 0 162 [number] Breaks on map read16 flow, or stop it if number = 0 163 [number] Breaks on map read32 flow, or stop it if number = 0 164 [number] Breaks on map write8 flow, or stop it if number = 0 165 [number] Breaks on map write16 flow, or stop it if number = 0 166 [number] Breaks on map write32 flow, or stop it if number = 0 170 Dumps the execution flow map in an IDC file Execution flow control commands (3xx): ------------------------------------- 300 [number] Get a list of the actual breakpoints. Will get '400' answers. 301 [number] Deletes a breakpoint, or all, if no arguments. 310
Sets an exec breakpoint. 320
Sets a read breakpoint, 1 byte / 8 bits. 321
Sets a read breakpoint, 2 bytes / 16 bits, has to be on an even address. 322
Sets a read breakpoint, 4 bytes / 32 bits, address has to be 4-bytes aligned. 330
Sets a write breakpoint, 1 byte / 8 bits. 331
Sets a write breakpoint, 2 bytes / 16 bits, has to be on an even address. 332
Sets a write breakpoint, 4 bytes / 32 bits, address has to be 4-bytes aligned. 390 Pauses execution. Equivalents to a breakpoint. 391 Restarts execution. 395 [number] Traces execution, 1 instruction by default. Formatted using %i 398 Soft (quick) resets. 399 Resets. Server outputs: ~~~~~~~~~~~~~~ Spontaneous messages (0xx): -------------------------- 000 Greeting banner. 010 / 011 / 012 / 013 / 014 / 015 / 016 Execution hit mapping flow automatic breakpoint. 030 @ Execution hit breakpoint, PCSX is paused. Displays PC's value. Basic commands acknowledge (2xx): -------------------------------- 200 Sends a dumb message. 201 Returns PCSX version. 202 Returns protocol version. 203 status = 0: running; = 1: paused; = 2: trace 210 PC= Displays current PC value. 211 = Displays one GP register value. 212 LO= HI= Displays LO/HI registers. 213 = Displays one COP0 register value. 214 = Displays one COP2 control register value. 215 = Displays one COP2 data register value. 219 Displays one line of disassembled code. 221 = Displays one GP register value, ack for modification. 222 LO= HI= Displays LO/HI registers, ack for modification. 223 = Displays one COP0 register value, ack for modification. 224 = Displays one COP2 control register value, ack for modification. 225 = Displays one COP2 data register value, ack for modification. 230 @ Dumping memory. Will then raw outputs size bytes. 240 @ Memory set acknowledge. 250 / 251 / 252 / 253 / 254 / 255 / 256 Acknolwedge of 15x commands. 260 / 261 / 262 / 263 / 264 / 265 / 266 Acknolwedge of 16x commands. 270 Acknolwedge of 170 command. Execution flow control commands acknowledge (4xx): ------------------------------------------------- 400 @
- Displays a breakpoint, where 'type' can be of E, R1, R2, R4, W1, W2 or W4. 401 Breakpoint deleting acknowledge. 410, 420, 421, 422, 430, 431, 432 Breakpoint adding acknowledge. Returns the number of the added breakpoint. 490 Pausing. 491 Resuming. 495 Tracing. 498 Soft resetting. 499 Resetting. Error messages (5xx): -------------------- 500 Command not understood. 511 Invalid GPR register. 512 Invalid LO/HI register. 513, 514 Invalid range or address. 530 Non existant breakpoint. 531, 532, 533 Invalid breakpoint address. */ static int debugger_active = 0, paused = 0, trace = 0, reset = 0, resetting = 0; static int mapping_e = 0, mapping_r8 = 0, mapping_r16 = 0, mapping_r32 = 0, mapping_w8 = 0, mapping_w16 = 0, mapping_w32 = 0; static int breakmp_e = 0, breakmp_r8 = 0, breakmp_r16 = 0, breakmp_r32 = 0, breakmp_w8 = 0, breakmp_w16 = 0, breakmp_w32 = 0; static void ProcessCommands(); static u8 *MemoryMap = NULL; enum { MAP_EXEC = 1, MAP_R8 = 2, MAP_R16 = 4, MAP_R32 = 8, MAP_W8 = 16, MAP_W16 = 32, MAP_W32 = 64, MAP_EXEC_JAL = 128, }; char *breakpoint_type_names[] = { "E", "R1", "R2", "R4", "W1", "W2", "W4" }; typedef struct breakpoint_s { struct breakpoint_s *next, *prev; int number, type; u32 address; } breakpoint_t; static breakpoint_t *first = NULL; int add_breakpoint(int type, u32 address) { breakpoint_t *bp = (breakpoint_t *)malloc(sizeof(breakpoint_t)); bp->type = type; bp->address = address; if (first) { bp->number = first->prev->number + 1; bp->next = first; bp->prev = first->prev; first->prev = bp; bp->prev->next = bp; } else { first = bp; bp->number = 1; bp->next = bp; bp->prev = bp; } return bp->number; } void delete_breakpoint(breakpoint_t * bp) { if (bp == first) { if (bp->next == bp) { first = NULL; } else { first = bp->next; } } bp->next->prev = bp->prev; bp->prev->next = bp->next; free(bp); } breakpoint_t *next_breakpoint(breakpoint_t *bp) { return bp->next != first ? bp->next : 0; } breakpoint_t *find_breakpoint(int number) { breakpoint_t *p; for (p = first; p; p = next_breakpoint(p)) { if (p->number == number) return p; } return 0; } void StartDebugger() { if (debugger_active) return; MemoryMap = (u8 *)malloc(0x200000); if (MemoryMap == NULL) { SysMessage(_("Error allocating memory")); return; } if (StartServer() == -1) { SysPrintf(_("Unable to start debug server.\n")); return; } SysPrintf(_("Debugger started.\n")); debugger_active = 1; } void StopDebugger() { if (debugger_active) { StopServer(); SysPrintf(_("Debugger stopped.\n")); } if (MemoryMap != NULL) { free(MemoryMap); MemoryMap = NULL; } while (first != NULL) delete_breakpoint(first); debugger_active = 0; } void PauseDebugger() { trace = 0; paused = 1; } void ResumeDebugger() { trace = 0; paused = 0; } void DebugVSync() { if (!debugger_active || resetting) return; if (reset) { resetting = 1; CheckCdrom(); SysReset(); if (reset == 2) LoadCdrom(); reset = resetting = 0; return; } GetClient(); ProcessCommands(); } void MarkMap(u32 address, int mask) { if ((address & 0xff000000) != 0x80000000) return; MemoryMap[address & 0x001fffff] |= mask; } int IsMapMarked(u32 address, int mask) { return (MemoryMap[address & 0x001fffff] & mask) != 0; } void ProcessDebug() { if (!debugger_active || reset || resetting) return; if (trace) { if (!(--trace)) { paused = 1; } } if (!paused) { DebugCheckBP(psxRegs.pc, E); } if (mapping_e) { MarkMap(psxRegs.pc, MAP_EXEC); if ((psxRegs.code >> 26) == 3) { MarkMap(_JumpTarget_, MAP_EXEC_JAL); } if (((psxRegs.code >> 26) == 0) && ((psxRegs.code & 0x3F) == 9)) { MarkMap(_Rd_, MAP_EXEC_JAL); } } while (paused) { GetClient(); ProcessCommands(); GPU_updateLace(); SysUpdate(); } } static void ProcessCommands() { int code, i, dumping; FILE *sfile; char cmd[257], *arguments, *p, reply[10240], *save, *dump; u32 reg, value, size, address; breakpoint_t *bp; if (!HasClient()) return; if (ReadSocket(cmd, 256) > 0) { arguments = NULL; if (strlen(cmd) <= 2) { code = 0; } else if (strlen(cmd) == 3) { code = strtol(cmd, 0, 16); } else if (!(isxdigit(cmd[0]) && isxdigit(cmd[1]) && isxdigit(cmd[2]) && (cmd[3] == 0x20))) { code = 0; } else if (sscanf(cmd, "%3X ", &code) != 1) { code = 0; } else { arguments = cmd + 4; } code = strtol(cmd, &arguments, 16); while (arguments && *arguments && *arguments == 0x20) arguments++; if (*arguments == '\0') arguments = NULL; dumping = 0; save = NULL; switch (code) { case 0x100: sprintf(reply, "200 %s\r\n", arguments == NULL ? "OK" : arguments); break; case 0x101: sprintf(reply, "201 %s\r\n", PCSX_VERSION); break; case 0x102: sprintf(reply, "202 1.0\r\n"); break; case 0x103: sprintf(reply, "203 %i\r\n", paused ? 1 : trace ? 2 : 0); break; case 0x110: sprintf(reply, "210 PC=%08X\r\n", psxRegs.pc); break; case 0x111: if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "511 Malformed 111 command '%s'\r\n", cmd); break; } } if (!arguments) { reply[0] = 0; for (i = 0; i < 32; i++) { sprintf(reply, "%s211 %02X=%08X\r\n", reply, i, psxRegs.GPR.r[i]); } } else { if ((code >= 0) && (code < 32)) { sprintf(reply, "211 %02X=%08X\r\n", code, psxRegs.GPR.r[code]); } else { sprintf(reply, "511 Invalid GPR register: %X\r\n", code); } } break; case 0x112: sprintf(reply, "212 LO=%08X HI=%08X\r\n", psxRegs.GPR.n.lo, psxRegs.GPR.n.hi); break; case 0x113: if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "511 Malformed 113 command '%s'\r\n", cmd); break; } } if (!arguments) { reply[0] = 0; for (i = 0; i < 32; i++) { sprintf(reply, "%s213 %02X=%08X\r\n", reply, i, psxRegs.CP0.r[i]); } } else { if ((code >= 0) && (code < 32)) { sprintf(reply, "213 %02X=%08X\r\n", code, psxRegs.CP0.r[code]); } else { sprintf(reply, "511 Invalid COP0 register: %X\r\n", code); } } break; case 0x114: if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "511 Malformed 114 command '%s'\r\n", cmd); break; } } if (!arguments) { reply[0] = 0; for (i = 0; i < 32; i++) { sprintf(reply, "%s214 %02X=%08X\r\n", reply, i, psxRegs.CP2C.r[i]); } } else { if ((code >= 0) && (code < 32)) { sprintf(reply, "214 %02X=%08X\r\n", code, psxRegs.CP2C.r[code]); } else { sprintf(reply, "511 Invalid COP2C register: %X\r\n", code); } } break; case 0x115: if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "511 Malformed 111 command '%s'\r\n", cmd); break; } } if (!arguments) { reply[0] = 0; for (i = 0; i < 32; i++) { sprintf(reply, "%s215 %02X=%08X\r\n", reply, i, psxRegs.CP2D.r[i]); } } else { if ((code >= 0) && (code < 32)) { sprintf(reply, "215 %02X=%08X\r\n", code, psxRegs.CP2D.r[code]); } else { sprintf(reply, "511 Invalid COP2D register: %X\r\n", code); } } break; case 0x119: if (arguments) { if (sscanf(arguments, "%08X", &code) != 1) { sprintf(reply, "511 Malformed 119 command '%s'\r\n", cmd); break; } } if (!arguments) code = psxRegs.pc; sprintf(reply, "219 %s\r\n", disR3000AF(psxMemRead32(code), code)); break; case 0x121: if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { sprintf(reply, "500 Malformed 121 command '%s'\r\n", arguments); break; } if (reg < 32) { psxRegs.GPR.r[reg] = value; sprintf(reply, "221 %02X=%08X\r\n", reg, value); } else { sprintf(reply, "512 Invalid GPR register: %02X\r\n", reg); } break; case 0x122: if (!arguments || strncmp(arguments, "HI=", 3) == 0) { reg = 33; } else if (arguments && strncmp(arguments, "LO=", 3) == 0) { reg = 32; } else { arguments[2] = 0; sprintf(reply, "512 Invalid LO/HI register: '%s'\r\n", arguments); break; } if (sscanf(arguments + 3, "%08X", &value) != 1) { sprintf(reply, "500 Malformed 122 command '%s'\r\n", arguments); } else { psxRegs.GPR.r[reg] = value; sprintf(reply, "222 LO=%08X HI=%08X\r\n", psxRegs.GPR.n.lo, psxRegs.GPR.n.hi); } break; case 0x123: if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { sprintf(reply, "500 Malformed 123 command '%s'\r\n", arguments); break; } if (reg < 32) { psxRegs.CP0.r[reg] = value; sprintf(reply, "223 %02X=%08X\r\n", reg, value); } else { sprintf(reply, "512 Invalid COP0 register: %02X\r\n", reg); } break; case 0x124: if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { sprintf(reply, "500 Malformed 124 command '%s'\r\n", arguments); break; } if (reg < 32) { psxRegs.CP2C.r[reg] = value; sprintf(reply, "224 %02X=%08X\r\n", reg, value); } else { sprintf(reply, "512 Invalid COP2C register: %02X\r\n", reg); } break; case 0x125: if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { sprintf(reply, "500 Malformed 121 command '%s'\r\n", arguments); break; } if (reg < 32) { psxRegs.CP2D.r[reg] = value; sprintf(reply, "225 %02X=%08X\r\n", reg, value); } else { sprintf(reply, "512 Invalid COP2D register: %02X\r\n", reg); } break; case 0x130: if (!arguments || sscanf(arguments, "%08X@%08X", &size, &address) != 2) { sprintf(reply, "500 Malformed 130 command '%s'\r\n", arguments); break; } if ((address >= 0x80000000) && ((address + size) <= 0x80200000)) { sprintf(reply, "230 %08X@%08X\r\n", size, address); dump = (char *) PSXM(address); dumping = 1; } else { sprintf(reply, "513 Invalid address or range: '%s'\r\n", arguments); } break; case 0x140: if (!arguments || sscanf(arguments, "%08X@%08X", &size, &address) != 2) { sprintf(reply, "500 Malformed 140 command '%s'\r\n", arguments); break; } if ((address >= 0x80000000) && ((address + size) <= 0x80200000)) { sprintf(reply, "240 %08X@%08X\r\n", size, address); RawReadSocket((char *)PSXM(address), size); } else { sprintf(reply, "514 Invalid address or range: '%s'\r\n", arguments); } break; case 0x150: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 150 command '%s'\r\n", cmd); break; } } if (code) { mapping_e = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_EXEC; MemoryMap[i] &= ~MAP_EXEC_JAL; } } else { mapping_e = 0; } sprintf(reply, "250 Mapping of exec flow %s\r\n", code ? "started" : "stopped"); break; case 0x151: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 151 command '%s'\r\n", cmd); break; } } if (code) { mapping_r8 = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_R8; } } else { mapping_r8 = 0; } sprintf(reply, "251 Mapping of read8 flow %s\r\n", code ? "started" : "stopped"); break; case 0x152: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 152 command '%s'\r\n", cmd); break; } } if (code) { mapping_r16 = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_R16; } } else { mapping_r16 = 0; } sprintf(reply, "252 Mapping of read16 flow %s\r\n", code ? "started" : "stopped"); break; case 0x153: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 153 command '%s'\r\n", cmd); break; } } if (code) { mapping_r32 = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_R32; } } else { mapping_r32 = 0; } sprintf(reply, "253 Mapping of read32 flow %s\r\n", code ? "started" : "stopped"); break; case 0x154: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 154 command '%s'\r\n", cmd); break; } } if (code) { mapping_w8 = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_W8; } } else { mapping_w8 = 0; } sprintf(reply, "254 Mapping of write8 flow %s\r\n", code ? "started" : "stopped"); break; case 0x155: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 155 command '%s'\r\n", cmd); break; } } if (code) { mapping_w16 = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_W16; } } else { mapping_w16 = 0; } sprintf(reply, "255 Mapping of write16 flow %s\r\n", code ? "started" : "stopped"); break; case 0x156: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 156 command '%s'\r\n", cmd); break; } } if (code) { mapping_w32 = 1; for (i = 0; i < 0x00200000; i++) { MemoryMap[i] &= ~MAP_W32; } } else { mapping_w32 = 0; } sprintf(reply, "256 Mapping of write32 flow %s\r\n", code ? "started" : "stopped"); break; case 0x160: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 160 command '%s'\r\n", cmd); break; } } if (code) { breakmp_e = 1; } else { breakmp_e = 0; } sprintf(reply, "260 Break on map of exec flow %s\r\n", code ? "started" : "stopped"); break; case 0x161: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 161 command '%s'\r\n", cmd); break; } } if (code) { breakmp_r8 = 1; } else { breakmp_r8 = 0; } sprintf(reply, "261 Break on map of read8 flow %s\r\n", code ? "started" : "stopped"); break; case 0x162: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 162 command '%s'\r\n", cmd); break; } } if (code) { breakmp_r16 = 1; } else { breakmp_r16 = 0; } sprintf(reply, "262 Break on map of read16 flow %s\r\n", code ? "started" : "stopped"); break; case 0x163: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 163 command '%s'\r\n", cmd); break; } } if (code) { breakmp_r32 = 1; } else { breakmp_r32 = 0; } sprintf(reply, "263 Break on map of read32 flow %s\r\n", code ? "started" : "stopped"); break; case 0x164: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 164 command '%s'\r\n", cmd); break; } } if (code) { breakmp_w8 = 1; } else { breakmp_w8 = 0; } sprintf(reply, "264 Break on map of write8 flow %s\r\n", code ? "started" : "stopped"); break; case 0x165: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 165 command '%s'\r\n", cmd); break; } } if (code) { breakmp_w16 = 1; } else { breakmp_w16 = 0; } sprintf(reply, "265 Break on map of write16 flow %s\r\n", code ? "started" : "stopped"); break; case 0x166: code = 1; if (arguments) { if (sscanf(arguments, "%02X", &code) != 1) { sprintf(reply, "500 Malformed 166 command '%s'\r\n", cmd); break; } } if (code) { breakmp_w32 = 1; } else { breakmp_w32 = 0; } sprintf(reply, "266 Break on map of write32 flow %s\r\n", code ? "started" : "stopped"); break; case 0x170: sfile = fopen("flow.idc", "wb"); fprintf(sfile, "#include \r\n\r\n"); fprintf(sfile, "static main(void) {\r\n"); for (i = 0; i < 0x00200000; i++) { if (IsMapMarked(i, MAP_EXEC_JAL)) { fprintf(sfile, "\tMakeFunction(0X8%07X,BADADDR);\r\n", i); } } fprintf(sfile, "}\r\n"); fclose(sfile); sfile = fopen("markcode.idc", "wb"); fprintf(sfile, "#include \r\n\r\n"); fprintf(sfile, "static main(void) {\r\n"); for (i = 0; i < 0x00200000; i++) { if (IsMapMarked(i, MAP_EXEC)) { fprintf(sfile, "\tMakeCode(0X8%07X);\r\n", i); } } fprintf(sfile, "}\r\n"); fclose(sfile); sprintf(reply, "270 flow.idc and markcode.idc dumped\r\n"); break; case 0x300: p = arguments; if (arguments) { code = strtol(arguments, &p, 16); } if (p == arguments) { if (first) { reply[0] = 0; for (bp = first; bp; bp = next_breakpoint(bp)) { sprintf(reply, "%s400 %X@%08X-%s\r\n", reply, bp->number, bp->address, breakpoint_type_names[bp->type]); } } else { sprintf(reply, "530 No breakpoint\r\n"); } } else { if ((bp = find_breakpoint(code))) { sprintf(reply, "400 %X@%08X-%s\r\n", bp->number, bp->address, breakpoint_type_names[bp->type]); } else { sprintf(reply, "530 Invalid breakpoint number: %X\r\n", code); } } break; case 0x301: p = arguments; if (arguments) { code = strtol(arguments, &p, 16); } if (p == arguments) { while (first != NULL) delete_breakpoint(first); sprintf(reply, "401 All breakpoints deleted.\r\n"); } else { if ((bp = find_breakpoint(code))) { delete_breakpoint(bp); sprintf(reply, "401 Breakpoint %X deleted.\r\n", code); } else { sprintf(reply, "530 Invalid breakpoint number: %X\r\n", code); } } break; case 0x310: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 310 command '%s'\r\n", arguments); break; } // if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) { // sprintf(reply, "531 Invalid address %08X\r\n", address); // break; // } code = add_breakpoint(E, address); sprintf(reply, "410 %X\r\n", code); break; case 0x320: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 320 command '%s'\r\n", arguments); break; } if ((address < 0x80000000) || (address >= 0x80200000)) { sprintf(reply, "532 Invalid address %08X\r\n", address); break; } code = add_breakpoint(R1, address); sprintf(reply, "420 %X\r\n", code); break; case 0x321: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 321 command '%s'\r\n", arguments); break; } if ((address & 1) || (address < 0x80000000) || (address >= 0x80200000)) { sprintf(reply, "532 Invalid address %08X\r\n", address); break; } code = add_breakpoint(R2, address); sprintf(reply, "421 %X\r\n", code); break; case 0x322: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 322 command '%s'\r\n", arguments); break; } if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) { sprintf(reply, "532 Invalid address %08X\r\n", address); break; } code = add_breakpoint(R4, address); sprintf(reply, "422 %X\r\n", code); break; case 0x330: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 330 command '%s'\r\n", arguments); break; } if ((address < 0x80000000) || (address >= 0x80200000)) { sprintf(reply, "533 Invalid address %08X\r\n", address); break; } code = add_breakpoint(W1, address); sprintf(reply, "430 %X\r\n", code); break; case 0x331: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 331 command '%s'\r\n", arguments); break; } if ((address & 1) || (address < 0x80000000) || (address >= 0x80200000)) { sprintf(reply, "533 Invalid address %08X\r\n", address); break; } code = add_breakpoint(W2, address); sprintf(reply, "431 %X\r\n", code); break; case 0x332: if (!arguments || sscanf(arguments, "%08X", &address) != 1) { sprintf(reply, "500 Malformed 332 command '%s'\r\n", arguments); break; } if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) { sprintf(reply, "533 Invalid address %08X\r\n", address); break; } code = add_breakpoint(W4, address); sprintf(reply, "432 %X\r\n", code); break; case 0x390: paused = 1; sprintf(reply, "490 Paused\r\n"); break; case 0x391: paused = 0; sprintf(reply, "491 Resumed\r\n"); break; case 0x395: p = arguments; if (arguments) { trace = strtol(arguments, &p, 10); } if (p == arguments) { trace = 1; } paused = 0; sprintf(reply, "495 Tracing\r\n"); break; case 0x398: paused = 0; trace = 0; reset = 2; sprintf(reply, "498 Soft resetting\r\n"); break; case 0x399: paused = 0; trace = 0; reset = 1; sprintf(reply, "499 Resetting\r\n"); break; default: sprintf(reply, "500 Unknown command '%s'\r\n", cmd); break; } WriteSocket(reply, strlen(reply)); if (dumping) { WriteSocket(dump, size); } if (save) { free(save); } } } void DebugCheckBP(u32 address, enum breakpoint_types type) { breakpoint_t *bp; char reply[512]; if (!debugger_active || reset) return; for (bp = first; bp; bp = next_breakpoint(bp)) { if ((bp->type == type) && (bp->address == address)) { sprintf(reply, "030 %X@%08X\r\n", bp->number, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; return; } } if (breakmp_e && type == E) { if (!IsMapMarked(address, MAP_EXEC)) { sprintf(reply, "010 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (breakmp_r8 && type == R1) { if (!IsMapMarked(address, MAP_R8)) { sprintf(reply, "011 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (breakmp_r16 && type == R2) { if (!IsMapMarked(address, MAP_R16)) { sprintf(reply, "012 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (breakmp_r32 && type == R4) { if (!IsMapMarked(address, MAP_R32)) { sprintf(reply, "013 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (breakmp_w8 && type == W1) { if (!IsMapMarked(address, MAP_W8)) { sprintf(reply, "014 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (breakmp_w16 && type == W2) { if (!IsMapMarked(address, MAP_W16)) { sprintf(reply, "015 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (breakmp_w32 && type == W4) { if (!IsMapMarked(address, MAP_W32)) { sprintf(reply, "016 %08X@%08X\r\n", address, psxRegs.pc); WriteSocket(reply, strlen(reply)); paused = 1; } } if (mapping_r8 && type == R1) MarkMap(address, MAP_R8); if (mapping_r16 && type == R2) MarkMap(address, MAP_R16); if (mapping_r32 && type == R4) MarkMap(address, MAP_R32); if (mapping_w8 && type == W1) MarkMap(address, MAP_W8); if (mapping_w16 && type == W2) MarkMap(address, MAP_W16); if (mapping_w32 && type == W4) MarkMap(address, MAP_W32); }