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}