all repos — mgba @ 526f86d08529aa8f501cb015c1e442aa743940da

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