all repos — mgba @ 67905d281bfecbb06f51f2ca5ac939df378734a5

mGBA Game Boy Advance Emulator

src/platform/test/fuzz-main.c (view raw)

  1/* Copyright (c) 2013-2015 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 "core/config.h"
  7#include "core/core.h"
  8#include "gba/core.h"
  9#include "gba/gba.h"
 10#include "gba/serialize.h"
 11
 12#include "feature/commandline.h"
 13#include "util/memory.h"
 14#include "util/string.h"
 15#include "util/vfs.h"
 16
 17#include <errno.h>
 18#include <signal.h>
 19
 20#define FUZZ_OPTIONS "F:NO:S:V:"
 21#define FUZZ_USAGE \
 22	"\nAdditional options:\n" \
 23	"  -F FRAMES        Run for the specified number of FRAMES before exiting\n" \
 24	"  -N               Disable video rendering entirely\n" \
 25	"  -O OFFSET        Offset to apply savestate overlay\n" \
 26	"  -S FILE          Load a savestate when starting the test\n" \
 27	"  -V FILE          Overlay a second savestate over the loaded savestate\n" \
 28
 29struct FuzzOpts {
 30	bool noVideo;
 31	int frames;
 32	size_t overlayOffset;
 33	char* savestate;
 34	char* ssOverlay;
 35};
 36
 37static void _GBAFuzzRunloop(struct mCore* core, int frames);
 38static void _GBAFuzzShutdown(int signal);
 39static bool _parseFuzzOpts(struct mSubParser* parser, int option, const char* arg);
 40
 41static bool _dispatchExiting = false;
 42
 43int main(int argc, char** argv) {
 44	signal(SIGINT, _GBAFuzzShutdown);
 45
 46	struct FuzzOpts fuzzOpts = { false, 0, 0, 0, 0 };
 47	struct mSubParser subparser = {
 48		.usage = FUZZ_USAGE,
 49		.parse = _parseFuzzOpts,
 50		.extraOptions = FUZZ_OPTIONS,
 51		.opts = &fuzzOpts
 52	};
 53
 54	struct mCore* core = GBACoreCreate();
 55	core->init(core);
 56	mCoreInitConfig(core, "fuzz");
 57	mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
 58
 59	struct mArguments args;
 60	bool parsed = parseArguments(&args, argc, argv, &subparser);
 61	if (!args.fname) {
 62		parsed = false;
 63	}
 64	if (!parsed || args.showHelp) {
 65		usage(argv[0], FUZZ_USAGE);
 66		core->deinit(core);
 67		return !parsed;
 68	}
 69	if (args.showVersion) {
 70		version(argv[0]);
 71		core->deinit(core);
 72		return 0;
 73	}
 74	applyArguments(&args, NULL, &core->config);
 75
 76	void* outputBuffer;
 77	outputBuffer = 0;
 78
 79	if (!fuzzOpts.noVideo) {
 80		outputBuffer = malloc(256 * 256 * 4);
 81		core->setVideoBuffer(core, outputBuffer, 256);
 82	}
 83
 84#ifdef __AFL_HAVE_MANUAL_CONTROL
 85	__AFL_INIT();
 86#endif
 87
 88	((struct GBA*) core->board)->hardCrash = false;
 89	mCoreLoadFile(core, args.fname);
 90
 91	struct VFile* savestate = 0;
 92	struct VFile* savestateOverlay = 0;
 93	size_t overlayOffset;
 94
 95	if (fuzzOpts.savestate) {
 96		savestate = VFileOpen(fuzzOpts.savestate, O_RDONLY);
 97		free(fuzzOpts.savestate);
 98	}
 99	if (fuzzOpts.ssOverlay) {
100		overlayOffset = fuzzOpts.overlayOffset;
101		if (overlayOffset < sizeof(struct GBASerializedState)) {
102			savestateOverlay = VFileOpen(fuzzOpts.ssOverlay, O_RDONLY);
103		}
104		free(fuzzOpts.ssOverlay);
105	}
106	if (savestate) {
107		if (!savestateOverlay) {
108			mCoreLoadStateNamed(core, savestate, 0);
109		} else {
110			struct GBASerializedState* state = GBAAllocateState();
111			savestate->read(savestate, state, sizeof(*state));
112			savestateOverlay->read(savestateOverlay, (uint8_t*) state + overlayOffset, sizeof(*state) - overlayOffset);
113			GBADeserialize(core->board, state);
114			GBADeallocateState(state);
115			savestateOverlay->close(savestateOverlay);
116			savestateOverlay = 0;
117		}
118		savestate->close(savestate);
119		savestate = 0;
120	}
121
122	blip_set_rates(core->getAudioChannel(core, 0), GBA_ARM7TDMI_FREQUENCY, 0x8000);
123	blip_set_rates(core->getAudioChannel(core, 1), GBA_ARM7TDMI_FREQUENCY, 0x8000);
124
125	core->reset(core);
126
127	_GBAFuzzRunloop(core, fuzzOpts.frames);
128
129	core->unloadROM(core);
130
131	if (savestate) {
132		savestate->close(savestate);
133	}
134	if (savestateOverlay) {
135		savestateOverlay->close(savestateOverlay);
136	}
137
138	freeArguments(&args);
139	if (outputBuffer) {
140		free(outputBuffer);
141	}
142	core->deinit(core);
143
144	return 0;
145}
146
147static void _GBAFuzzRunloop(struct mCore* core, int frames) {
148	do {
149		core->runFrame(core);
150		blip_clear(core->getAudioChannel(core, 0));
151		blip_clear(core->getAudioChannel(core, 1));
152	} while (core->frameCounter(core) < frames && !_dispatchExiting);
153}
154
155static void _GBAFuzzShutdown(int signal) {
156	UNUSED(signal);
157	_dispatchExiting = true;
158}
159
160static bool _parseFuzzOpts(struct mSubParser* parser, int option, const char* arg) {
161	struct FuzzOpts* opts = parser->opts;
162	errno = 0;
163	switch (option) {
164	case 'F':
165		opts->frames = strtoul(arg, 0, 10);
166		return !errno;
167	case 'N':
168		opts->noVideo = true;
169		return true;
170	case 'O':
171		opts->overlayOffset = strtoul(arg, 0, 10);
172		return !errno;
173	case 'S':
174		opts->savestate = strdup(arg);
175		return true;
176	case 'V':
177		opts->ssOverlay = strdup(arg);
178		return true;
179	default:
180		return false;
181	}
182}