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