src/debugger/gdb-stub.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/debugger/gdb-stub.h>
7
8#include <mgba/core/core.h>
9#include <mgba/internal/arm/debugger/debugger.h>
10#include <mgba/internal/arm/isa-inlines.h>
11#include <mgba/internal/gba/memory.h>
12
13#include <signal.h>
14
15#ifndef SIGTRAP
16#define SIGTRAP 5 /* Win32 Signals do not include SIGTRAP */
17#endif
18
19#define SOCKET_TIMEOUT 50
20
21enum GDBError {
22 GDB_NO_ERROR = 0x00,
23 GDB_BAD_ARGUMENTS = 0x06,
24 GDB_UNSUPPORTED_COMMAND = 0x07
25};
26
27enum {
28 MACH_O_ARM = 12,
29 MACH_O_ARM_V4T = 5
30};
31
32static void _sendMessage(struct GDBStub* stub);
33
34static void _gdbStubDeinit(struct mDebugger* debugger) {
35 struct GDBStub* stub = (struct GDBStub*) debugger;
36 if (!SOCKET_FAILED(stub->socket)) {
37 GDBStubShutdown(stub);
38 }
39}
40
41static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
42 struct GDBStub* stub = (struct GDBStub*) debugger;
43 switch (reason) {
44 case DEBUGGER_ENTER_MANUAL:
45 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT);
46 break;
47 case DEBUGGER_ENTER_BREAKPOINT:
48 if (stub->supportsHwbreak && stub->supportsSwbreak && info) {
49 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%cwbreak:;", SIGTRAP, info->type.bp.breakType == BREAKPOINT_SOFTWARE ? 's' : 'h');
50 } else {
51 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02xk", SIGTRAP);
52 }
53 break;
54 case DEBUGGER_ENTER_WATCHPOINT:
55 if (info) {
56 const char* type = 0;
57 switch (info->type.wp.watchType) {
58 case WATCHPOINT_WRITE:
59 if (info->type.wp.newValue == info->type.wp.oldValue) {
60 if (stub->d.state == DEBUGGER_PAUSED) {
61 stub->d.state = DEBUGGER_RUNNING;
62 }
63 return;
64 }
65 type = "watch";
66 break;
67 case WATCHPOINT_READ:
68 type = "rwatch";
69 break;
70 case WATCHPOINT_RW:
71 type = "awatch";
72 break;
73 }
74 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08x;", SIGTRAP, type, info->address);
75 } else {
76 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
77 }
78 break;
79 case DEBUGGER_ENTER_ILLEGAL_OP:
80 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGILL);
81 break;
82 case DEBUGGER_ENTER_ATTACHED:
83 return;
84 }
85 _sendMessage(stub);
86}
87
88static void _gdbStubPoll(struct mDebugger* debugger) {
89 struct GDBStub* stub = (struct GDBStub*) debugger;
90 --stub->untilPoll;
91 if (stub->untilPoll > 0) {
92 return;
93 }
94 stub->untilPoll = GDB_STUB_INTERVAL;
95 stub->shouldBlock = false;
96 GDBStubUpdate(stub);
97}
98
99static void _gdbStubWait(struct mDebugger* debugger) {
100 struct GDBStub* stub = (struct GDBStub*) debugger;
101 stub->shouldBlock = true;
102 GDBStubUpdate(stub);
103}
104
105static void _ack(struct GDBStub* stub) {
106 char ack = '+';
107 SocketSend(stub->connection, &ack, 1);
108}
109
110static void _nak(struct GDBStub* stub) {
111 char nak = '-';
112 mLOG(DEBUGGER, WARN, "Packet error");
113 SocketSend(stub->connection, &nak, 1);
114}
115
116static uint32_t _hex2int(const char* hex, int maxDigits) {
117 uint32_t value = 0;
118 uint8_t letter;
119
120 while (maxDigits--) {
121 letter = *hex - '0';
122 if (letter > 9) {
123 letter = *hex - 'a';
124 if (letter > 5) {
125 break;
126 }
127 value *= 0x10;
128 value += letter + 10;
129 } else {
130 value *= 0x10;
131 value += letter;
132 }
133 ++hex;
134 }
135 return value;
136}
137
138static void _int2hex8(uint8_t value, char* out) {
139 static const char language[] = "0123456789abcdef";
140 out[0] = language[value >> 4];
141 out[1] = language[value & 0xF];
142}
143
144static void _int2hex32(uint32_t value, char* out) {
145 static const char language[] = "0123456789abcdef";
146 out[6] = language[value >> 28];
147 out[7] = language[(value >> 24) & 0xF];
148 out[4] = language[(value >> 20) & 0xF];
149 out[5] = language[(value >> 16) & 0xF];
150 out[2] = language[(value >> 12) & 0xF];
151 out[3] = language[(value >> 8) & 0xF];
152 out[0] = language[(value >> 4) & 0xF];
153 out[1] = language[value & 0xF];
154}
155
156static uint32_t _readHex(const char* in, unsigned* out) {
157 unsigned i;
158 for (i = 0; i < 8; ++i) {
159 if (in[i] == ',' || in[i] == ':' || in[i] == '=') {
160 break;
161 }
162 }
163 *out += i;
164 return _hex2int(in, i);
165}
166
167static void _sendMessage(struct GDBStub* stub) {
168 if (stub->lineAck != GDB_ACK_OFF) {
169 stub->lineAck = GDB_ACK_PENDING;
170 }
171 uint8_t checksum = 0;
172 int i = 1;
173 char buffer = stub->outgoing[0];
174 char swap;
175 stub->outgoing[0] = '$';
176 if (buffer) {
177 for (; i < GDB_STUB_MAX_LINE - 5; ++i) {
178 checksum += buffer;
179 swap = stub->outgoing[i];
180 stub->outgoing[i] = buffer;
181 buffer = swap;
182 if (!buffer) {
183 ++i;
184 break;
185 }
186 }
187 }
188 stub->outgoing[i] = '#';
189 _int2hex8(checksum, &stub->outgoing[i + 1]);
190 stub->outgoing[i + 3] = 0;
191 mLOG(DEBUGGER, DEBUG, "> %s", stub->outgoing);
192 SocketSend(stub->connection, stub->outgoing, i + 3);
193}
194
195static void _error(struct GDBStub* stub, enum GDBError error) {
196 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "E%02x", error);
197 _sendMessage(stub);
198}
199
200static void _writeHostInfo(struct GDBStub* stub) {
201 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "cputype:%u;cpusubtype:%u:ostype:none;vendor:none;endian:little;ptrsize:4;", MACH_O_ARM, MACH_O_ARM_V4T);
202 _sendMessage(stub);
203}
204
205static void _continue(struct GDBStub* stub, const char* message) {
206 stub->d.state = DEBUGGER_CUSTOM;
207 stub->untilPoll = GDB_STUB_INTERVAL;
208 // TODO: parse message
209 UNUSED(message);
210}
211
212static void _step(struct GDBStub* stub, const char* message) {
213 stub->d.core->step(stub->d.core);
214 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
215 _sendMessage(stub);
216 // TODO: parse message
217 UNUSED(message);
218}
219
220static void _writeMemoryBinary(struct GDBStub* stub, const char* message) {
221 const char* readAddress = message;
222 unsigned i = 0;
223 uint32_t address = _readHex(readAddress, &i);
224 readAddress += i + 1;
225
226 i = 0;
227 uint32_t size = _readHex(readAddress, &i);
228 readAddress += i + 1;
229
230 if (size > 512) {
231 _error(stub, GDB_BAD_ARGUMENTS);
232 return;
233 }
234
235 struct ARMCore* cpu = stub->d.core->cpu;
236 for (i = 0; i < size; i++) {
237 uint8_t byte = *readAddress;
238 ++readAddress;
239
240 // Parse escape char
241 if (byte == 0x7D) {
242 byte = *readAddress ^ 0x20;
243 ++readAddress;
244 }
245
246 GBAPatch8(cpu, address + i, byte, 0);
247 }
248
249 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
250 _sendMessage(stub);
251}
252
253
254static void _writeMemory(struct GDBStub* stub, const char* message) {
255 const char* readAddress = message;
256 unsigned i = 0;
257 uint32_t address = _readHex(readAddress, &i);
258 readAddress += i + 1;
259
260 i = 0;
261 uint32_t size = _readHex(readAddress, &i);
262 readAddress += i + 1;
263
264 if (size > 512) {
265 _error(stub, GDB_BAD_ARGUMENTS);
266 return;
267 }
268
269 struct ARMCore* cpu = stub->d.core->cpu;
270 for (i = 0; i < size; ++i, readAddress += 2) {
271 uint8_t byte = _hex2int(readAddress, 2);
272 GBAPatch8(cpu, address + i, byte, 0);
273 }
274
275 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
276 _sendMessage(stub);
277}
278
279static void _readMemory(struct GDBStub* stub, const char* message) {
280 const char* readAddress = message;
281 unsigned i = 0;
282 uint32_t address = _readHex(readAddress, &i);
283 readAddress += i + 1;
284 uint32_t size = _readHex(readAddress, &i);
285 if (size > 512) {
286 _error(stub, GDB_BAD_ARGUMENTS);
287 return;
288 }
289 struct ARMCore* cpu = stub->d.core->cpu;
290 int writeAddress = 0;
291 for (i = 0; i < size; ++i, writeAddress += 2) {
292 uint8_t byte = cpu->memory.load8(cpu, address + i, 0);
293 _int2hex8(byte, &stub->outgoing[writeAddress]);
294 }
295 stub->outgoing[writeAddress] = 0;
296 _sendMessage(stub);
297}
298
299static void _writeGPRs(struct GDBStub* stub, const char* message) {
300 struct ARMCore* cpu = stub->d.core->cpu;
301 const char* readAddress = message;
302
303 int r;
304 for (r = 0; r <= ARM_PC; ++r) {
305 cpu->gprs[r] = _hex2int(readAddress, 8);
306 readAddress += 8;
307 }
308 if (cpu->executionMode == MODE_ARM) {
309 ARMWritePC(cpu);
310 } else {
311 ThumbWritePC(cpu);
312 }
313
314 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
315 _sendMessage(stub);
316}
317
318static void _readGPRs(struct GDBStub* stub, const char* message) {
319 struct ARMCore* cpu = stub->d.core->cpu;
320 UNUSED(message);
321 int r;
322 int i = 0;
323
324 // General purpose registers
325 for (r = 0; r < ARM_PC; ++r) {
326 _int2hex32(cpu->gprs[r], &stub->outgoing[i]);
327 i += 8;
328 }
329
330 // Program counter
331 _int2hex32(cpu->gprs[ARM_PC] - (cpu->cpsr.t ? WORD_SIZE_THUMB : WORD_SIZE_ARM), &stub->outgoing[i]);
332 i += 8;
333
334 // Floating point registers, unused on the GBA (8 of them, 24 bits each)
335 for (r = 0; r < 8 * 3; ++r) {
336 _int2hex32(0, &stub->outgoing[i]);
337 i += 8;
338 }
339
340 // Floating point status, unused on the GBA (32 bits)
341 _int2hex32(0, &stub->outgoing[i]);
342 i += 8;
343
344 // CPU status
345 _int2hex32(cpu->cpsr.packed, &stub->outgoing[i]);
346 i += 8;
347
348 stub->outgoing[i] = 0;
349 _sendMessage(stub);
350}
351
352static void _writeRegister(struct GDBStub* stub, const char* message) {
353 struct ARMCore* cpu = stub->d.core->cpu;
354 const char* readAddress = message;
355
356 unsigned i = 0;
357 uint32_t reg = _readHex(readAddress, &i);
358 readAddress += i + 1;
359
360 uint32_t value = _readHex(readAddress, &i);
361
362#ifdef _MSC_VER
363 value = _byteswap_ulong(value);
364#else
365 LOAD_32BE(value, 0, &value);
366#endif
367
368 if (reg <= ARM_PC) {
369 cpu->gprs[reg] = value;
370 if (reg == ARM_PC) {
371 if (cpu->executionMode == MODE_ARM) {
372 ARMWritePC(cpu);
373 } else {
374 ThumbWritePC(cpu);
375 }
376 }
377 } else if (reg == 0x19) {
378 cpu->cpsr.packed = value;
379 } else {
380 stub->outgoing[0] = '\0';
381 _sendMessage(stub);
382 return;
383 }
384
385 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
386 _sendMessage(stub);
387}
388
389static void _readRegister(struct GDBStub* stub, const char* message) {
390 struct ARMCore* cpu = stub->d.core->cpu;
391 const char* readAddress = message;
392 unsigned i = 0;
393 uint32_t reg = _readHex(readAddress, &i);
394 uint32_t value;
395 if (reg < 0x10) {
396 value = cpu->gprs[reg];
397 } else if (reg == 0x19) {
398 value = cpu->cpsr.packed;
399 } else {
400 stub->outgoing[0] = '\0';
401 _sendMessage(stub);
402 return;
403 }
404 _int2hex32(value, stub->outgoing);
405 stub->outgoing[8] = '\0';
406 _sendMessage(stub);
407}
408
409static void _processQSupportedCommand(struct GDBStub* stub, const char* message) {
410 const char* terminator = strrchr(message, '#');
411 stub->supportsSwbreak = false;
412 stub->supportsHwbreak = false;
413 while (message < terminator) {
414 const char* end = strchr(message, ';');
415 size_t len;
416 if (end && end < terminator) {
417 len = end - message;
418 } else {
419 len = terminator - message;
420 }
421 if (!strncmp(message, "swbreak+", len)) {
422 stub->supportsSwbreak = true;
423 } else if (!strncmp(message, "hwbreak+", len)) {
424 stub->supportsHwbreak = true;
425 } else if (!strncmp(message, "swbreak-", len)) {
426 stub->supportsSwbreak = false;
427 } else if (!strncmp(message, "hwbreak-", len)) {
428 stub->supportsHwbreak = false;
429 }
430 if (!end) {
431 break;
432 }
433 message = end + 1;
434 }
435 strncpy(stub->outgoing, "swbreak+;hwbreak+", GDB_STUB_MAX_LINE - 4);
436}
437
438static void _processQReadCommand(struct GDBStub* stub, const char* message) {
439 stub->outgoing[0] = '\0';
440 if (!strncmp("HostInfo#", message, 9)) {
441 _writeHostInfo(stub);
442 return;
443 }
444 if (!strncmp("Attached#", message, 9)) {
445 strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
446 } else if (!strncmp("VAttachOrWaitSupported#", message, 23)) {
447 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
448 } else if (!strncmp("C#", message, 2)) {
449 strncpy(stub->outgoing, "QC1", GDB_STUB_MAX_LINE - 4);
450 } else if (!strncmp("fThreadInfo#", message, 12)) {
451 strncpy(stub->outgoing, "m1", GDB_STUB_MAX_LINE - 4);
452 } else if (!strncmp("sThreadInfo#", message, 12)) {
453 strncpy(stub->outgoing, "l", GDB_STUB_MAX_LINE - 4);
454 } else if (!strncmp("Supported:", message, 10)) {
455 _processQSupportedCommand(stub, message + 10);
456 }
457 _sendMessage(stub);
458}
459
460static void _processQWriteCommand(struct GDBStub* stub, const char* message) {
461 stub->outgoing[0] = '\0';
462 if (!strncmp("StartNoAckMode#", message, 16)) {
463 stub->lineAck = GDB_ACK_OFF;
464 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
465 }
466 _sendMessage(stub);
467}
468
469static void _processVWriteCommand(struct GDBStub* stub, const char* message) {
470 UNUSED(message);
471 stub->outgoing[0] = '\0';
472 _sendMessage(stub);
473}
474
475static void _processVReadCommand(struct GDBStub* stub, const char* message) {
476 stub->outgoing[0] = '\0';
477 if (!strncmp("Attach", message, 6)) {
478 strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
479 mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
480 }
481 _sendMessage(stub);
482}
483
484static void _setBreakpoint(struct GDBStub* stub, const char* message) {
485 const char* readAddress = &message[2];
486 unsigned i = 0;
487 uint32_t address = _readHex(readAddress, &i);
488 readAddress += i + 1;
489 uint32_t kind = _readHex(readAddress, &i);
490
491 switch (message[0]) {
492 case '0':
493 ARMDebuggerSetSoftwareBreakpoint(stub->d.platform, address, kind == 2 ? MODE_THUMB : MODE_ARM);
494 break;
495 case '1':
496 stub->d.platform->setBreakpoint(stub->d.platform, address, -1);
497 break;
498 case '2':
499 stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_WRITE);
500 break;
501 case '3':
502 stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_READ);
503 break;
504 case '4':
505 stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_RW);
506 break;
507 default:
508 stub->outgoing[0] = '\0';
509 _sendMessage(stub);
510 return;
511 }
512 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
513 _sendMessage(stub);
514}
515
516static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
517 const char* readAddress = &message[2];
518 unsigned i = 0;
519 uint32_t address = _readHex(readAddress, &i);
520 switch (message[0]) {
521 case '0':
522 ARMDebuggerClearSoftwareBreakpoint(stub->d.platform, address);
523 break;
524 case '1':
525 stub->d.platform->clearBreakpoint(stub->d.platform, address, -1);
526 break;
527 case '2':
528 case '3':
529 case '4':
530 stub->d.platform->clearWatchpoint(stub->d.platform, address, -1);
531 break;
532 default:
533 break;
534 }
535 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
536 _sendMessage(stub);
537}
538
539size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
540 uint8_t checksum = 0;
541 int parsed = 1;
542 switch (*message) {
543 case '+':
544 stub->lineAck = GDB_ACK_RECEIVED;
545 return parsed;
546 case '-':
547 stub->lineAck = GDB_NAK_RECEIVED;
548 return parsed;
549 case '$':
550 ++message;
551 break;
552 case '\x03':
553 mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
554 return parsed;
555 default:
556 _nak(stub);
557 return parsed;
558 }
559
560 int i;
561 char messageType = message[0];
562 for (i = 0; message[i] != '#'; ++i, ++parsed) {
563 checksum += message[i];
564 }
565 if (!message[i]) {
566 _nak(stub);
567 return parsed;
568 }
569 ++i;
570 ++parsed;
571 if (!message[i]) {
572 _nak(stub);
573 return parsed;
574 } else if (!message[i + 1]) {
575 ++parsed;
576 _nak(stub);
577 return parsed;
578 }
579 parsed += 2;
580 int networkChecksum = _hex2int(&message[i], 2);
581 if (networkChecksum != checksum) {
582 mLOG(DEBUGGER, WARN, "Checksum error: expected %02x, got %02x", checksum, networkChecksum);
583 _nak(stub);
584 return parsed;
585 }
586
587 _ack(stub);
588 ++message;
589 switch (messageType) {
590 case '?':
591 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT);
592 _sendMessage(stub);
593 break;
594 case 'c':
595 _continue(stub, message);
596 break;
597 case 'G':
598 _writeGPRs(stub, message);
599 break;
600 case 'g':
601 _readGPRs(stub, message);
602 break;
603 case 'H':
604 // This is faked because we only have one thread
605 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
606 _sendMessage(stub);
607 break;
608 case 'M':
609 _writeMemory(stub, message);
610 break;
611 case 'm':
612 _readMemory(stub, message);
613 break;
614 case 'P':
615 _writeRegister(stub, message);
616 break;
617 case 'p':
618 _readRegister(stub, message);
619 break;
620 case 'Q':
621 _processQWriteCommand(stub, message);
622 break;
623 case 'q':
624 _processQReadCommand(stub, message);
625 break;
626 case 's':
627 _step(stub, message);
628 break;
629 case 'V':
630 _processVWriteCommand(stub, message);
631 break;
632 case 'v':
633 _processVReadCommand(stub, message);
634 break;
635 case 'X':
636 _writeMemoryBinary(stub, message);
637 break;
638 case 'Z':
639 _setBreakpoint(stub, message);
640 break;
641 case 'z':
642 _clearBreakpoint(stub, message);
643 break;
644 default:
645 _error(stub, GDB_UNSUPPORTED_COMMAND);
646 break;
647 }
648 return parsed;
649}
650
651void GDBStubCreate(struct GDBStub* stub) {
652 stub->socket = INVALID_SOCKET;
653 stub->connection = INVALID_SOCKET;
654 stub->d.init = 0;
655 stub->d.deinit = _gdbStubDeinit;
656 stub->d.paused = _gdbStubWait;
657 stub->d.entered = _gdbStubEntered;
658 stub->d.custom = _gdbStubPoll;
659 stub->d.type = DEBUGGER_GDB;
660 stub->untilPoll = GDB_STUB_INTERVAL;
661 stub->lineAck = GDB_ACK_PENDING;
662 stub->shouldBlock = false;
663}
664
665bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) {
666 if (!SOCKET_FAILED(stub->socket)) {
667 GDBStubShutdown(stub);
668 }
669 stub->socket = SocketOpenTCP(port, bindAddress);
670 if (SOCKET_FAILED(stub->socket)) {
671 mLOG(DEBUGGER, ERROR, "Couldn't open socket");
672 return false;
673 }
674 if (!SocketSetBlocking(stub->socket, false)) {
675 goto cleanup;
676 }
677 int err = SocketListen(stub->socket, 1);
678 if (err) {
679 goto cleanup;
680 }
681
682 return true;
683
684cleanup:
685 mLOG(DEBUGGER, ERROR, "Couldn't listen on port");
686 SocketClose(stub->socket);
687 stub->socket = INVALID_SOCKET;
688 return false;
689}
690
691void GDBStubHangup(struct GDBStub* stub) {
692 if (!SOCKET_FAILED(stub->connection)) {
693 SocketClose(stub->connection);
694 stub->connection = INVALID_SOCKET;
695 }
696 if (stub->d.state == DEBUGGER_PAUSED) {
697 stub->d.state = DEBUGGER_RUNNING;
698 }
699}
700
701void GDBStubShutdown(struct GDBStub* stub) {
702 GDBStubHangup(stub);
703 if (!SOCKET_FAILED(stub->socket)) {
704 SocketClose(stub->socket);
705 stub->socket = INVALID_SOCKET;
706 }
707}
708
709void GDBStubUpdate(struct GDBStub* stub) {
710 if (stub->socket == INVALID_SOCKET) {
711 if (stub->d.state == DEBUGGER_PAUSED) {
712 stub->d.state = DEBUGGER_RUNNING;
713 }
714 return;
715 }
716 if (stub->connection == INVALID_SOCKET) {
717 if (stub->shouldBlock) {
718 Socket reads = stub->socket;
719 SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
720 }
721 stub->connection = SocketAccept(stub->socket, 0);
722 if (!SOCKET_FAILED(stub->connection)) {
723 if (!SocketSetBlocking(stub->connection, false)) {
724 goto connectionLost;
725 }
726 mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
727 } else if (SocketWouldBlock()) {
728 return;
729 } else {
730 goto connectionLost;
731 }
732 }
733 while (true) {
734 if (stub->shouldBlock) {
735 Socket reads = stub->connection;
736 SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
737 }
738 ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1);
739 if (messageLen == 0) {
740 goto connectionLost;
741 }
742 if (messageLen == -1) {
743 if (SocketWouldBlock()) {
744 return;
745 }
746 goto connectionLost;
747 }
748 stub->line[messageLen] = '\0';
749 mLOG(DEBUGGER, DEBUG, "< %s", stub->line);
750 ssize_t position = 0;
751 while (position < messageLen) {
752 position += _parseGDBMessage(stub, &stub->line[position]);
753 }
754 }
755
756connectionLost:
757 mLOG(DEBUGGER, WARN, "Connection lost");
758 GDBStubHangup(stub);
759}