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}