all repos — mgba @ 13a68a0dac2bbc7cd47a8cc9007bea580f076338

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 "core/serialize.h"
  9#include "gb/core.h"
 10#include "gba/gba.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 _fuzzRunloop(struct mCore* core, int frames);
 38static void _fuzzShutdown(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, _fuzzShutdown);
 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 mArguments args;
 55	bool parsed = parseArguments(&args, argc, argv, &subparser);
 56	if (!args.fname) {
 57		parsed = false;
 58	}
 59	if (!parsed || args.showHelp) {
 60		usage(argv[0], FUZZ_USAGE);
 61		return !parsed;
 62	}
 63	if (args.showVersion) {
 64		version(argv[0]);
 65		return 0;
 66	}
 67	struct mCore* core = mCoreFind(args.fname);
 68	core->init(core);
 69	mCoreInitConfig(core, "fuzz");
 70	applyArguments(&args, NULL, &core->config);
 71
 72	mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
 73
 74	void* outputBuffer;
 75	outputBuffer = 0;
 76
 77	if (!fuzzOpts.noVideo) {
 78		outputBuffer = malloc(256 * 256 * 4);
 79		core->setVideoBuffer(core, outputBuffer, 256);
 80	}
 81
 82#ifdef __AFL_HAVE_MANUAL_CONTROL
 83	__AFL_INIT();
 84#endif
 85
 86#ifdef M_CORE_GBA
 87	if (core->platform(core) == PLATFORM_GBA) {
 88		((struct GBA*) core->board)->hardCrash = false;
 89	}
 90#endif
 91	mCoreLoadFile(core, args.fname);
 92
 93	struct VFile* savestate = 0;
 94	struct VFile* savestateOverlay = 0;
 95	size_t overlayOffset;
 96
 97	if (fuzzOpts.savestate) {
 98		savestate = VFileOpen(fuzzOpts.savestate, O_RDONLY);
 99		free(fuzzOpts.savestate);
100	}
101	if (fuzzOpts.ssOverlay) {
102		overlayOffset = fuzzOpts.overlayOffset;
103		if (overlayOffset < core->stateSize(core)) {
104			savestateOverlay = VFileOpen(fuzzOpts.ssOverlay, O_RDONLY);
105		}
106		free(fuzzOpts.ssOverlay);
107	}
108
109	core->reset(core);
110
111	if (savestate) {
112		if (!savestateOverlay) {
113			mCoreLoadStateNamed(core, savestate, 0);
114		} else {
115			size_t size = core->stateSize(core);
116			uint8_t* state = malloc(size);
117			savestate->read(savestate, state, size);
118			savestateOverlay->read(savestateOverlay, state + overlayOffset, size - overlayOffset);
119			core->loadState(core, state);
120			free(state);
121			savestateOverlay->close(savestateOverlay);
122			savestateOverlay = 0;
123		}
124		savestate->close(savestate);
125		savestate = 0;
126	}
127
128	blip_set_rates(core->getAudioChannel(core, 0), GBA_ARM7TDMI_FREQUENCY, 0x8000);
129	blip_set_rates(core->getAudioChannel(core, 1), GBA_ARM7TDMI_FREQUENCY, 0x8000);
130
131	_fuzzRunloop(core, fuzzOpts.frames);
132
133	core->unloadROM(core);
134
135	if (savestate) {
136		savestate->close(savestate);
137	}
138	if (savestateOverlay) {
139		savestateOverlay->close(savestateOverlay);
140	}
141
142	freeArguments(&args);
143	if (outputBuffer) {
144		free(outputBuffer);
145	}
146	core->deinit(core);
147
148	return 0;
149}
150
151static void _fuzzRunloop(struct mCore* core, int frames) {
152	do {
153		core->runFrame(core);
154		blip_clear(core->getAudioChannel(core, 0));
155		blip_clear(core->getAudioChannel(core, 1));
156	} while (core->frameCounter(core) < frames && !_dispatchExiting);
157}
158
159static void _fuzzShutdown(int signal) {
160	UNUSED(signal);
161	_dispatchExiting = true;
162}
163
164static bool _parseFuzzOpts(struct mSubParser* parser, int option, const char* arg) {
165	struct FuzzOpts* opts = parser->opts;
166	errno = 0;
167	switch (option) {
168	case 'F':
169		opts->frames = strtoul(arg, 0, 10);
170		return !errno;
171	case 'N':
172		opts->noVideo = true;
173		return true;
174	case 'O':
175		opts->overlayOffset = strtoul(arg, 0, 10);
176		return !errno;
177	case 'S':
178		opts->savestate = strdup(arg);
179		return true;
180	case 'V':
181		opts->ssOverlay = strdup(arg);
182		return true;
183	default:
184		return false;
185	}
186}