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