<commit_before>#include "gdb-stub.h"

#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

enum GDBError {
	GDB_NO_ERROR = 0x00,
	GDB_BAD_ARGUMENTS = 0x06,
	GDB_UNSUPPORTED_COMMAND = 0x07
};

static void _gdbStubDeinit(struct ARMDebugger* debugger) {
	struct GDBStub* stub = (struct GDBStub*) debugger;
	if (stub->socket >= 0) {
		GDBStubShutdown(stub);
	}
}

static void _ack(struct GDBStub* stub) {
	char ack = '+';
	send(stub->connection, &ack, 1, 0);
}

static void _nak(struct GDBStub* stub) {
	char nak = '-';
	printf("Packet error\n");
	send(stub->connection, &nak, 1, 0);
}

static uint32_t _hex2int(const char* hex, int maxDigits) {
	uint32_t value = 0;
	uint8_t letter;

	while (maxDigits--) {
		letter = *hex - '0';
		if (letter > 9) {
			letter = *hex - 'a';
			if  (letter > 5) {
				break;
			}
			value *= 0x10;
			value += letter + 10;
		} else {
			value *= 0x10;
			value += letter;
		}
		++hex;
	}
	return value;
}

static void _int2hex8(uint8_t value, char* out) {
	static const char language[] = "0123456789abcdef";
	out[0] = language[value >> 4];
	out[1] = language[value & 0xF];
}

static void _int2hex32(uint32_t value, char* out) {
	static const char language[] = "0123456789abcdef";
	out[6] = language[value >> 28];
	out[7] = language[(value >> 24) & 0xF];
	out[4] = language[(value >> 20) & 0xF];
	out[5] = language[(value >> 16) & 0xF];
	out[2] = language[(value >> 12) & 0xF];
	out[3] = language[(value >> 8) & 0xF];
	out[0] = language[(value >> 4) & 0xF];
	out[1] = language[value & 0xF];
}

static void _sendMessage(struct GDBStub* stub) {
	if (stub->lineAck != GDB_ACK_OFF) {
		stub->lineAck = GDB_ACK_PENDING;
	}
	uint8_t checksum = 0;
	int i = 1;
	char buffer = stub->outgoing[0];
	char swap;
	stub->outgoing[0] = '$';
	if (buffer) {
		for (; i < GDB_STUB_MAX_LINE - 5; ++i) {
			checksum += buffer;
			swap = stub->outgoing[i];
			stub->outgoing[i] = buffer;
			buffer = swap;
			if (!buffer) {
				++i;
				break;
			}
		}
	}
	stub->outgoing[i] = '#';
	_int2hex8(checksum, &stub->outgoing[i + 1]);
	stub->outgoing[i + 3] = 0;
	printf("> %s\n", stub->outgoing);
	send(stub->connection, stub->outgoing, i + 3, 0);
}

static void _error(struct GDBStub* stub, enum GDBError error) {
	snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 1, "E%02x", error);
	_sendMessage(stub);
}

static void _readMemory(struct GDBStub* stub, const char* message) {
	const char* readAddress = message;
	unsigned i;
	for (i = 0; i < 8; ++i) {
		if (readAddress[i] == ',') {
			break;
		}
	}
	uint32_t address = _hex2int(readAddress, i);
	readAddress += i + 1;
	// TODO: expand this capacity
	for (i = 0; i < 1; ++i) {
		if (readAddress[i] == '#') {
			break;
		}
	}
	uint32_t size = _hex2int(readAddress, i);
	if (size > 4) {
		_error(stub, GDB_BAD_ARGUMENTS);
		return;
	}
	struct ARMMemory* memory = stub->d.memoryShim.original;
	int writeAddress = 0;
	for (i = 0; i < size; ++i, writeAddress += 2) {
		uint8_t byte = memory->load8(memory, address + i, 0);
		_int2hex8(byte, &stub->outgoing[writeAddress]);
	}
	stub->outgoing[writeAddress] = 0;
	_sendMessage(stub);
}

static void _readGPRs(struct GDBStub* stub, const char* message) {
	(void) (message);
	int r;
	int i = 0;
	for (r = 0; r < 16; ++r) {
		_int2hex32(stub->d.cpu->gprs[r], &stub->outgoing[i]);
		i += 8;
	}
	stub->outgoing[i] = 0;
	_sendMessage(stub);
}

static void _readRegister(struct GDBStub* stub, const char* message) {
	const char* readAddress = message;
	unsigned i;
	for (i = 0; i < 8; ++i) {
		if (readAddress[i] == '#') {
			break;
		}
	}
	uint32_t reg = _hex2int(readAddress, i);
	uint32_t value;
	if (reg < 0x10) {
		value = stub->d.cpu->gprs[reg];
	} else if (reg == 0x19) {
		value = stub->d.cpu->cpsr.packed;
	} else {
		stub->outgoing[0] = '\0';
		_sendMessage(stub);
		return;
	}
	_int2hex32(value, stub->outgoing);
	stub->outgoing[8] = '\0';
	_sendMessage(stub);
}

static void _processQMinCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

static void _processQMajCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

static void _processVMajCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

static void _processVMinCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
	uint8_t checksum = 0;
	int parsed = 1;
	printf("< %s\n", stub->line);
	switch (*message) {
	case '+':
		stub->lineAck = GDB_ACK_RECEIVED;
		return parsed;
	case '-':
		stub->lineAck = GDB_NAK_RECEIVED;
		return parsed;
	case '$':
		++message;
		break;
	default:
		_nak(stub);
		return parsed;
	}

	int i;
	char messageType = message[0];
	for (i = 0; message[i] && message[i] != '#'; ++i, ++parsed) {
		checksum += message[i];
	}
	if (!message[i]) {
		_nak(stub);
		return parsed;
	}
	++i;
	++parsed;
	if (!message[i]) {
		_nak(stub);
		return parsed;
	} else if (!message[i + 1]) {
		++parsed;
		_nak(stub);
		return parsed;
	}
	parsed += 2;
	int networkChecksum = _hex2int(&message[i], 2);
	if (networkChecksum != checksum) {
		printf("Checksum error: expected %02x, got %02x\n", checksum, networkChecksum);
		_nak(stub);
		return parsed;
	}

	_ack(stub);
	++message;
	switch (messageType) {
	case 'g':
		_readGPRs(stub, message);
		break;
	case 'm':
		_readMemory(stub, message);
		break;
	case 'p':
		_readRegister(stub, message);
		break;
	case 'Q':
		_processQMajCommand(stub, message);
		break;
	case 'q':
		_processQMinCommand(stub, message);
		break;
	case 'V':
		_processVMajCommand(stub, message);
		break;
	case 'v':
		_processVMinCommand(stub, message);<commit_msg>Add support for qHostInfo command for lldb<commit_after>#include "gdb-stub.h"

#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

enum GDBError {
	GDB_NO_ERROR = 0x00,
	GDB_BAD_ARGUMENTS = 0x06,
	GDB_UNSUPPORTED_COMMAND = 0x07
};

enum {
	MACH_O_ARM = 12,
	MACH_O_ARM_V4T = 5
};

static void _gdbStubDeinit(struct ARMDebugger* debugger) {
	struct GDBStub* stub = (struct GDBStub*) debugger;
	if (stub->socket >= 0) {
		GDBStubShutdown(stub);
	}
}

static void _ack(struct GDBStub* stub) {
	char ack = '+';
	send(stub->connection, &ack, 1, 0);
}

static void _nak(struct GDBStub* stub) {
	char nak = '-';
	printf("Packet error\n");
	send(stub->connection, &nak, 1, 0);
}

static uint32_t _hex2int(const char* hex, int maxDigits) {
	uint32_t value = 0;
	uint8_t letter;

	while (maxDigits--) {
		letter = *hex - '0';
		if (letter > 9) {
			letter = *hex - 'a';
			if  (letter > 5) {
				break;
			}
			value *= 0x10;
			value += letter + 10;
		} else {
			value *= 0x10;
			value += letter;
		}
		++hex;
	}
	return value;
}

static void _int2hex8(uint8_t value, char* out) {
	static const char language[] = "0123456789abcdef";
	out[0] = language[value >> 4];
	out[1] = language[value & 0xF];
}

static void _int2hex32(uint32_t value, char* out) {
	static const char language[] = "0123456789abcdef";
	out[6] = language[value >> 28];
	out[7] = language[(value >> 24) & 0xF];
	out[4] = language[(value >> 20) & 0xF];
	out[5] = language[(value >> 16) & 0xF];
	out[2] = language[(value >> 12) & 0xF];
	out[3] = language[(value >> 8) & 0xF];
	out[0] = language[(value >> 4) & 0xF];
	out[1] = language[value & 0xF];
}

static void _sendMessage(struct GDBStub* stub) {
	if (stub->lineAck != GDB_ACK_OFF) {
		stub->lineAck = GDB_ACK_PENDING;
	}
	uint8_t checksum = 0;
	int i = 1;
	char buffer = stub->outgoing[0];
	char swap;
	stub->outgoing[0] = '$';
	if (buffer) {
		for (; i < GDB_STUB_MAX_LINE - 5; ++i) {
			checksum += buffer;
			swap = stub->outgoing[i];
			stub->outgoing[i] = buffer;
			buffer = swap;
			if (!buffer) {
				++i;
				break;
			}
		}
	}
	stub->outgoing[i] = '#';
	_int2hex8(checksum, &stub->outgoing[i + 1]);
	stub->outgoing[i + 3] = 0;
	printf("> %s\n", stub->outgoing);
	send(stub->connection, stub->outgoing, i + 3, 0);
}

static void _error(struct GDBStub* stub, enum GDBError error) {
	snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "E%02x", error);
	_sendMessage(stub);
}

static void _writeHostInfo(struct GDBStub* stub) {
	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);
	_sendMessage(stub);
}

static void _readMemory(struct GDBStub* stub, const char* message) {
	const char* readAddress = message;
	unsigned i;
	for (i = 0; i < 8; ++i) {
		if (readAddress[i] == ',') {
			break;
		}
	}
	uint32_t address = _hex2int(readAddress, i);
	readAddress += i + 1;
	// TODO: expand this capacity
	for (i = 0; i < 1; ++i) {
		if (readAddress[i] == '#') {
			break;
		}
	}
	uint32_t size = _hex2int(readAddress, i);
	if (size > 4) {
		_error(stub, GDB_BAD_ARGUMENTS);
		return;
	}
	struct ARMMemory* memory = stub->d.memoryShim.original;
	int writeAddress = 0;
	for (i = 0; i < size; ++i, writeAddress += 2) {
		uint8_t byte = memory->load8(memory, address + i, 0);
		_int2hex8(byte, &stub->outgoing[writeAddress]);
	}
	stub->outgoing[writeAddress] = 0;
	_sendMessage(stub);
}

static void _readGPRs(struct GDBStub* stub, const char* message) {
	(void) (message);
	int r;
	int i = 0;
	for (r = 0; r < 16; ++r) {
		_int2hex32(stub->d.cpu->gprs[r], &stub->outgoing[i]);
		i += 8;
	}
	stub->outgoing[i] = 0;
	_sendMessage(stub);
}

static void _readRegister(struct GDBStub* stub, const char* message) {
	const char* readAddress = message;
	unsigned i;
	for (i = 0; i < 8; ++i) {
		if (readAddress[i] == '#') {
			break;
		}
	}
	uint32_t reg = _hex2int(readAddress, i);
	uint32_t value;
	if (reg < 0x10) {
		value = stub->d.cpu->gprs[reg];
	} else if (reg == 0x19) {
		value = stub->d.cpu->cpsr.packed;
	} else {
		stub->outgoing[0] = '\0';
		_sendMessage(stub);
		return;
	}
	_int2hex32(value, stub->outgoing);
	stub->outgoing[8] = '\0';
	_sendMessage(stub);
}

static void _processQReadCommand(struct GDBStub* stub, const char* message) {
	if (!strncmp("HostInfo", message, 8)) {
		_writeHostInfo(stub);
		return;
	}
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

static void _processQWriteCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

static void _processVMajCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

static void _processVMinCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	_sendMessage(stub);
}

size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
	uint8_t checksum = 0;
	int parsed = 1;
	printf("< %s\n", stub->line);
	switch (*message) {
	case '+':
		stub->lineAck = GDB_ACK_RECEIVED;
		return parsed;
	case '-':
		stub->lineAck = GDB_NAK_RECEIVED;
		return parsed;
	case '$':
		++message;
		break;
	default:
		_nak(stub);
		return parsed;
	}

	int i;
	char messageType = message[0];
	for (i = 0; message[i] && message[i] != '#'; ++i, ++parsed) {
		checksum += message[i];
	}
	if (!message[i]) {
		_nak(stub);
		return parsed;
	}
	++i;
	++parsed;
	if (!message[i]) {
		_nak(stub);
		return parsed;
	} else if (!message[i + 1]) {
		++parsed;
		_nak(stub);
		return parsed;
	}
	parsed += 2;
	int networkChecksum = _hex2int(&message[i], 2);
	if (networkChecksum != checksum) {
		printf("Checksum error: expected %02x, got %02x\n", checksum, networkChecksum);
		_nak(stub);
		return parsed;
	}

	_ack(stub);
	++message;
	switch (messageType) {
	case 'g':
		_readGPRs(stub, message);
		break;
	case 'm':
		_readMemory(stub, message);
		break;
	case 'p':
		_readRegister(stub, message);
		break;
	case 'Q':
		_processQWriteCommand(stub, message);
		break;
	case 'q':
		_processQReadCommand(stub, message);
		break;
	case 'V':
		_processVMajCommand(stub, message);
		break;
	case 'v':
		_processVMinCommand(stub, message);
{'fraction_non_alphanumeric': 0.1752122523722324, 'fraction_numerical': 0.030297985683369402, 'mean_word_length': 4.004164931278634, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 136, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7185766', 'n_tokens_mistral': 5381, 'n_tokens_neox': 5109, 'n_words': 1146}