all repos — mgba @ 88212fc2deb72b3ab85313852b0b091edc88403b

mGBA Game Boy Advance Emulator

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