deal with some more annoying warnings
[pcsx_rearmed.git] / libpcsxcore / debug.c
1 /*  Pcsx - Pc Psx Emulator
2  *  Copyright (C) 1999-2003  Pcsx Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, see <http://www.gnu.org/licenses>.
16  */
17
18 #include "psxcommon.h"
19 #include "r3000a.h"
20 #include "debug.h"
21 #include "socket.h"
22
23 // XXX: don't care but maybe fix it someday
24 #if defined(__GNUC__) && __GNUC__ >= 7
25 #pragma GCC diagnostic ignored "-Wrestrict"
26 #endif
27
28 /*
29 PCSX Debug console protocol description, version 1.0
30 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31
32 Commands number are formatted using %03X (yes)
33 Registers number are formatted using %02X.
34 Breakpoints numbers are formatted using %X
35 All other values are formatted using %08X, unless specified.
36
37
38 Client inputs:
39 ~~~~~~~~~~~~~
40 Basic commands (1xx):
41 --------------------
42 100 <message>
43     Sends a dumb message. Will be replied with a 200 reply, followed by the message.
44 101
45     Gets PCSX version.
46 102
47     Gets protocol version.
48 103
49     Gets status
50 110
51     Gets PC.
52 111 [reg]
53     Gets GP register, or all, if no argument.
54 112
55     Gets LO/HI registers.
56 113 [reg]
57     Gets COP0 register, or all, if no argument.
58 114 [reg]
59     Gets COP2 control register, or all, if no argument.
60 115 [reg]
61     Gets COP2 data register, or all, if no argument.
62 119 [pc]
63     Disassemble current PC, or given PC.
64 121 <reg>=<value>
65     Sets a GP register. Will return a 221 message.
66 122 <LO|HI>=<value>
67     Sets LO or HI register. Will return a 222 message.
68 123 <reg>=<value>
69     Sets a COP0 register. Will return a 223 message.
70 124 <reg>=<value>
71     Sets a COP2 control register. Will return a 224 message.
72 125 <reg>=<value>
73     Sets a COP2 data register. Will return a 225 message.
74 130 <size>@<addr>
75     Dumps a range of memory, of size bytes starting at addr.
76 140 <size>@<addr>
77     Sets a range of memory, of size bytes starting at addr.
78     Will have to send immediately exactly size bytes afterward.
79 150 [number]
80     Starts/reset mapping execution flow, or stop it if number = 0
81 151 [number]
82     Starts/reset mapping read8 flow, or stop it if number = 0
83 152 [number]
84     Starts/reset mapping read16 flow, or stop it if number = 0
85 153 [number]
86     Starts/reset mapping read32 flow, or stop it if number = 0
87 154 [number]
88     Starts/reset mapping write8 flow, or stop it if number = 0
89 155 [number]
90     Starts/reset mapping write16 flow, or stop it if number = 0
91 156 [number]
92     Starts/reset mapping write32 flow, or stop it if number = 0
93 160 [number]
94     Breaks on map exec flow, or stop it if number = 0
95 161 [number]
96     Breaks on map read8 flow, or stop it if number = 0
97 162 [number]
98     Breaks on map read16 flow, or stop it if number = 0
99 163 [number]
100     Breaks on map read32 flow, or stop it if number = 0
101 164 [number]
102     Breaks on map write8 flow, or stop it if number = 0
103 165 [number]
104     Breaks on map write16 flow, or stop it if number = 0
105 166 [number]
106     Breaks on map write32 flow, or stop it if number = 0
107 170
108     Dumps the execution flow map in an IDC file
109
110 Execution flow control commands (3xx):
111 -------------------------------------
112 300 [number]
113     Get a list of the actual breakpoints. Will get '400' answers.
114 301 [number]
115     Deletes a breakpoint, or all, if no arguments.
116 310 <address>
117     Sets an exec breakpoint.
118 320 <address>
119     Sets a read breakpoint, 1 byte / 8 bits.
120 321 <address>
121     Sets a read breakpoint, 2 bytes / 16 bits, has to be on an even address.
122 322 <address>
123     Sets a read breakpoint, 4 bytes / 32 bits, address has to be 4-bytes aligned.
124 330 <address>
125     Sets a write breakpoint, 1 byte / 8 bits.
126 331 <address>
127     Sets a write breakpoint, 2 bytes / 16 bits, has to be on an even address.
128 332 <address>
129     Sets a write breakpoint, 4 bytes / 32 bits, address has to be 4-bytes aligned.
130 390
131     Pauses execution. Equivalents to a breakpoint.
132 391
133     Restarts execution.
134 395 [number]
135     Traces execution, 1 instruction by default. Formatted using %i
136 398
137     Soft (quick) resets.
138 399
139     Resets.
140     
141
142 Server outputs:
143 ~~~~~~~~~~~~~~
144 Spontaneous messages (0xx):
145 --------------------------
146 000 <message>
147     Greeting banner.
148 010 / 011 / 012 / 013 / 014 / 015 / 016
149     Execution hit mapping flow automatic breakpoint.
150 030 <number>@<PC>
151     Execution hit breakpoint, PCSX is paused. Displays PC's value.
152
153 Basic commands acknowledge (2xx):
154 --------------------------------
155 200 <message>
156     Sends a dumb message.
157 201 <message>
158     Returns PCSX version.
159 202 <message>
160     Returns protocol version.
161 203 <status>
162     status = 0: running; = 1: paused; = 2: trace
163 210 PC=<value>
164     Displays current PC value.
165 211 <reg>=<value>
166     Displays one GP register value.
167 212 LO=<value> HI=<value>
168     Displays LO/HI registers.
169 213 <reg>=<value>
170     Displays one COP0 register value.
171 214 <reg>=<value>
172     Displays one COP2 control register value.
173 215 <reg>=<value>
174     Displays one COP2 data register value.
175 219 <message>
176     Displays one line of disassembled code.
177 221 <reg>=<value>
178     Displays one GP register value, ack for modification.
179 222 LO=<value> HI=<value>
180     Displays LO/HI registers, ack for modification.
181 223 <reg>=<value>
182     Displays one COP0 register value, ack for modification.
183 224 <reg>=<value>
184     Displays one COP2 control register value, ack for modification.
185 225 <reg>=<value>
186     Displays one COP2 data register value, ack for modification.
187 230 <size>@<addr>
188     Dumping memory. Will then raw outputs size bytes.
189 240 <size>@<addr>
190     Memory set acknowledge.
191 250 / 251 / 252 / 253 / 254 / 255 / 256
192     Acknolwedge of 15x commands.
193 260 / 261 / 262 / 263 / 264 / 265 / 266
194     Acknolwedge of 16x commands.
195 270
196     Acknolwedge of 170 command.
197
198 Execution flow control commands acknowledge (4xx):
199 -------------------------------------------------
200 400 <number>@<address>-<type>
201     Displays a breakpoint, where 'type' can be of E, R1, R2, R4, W1, W2 or W4.
202 401 <message>
203     Breakpoint deleting acknowledge.
204 410, 420, 421, 422, 430, 431, 432 <number>
205     Breakpoint adding acknowledge. Returns the number of the added breakpoint.
206 490 <message>
207     Pausing.
208 491 <message>
209     Resuming.
210 495 <message>
211     Tracing.
212 498 <message>
213     Soft resetting.
214 499 <message>
215     Resetting.
216
217 Error messages (5xx):
218 --------------------
219 500 <message>
220     Command not understood.
221 511 <message>
222     Invalid GPR register.
223 512 <message>
224     Invalid LO/HI register.
225 513, 514 <message>
226     Invalid range or address.
227 530 <message>
228     Non existant breakpoint.
229 531, 532, 533 <message>
230     Invalid breakpoint address.
231 */
232
233 static int debugger_active = 0, paused = 0, trace = 0, reset = 0, resetting = 0;
234 static int mapping_e = 0, mapping_r8 = 0, mapping_r16 = 0, mapping_r32 = 0, mapping_w8 = 0, mapping_w16 = 0, mapping_w32 = 0;
235 static int breakmp_e = 0, breakmp_r8 = 0, breakmp_r16 = 0, breakmp_r32 = 0, breakmp_w8 = 0, breakmp_w16 = 0, breakmp_w32 = 0;
236
237 static void ProcessCommands();
238
239 static u8 *MemoryMap = NULL;
240
241 enum {
242     MAP_EXEC = 1,
243     MAP_R8 = 2,
244     MAP_R16 = 4,
245     MAP_R32 = 8,
246     MAP_W8 = 16,
247     MAP_W16 = 32,
248     MAP_W32 = 64,
249     MAP_EXEC_JAL = 128,
250 };
251
252 char *breakpoint_type_names[] = {
253     "E", "R1", "R2", "R4", "W1", "W2", "W4"
254 };
255
256 typedef struct breakpoint_s {
257     struct breakpoint_s *next, *prev;
258     int number, type;
259     u32 address;
260 } breakpoint_t;
261
262 static breakpoint_t *first = NULL;
263
264 int add_breakpoint(int type, u32 address) {
265     breakpoint_t *bp = (breakpoint_t *)malloc(sizeof(breakpoint_t));
266
267     bp->type = type;
268     bp->address = address;
269
270     if (first) {
271         bp->number = first->prev->number + 1;
272         bp->next = first;
273         bp->prev = first->prev;
274         first->prev = bp;
275         bp->prev->next = bp;
276     } else {
277         first = bp;
278         bp->number = 1;
279         bp->next = bp;
280         bp->prev = bp;
281     }
282
283     return bp->number;
284 }
285
286 void delete_breakpoint(breakpoint_t * bp) {
287     if (bp == first) {
288         if (bp->next == bp) {
289             first = NULL;
290         } else {
291             first = bp->next;
292         }
293     }
294
295     bp->next->prev = bp->prev;
296     bp->prev->next = bp->next;
297
298     free(bp);
299 }
300
301 breakpoint_t *next_breakpoint(breakpoint_t *bp) {
302     return bp->next != first ? bp->next : 0;
303 }
304
305 breakpoint_t *find_breakpoint(int number) {
306     breakpoint_t *p;
307
308     for (p = first; p; p = next_breakpoint(p)) {
309         if (p->number == number)
310             return p;
311     }
312
313     return 0;
314 }
315
316 void StartDebugger() {
317     if (debugger_active)
318         return;
319
320     MemoryMap = (u8 *)malloc(0x200000);
321     if (MemoryMap == NULL) {
322         SysMessage(_("Error allocating memory"));
323         return;
324     }
325
326     if (StartServer() == -1) {
327         SysPrintf(_("Unable to start debug server.\n"));
328         return;
329     }
330
331     SysPrintf(_("Debugger started.\n"));
332     debugger_active = 1;
333 }
334
335 void StopDebugger() {
336     if (debugger_active) {
337         StopServer();
338         SysPrintf(_("Debugger stopped.\n"));
339     }
340
341     if (MemoryMap != NULL) {
342         free(MemoryMap);
343         MemoryMap = NULL;
344     }
345
346     while (first != NULL) delete_breakpoint(first);
347
348     debugger_active = 0;
349 }
350
351 void PauseDebugger() {
352     trace = 0;
353     paused = 1;
354 }
355
356 void ResumeDebugger() {
357     trace = 0;
358     paused = 0;
359 }
360
361 void DebugVSync() {
362     if (!debugger_active || resetting)
363         return;
364
365     if (reset) {
366         resetting = 1;
367         CheckCdrom();
368         SysReset();
369         if (reset == 2)
370             LoadCdrom();
371         reset = resetting = 0;
372         return;
373     }
374
375     GetClient();
376     ProcessCommands();
377 }
378
379 void MarkMap(u32 address, int mask) {
380     if ((address & 0xff000000) != 0x80000000) return;
381     MemoryMap[address & 0x001fffff] |= mask;
382 }
383
384 int IsMapMarked(u32 address, int mask) {
385     return (MemoryMap[address & 0x001fffff] & mask) != 0;
386 }
387
388 void ProcessDebug() {
389     if (!debugger_active || reset || resetting)
390         return;
391     if (trace) {
392         if (!(--trace)) {
393             paused = 1;
394         }
395     }
396     if (!paused) {
397         DebugCheckBP(psxRegs.pc, E);
398     }
399     if (mapping_e) {
400         MarkMap(psxRegs.pc, MAP_EXEC);
401         if ((psxRegs.code >> 26) == 3) {
402             MarkMap(_JumpTarget_, MAP_EXEC_JAL);
403         }
404         if (((psxRegs.code >> 26) == 0) && ((psxRegs.code & 0x3F) == 9)) {
405             MarkMap(_Rd_, MAP_EXEC_JAL);
406         }
407     }
408     while (paused) {
409         GetClient();
410         ProcessCommands();
411         GPU_updateLace();
412         SysUpdate();
413     }
414 }
415
416 static void ProcessCommands() {
417     int code, i, dumping;
418     FILE *sfile;
419     char cmd[257], *arguments, *p, reply[10240], *save, *dump;
420     u32 reg, value, size, address;
421     breakpoint_t *bp;
422
423     if (!HasClient())
424         return;
425     if (ReadSocket(cmd, 256) > 0) {
426         arguments = NULL;
427         if (strlen(cmd) <= 2) {
428             code = 0;
429         } else if (strlen(cmd) == 3) {
430             code = strtol(cmd, 0, 16);
431         } else if (!(isxdigit(cmd[0]) && isxdigit(cmd[1]) && isxdigit(cmd[2]) && (cmd[3] == 0x20))) {
432             code = 0;
433         } else if (sscanf(cmd, "%3X ", &code) != 1) {
434             code = 0;
435         } else {
436             arguments = cmd + 4;
437         }
438         code = strtol(cmd, &arguments, 16);
439         while (arguments && *arguments && *arguments == 0x20)
440             arguments++;
441
442         if (*arguments == '\0')
443             arguments = NULL;
444
445         dumping = 0;
446         save = NULL;
447
448         switch (code) {
449         case 0x100:
450             sprintf(reply, "200 %s\r\n", arguments == NULL ? "OK" : arguments);
451             break;
452         case 0x101:
453             sprintf(reply, "201 %s\r\n", PACKAGE_VERSION);
454             break;
455         case 0x102:
456             sprintf(reply, "202 1.0\r\n");
457             break;
458         case 0x103:
459             sprintf(reply, "203 %i\r\n", paused ? 1 : trace ? 2 : 0);
460             break;
461         case 0x110:
462             sprintf(reply, "210 PC=%08X\r\n", psxRegs.pc);
463             break;
464         case 0x111:
465             if (arguments) {
466                 if (sscanf(arguments, "%02X", &code) != 1) {
467                     sprintf(reply, "511 Malformed 111 command '%s'\r\n", cmd);
468                     break;
469                 }
470             }
471             if (!arguments) {
472                 reply[0] = 0;
473                 for (i = 0; i < 32; i++) {
474                     sprintf(reply, "%s211 %02X=%08X\r\n", reply, i, psxRegs.GPR.r[i]);
475                 }
476             } else {
477                 if ((code >= 0) && (code < 32)) {
478                     sprintf(reply, "211 %02X=%08X\r\n", code, psxRegs.GPR.r[code]);
479                 } else {
480                     sprintf(reply, "511 Invalid GPR register: %X\r\n", code);
481                 }
482             }
483             break;
484         case 0x112:
485             sprintf(reply, "212 LO=%08X HI=%08X\r\n", psxRegs.GPR.n.lo, psxRegs.GPR.n.hi);
486             break;
487         case 0x113:
488             if (arguments) {
489                 if (sscanf(arguments, "%02X", &code) != 1) {
490                     sprintf(reply, "511 Malformed 113 command '%s'\r\n", cmd);
491                     break;
492                 }
493             }
494             if (!arguments) {
495                 reply[0] = 0;
496                 for (i = 0; i < 32; i++) {
497                     sprintf(reply, "%s213 %02X=%08X\r\n", reply, i, psxRegs.CP0.r[i]);
498                 }
499             } else {
500                 if ((code >= 0) && (code < 32)) {
501                     sprintf(reply, "213 %02X=%08X\r\n", code, psxRegs.CP0.r[code]);
502                 } else {
503                     sprintf(reply, "511 Invalid COP0 register: %X\r\n", code);
504                 }
505             }
506             break;
507         case 0x114:
508             if (arguments) {
509                 if (sscanf(arguments, "%02X", &code) != 1) {
510                     sprintf(reply, "511 Malformed 114 command '%s'\r\n", cmd);
511                     break;
512                 }
513             }
514             if (!arguments) {
515                 reply[0] = 0;
516                 for (i = 0; i < 32; i++) {
517                     sprintf(reply, "%s214 %02X=%08X\r\n", reply, i, psxRegs.CP2C.r[i]);
518                 }
519             } else {
520                 if ((code >= 0) && (code < 32)) {
521                     sprintf(reply, "214 %02X=%08X\r\n", code, psxRegs.CP2C.r[code]);
522                 } else {
523                     sprintf(reply, "511 Invalid COP2C register: %X\r\n", code);
524                 }
525             }
526             break;
527         case 0x115:
528             if (arguments) {
529                 if (sscanf(arguments, "%02X", &code) != 1) {
530                     sprintf(reply, "511 Malformed 111 command '%s'\r\n", cmd);
531                     break;
532                 }
533             }
534             if (!arguments) {
535                 reply[0] = 0;
536                 for (i = 0; i < 32; i++) {
537                     sprintf(reply, "%s215 %02X=%08X\r\n", reply, i, psxRegs.CP2D.r[i]);
538                 }
539             } else {
540                 if ((code >= 0) && (code < 32)) {
541                     sprintf(reply, "215 %02X=%08X\r\n", code, psxRegs.CP2D.r[code]);
542                 } else {
543                     sprintf(reply, "511 Invalid COP2D register: %X\r\n", code);
544                 }
545             }
546             break;
547         case 0x119:
548             if (arguments) {
549                 if (sscanf(arguments, "%08X", &code) != 1) {
550                     sprintf(reply, "511 Malformed 119 command '%s'\r\n", cmd);
551                     break;
552                 }
553             }
554             if (!arguments)
555                 code = psxRegs.pc;
556
557             sprintf(reply, "219 %s\r\n", disR3000AF(psxMemRead32(code), code));
558             break;
559         case 0x121:
560             if (!arguments || sscanf(arguments, "%02X=%08X", &reg, &value) != 2) {
561                 sprintf(reply, "500 Malformed 121 command '%s'\r\n", arguments);
562                 break;
563             }
564
565             if (reg < 32) {
566                 psxRegs.GPR.r[reg] = value;
567                 sprintf(reply, "221 %02X=%08X\r\n", reg, value);
568             } else {
569                 sprintf(reply, "512 Invalid GPR register: %02X\r\n", reg);
570             }
571             break;
572         case 0x122:
573             if (!arguments || strncmp(arguments, "HI=", 3) == 0) {
574                 reg = 33;
575             } else if (arguments && strncmp(arguments, "LO=", 3) == 0) {
576                 reg = 32;
577             } else {
578                 arguments[2] = 0;
579                 sprintf(reply, "512 Invalid LO/HI register: '%s'\r\n", arguments);
580                 break;
581             }
582
583             if (sscanf(arguments + 3, "%08X", &value) != 1) {
584                 sprintf(reply, "500 Malformed 122 command '%s'\r\n", arguments);
585             } else {
586                 psxRegs.GPR.r[reg] = value;
587                 sprintf(reply, "222 LO=%08X HI=%08X\r\n", psxRegs.GPR.n.lo, psxRegs.GPR.n.hi);
588             }
589             break;
590         case 0x123:
591             if (!arguments || sscanf(arguments, "%02X=%08X", &reg, &value) != 2) {
592                 sprintf(reply, "500 Malformed 123 command '%s'\r\n", arguments);
593                 break;
594             }
595
596             if (reg < 32) {
597                 psxRegs.CP0.r[reg] = value;
598                 sprintf(reply, "223 %02X=%08X\r\n", reg, value);
599             } else {
600                 sprintf(reply, "512 Invalid COP0 register: %02X\r\n", reg);
601             }
602             break;
603         case 0x124:
604             if (!arguments || sscanf(arguments, "%02X=%08X", &reg, &value) != 2) {
605                 sprintf(reply, "500 Malformed 124 command '%s'\r\n", arguments);
606                 break;
607             }
608
609             if (reg < 32) {
610                 psxRegs.CP2C.r[reg] = value;
611                 sprintf(reply, "224 %02X=%08X\r\n", reg, value);
612             } else {
613                 sprintf(reply, "512 Invalid COP2C register: %02X\r\n", reg);
614             }
615             break;
616         case 0x125:
617             if (!arguments || sscanf(arguments, "%02X=%08X", &reg, &value) != 2) {
618                 sprintf(reply, "500 Malformed 121 command '%s'\r\n", arguments);
619                 break;
620             }
621
622             if (reg < 32) {
623                 psxRegs.CP2D.r[reg] = value;
624                 sprintf(reply, "225 %02X=%08X\r\n", reg, value);
625             } else {
626                 sprintf(reply, "512 Invalid COP2D register: %02X\r\n", reg);
627             }
628             break;
629         case 0x130:
630             if (!arguments || sscanf(arguments, "%08X@%08X", &size, &address) != 2) {
631                 sprintf(reply, "500 Malformed 130 command '%s'\r\n", arguments);
632                 break;
633             }
634
635             if ((address >= 0x80000000) && ((address + size) <= 0x80200000)) {
636                 sprintf(reply, "230 %08X@%08X\r\n", size, address);
637                 dump = (char *) PSXM(address);
638                 dumping = 1;
639             } else {
640                 sprintf(reply, "513 Invalid address or range: '%s'\r\n", arguments);
641             }
642             break;
643         case 0x140:
644             if (!arguments || sscanf(arguments, "%08X@%08X", &size, &address) != 2) {
645                 sprintf(reply, "500 Malformed 140 command '%s'\r\n", arguments);
646                 break;
647             }
648
649             if ((address >= 0x80000000) && ((address + size) <= 0x80200000)) {
650                 sprintf(reply, "240 %08X@%08X\r\n", size, address);
651                 RawReadSocket((char *)PSXM(address), size);
652             } else {
653                 sprintf(reply, "514 Invalid address or range: '%s'\r\n", arguments);
654             }
655             break;
656         case 0x150:
657             code = 1;
658             if (arguments) {
659                 if (sscanf(arguments, "%02X", &code) != 1) {
660                     sprintf(reply, "500 Malformed 150 command '%s'\r\n", cmd);
661                     break;
662                 }
663             }
664             if (code) {
665                 mapping_e = 1;
666                 for (i = 0; i < 0x00200000; i++) {
667                     MemoryMap[i] &= ~MAP_EXEC;
668                     MemoryMap[i] &= ~MAP_EXEC_JAL;
669                 }
670             } else {
671                 mapping_e = 0;
672             }
673             sprintf(reply, "250 Mapping of exec flow %s\r\n", code ? "started" : "stopped");
674             break;
675         case 0x151:
676             code = 1;
677             if (arguments) {
678                 if (sscanf(arguments, "%02X", &code) != 1) {
679                     sprintf(reply, "500 Malformed 151 command '%s'\r\n", cmd);
680                     break;
681                 }
682             }
683             if (code) {
684                 mapping_r8 = 1;
685                 for (i = 0; i < 0x00200000; i++) {
686                     MemoryMap[i] &= ~MAP_R8;
687                 }
688             } else {
689                 mapping_r8 = 0;
690             }
691             sprintf(reply, "251 Mapping of read8 flow %s\r\n", code ? "started" : "stopped");
692             break;
693         case 0x152:
694             code = 1;
695             if (arguments) {
696                 if (sscanf(arguments, "%02X", &code) != 1) {
697                     sprintf(reply, "500 Malformed 152 command '%s'\r\n", cmd);
698                     break;
699                 }
700             }
701             if (code) {
702                 mapping_r16 = 1;
703                 for (i = 0; i < 0x00200000; i++) {
704                     MemoryMap[i] &= ~MAP_R16;
705                 }
706             } else {
707                 mapping_r16 = 0;
708             }
709             sprintf(reply, "252 Mapping of read16 flow %s\r\n", code ? "started" : "stopped");
710             break;
711         case 0x153:
712             code = 1;
713             if (arguments) {
714                 if (sscanf(arguments, "%02X", &code) != 1) {
715                     sprintf(reply, "500 Malformed 153 command '%s'\r\n", cmd);
716                     break;
717                 }
718             }
719             if (code) {
720                 mapping_r32 = 1;
721                 for (i = 0; i < 0x00200000; i++) {
722                     MemoryMap[i] &= ~MAP_R32;
723                 }
724             } else {
725                 mapping_r32 = 0;
726             }
727             sprintf(reply, "253 Mapping of read32 flow %s\r\n", code ? "started" : "stopped");
728             break;
729         case 0x154:
730             code = 1;
731             if (arguments) {
732                 if (sscanf(arguments, "%02X", &code) != 1) {
733                     sprintf(reply, "500 Malformed 154 command '%s'\r\n", cmd);
734                     break;
735                 }
736             }
737             if (code) {
738                 mapping_w8 = 1;
739                 for (i = 0; i < 0x00200000; i++) {
740                     MemoryMap[i] &= ~MAP_W8;
741                 }
742             } else {
743                 mapping_w8 = 0;
744             }
745             sprintf(reply, "254 Mapping of write8 flow %s\r\n", code ? "started" : "stopped");
746             break;
747         case 0x155:
748             code = 1;
749             if (arguments) {
750                 if (sscanf(arguments, "%02X", &code) != 1) {
751                     sprintf(reply, "500 Malformed 155 command '%s'\r\n", cmd);
752                     break;
753                 }
754             }
755             if (code) {
756                 mapping_w16 = 1;
757                 for (i = 0; i < 0x00200000; i++) {
758                     MemoryMap[i] &= ~MAP_W16;
759                 }
760             } else {
761                 mapping_w16 = 0;
762             }
763             sprintf(reply, "255 Mapping of write16 flow %s\r\n", code ? "started" : "stopped");
764             break;
765         case 0x156:
766             code = 1;
767             if (arguments) {
768                 if (sscanf(arguments, "%02X", &code) != 1) {
769                     sprintf(reply, "500 Malformed 156 command '%s'\r\n", cmd);
770                     break;
771                 }
772             }
773             if (code) {
774                 mapping_w32 = 1;
775                 for (i = 0; i < 0x00200000; i++) {
776                     MemoryMap[i] &= ~MAP_W32;
777                 }
778             } else {
779                 mapping_w32 = 0;
780             }
781             sprintf(reply, "256 Mapping of write32 flow %s\r\n", code ? "started" : "stopped");
782             break;
783         case 0x160:
784             code = 1;
785             if (arguments) {
786                 if (sscanf(arguments, "%02X", &code) != 1) {
787                     sprintf(reply, "500 Malformed 160 command '%s'\r\n", cmd);
788                     break;
789                 }
790             }
791             if (code) {
792                 breakmp_e = 1;
793             } else {
794                 breakmp_e = 0;
795             }
796             sprintf(reply, "260 Break on map of exec flow %s\r\n", code ? "started" : "stopped");
797             break;
798         case 0x161:
799             code = 1;
800             if (arguments) {
801                 if (sscanf(arguments, "%02X", &code) != 1) {
802                     sprintf(reply, "500 Malformed 161 command '%s'\r\n", cmd);
803                     break;
804                 }
805             }
806             if (code) {
807                 breakmp_r8 = 1;
808             } else {
809                 breakmp_r8 = 0;
810             }
811             sprintf(reply, "261 Break on map of read8 flow %s\r\n", code ? "started" : "stopped");
812             break;
813         case 0x162:
814             code = 1;
815             if (arguments) {
816                 if (sscanf(arguments, "%02X", &code) != 1) {
817                     sprintf(reply, "500 Malformed 162 command '%s'\r\n", cmd);
818                     break;
819                 }
820             }
821             if (code) {
822                 breakmp_r16 = 1;
823             } else {
824                 breakmp_r16 = 0;
825             }
826             sprintf(reply, "262 Break on map of read16 flow %s\r\n", code ? "started" : "stopped");
827             break;
828         case 0x163:
829             code = 1;
830             if (arguments) {
831                 if (sscanf(arguments, "%02X", &code) != 1) {
832                     sprintf(reply, "500 Malformed 163 command '%s'\r\n", cmd);
833                     break;
834                 }
835             }
836             if (code) {
837                 breakmp_r32 = 1;
838             } else {
839                 breakmp_r32 = 0;
840             }
841             sprintf(reply, "263 Break on map of read32 flow %s\r\n", code ? "started" : "stopped");
842             break;
843         case 0x164:
844             code = 1;
845             if (arguments) {
846                 if (sscanf(arguments, "%02X", &code) != 1) {
847                     sprintf(reply, "500 Malformed 164 command '%s'\r\n", cmd);
848                     break;
849                 }
850             }
851             if (code) {
852                 breakmp_w8 = 1;
853             } else {
854                 breakmp_w8 = 0;
855             }
856             sprintf(reply, "264 Break on map of write8 flow %s\r\n", code ? "started" : "stopped");
857             break;
858         case 0x165:
859             code = 1;
860             if (arguments) {
861                 if (sscanf(arguments, "%02X", &code) != 1) {
862                     sprintf(reply, "500 Malformed 165 command '%s'\r\n", cmd);
863                     break;
864                 }
865             }
866             if (code) {
867                 breakmp_w16 = 1;
868             } else {
869                 breakmp_w16 = 0;
870             }
871             sprintf(reply, "265 Break on map of write16 flow %s\r\n", code ? "started" : "stopped");
872             break;
873         case 0x166:
874             code = 1;
875             if (arguments) {
876                 if (sscanf(arguments, "%02X", &code) != 1) {
877                     sprintf(reply, "500 Malformed 166 command '%s'\r\n", cmd);
878                     break;
879                 }
880             }
881             if (code) {
882                 breakmp_w32 = 1;
883             } else {
884                 breakmp_w32 = 0;
885             }
886             sprintf(reply, "266 Break on map of write32 flow %s\r\n", code ? "started" : "stopped");
887             break;
888         case 0x170:
889             sfile = fopen("flow.idc", "wb");
890             fprintf(sfile, "#include <idc.idc>\r\n\r\n");
891             fprintf(sfile, "static main(void) {\r\n");
892             for (i = 0; i < 0x00200000; i++) {
893                 if (IsMapMarked(i, MAP_EXEC_JAL)) {
894                     fprintf(sfile, "\tMakeFunction(0X8%07X,BADADDR);\r\n", i);
895                 }
896             }
897             fprintf(sfile, "}\r\n");
898             fclose(sfile);
899             sfile = fopen("markcode.idc", "wb");
900             fprintf(sfile, "#include <idc.idc>\r\n\r\n");
901             fprintf(sfile, "static main(void) {\r\n");
902             for (i = 0; i < 0x00200000; i++) {
903                 if (IsMapMarked(i, MAP_EXEC)) {
904                     fprintf(sfile, "\tMakeCode(0X8%07X);\r\n", i);
905                 }
906             }
907             fprintf(sfile, "}\r\n");
908             fclose(sfile);
909             sprintf(reply, "270 flow.idc and markcode.idc dumped\r\n");
910             break;
911         case 0x300:
912             p = arguments;
913             if (arguments) {
914                 code = strtol(arguments, &p, 16);
915             }
916             if (p == arguments) {
917                 if (first) {
918                     reply[0] = 0;
919                     for (bp = first; bp; bp = next_breakpoint(bp)) {
920                         sprintf(reply, "%s400 %X@%08X-%s\r\n", reply, bp->number, bp->address, breakpoint_type_names[bp->type]);
921                     }
922                 } else {
923                     sprintf(reply, "530 No breakpoint\r\n");
924                 }
925             } else {
926                 if ((bp = find_breakpoint(code))) {
927                     sprintf(reply, "400 %X@%08X-%s\r\n", bp->number, bp->address, breakpoint_type_names[bp->type]);
928                 } else {
929                     sprintf(reply, "530 Invalid breakpoint number: %X\r\n", code);
930                 }
931             }
932             break;
933         case 0x301:
934             p = arguments;
935             if (arguments) {
936                 code = strtol(arguments, &p, 16);
937             }
938             if (p == arguments) {
939                 while (first != NULL) delete_breakpoint(first);
940                 sprintf(reply, "401 All breakpoints deleted.\r\n");
941             } else {
942                 if ((bp = find_breakpoint(code))) {
943                     delete_breakpoint(bp);
944                     sprintf(reply, "401 Breakpoint %X deleted.\r\n", code);
945                 } else {
946                     sprintf(reply, "530 Invalid breakpoint number: %X\r\n", code);
947                 }
948             }
949             break;
950         case 0x310:
951             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
952                 sprintf(reply, "500 Malformed 310 command '%s'\r\n", arguments);
953                 break;
954             }
955 //            if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) {
956 //                sprintf(reply, "531 Invalid address %08X\r\n", address);
957 //                break;
958 //            }
959             code = add_breakpoint(E, address);
960             sprintf(reply, "410 %X\r\n", code);
961             break;
962         case 0x320:
963             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
964                 sprintf(reply, "500 Malformed 320 command '%s'\r\n", arguments);
965                 break;
966             }
967             if ((address < 0x80000000) || (address >= 0x80200000)) {
968                 sprintf(reply, "532 Invalid address %08X\r\n", address);
969                 break;
970             }
971             code = add_breakpoint(R1, address);
972             sprintf(reply, "420 %X\r\n", code);
973             break;
974         case 0x321:
975             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
976                 sprintf(reply, "500 Malformed 321 command '%s'\r\n", arguments);
977                 break;
978             }
979             if ((address & 1) || (address < 0x80000000) || (address >= 0x80200000)) {
980                 sprintf(reply, "532 Invalid address %08X\r\n", address);
981                 break;
982             }
983             code = add_breakpoint(R2, address);
984             sprintf(reply, "421 %X\r\n", code);
985             break;
986         case 0x322:
987             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
988                 sprintf(reply, "500 Malformed 322 command '%s'\r\n", arguments);
989                 break;
990             }
991             if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) {
992                 sprintf(reply, "532 Invalid address %08X\r\n", address);
993                 break;
994             }
995             code = add_breakpoint(R4, address);
996             sprintf(reply, "422 %X\r\n", code);
997             break;
998         case 0x330:
999             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
1000                 sprintf(reply, "500 Malformed 330 command '%s'\r\n", arguments);
1001                 break;
1002             }
1003             if ((address < 0x80000000) || (address >= 0x80200000)) {
1004                 sprintf(reply, "533 Invalid address %08X\r\n", address);
1005                 break;
1006             }
1007             code = add_breakpoint(W1, address);
1008             sprintf(reply, "430 %X\r\n", code);
1009             break;
1010         case 0x331:
1011             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
1012                 sprintf(reply, "500 Malformed 331 command '%s'\r\n", arguments);
1013                 break;
1014             }
1015             if ((address & 1) || (address < 0x80000000) || (address >= 0x80200000)) {
1016                 sprintf(reply, "533 Invalid address %08X\r\n", address);
1017                 break;
1018             }
1019             code = add_breakpoint(W2, address);
1020             sprintf(reply, "431 %X\r\n", code);
1021             break;
1022         case 0x332:
1023             if (!arguments || sscanf(arguments, "%08X", &address) != 1) {
1024                 sprintf(reply, "500 Malformed 332 command '%s'\r\n", arguments);
1025                 break;
1026             }
1027             if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) {
1028                 sprintf(reply, "533 Invalid address %08X\r\n", address);
1029                 break;
1030             }
1031             code = add_breakpoint(W4, address);
1032             sprintf(reply, "432 %X\r\n", code);
1033             break;
1034         case 0x390:
1035             paused = 1;
1036             sprintf(reply, "490 Paused\r\n");
1037             break;
1038         case 0x391:
1039             paused = 0;
1040             sprintf(reply, "491 Resumed\r\n");
1041             break;
1042         case 0x395:
1043             p = arguments;
1044             if (arguments) {
1045                 trace = strtol(arguments, &p, 10);
1046             }
1047             if (p == arguments) {
1048                 trace = 1;
1049             }
1050             paused = 0;
1051             sprintf(reply, "495 Tracing\r\n");
1052             break;
1053         case 0x398:
1054             paused = 0;
1055             trace = 0;
1056             reset = 2;
1057             sprintf(reply, "498 Soft resetting\r\n");
1058             break;
1059         case 0x399:
1060             paused = 0;
1061             trace = 0;
1062             reset = 1;
1063             sprintf(reply, "499 Resetting\r\n");
1064             break;
1065         default:
1066             sprintf(reply, "500 Unknown command '%s'\r\n", cmd);
1067             break;
1068         }
1069         WriteSocket(reply, strlen(reply));
1070
1071         if (dumping) {
1072             WriteSocket(dump, size);
1073         }
1074
1075         if (save) {
1076             free(save);
1077         }
1078     }
1079 }
1080
1081 void DebugCheckBP(u32 address, enum breakpoint_types type) {
1082     breakpoint_t *bp;
1083     char reply[512];
1084
1085     if (!debugger_active || reset)
1086         return;
1087     for (bp = first; bp; bp = next_breakpoint(bp)) {
1088         if ((bp->type == type) && (bp->address == address)) {
1089             sprintf(reply, "030 %X@%08X\r\n", bp->number, psxRegs.pc);
1090             WriteSocket(reply, strlen(reply));
1091             paused = 1;
1092             return;
1093         }
1094     }
1095     if (breakmp_e && type == E) {
1096         if (!IsMapMarked(address, MAP_EXEC)) {
1097             sprintf(reply, "010 %08X@%08X\r\n", address, psxRegs.pc);
1098             WriteSocket(reply, strlen(reply));
1099             paused = 1;
1100         }
1101     }
1102     if (breakmp_r8 && type == R1) {
1103         if (!IsMapMarked(address, MAP_R8)) {
1104             sprintf(reply, "011 %08X@%08X\r\n", address, psxRegs.pc);
1105             WriteSocket(reply, strlen(reply));
1106             paused = 1;
1107         }
1108     }
1109     if (breakmp_r16 && type == R2) {
1110         if (!IsMapMarked(address, MAP_R16)) {
1111             sprintf(reply, "012 %08X@%08X\r\n", address, psxRegs.pc);
1112             WriteSocket(reply, strlen(reply));
1113             paused = 1;
1114         }
1115     }
1116     if (breakmp_r32 && type == R4) {
1117         if (!IsMapMarked(address, MAP_R32)) {
1118             sprintf(reply, "013 %08X@%08X\r\n", address, psxRegs.pc);
1119             WriteSocket(reply, strlen(reply));
1120             paused = 1;
1121         }
1122     }
1123     if (breakmp_w8 && type == W1) {
1124         if (!IsMapMarked(address, MAP_W8)) {
1125             sprintf(reply, "014 %08X@%08X\r\n", address, psxRegs.pc);
1126             WriteSocket(reply, strlen(reply));
1127             paused = 1;
1128         }
1129     }
1130     if (breakmp_w16 && type == W2) {
1131         if (!IsMapMarked(address, MAP_W16)) {
1132             sprintf(reply, "015 %08X@%08X\r\n", address, psxRegs.pc);
1133             WriteSocket(reply, strlen(reply));
1134             paused = 1;
1135         }
1136     }
1137     if (breakmp_w32 && type == W4) {
1138         if (!IsMapMarked(address, MAP_W32)) {
1139             sprintf(reply, "016 %08X@%08X\r\n", address, psxRegs.pc);
1140             WriteSocket(reply, strlen(reply));
1141             paused = 1;
1142         }
1143     }
1144     if (mapping_r8 && type == R1) MarkMap(address, MAP_R8);
1145     if (mapping_r16 && type == R2) MarkMap(address, MAP_R16);
1146     if (mapping_r32 && type == R4) MarkMap(address, MAP_R32);
1147     if (mapping_w8 && type == W1) MarkMap(address, MAP_W8);
1148     if (mapping_w16 && type == W2) MarkMap(address, MAP_W16);
1149     if (mapping_w32 && type == W4) MarkMap(address, MAP_W32);
1150  }