Esempio n. 1
0
static void _processVReadCommand(struct GDBStub* stub, const char* message) {
	stub->outgoing[0] = '\0';
	if (!strncmp("Attach", message, 6)) {
		strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
		mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
	}
	_sendMessage(stub);
}
Esempio n. 2
0
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
	struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc - 1);
	if (!breakpoint) {
		return;
	}
	// TODO: Segments
	struct mDebuggerEntryInfo info = {
		.address = breakpoint->address
	};
	mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
}

static void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);

static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);

static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address);
static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address);
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);

struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
	struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));
	platform->entered = LR35902DebuggerEnter;
	platform->init = LR35902DebuggerInit;
	platform->deinit = LR35902DebuggerDeinit;
	platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
	platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
	platform->setWatchpoint = NULL;
	platform->clearWatchpoint = NULL;
	platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
	platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
	return platform;
}

void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
	debugger->cpu = cpu;
	LR35902DebugBreakpointListInit(&debugger->breakpoints, 0);
	LR35902DebugWatchpointListInit(&debugger->watchpoints, 0);
}

void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
	LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
	LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
}

static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
	UNUSED(reason);
	UNUSED(info);
	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
	struct LR35902Core* cpu = debugger->cpu;
	cpu->nextEvent = cpu->cycles;
}
Esempio n. 3
0
void GDBStubUpdate(struct GDBStub* stub) {
	if (stub->socket == INVALID_SOCKET) {
		if (stub->d.state == DEBUGGER_PAUSED) {
			stub->d.state = DEBUGGER_RUNNING;
		}
		return;
	}
	if (stub->connection == INVALID_SOCKET) {
		if (stub->shouldBlock) {
			Socket reads = stub->socket;
			SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
		}
		stub->connection = SocketAccept(stub->socket, 0);
		if (!SOCKET_FAILED(stub->connection)) {
			if (!SocketSetBlocking(stub->connection, false)) {
				goto connectionLost;
			}
			mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
		} else if (SocketWouldBlock()) {
			return;
		} else {
			goto connectionLost;
		}
	}
	while (true) {
		if (stub->shouldBlock) {
			Socket reads = stub->connection;
			SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
		}
		ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1);
		if (messageLen == 0) {
			goto connectionLost;
		}
		if (messageLen == -1) {
			if (SocketWouldBlock()) {
				return;
			}
			goto connectionLost;
		}
		stub->line[messageLen] = '\0';
		mLOG(DEBUGGER, DEBUG, "< %s", stub->line);
		ssize_t position = 0;
		while (position < messageLen) {
			position += _parseGDBMessage(stub, &stub->line[position]);
		}
	}

connectionLost:
	mLOG(DEBUGGER, WARN, "Connection lost");
	GDBStubHangup(stub);
}
Esempio n. 4
0
int main(int argc, char** argv) {
	struct mSDLRenderer renderer = {};

	struct mCoreOptions opts = {
		.useBios = true,
		.rewindEnable = true,
		.audioBuffers = 512,
		.videoSync = false,
		.audioSync = true,
		.volume = 0x100,
	};

	struct mArguments args;
	struct mGraphicsOpts graphicsOpts;

	struct mSubParser subparser;

	initParserForGraphics(&subparser, &graphicsOpts);
	bool parsed = parseArguments(&args, argc, argv, &subparser);
	if (!parsed || args.showHelp) {
		usage(argv[0], subparser.usage);
		freeArguments(&args);
		return !parsed;
	}
	if (args.showVersion) {
		version(argv[0]);
		freeArguments(&args);
		return 0;
	}

	renderer.core = mCoreFind(args.fname);
	if (!renderer.core) {
		printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
		freeArguments(&args);
		return 1;
	}
	renderer.core->desiredVideoDimensions(renderer.core, &renderer.width, &renderer.height);
#ifdef BUILD_GL
	mSDLGLCreate(&renderer);
#elif defined(BUILD_GLES2) || defined(USE_EPOXY)
	mSDLGLES2Create(&renderer);
#else
	mSDLSWCreate(&renderer);
#endif

	renderer.ratio = graphicsOpts.multiplier;
	if (renderer.ratio == 0) {
		renderer.ratio = 1;
	}
	opts.width = renderer.width * renderer.ratio;
	opts.height = renderer.height * renderer.ratio;

	if (!renderer.core->init(renderer.core)) {
		freeArguments(&args);
		return 1;
	}

	mInputMapInit(&renderer.core->inputMap, &GBAInputInfo);
	mCoreInitConfig(renderer.core, PORT);
	applyArguments(&args, &subparser, &renderer.core->config);

	mCoreConfigLoadDefaults(&renderer.core->config, &opts);
	mCoreLoadConfig(renderer.core);

	renderer.viewportWidth = renderer.core->opts.width;
	renderer.viewportHeight = renderer.core->opts.height;
#if SDL_VERSION_ATLEAST(2, 0, 0)
	renderer.player.fullscreen = renderer.core->opts.fullscreen;
	renderer.player.windowUpdated = 0;
#else
	renderer.fullscreen = renderer.core->opts.fullscreen;
#endif

	renderer.lockAspectRatio = renderer.core->opts.lockAspectRatio;
	renderer.filter = renderer.core->opts.resampleVideo;

	if (!mSDLInit(&renderer)) {
		freeArguments(&args);
		renderer.core->deinit(renderer.core);
		return 1;
	}

	renderer.player.bindings = &renderer.core->inputMap;
	mSDLInitBindingsGBA(&renderer.core->inputMap);
	mSDLInitEvents(&renderer.events);
	mSDLEventsLoadConfig(&renderer.events, mCoreConfigGetInput(&renderer.core->config));
	mSDLAttachPlayer(&renderer.events, &renderer.player);
	mSDLPlayerLoadConfig(&renderer.player, mCoreConfigGetInput(&renderer.core->config));

	int ret;

	// TODO: Use opts and config
	ret = mSDLRun(&renderer, &args);
	mSDLDetachPlayer(&renderer.events, &renderer.player);
	mInputMapDeinit(&renderer.core->inputMap);

	mSDLDeinit(&renderer);

	freeArguments(&args);
	mCoreConfigFreeOpts(&opts);
	mCoreConfigDeinit(&renderer.core->config);
	renderer.core->deinit(renderer.core);

	return ret;
}

int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
	struct mCoreThread thread = {
		.core = renderer->core
	};
	if (!mCoreLoadFile(renderer->core, args->fname)) {
		return 1;
	}
	mCoreAutoloadSave(renderer->core);
	struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core);
	if (debugger) {
		mDebuggerAttach(debugger, renderer->core);
		mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
	}

	if (args->patch) {
		struct VFile* patch = VFileOpen(args->patch, O_RDONLY);
		if (patch) {
			renderer->core->loadPatch(renderer->core, patch);
		}
	} else {
		mCoreAutoloadPatch(renderer->core);
	}

	renderer->audio.samples = renderer->core->opts.audioBuffers;
	renderer->audio.sampleRate = 44100;

	bool didFail = !mSDLInitAudio(&renderer->audio, &thread);
	if (!didFail) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
		mSDLSetScreensaverSuspendable(&renderer->events, renderer->core->opts.suspendScreensaver);
		mSDLSuspendScreensaver(&renderer->events);
#endif
		if (mCoreThreadStart(&thread)) {
			renderer->runloop(renderer, &thread);
			mSDLPauseAudio(&renderer->audio);
			mCoreThreadJoin(&thread);
		} else {
			didFail = true;
			printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
		}

#if SDL_VERSION_ATLEAST(2, 0, 0)
		mSDLResumeScreensaver(&renderer->events);
		mSDLSetScreensaverSuspendable(&renderer->events, false);
#endif

		if (mCoreThreadHasCrashed(&thread)) {
			didFail = true;
			printf("The game crashed!\n");
		}
	}
	renderer->core->unloadROM(renderer->core);
	return didFail;
}

static bool mSDLInit(struct mSDLRenderer* renderer) {
	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
		printf("Could not initialize video: %s\n", SDL_GetError());
		return false;
	}

	return renderer->init(renderer);
}

static void mSDLDeinit(struct mSDLRenderer* renderer) {
	mSDLDeinitEvents(&renderer->events);
	mSDLDeinitAudio(&renderer->audio);
#if SDL_VERSION_ATLEAST(2, 0, 0)
	SDL_DestroyWindow(renderer->window);
#endif

	renderer->deinit(renderer);

	SDL_Quit();
}
Esempio n. 5
0
static void _breakIntoDefault(int signal) {
	UNUSED(signal);
	mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
}
Esempio n. 6
0
size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
	uint8_t checksum = 0;
	int parsed = 1;
	switch (*message) {
	case '+':
		stub->lineAck = GDB_ACK_RECEIVED;
		return parsed;
	case '-':
		stub->lineAck = GDB_NAK_RECEIVED;
		return parsed;
	case '$':
		++message;
		break;
	case '\x03':
		mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
		return parsed;
	default:
		_nak(stub);
		return parsed;
	}

	int i;
	char messageType = message[0];
	for (i = 0; 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) {
		mLOG(DEBUGGER, WARN, "Checksum error: expected %02x, got %02x", checksum, networkChecksum);
		_nak(stub);
		return parsed;
	}

	_ack(stub);
	++message;
	switch (messageType) {
	case '?':
		snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT);
		_sendMessage(stub);
		break;
	case 'c':
		_continue(stub, message);
		break;
	case 'G':
		_writeGPRs(stub, message);
		break;
	case 'g':
		_readGPRs(stub, message);
		break;
	case 'H':
		// This is faked because we only have one thread
		strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
		_sendMessage(stub);
		break;
	case 'M':
		_writeMemory(stub, message);
		break;
	case 'm':
		_readMemory(stub, message);
		break;
	case 'P':
		_writeRegister(stub, message);
		break;
	case 'p':
		_readRegister(stub, message);
		break;
	case 'Q':
		_processQWriteCommand(stub, message);
		break;
	case 'q':
		_processQReadCommand(stub, message);
		break;
	case 's':
		_step(stub, message);
		break;
	case 'V':
		_processVWriteCommand(stub, message);
		break;
	case 'v':
		_processVReadCommand(stub, message);
		break;
	case 'X':
		_writeMemoryBinary(stub, message);
                break;
	case 'Z':
		_setBreakpoint(stub, message);
		break;
	case 'z':
		_clearBreakpoint(stub, message);
		break;
	default:
		_error(stub, GDB_UNSUPPORTED_COMMAND);
		break;
	}
	return parsed;
}
Esempio n. 7
0
void GBStop(struct LR35902Core* cpu) {
	struct GB* gb = (struct GB*) cpu->master;
	if (cpu->bus) {
		mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X\n", cpu->pc, cpu->bus);
	}
	if (gb->memory.io[REG_KEY1] & 1) {
		gb->doubleSpeed ^= 1;
		gb->memory.io[REG_KEY1] = 0;
		gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
	} else if (cpu->bus) {
		if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
			struct mDebuggerEntryInfo info = {
				.address = cpu->pc - 1,
				.a.c.opcode = 0x1000 | cpu->bus
			};
			mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
		}
		// Hang forever
		gb->memory.ime = 0;
		cpu->pc -= 2;
	}
	// TODO: Actually stop
}

void GBIllegal(struct LR35902Core* cpu) {
	struct GB* gb = (struct GB*) cpu->master;
	mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus);
	if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
		struct mDebuggerEntryInfo info = {
			.address = cpu->pc,
			.a.c.opcode = cpu->bus
		};
		mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
	}
	// Hang forever
	gb->memory.ime = 0;
	--cpu->pc;
}

bool GBIsROM(struct VFile* vf) {
	vf->seek(vf, 0x104, SEEK_SET);
	uint8_t header[4];
	static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};

	if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
		return false;
	}
	if (memcmp(header, knownHeader, sizeof(header))) {
		return false;
	}
	return true;
}

void GBGetGameTitle(struct GB* gb, char* out) {
	const struct GBCartridge* cart = NULL;
	if (gb->memory.rom) {
		cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
	}
	if (gb->pristineRom) {
		cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
	}
	if (!cart) {
		return;
	}
	if (cart->oldLicensee != 0x33) {
		memcpy(out, cart->titleLong, 16);
	} else {
		memcpy(out, cart->titleShort, 11);
	}
}

void GBGetGameCode(struct GB* gb, char* out) {
	memset(out, 0, 8);
	const struct GBCartridge* cart = NULL;
	if (gb->memory.rom) {
		cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
	}
	if (gb->pristineRom) {
		cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
	}
	if (!cart) {
		return;
	}
	if (cart->cgb == 0xC0) {
		memcpy(out, "CGB-????", 8);
	} else {
		memcpy(out, "DMG-????", 8);
	}
	if (cart->oldLicensee == 0x33) {
		memcpy(&out[4], cart->maker, 4);
	}
}