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->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->watchType) {
58 case WATCHPOINT_WRITE:
59 if (info->newValue == info->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 int32_t currentCycles = 0;
309 if (cpu->executionMode == MODE_ARM) {
310 ARM_WRITE_PC;
311 } else {
312 THUMB_WRITE_PC;
313 }
314
315 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
316 _sendMessage(stub);
317}
318
319static void _readGPRs(struct GDBStub* stub, const char* message) {
320 struct ARMCore* cpu = stub->d.core->cpu;
321 UNUSED(message);
322 int r;
323 int i = 0;
324
325 // General purpose registers
326 for (r = 0; r < ARM_PC; ++r) {
327 _int2hex32(cpu->gprs[r], &stub->outgoing[i]);
328 i += 8;
329 }
330
331 // Program counter
332 _int2hex32(cpu->gprs[ARM_PC] - (cpu->cpsr.t ? WORD_SIZE_THUMB : WORD_SIZE_ARM), &stub->outgoing[i]);
333 i += 8;
334
335 // Floating point registers, unused on the GBA (8 of them, 24 bits each)
336 for (r = 0; r < 8 * 3; ++r) {
337 _int2hex32(0, &stub->outgoing[i]);
338 i += 8;
339 }
340
341 // Floating point status, unused on the GBA (32 bits)
342 _int2hex32(0, &stub->outgoing[i]);
343 i += 8;
344
345 // CPU status
346 _int2hex32(cpu->cpsr.packed, &stub->outgoing[i]);
347 i += 8;
348
349 stub->outgoing[i] = 0;
350 _sendMessage(stub);
351}
352
353static void _writeRegister(struct GDBStub* stub, const char* message) {
354 struct ARMCore* cpu = stub->d.core->cpu;
355 const char* readAddress = message;
356
357 unsigned i = 0;
358 uint32_t reg = _readHex(readAddress, &i);
359 readAddress += i + 1;
360
361 uint32_t value = _readHex(readAddress, &i);
362
363#ifdef _MSC_VER
364 value = _byteswap_ulong(value);
365#else
366 value = __builtin_bswap32(value);
367#endif
368
369 if (reg <= ARM_PC) {
370 cpu->gprs[reg] = value;
371 if (reg == ARM_PC) {
372 int32_t currentCycles = 0;
373 if (cpu->executionMode == MODE_ARM) {
374 ARM_WRITE_PC;
375 } else {
376 THUMB_WRITE_PC;
377 }
378 }
379 } else if (reg == 0x19) {
380 cpu->cpsr.packed = value;
381 } else {
382 stub->outgoing[0] = '\0';
383 _sendMessage(stub);
384 return;
385 }
386
387 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
388 _sendMessage(stub);
389}
390
391static void _readRegister(struct GDBStub* stub, const char* message) {
392 struct ARMCore* cpu = stub->d.core->cpu;
393 const char* readAddress = message;
394 unsigned i = 0;
395 uint32_t reg = _readHex(readAddress, &i);
396 uint32_t value;
397 if (reg < 0x10) {
398 value = cpu->gprs[reg];
399 } else if (reg == 0x19) {
400 value = cpu->cpsr.packed;
401 } else {
402 stub->outgoing[0] = '\0';
403 _sendMessage(stub);
404 return;
405 }
406 _int2hex32(value, stub->outgoing);
407 stub->outgoing[8] = '\0';
408 _sendMessage(stub);
409}
410
411static void _processQSupportedCommand(struct GDBStub* stub, const char* message) {
412 const char* terminator = strrchr(message, '#');
413 stub->supportsSwbreak = false;
414 stub->supportsHwbreak = false;
415 while (message < terminator) {
416 const char* end = strchr(message, ';');
417 size_t len;
418 if (end && end < terminator) {
419 len = end - message;
420 } else {
421 len = terminator - message;
422 }
423 if (!strncmp(message, "swbreak+", len)) {
424 stub->supportsSwbreak = true;
425 } else if (!strncmp(message, "hwbreak+", len)) {
426 stub->supportsHwbreak = true;
427 } else if (!strncmp(message, "swbreak-", len)) {
428 stub->supportsSwbreak = false;
429 } else if (!strncmp(message, "hwbreak-", len)) {
430 stub->supportsHwbreak = false;
431 }
432 if (!end) {
433 break;
434 }
435 message = end + 1;
436 }
437 strncpy(stub->outgoing, "swbreak+;hwbreak+", GDB_STUB_MAX_LINE - 4);
438}
439
440static void _processQReadCommand(struct GDBStub* stub, const char* message) {
441 stub->outgoing[0] = '\0';
442 if (!strncmp("HostInfo#", message, 9)) {
443 _writeHostInfo(stub);
444 return;
445 }
446 if (!strncmp("Attached#", message, 9)) {
447 strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
448 } else if (!strncmp("VAttachOrWaitSupported#", message, 23)) {
449 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
450 } else if (!strncmp("C#", message, 2)) {
451 strncpy(stub->outgoing, "QC1", GDB_STUB_MAX_LINE - 4);
452 } else if (!strncmp("fThreadInfo#", message, 12)) {
453 strncpy(stub->outgoing, "m1", GDB_STUB_MAX_LINE - 4);
454 } else if (!strncmp("sThreadInfo#", message, 12)) {
455 strncpy(stub->outgoing, "l", GDB_STUB_MAX_LINE - 4);
456 } else if (!strncmp("Supported:", message, 10)) {
457 _processQSupportedCommand(stub, message + 10);
458 }
459 _sendMessage(stub);
460}
461
462static void _processQWriteCommand(struct GDBStub* stub, const char* message) {
463 stub->outgoing[0] = '\0';
464 if (!strncmp("StartNoAckMode#", message, 16)) {
465 stub->lineAck = GDB_ACK_OFF;
466 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
467 }
468 _sendMessage(stub);
469}
470
471static void _processVWriteCommand(struct GDBStub* stub, const char* message) {
472 UNUSED(message);
473 stub->outgoing[0] = '\0';
474 _sendMessage(stub);
475}
476
477static void _processVReadCommand(struct GDBStub* stub, const char* message) {
478 stub->outgoing[0] = '\0';
479 if (!strncmp("Attach", message, 6)) {
480 strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
481 mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
482 }
483 _sendMessage(stub);
484}
485
486static void _setBreakpoint(struct GDBStub* stub, const char* message) {
487 const char* readAddress = &message[2];
488 unsigned i = 0;
489 uint32_t address = _readHex(readAddress, &i);
490 readAddress += i + 1;
491 uint32_t kind = _readHex(readAddress, &i);
492
493 switch (message[0]) {
494 case '0':
495 ARMDebuggerSetSoftwareBreakpoint(stub->d.platform, address, kind == 2 ? MODE_THUMB : MODE_ARM);
496 break;
497 case '1':
498 stub->d.platform->setBreakpoint(stub->d.platform, address, -1);
499 break;
500 case '2':
501 stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_WRITE);
502 break;
503 case '3':
504 stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_READ);
505 break;
506 case '4':
507 stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_RW);
508 break;
509 default:
510 stub->outgoing[0] = '\0';
511 _sendMessage(stub);
512 return;
513 }
514 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
515 _sendMessage(stub);
516}
517
518static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
519 const char* readAddress = &message[2];
520 unsigned i = 0;
521 uint32_t address = _readHex(readAddress, &i);
522 switch (message[0]) {
523 case '0':
524 ARMDebuggerClearSoftwareBreakpoint(stub->d.platform, address);
525 break;
526 case '1':
527 stub->d.platform->clearBreakpoint(stub->d.platform, address, -1);
528 break;
529 case '2':
530 case '3':
531 case '4':
532 stub->d.platform->clearWatchpoint(stub->d.platform, address);
533 break;
534 default:
535 break;
536 }
537 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
538 _sendMessage(stub);
539}
540
541size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
542 uint8_t checksum = 0;
543 int parsed = 1;
544 switch (*message) {
545 case '+':
546 stub->lineAck = GDB_ACK_RECEIVED;
547 return parsed;
548 case '-':
549 stub->lineAck = GDB_NAK_RECEIVED;
550 return parsed;
551 case '$':
552 ++message;
553 break;
554 case '\x03':
555 mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
556 return parsed;
557 default:
558 _nak(stub);
559 return parsed;
560 }
561
562 int i;
563 char messageType = message[0];
564 for (i = 0; message[i] != '#'; ++i, ++parsed) {
565 checksum += message[i];
566 }
567 if (!message[i]) {
568 _nak(stub);
569 return parsed;
570 }
571 ++i;
572 ++parsed;
573 if (!message[i]) {
574 _nak(stub);
575 return parsed;
576 } else if (!message[i + 1]) {
577 ++parsed;
578 _nak(stub);
579 return parsed;
580 }
581 parsed += 2;
582 int networkChecksum = _hex2int(&message[i], 2);
583 if (networkChecksum != checksum) {
584 mLOG(DEBUGGER, WARN, "Checksum error: expected %02x, got %02x", checksum, networkChecksum);
585 _nak(stub);
586 return parsed;
587 }
588
589 _ack(stub);
590 ++message;
591 switch (messageType) {
592 case '?':
593 snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT);
594 _sendMessage(stub);
595 break;
596 case 'c':
597 _continue(stub, message);
598 break;
599 case 'G':
600 _writeGPRs(stub, message);
601 break;
602 case 'g':
603 _readGPRs(stub, message);
604 break;
605 case 'H':
606 // This is faked because we only have one thread
607 strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
608 _sendMessage(stub);
609 break;
610 case 'M':
611 _writeMemory(stub, message);
612 break;
613 case 'm':
614 _readMemory(stub, message);
615 break;
616 case 'P':
617 _writeRegister(stub, message);
618 break;
619 case 'p':
620 _readRegister(stub, message);
621 break;
622 case 'Q':
623 _processQWriteCommand(stub, message);
624 break;
625 case 'q':
626 _processQReadCommand(stub, message);
627 break;
628 case 's':
629 _step(stub, message);
630 break;
631 case 'V':
632 _processVWriteCommand(stub, message);
633 break;
634 case 'v':
635 _processVReadCommand(stub, message);
636 break;
637 case 'X':
638 _writeMemoryBinary(stub, message);
639 break;
640 case 'Z':
641 _setBreakpoint(stub, message);
642 break;
643 case 'z':
644 _clearBreakpoint(stub, message);
645 break;
646 default:
647 _error(stub, GDB_UNSUPPORTED_COMMAND);
648 break;
649 }
650 return parsed;
651}
652
653void GDBStubCreate(struct GDBStub* stub) {
654 stub->socket = INVALID_SOCKET;
655 stub->connection = INVALID_SOCKET;
656 stub->d.init = 0;
657 stub->d.deinit = _gdbStubDeinit;
658 stub->d.paused = _gdbStubWait;
659 stub->d.entered = _gdbStubEntered;
660 stub->d.custom = _gdbStubPoll;
661 stub->untilPoll = GDB_STUB_INTERVAL;
662 stub->lineAck = GDB_ACK_PENDING;
663 stub->shouldBlock = false;
664}
665
666bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) {
667 if (!SOCKET_FAILED(stub->socket)) {
668 GDBStubShutdown(stub);
669 }
670 stub->socket = SocketOpenTCP(port, bindAddress);
671 if (SOCKET_FAILED(stub->socket)) {
672 mLOG(DEBUGGER, ERROR, "Couldn't open socket");
673 return false;
674 }
675 if (!SocketSetBlocking(stub->socket, false)) {
676 goto cleanup;
677 }
678 int err = SocketListen(stub->socket, 1);
679 if (err) {
680 goto cleanup;
681 }
682
683 return true;
684
685cleanup:
686 mLOG(DEBUGGER, ERROR, "Couldn't listen on port");
687 SocketClose(stub->socket);
688 stub->socket = INVALID_SOCKET;
689 return false;
690}
691
692void GDBStubHangup(struct GDBStub* stub) {
693 if (!SOCKET_FAILED(stub->connection)) {
694 SocketClose(stub->connection);
695 stub->connection = INVALID_SOCKET;
696 }
697 if (stub->d.state == DEBUGGER_PAUSED) {
698 stub->d.state = DEBUGGER_RUNNING;
699 }
700}
701
702void GDBStubShutdown(struct GDBStub* stub) {
703 GDBStubHangup(stub);
704 if (!SOCKET_FAILED(stub->socket)) {
705 SocketClose(stub->socket);
706 stub->socket = INVALID_SOCKET;
707 }
708}
709
710void GDBStubUpdate(struct GDBStub* stub) {
711 if (stub->socket == INVALID_SOCKET) {
712 if (stub->d.state == DEBUGGER_PAUSED) {
713 stub->d.state = DEBUGGER_RUNNING;
714 }
715 return;
716 }
717 if (stub->connection == INVALID_SOCKET) {
718 if (stub->shouldBlock) {
719 Socket reads = stub->socket;
720 SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
721 }
722 stub->connection = SocketAccept(stub->socket, 0);
723 if (!SOCKET_FAILED(stub->connection)) {
724 if (!SocketSetBlocking(stub->connection, false)) {
725 goto connectionLost;
726 }
727 mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
728 } else if (SocketWouldBlock()) {
729 return;
730 } else {
731 goto connectionLost;
732 }
733 }
734 while (true) {
735 if (stub->shouldBlock) {
736 Socket reads = stub->connection;
737 SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
738 }
739 ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1);
740 if (messageLen == 0) {
741 goto connectionLost;
742 }
743 if (messageLen == -1) {
744 if (SocketWouldBlock()) {
745 return;
746 }
747 goto connectionLost;
748 }
749 stub->line[messageLen] = '\0';
750 mLOG(DEBUGGER, DEBUG, "< %s", stub->line);
751 ssize_t position = 0;
752 while (position < messageLen) {
753 position += _parseGDBMessage(stub, &stub->line[position]);
754 }
755 }
756
757connectionLost:
758 mLOG(DEBUGGER, WARN, "Connection lost");
759 GDBStubHangup(stub);
760}