all repos — mgba @ 264f238ec31b3c29e3bcd84fe561d1d32d5f57e2

mGBA Game Boy Advance Emulator

src/core/mem-search.c (view raw)

  1/* Copyright (c) 2013-2017 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 <mgba/core/mem-search.h>
  7
  8#include <mgba/core/core.h>
  9#include <mgba/core/interface.h>
 10
 11DEFINE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult);
 12
 13static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint32_t value32, struct mCoreMemorySearchResults* out, size_t limit) {
 14	const uint32_t* mem32 = mem;
 15	size_t found = 0;
 16	uint32_t start = block->start;
 17	uint32_t end = size; // TODO: Segments
 18	size_t i;
 19	// TODO: Big endian
 20	for (i = 0; (!limit || found < limit) && i < end; i += 16) {
 21		int mask = 0;
 22		mask |= (mem32[(i >> 2) + 0] == value32) << 0;
 23		mask |= (mem32[(i >> 2) + 1] == value32) << 1;
 24		mask |= (mem32[(i >> 2) + 2] == value32) << 2;
 25		mask |= (mem32[(i >> 2) + 3] == value32) << 3;
 26		if (!mask) {
 27			continue;
 28		}
 29		if ((mask & 1) && (!limit || found < limit)) {
 30			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
 31			res->address = start + i;
 32			res->type = mCORE_MEMORY_SEARCH_32;
 33			res->segment = -1; // TODO
 34			res->guessDivisor = 1;
 35			++found;
 36		}
 37		if ((mask & 2) && (!limit || found < limit)) {
 38			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
 39			res->address = start + i + 4;
 40			res->type = mCORE_MEMORY_SEARCH_32;
 41			res->segment = -1; // TODO
 42			res->guessDivisor = 1;
 43			++found;
 44		}
 45		if ((mask & 4) && (!limit || found < limit)) {
 46			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
 47			res->address = start + i + 8;
 48			res->type = mCORE_MEMORY_SEARCH_32;
 49			res->segment = -1; // TODO
 50			res->guessDivisor = 1;
 51			++found;
 52		}
 53		if ((mask & 8) && (!limit || found < limit)) {
 54			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
 55			res->address = start + i + 12;
 56			res->type = mCORE_MEMORY_SEARCH_32;
 57			res->segment = -1; // TODO
 58			res->guessDivisor = 1;
 59			++found;
 60		}
 61	}
 62	// TODO: last 12 bytes
 63	return found;
 64}
 65
 66static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint16_t value16, struct mCoreMemorySearchResults* out, size_t limit) {
 67	const uint16_t* mem16 = mem;
 68	size_t found = 0;
 69	uint32_t start = block->start;
 70	uint32_t end = size; // TODO: Segments
 71	size_t i;
 72	// TODO: Big endian
 73	for (i = 0; (!limit || found < limit) && i < end; i += 16) {
 74		int mask = 0;
 75		mask |= (mem16[(i >> 1) + 0] == value16) << 0;
 76		mask |= (mem16[(i >> 1) + 1] == value16) << 1;
 77		mask |= (mem16[(i >> 1) + 2] == value16) << 2;
 78		mask |= (mem16[(i >> 1) + 3] == value16) << 3;
 79		mask |= (mem16[(i >> 1) + 4] == value16) << 4;
 80		mask |= (mem16[(i >> 1) + 5] == value16) << 5;
 81		mask |= (mem16[(i >> 1) + 6] == value16) << 6;
 82		mask |= (mem16[(i >> 1) + 7] == value16) << 7;
 83		if (!mask) {
 84			continue;
 85		}
 86		if ((mask & 1) && (!limit || found < limit)) {
 87			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
 88			res->address = start + i;
 89			res->type = mCORE_MEMORY_SEARCH_16;
 90			res->segment = -1; // TODO
 91			res->guessDivisor = 1;
 92			++found;
 93		}
 94		if ((mask & 2) && (!limit || found < limit)) {
 95			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
 96			res->address = start + i + 2;
 97			res->type = mCORE_MEMORY_SEARCH_16;
 98			res->segment = -1; // TODO
 99			res->guessDivisor = 1;
100			++found;
101		}
102		if ((mask & 4) && (!limit || found < limit)) {
103			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
104			res->address = start + i + 4;
105			res->type = mCORE_MEMORY_SEARCH_16;
106			res->segment = -1; // TODO
107			res->guessDivisor = 1;
108			++found;
109		}
110		if ((mask & 8) && (!limit || found < limit)) {
111			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
112			res->address = start + i + 6;
113			res->type = mCORE_MEMORY_SEARCH_16;
114			res->segment = -1; // TODO
115			res->guessDivisor = 1;
116			++found;
117		}
118		if ((mask & 16) && (!limit || found < limit)) {
119			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
120			res->address = start + i + 8;
121			res->type = mCORE_MEMORY_SEARCH_16;
122			res->segment = -1; // TODO
123			res->guessDivisor = 1;
124			++found;
125		}
126		if ((mask & 32) && (!limit || found < limit)) {
127			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
128			res->address = start + i + 10;
129			res->type = mCORE_MEMORY_SEARCH_16;
130			res->segment = -1; // TODO
131			res->guessDivisor = 1;
132			++found;
133		}
134		if ((mask & 64) && (!limit || found < limit)) {
135			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
136			res->address = start + i + 12;
137			res->type = mCORE_MEMORY_SEARCH_16;
138			res->segment = -1; // TODO
139			res->guessDivisor = 1;
140			++found;
141		}
142		if ((mask & 128) && (!limit || found < limit)) {
143			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
144			res->address = start + i + 14;
145			res->type = mCORE_MEMORY_SEARCH_16;
146			res->segment = -1; // TODO
147			res->guessDivisor = 1;
148			++found;
149		}
150	}
151	// TODO: last 14 bytes
152	return found;
153}
154
155static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint8_t value8, struct mCoreMemorySearchResults* out, size_t limit) {
156	const uint8_t* mem8 = mem;
157	size_t found = 0;
158	uint32_t start = block->start;
159	uint32_t end = size; // TODO: Segments
160	size_t i;
161	for (i = 0; (!limit || found < limit) && i < end; i += 8) {
162		int mask = 0;
163		mask |= (mem8[i + 0] == value8) << 0;
164		mask |= (mem8[i + 1] == value8) << 1;
165		mask |= (mem8[i + 2] == value8) << 2;
166		mask |= (mem8[i + 3] == value8) << 3;
167		mask |= (mem8[i + 4] == value8) << 4;
168		mask |= (mem8[i + 5] == value8) << 5;
169		mask |= (mem8[i + 6] == value8) << 6;
170		mask |= (mem8[i + 7] == value8) << 7;
171		if (!mask) {
172			continue;
173		}
174		if ((mask & 1) && (!limit || found < limit)) {
175			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
176			res->address = start + i;
177			res->type = mCORE_MEMORY_SEARCH_8;
178			res->segment = -1; // TODO
179			res->guessDivisor = 1;
180			++found;
181		}
182		if ((mask & 2) && (!limit || found < limit)) {
183			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
184			res->address = start + i + 1;
185			res->type = mCORE_MEMORY_SEARCH_8;
186			res->segment = -1; // TODO
187			res->guessDivisor = 1;
188			++found;
189		}
190		if ((mask & 4) && (!limit || found < limit)) {
191			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
192			res->address = start + i + 2;
193			res->type = mCORE_MEMORY_SEARCH_8;
194			res->segment = -1; // TODO
195			res->guessDivisor = 1;
196			++found;
197		}
198		if ((mask & 8) && (!limit || found < limit)) {
199			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
200			res->address = start + i + 3;
201			res->type = mCORE_MEMORY_SEARCH_8;
202			res->segment = -1; // TODO
203			res->guessDivisor = 1;
204			++found;
205		}
206		if ((mask & 16) && (!limit || found < limit)) {
207			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
208			res->address = start + i + 4;
209			res->type = mCORE_MEMORY_SEARCH_8;
210			res->segment = -1; // TODO
211			res->guessDivisor = 1;
212			++found;
213		}
214		if ((mask & 32) && (!limit || found < limit)) {
215			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
216			res->address = start + i + 5;
217			res->type = mCORE_MEMORY_SEARCH_8;
218			res->segment = -1; // TODO
219			res->guessDivisor = 1;
220			++found;
221		}
222		if ((mask & 64) && (!limit || found < limit)) {
223			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
224			res->address = start + i + 6;
225			res->type = mCORE_MEMORY_SEARCH_8;
226			res->segment = -1; // TODO
227			res->guessDivisor = 1;
228			++found;
229		}
230		if ((mask & 128) && (!limit || found < limit)) {
231			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
232			res->address = start + i + 7;
233			res->type = mCORE_MEMORY_SEARCH_8;
234			res->segment = -1; // TODO
235			res->guessDivisor = 1;
236			++found;
237		}
238	}
239	// TODO: last 7 bytes
240	return found;
241}
242
243static size_t _searchStr(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) {
244	const char* memStr = mem;
245	size_t found = 0;
246	size_t len = strlen(valueStr);
247	uint32_t start = block->start;
248	uint32_t end = size; // TODO: Segments
249	size_t i;
250	for (i = 0; (!limit || found < limit) && i < end - len; ++i) {
251		if (!strncmp(valueStr, &memStr[i], len)) {
252			struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
253			res->address = start + i;
254			res->type = mCORE_MEMORY_SEARCH_STRING;
255			res->segment = -1; // TODO
256			++found;
257		}
258	}
259	return found;
260}
261
262static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) {
263	// TODO: As str
264
265	char* end;
266	uint64_t value;
267
268	size_t found = 0;
269
270	struct mCoreMemorySearchResults tmp;
271	mCoreMemorySearchResultsInit(&tmp, 0);
272
273	// Decimal:
274	value = strtoull(valueStr, &end, 10);
275	if (end && !end[0]) {
276		if (value > 0x10000) {
277			found += _search32(mem, size, block, value, out, limit ? limit - found : 0);
278		} else if (value > 0x100) {
279			found += _search16(mem, size, block, value, out, limit ? limit - found : 0);
280		} else {
281			found += _search8(mem, size, block, value, out, limit ? limit - found : 0);
282		}
283
284		uint32_t divisor = 1;
285		while (value && !(value % 10)) {
286			mCoreMemorySearchResultsClear(&tmp);
287			value /= 10;
288			divisor *= 10;
289
290			if (value > 0x10000) {
291				found += _search32(mem, size, block, value, &tmp, limit ? limit - found : 0);
292			} else if (value > 0x100) {
293				found += _search16(mem, size, block, value, &tmp, limit ? limit - found : 0);
294			} else {
295				found += _search8(mem, size, block, value, &tmp, limit ? limit - found : 0);
296			}
297			size_t i;
298			for (i = 0; i < mCoreMemorySearchResultsSize(&tmp); ++i) {
299				struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(&tmp, i);
300				res->guessDivisor = divisor;
301				*mCoreMemorySearchResultsAppend(out) = *res;
302			}
303		}
304	}
305
306	// Hex:
307	value = strtoull(valueStr, &end, 16);
308	if (end && !end[0]) {
309		if (value > 0x10000) {
310			found += _search32(mem, size, block, value, out, limit ? limit - found : 0);
311		} else if (value > 0x100) {
312			found += _search16(mem, size, block, value, out, limit ? limit - found : 0);
313		} else {
314			found += _search8(mem, size, block, value, out, limit ? limit - found : 0);
315		}
316
317		uint32_t divisor = 1;
318		while (value && !(value & 0xF)) {
319			mCoreMemorySearchResultsClear(&tmp);
320			value >>= 4;
321			divisor <<= 4;
322
323			if (value > 0x10000) {
324				found += _search32(mem, size, block, value, &tmp, limit ? limit - found : 0);
325			} else if (value > 0x100) {
326				found += _search16(mem, size, block, value, &tmp, limit ? limit - found : 0);
327			} else {
328				found += _search8(mem, size, block, value, &tmp, limit ? limit - found : 0);
329			}
330			size_t i;
331			for (i = 0; i < mCoreMemorySearchResultsSize(&tmp); ++i) {
332				struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(&tmp, i);
333				res->guessDivisor = divisor;
334				*mCoreMemorySearchResultsAppend(out) = *res;
335			}
336		}
337	}
338
339	mCoreMemorySearchResultsDeinit(&tmp);
340	return found;
341}
342
343static size_t _search(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) {
344	switch (params->type) {
345	case mCORE_MEMORY_SEARCH_32:
346		return _search32(mem, size, block, params->value32, out, limit);
347	case mCORE_MEMORY_SEARCH_16:
348		return _search16(mem, size, block, params->value16, out, limit);
349	case mCORE_MEMORY_SEARCH_8:
350		return _search8(mem, size, block, params->value8, out, limit);
351	case mCORE_MEMORY_SEARCH_STRING:
352		return _searchStr(mem, size, block, params->valueStr, out, limit);
353	case mCORE_MEMORY_SEARCH_GUESS:
354		return _searchGuess(mem, size, block, params->valueStr, out, limit);
355	}
356}
357
358void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) {
359	const struct mCoreMemoryBlock* blocks;
360	size_t nBlocks = core->listMemoryBlocks(core, &blocks);
361	size_t found = 0;
362
363	size_t b;
364	for (b = 0; (!limit || found < limit) && b < nBlocks; ++b) {
365		size_t size;
366		const struct mCoreMemoryBlock* block = &blocks[b];
367		if (!(block->flags & params->memoryFlags)) {
368			continue;
369		}
370		void* mem = core->getMemoryBlock(core, block->id, &size);
371		if (!mem) {
372			continue;
373		}
374		if (size > block->end - block->start) {
375			size = block->end - block->start; // TOOD: Segments
376		}
377		found += _search(mem, size, block, params, out, limit ? limit - found : 0);
378	}
379}
380
381bool _testGuess(struct mCore* core, const struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
382	uint64_t value;
383	char* end;
384
385	value = strtoull(params->valueStr, &end, 10);
386	if (end) {
387		if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor == value) {
388			return true;
389		}
390		if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor == value) {
391			return true;
392		}
393		if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor == value) {
394			return true;
395		}
396	}
397
398	value = strtoull(params->valueStr, &end, 16);
399	if (end) {
400		if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor == value) {
401			return true;
402		}
403		if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor == value) {
404			return true;
405		}
406		if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor == value) {
407			return true;
408		}
409	}
410	return false;
411}
412
413void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* inout) {
414	size_t i;
415	for (i = 0; i < mCoreMemorySearchResultsSize(inout); ++i) {
416		struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(inout, i);
417		switch (res->type) {
418		case mCORE_MEMORY_SEARCH_8:
419			switch (params->type) {
420			case mCORE_MEMORY_SEARCH_8:
421				if (core->rawRead8(core, res->address, res->segment) != params->value8) {
422					mCoreMemorySearchResultsShift(inout, i, 1);
423					--i;
424				}
425				break;
426			case mCORE_MEMORY_SEARCH_16:
427				if (core->rawRead8(core, res->address, res->segment) != params->value16) {
428					mCoreMemorySearchResultsShift(inout, i, 1);
429					--i;
430				}
431				break;
432			case mCORE_MEMORY_SEARCH_32:
433				if (core->rawRead32(core, res->address, res->segment) != params->value32) {
434					mCoreMemorySearchResultsShift(inout, i, 1);
435					--i;
436				}
437				break;
438			case mCORE_MEMORY_SEARCH_GUESS:
439				if (!_testGuess(core, res, params)) {
440					mCoreMemorySearchResultsShift(inout, i, 1);
441					--i;
442				}
443				break;
444			default:
445				break;
446			}
447			break;
448		case mCORE_MEMORY_SEARCH_16:
449			switch (params->type) {
450			case mCORE_MEMORY_SEARCH_16:
451				if (core->rawRead16(core, res->address, res->segment) != params->value16) {
452					mCoreMemorySearchResultsShift(inout, i, 1);
453					--i;
454				}
455				break;
456			case mCORE_MEMORY_SEARCH_32:
457				if (core->rawRead32(core, res->address, res->segment) != params->value32) {
458					mCoreMemorySearchResultsShift(inout, i, 1);
459					--i;
460				}
461				break;
462			case mCORE_MEMORY_SEARCH_GUESS:
463				if (!_testGuess(core, res, params)) {
464					mCoreMemorySearchResultsShift(inout, i, 1);
465					--i;
466				}
467				break;
468			default:
469				break;
470			}
471			break;
472		case mCORE_MEMORY_SEARCH_32:
473			switch (params->type) {
474			case mCORE_MEMORY_SEARCH_32:
475				if (core->rawRead32(core, res->address, res->segment) != params->value32) {
476					mCoreMemorySearchResultsShift(inout, i, 1);
477					--i;
478				}
479				break;
480			case mCORE_MEMORY_SEARCH_GUESS:
481				if (!_testGuess(core, res, params)) {
482					mCoreMemorySearchResultsShift(inout, i, 1);
483					--i;
484				}
485				break;
486			default:
487				break;
488			}
489			break;
490		case mCORE_MEMORY_SEARCH_STRING:
491		case mCORE_MEMORY_SEARCH_GUESS:
492			// TOOD
493			break;
494		}
495	}
496}