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}