configure.in: default profiling to off, as its broken
[rofl0r-VisualBoyAdvance.git] / src / remote.cpp
blobd673a553800ccf6a857cb258658d370053418b24
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
23 #ifndef _WIN32
24 # include <unistd.h>
25 # include <sys/socket.h>
26 # include <netdb.h>
27 # ifdef HAVE_NETINET_IN_H
28 # include <netinet/in.h>
29 # endif // HAVE_NETINET_IN_H
30 # ifdef HAVE_ARPA_INET_H
31 # include <arpa/inet.h>
32 # else // ! HAVE_ARPA_INET_H
33 # define socklen_t int
34 # endif // ! HAVE_ARPA_INET_H
35 # define SOCKET int
36 #else // _WIN32
37 # include <winsock.h>
38 # include <io.h>
39 # define socklen_t int
40 # define close closesocket
41 # define read _read
42 # define write _write
43 #endif // _WIN32
45 #include "GBA.h"
47 extern bool debugger;
48 extern void CPUUpdateCPSR();
49 #ifdef SDL
50 extern void (*dbgMain)();
51 extern void (*dbgSignal)(int,int);
52 extern void debuggerMain();
53 extern void debuggerSignal(int,int);
54 #endif
56 int remotePort = 55555;
57 int remoteSignal = 5;
58 SOCKET remoteSocket = -1;
59 SOCKET remoteListenSocket = -1;
60 bool remoteConnected = false;
61 bool remoteResumed = false;
63 int (*remoteSendFnc)(char *, int) = NULL;
64 int (*remoteRecvFnc)(char *, int) = NULL;
65 bool (*remoteInitFnc)() = NULL;
66 void (*remoteCleanUpFnc)() = NULL;
68 #ifndef SDL
69 void remoteSetSockets(SOCKET l, SOCKET r)
71 remoteSocket = r;
72 remoteListenSocket = l;
74 #endif
76 int remoteTcpSend(char *data, int len)
78 return send(remoteSocket, data, len, 0);
81 int remoteTcpRecv(char *data, int len)
83 return recv(remoteSocket, data, len, 0);
86 bool remoteTcpInit()
88 if(remoteSocket == -1) {
89 #ifdef _WIN32
90 WSADATA wsaData;
91 int error = WSAStartup(MAKEWORD(1,1),&wsaData);
92 #endif // _WIN32
93 SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
95 remoteListenSocket = s;
97 if(s < 0) {
98 fprintf(stderr,"Error opening socket\n");
99 exit(-1);
101 int tmp = 1;
102 setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
104 // char hostname[256];
105 // gethostname(hostname, 256);
107 // hostent *ent = gethostbyname(hostname);
108 // unsigned long a = *((unsigned long *)ent->h_addr);
110 sockaddr_in addr;
111 addr.sin_family = AF_INET;
112 addr.sin_port = htons(remotePort);
113 addr.sin_addr.s_addr = htonl(0);
114 int count = 0;
115 while(count < 3) {
116 if(bind(s, (sockaddr *)&addr, sizeof(addr))) {
117 addr.sin_port = htons(ntohs(addr.sin_port)+1);
118 } else
119 break;
121 if(count == 3) {
122 fprintf(stderr,"Error binding \n");
123 exit(-1);
126 fprintf(stderr,"Listening for a connection at port %d\n",
127 ntohs(addr.sin_port));
129 if(listen(s, 1)) {
130 fprintf(stderr, "Error listening\n");
131 exit(-1);
133 socklen_t len = sizeof(addr);
135 #ifdef _WIN32
136 int flag = 0;
137 ioctlsocket(s, FIONBIO, (unsigned long *)&flag);
138 #endif // _WIN32
139 SOCKET s2 = accept(s, (sockaddr *)&addr, &len);
140 if(s2 > 0) {
141 fprintf(stderr, "Got a connection from %s %d\n",
142 inet_ntoa((in_addr)addr.sin_addr),
143 ntohs(addr.sin_port));
144 } else {
145 #ifdef _WIN32
146 int error = WSAGetLastError();
147 #endif // _WIN32
149 char dummy;
150 recv(s2, &dummy, 1, 0);
151 if(dummy != '+') {
152 fprintf(stderr, "ACK not received\n");
153 exit(-1);
155 remoteSocket = s2;
156 // close(s);
158 return true;
161 void remoteTcpCleanUp()
163 if(remoteSocket > 0) {
164 fprintf(stderr, "Closing remote socket\n");
165 close(remoteSocket);
166 remoteSocket = -1;
168 if(remoteListenSocket > 0) {
169 fprintf(stderr, "Closing listen socket\n");
170 close(remoteListenSocket);
171 remoteListenSocket = -1;
175 int remotePipeSend(char *data, int len)
177 int res = write(1, data, len);
178 return res;
181 int remotePipeRecv(char *data, int len)
183 int res = read(0, data, len);
184 return res;
187 bool remotePipeInit()
189 char dummy;
190 read(0, &dummy, 1);
191 if(dummy != '+') {
192 fprintf(stderr, "ACK not received\n");
193 exit(-1);
196 return true;
199 void remotePipeCleanUp()
203 void remoteSetPort(int port)
205 remotePort = port;
208 void remoteSetProtocol(int p)
210 if(p == 0) {
211 remoteSendFnc = remoteTcpSend;
212 remoteRecvFnc = remoteTcpRecv;
213 remoteInitFnc = remoteTcpInit;
214 remoteCleanUpFnc = remoteTcpCleanUp;
215 } else {
216 remoteSendFnc = remotePipeSend;
217 remoteRecvFnc = remotePipeRecv;
218 remoteInitFnc = remotePipeInit;
219 remoteCleanUpFnc = remotePipeCleanUp;
223 void remoteInit()
225 if(remoteInitFnc)
226 remoteInitFnc();
229 void remotePutPacket(char *packet)
231 char *hex = "0123456789abcdef";
232 char buffer[1024];
234 size_t count = strlen(packet);
236 unsigned char csum = 0;
238 char *p = buffer;
239 *p++ = '$';
241 for(size_t i = 0 ;i < count; i++) {
242 csum += packet[i];
243 *p++ = packet[i];
245 *p++ = '#';
246 *p++ = hex[csum>>4];
247 *p++ = hex[csum & 15];
248 *p++ = 0;
249 // printf("Sending %s\n", buffer);
250 remoteSendFnc(buffer, (int)count + 4);
252 char c = 0;
253 remoteRecvFnc(&c, 1);
255 if(c == '+')
256 printf("ACK\n");
257 else if(c=='-')
258 printf("NACK\n");
262 #define debuggerReadMemory(addr) \
263 (*(u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])
265 #define debuggerReadHalfWord(addr) \
266 (*(u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])
268 #define debuggerReadByte(addr) \
269 map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
271 #define debuggerWriteMemory(addr, value) \
272 *(u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] = (value)
274 #define debuggerWriteHalfWord(addr, value) \
275 *(u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] = (value)
277 #define debuggerWriteByte(addr, value) \
278 map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] = (value)
280 void remoteOutput(char *s, u32 addr)
282 char buffer[16384];
284 char *d = buffer;
285 *d++ = 'O';
287 if(s) {
288 char c = *s++;
289 while(c) {
290 sprintf(d, "%02x", c);
291 d += 2;
292 c = *s++;
294 } else {
295 char c= debuggerReadByte(addr);
296 addr++;
297 while(c) {
298 sprintf(d, "%02x", c);
299 d += 2;
300 c = debuggerReadByte(addr);
301 addr++;
304 remotePutPacket(buffer);
305 // fprintf(stderr, "Output sent %s\n", buffer);
308 void remoteSendSignal()
310 char buffer[1024];
311 sprintf(buffer, "S%02x", remoteSignal);
312 remotePutPacket(buffer);
315 void remoteSendStatus()
317 char buffer[1024];
318 sprintf(buffer, "T%02x", remoteSignal);
319 char *s = buffer;
320 s += 3;
321 for(int i = 0; i < 15; i++) {
322 u32 v = reg[i].I;
323 sprintf(s, "%02x:%02x%02x%02x%02x;",i,
324 (v & 255),
325 (v >> 8) & 255,
326 (v >> 16) & 255,
327 (v >> 24) & 255);
328 s += 12;
330 u32 v = armNextPC;
331 sprintf(s, "0f:%02x%02x%02x%02x;", (v & 255),
332 (v >> 8) & 255,
333 (v >> 16) & 255,
334 (v >> 24) & 255);
335 s += 12;
336 CPUUpdateCPSR();
337 v = reg[16].I;
338 sprintf(s, "19:%02x%02x%02x%02x;", (v & 255),
339 (v >> 8) & 255,
340 (v >> 16) & 255,
341 (v >> 24) & 255);
342 s += 12;
343 *s = 0;
344 // printf("Sending %s\n", buffer);
345 remotePutPacket(buffer);
348 void remoteBinaryWrite(char *p)
350 u32 address;
351 int count;
352 sscanf(p,"%x,%x:", &address, &count);
353 // printf("Binary write for %08x %d\n", address, count);
355 p = strchr(p, ':');
356 p++;
357 for(int i = 0; i < count; i++) {
358 u8 b = *p++;
359 switch(b) {
360 case 0x7d:
361 b = *p++;
362 debuggerWriteByte(address, (b^0x20));
363 address++;
364 break;
365 default:
366 debuggerWriteByte(address, b);
367 address++;
368 break;
371 // printf("ROM is %08x\n", debuggerReadMemory(0x8000254));
372 remotePutPacket("OK");
375 void remoteMemoryWrite(char *p)
377 u32 address;
378 int count;
379 sscanf(p,"%x,%x:", &address, &count);
380 // printf("Memory write for %08x %d\n", address, count);
382 p = strchr(p, ':');
383 p++;
384 for(int i = 0; i < count; i++) {
385 u8 v = 0;
386 char c = *p++;
387 if(c <= '9')
388 v = (c - '0') << 4;
389 else
390 v = (c + 10 - 'a') << 4;
391 c = *p++;
392 if(c <= '9')
393 v += (c - '0');
394 else
395 v += (c + 10 - 'a');
396 debuggerWriteByte(address, v);
397 address++;
399 // printf("ROM is %08x\n", debuggerReadMemory(0x8000254));
400 remotePutPacket("OK");
403 void remoteMemoryRead(char *p)
405 u32 address;
406 int count;
407 sscanf(p,"%x,%x:", &address, &count);
408 // printf("Memory read for %08x %d\n", address, count);
410 char buffer[1024];
412 char *s = buffer;
413 for(int i = 0; i < count; i++) {
414 u8 b = debuggerReadByte(address);
415 sprintf(s, "%02x", b);
416 address++;
417 s += 2;
419 *s = 0;
420 remotePutPacket(buffer);
423 void remoteStepOverRange(char *p)
425 u32 address;
426 u32 final;
427 sscanf(p, "%x,%x", &address, &final);
429 remotePutPacket("OK");
431 remoteResumed = true;
432 do {
433 CPULoop(1);
434 if(debugger)
435 break;
436 } while(armNextPC >= address && armNextPC < final);
438 remoteResumed = false;
440 remoteSendStatus();
443 void remoteWriteWatch(char *p, bool active)
445 u32 address;
446 int count;
447 sscanf(p, ",%x,%x#", &address, &count);
449 fprintf(stderr, "Write watch for %08x %d\n", address, count);
451 if(address < 0x2000000 || address > 0x3007fff) {
452 remotePutPacket("E01");
453 return;
456 if(address > 0x203ffff && address < 0x3000000) {
457 remotePutPacket("E01");
458 return;
461 u32 final = address + count;
463 if(address < 0x2040000 && final > 0x2040000) {
464 remotePutPacket("E01");
465 return;
466 } else if(address < 0x3008000 && final > 0x3008000) {
467 remotePutPacket("E01");
468 return;
471 for(int i = 0; i < count; i++) {
472 if((address >> 24) == 2)
473 freezeWorkRAM[address & 0x3ffff] = active;
474 else
475 freezeInternalRAM[address & 0x7fff] = active;
476 address++;
479 remotePutPacket("OK");
482 void remoteReadRegisters(char *p)
484 char buffer[1024];
486 char *s = buffer;
487 int i;
488 // regular registers
489 for(i = 0; i < 15; i++) {
490 u32 v = reg[i].I;
491 sprintf(s, "%02x%02x%02x%02x", v & 255, (v >> 8) & 255,
492 (v >> 16) & 255, (v >> 24) & 255);
493 s += 8;
495 // PC
496 u32 pc = armNextPC;
497 sprintf(s, "%02x%02x%02x%02x", pc & 255, (pc >> 8) & 255,
498 (pc >> 16) & 255, (pc >> 24) & 255);
499 s += 8;
501 // floating point registers (24-bit)
502 for(i = 0; i < 8; i++) {
503 sprintf(s, "000000000000000000000000");
504 s += 24;
507 // FP status register
508 sprintf(s, "00000000");
509 s += 8;
510 // CPSR
511 CPUUpdateCPSR();
512 u32 v = reg[16].I;
513 sprintf(s, "%02x%02x%02x%02x", v & 255, (v >> 8) & 255,
514 (v >> 16) & 255, (v >> 24) & 255);
515 s += 8;
516 *s = 0;
517 remotePutPacket(buffer);
520 void remoteWriteRegister(char *p)
522 int r;
524 sscanf(p, "%x=", &r);
526 p = strchr(p, '=');
527 p++;
529 char c = *p++;
531 u32 v = 0;
533 u8 data[4] = {0,0,0,0};
535 int i = 0;
537 while(c != '#') {
538 u8 b = 0;
539 if(c <= '9')
540 b = (c - '0') << 4;
541 else
542 b = (c + 10 - 'a') << 4;
543 c = *p++;
544 if(c <= '9')
545 b += (c - '0');
546 else
547 b += (c + 10 - 'a');
548 data[i++] = b;
549 c = *p++;
552 v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
554 // printf("Write register %d=%08x\n", r, v);
555 reg[r].I = v;
556 if(r == 15) {
557 armNextPC = v;
558 if(armState)
559 reg[15].I = v + 4;
560 else
561 reg[15].I = v + 2;
563 remotePutPacket("OK");
566 extern int emulating;
568 void remoteStubMain()
570 if(!debugger)
571 return;
573 if(remoteResumed) {
574 remoteSendStatus();
575 remoteResumed = false;
578 while(1) {
579 char buffer[1024];
580 int res = remoteRecvFnc(buffer, 1024);
582 if(res == -1) {
583 fprintf(stderr, "GDB connection lost\n");
584 #ifdef SDL
585 dbgMain = debuggerMain;
586 dbgSignal = debuggerSignal;
587 #endif
588 debugger = false;
589 break;
592 // fprintf(stderr, "Received %s\n", buffer);
593 char *p = buffer;
594 char c = *p++;
595 char pp = '+';
596 remoteSendFnc(&pp, 1);
598 if(c != '$')
599 continue;
600 c= *p++;
601 switch(c) {
602 case '?':
603 remoteSendSignal();
604 break;
605 case 'D':
606 remotePutPacket("OK");
607 #ifdef SDL
608 dbgMain = debuggerMain;
609 dbgSignal = debuggerSignal;
610 #endif
611 remoteResumed = true;
612 debugger = false;
613 return;
614 case 'e':
615 remoteStepOverRange(p);
616 break;
617 case 'k':
618 remotePutPacket("OK");
619 #ifdef SDL
620 dbgMain = debuggerMain;
621 dbgSignal = debuggerSignal;
622 #endif
623 debugger = false;
624 emulating = false;
625 return;
626 case 'C':
627 remoteResumed = true;
628 debugger = false;
629 return;
630 case 'c':
631 remoteResumed = true;
632 debugger = false;
633 return;
634 case 's':
635 remoteResumed = true;
636 remoteSignal = 5;
637 CPULoop(1);
638 if(remoteResumed) {
639 remoteResumed = false;
640 remoteSendStatus();
642 break;
643 case 'g':
644 remoteReadRegisters(p);
645 break;
646 case 'P':
647 remoteWriteRegister(p);
648 break;
649 case 'M':
650 remoteMemoryWrite(p);
651 break;
652 case 'm':
653 remoteMemoryRead(p);
654 break;
655 case 'X':
656 remoteBinaryWrite(p);
657 break;
658 case 'H':
659 remotePutPacket("OK");
660 break;
661 case 'q':
662 remotePutPacket("");
663 break;
664 case 'Z':
665 if(*p++ == '2') {
666 remoteWriteWatch(p, true);
667 } else
668 remotePutPacket("");
669 break;
670 case 'z':
671 if(*p++ == '2') {
672 remoteWriteWatch(p, false);
673 } else
674 remotePutPacket("");
675 break;
676 default:
678 *(strchr(p, '#') + 3) = 0;
679 fprintf(stderr, "Unknown packet %s\n", --p);
680 remotePutPacket("");
682 break;
687 void remoteStubSignal(int sig, int number)
689 remoteSignal = sig;
690 remoteResumed = false;
691 remoteSendStatus();
692 debugger = true;
695 void remoteCleanUp()
697 if(remoteCleanUpFnc)
698 remoteCleanUpFnc();