all repos — mgba @ a4faf9f07956bbb27c89be21eca9b541f6d84853

mGBA Game Boy Advance Emulator

Core: Add memory search "guessing"
Vicki Pfau vi@endrift.com
Mon, 05 Jun 2017 18:41:09 -0700
commit

a4faf9f07956bbb27c89be21eca9b541f6d84853

parent

cf7017dd867a542f3808f1e6287b683da92d0553

M CHANGESCHANGES

@@ -23,6 +23,7 @@ - GB: Symbol table support

- GB MBC: Add MBC1 multicart support - GBA: Implement keypad interrupts - LR35902: Watchpoints + - Memory search Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior
M include/mgba/core/mem-search.hinclude/mgba/core/mem-search.h

@@ -34,6 +34,7 @@

struct mCoreMemorySearchResult { uint32_t address; int segment; + uint64_t guessDivisor; enum mCoreMemorySearchType type; };
M src/core/mem-search.csrc/core/mem-search.c

@@ -31,6 +31,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 2) && (!limit || found < limit)) {

@@ -38,6 +39,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 4; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 4) && (!limit || found < limit)) {

@@ -45,6 +47,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 8; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 8) && (!limit || found < limit)) {

@@ -52,6 +55,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 12; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } }

@@ -84,6 +88,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 2) && (!limit || found < limit)) {

@@ -91,6 +96,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 2; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 4) && (!limit || found < limit)) {

@@ -98,6 +104,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 4; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 8) && (!limit || found < limit)) {

@@ -105,6 +112,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 6; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 16) && (!limit || found < limit)) {

@@ -112,6 +120,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 8; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 32) && (!limit || found < limit)) {

@@ -119,6 +128,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 10; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 64) && (!limit || found < limit)) {

@@ -126,6 +136,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 12; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 128) && (!limit || found < limit)) {

@@ -133,6 +144,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 14; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } }

@@ -164,6 +176,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 2) && (!limit || found < limit)) {

@@ -171,6 +184,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 1; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 4) && (!limit || found < limit)) {

@@ -178,6 +192,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 2; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 8) && (!limit || found < limit)) {

@@ -185,6 +200,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 3; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 16) && (!limit || found < limit)) {

@@ -192,6 +208,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 4; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 32) && (!limit || found < limit)) {

@@ -199,6 +216,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 5; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 64) && (!limit || found < limit)) {

@@ -206,6 +224,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 6; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } if ((mask & 128) && (!limit || found < limit)) {

@@ -213,6 +232,7 @@ struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);

res->address = start + i + 7; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } }

@@ -240,11 +260,84 @@ return found;

} static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) { - // TODO: As hex - // TODO: As decimal - // TODO: As BCD // TODO: As str - return 0; + + char* end; + uint64_t value; + + size_t found = 0; + + struct mCoreMemorySearchResults tmp; + mCoreMemorySearchResultsInit(&tmp, 0); + + // Decimal: + value = strtoull(valueStr, &end, 10); + if (end) { + if (value > 0x10000) { + found += _search32(mem, size, block, value, out, limit ? limit - found : 0); + } else if (value > 0x100) { + found += _search16(mem, size, block, value, out, limit ? limit - found : 0); + } else { + found += _search8(mem, size, block, value, out, limit ? limit - found : 0); + } + + uint32_t divisor = 1; + while (value && !(value % 10)) { + mCoreMemorySearchResultsClear(&tmp); + value /= 10; + divisor *= 10; + + if (value > 0x10000) { + found += _search32(mem, size, block, value, &tmp, limit ? limit - found : 0); + } else if (value > 0x100) { + found += _search16(mem, size, block, value, &tmp, limit ? limit - found : 0); + } else { + found += _search8(mem, size, block, value, &tmp, limit ? limit - found : 0); + } + size_t i; + for (i = 0; i < mCoreMemorySearchResultsSize(&tmp); ++i) { + struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(&tmp, i); + res->guessDivisor = divisor; + *mCoreMemorySearchResultsAppend(out) = *res; + } + } + } + + // Hex: + value = strtoull(valueStr, &end, 16); + if (end) { + if (value > 0x10000) { + found += _search32(mem, size, block, value, out, limit ? limit - found : 0); + } else if (value > 0x100) { + found += _search16(mem, size, block, value, out, limit ? limit - found : 0); + } else { + found += _search8(mem, size, block, value, out, limit ? limit - found : 0); + } + + uint32_t divisor = 1; + while (value && !(value & 0xF)) { + mCoreMemorySearchResultsClear(&tmp); + value >>= 4; + divisor <<= 4; + + if (value > 0x10000) { + found += _search32(mem, size, block, value, &tmp, limit ? limit - found : 0); + } else if (value > 0x100) { + found += _search16(mem, size, block, value, &tmp, limit ? limit - found : 0); + } else { + found += _search8(mem, size, block, value, &tmp, limit ? limit - found : 0); + } + size_t i; + for (i = 0; i < mCoreMemorySearchResultsSize(&tmp); ++i) { + struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(&tmp, i); + res->guessDivisor = divisor; + *mCoreMemorySearchResultsAppend(out) = *res; + } + } + } + + mCoreMemorySearchResultsDeinit(&tmp); + return found; } static size_t _search(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) {

@@ -285,6 +378,38 @@ found += _search(mem, size, block, params, out, limit ? limit - found : 0);

} } +bool _testGuess(struct mCore* core, const struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) { + uint64_t value; + char* end; + + value = strtoull(params->valueStr, &end, 10); + if (end) { + if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor == value) { + return true; + } + if ((!res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor == value) { + return true; + } + if ((!res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor == value) { + return true; + } + } + + value = strtoull(params->valueStr, &end, 16); + if (end) { + if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor == value) { + return true; + } + if ((!res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor == value) { + return true; + } + if ((!res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor == value) { + return true; + } + } + return false; +} + void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* inout) { size_t i; for (i = 0; i < mCoreMemorySearchResultsSize(inout); ++i) {

@@ -293,7 +418,6 @@ switch (res->type) {

case mCORE_MEMORY_SEARCH_8: switch (params->type) { case mCORE_MEMORY_SEARCH_8: - case mCORE_MEMORY_SEARCH_GUESS: if (core->rawRead8(core, res->address, res->segment) != params->value8) { mCoreMemorySearchResultsShift(inout, i, 1); --i;

@@ -311,6 +435,12 @@ mCoreMemorySearchResultsShift(inout, i, 1);

--i; } break; + case mCORE_MEMORY_SEARCH_GUESS: + if (!_testGuess(core, res, params)) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; default: break; }

@@ -318,7 +448,6 @@ break;

case mCORE_MEMORY_SEARCH_16: switch (params->type) { case mCORE_MEMORY_SEARCH_16: - case mCORE_MEMORY_SEARCH_GUESS: if (core->rawRead16(core, res->address, res->segment) != params->value16) { mCoreMemorySearchResultsShift(inout, i, 1); --i;

@@ -330,6 +459,12 @@ mCoreMemorySearchResultsShift(inout, i, 1);

--i; } break; + case mCORE_MEMORY_SEARCH_GUESS: + if (!_testGuess(core, res, params)) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; default: break; }

@@ -337,8 +472,13 @@ break;

case mCORE_MEMORY_SEARCH_32: switch (params->type) { case mCORE_MEMORY_SEARCH_32: + if (core->rawRead32(core, res->address, res->segment) != params->value32) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; case mCORE_MEMORY_SEARCH_GUESS: - if (core->rawRead32(core, res->address, res->segment) != params->value32) { + if (!_testGuess(core, res, params)) { mCoreMemorySearchResultsShift(inout, i, 1); --i; }
M src/platform/qt/MemorySearch.cppsrc/platform/qt/MemorySearch.cpp

@@ -87,6 +87,12 @@ ok = false;

} } } + if (m_ui.numGuess->isChecked()) { + params->type = mCORE_MEMORY_SEARCH_GUESS; + m_string = m_ui.value->text().toLocal8Bit(); + params->valueStr = m_string.constData(); + ok = true; + } } if (m_ui.typeStr->isChecked()) { params->type = mCORE_MEMORY_SEARCH_STRING;
M src/platform/qt/MemorySearch.uisrc/platform/qt/MemorySearch.ui

@@ -160,6 +160,13 @@ <string>Decimal</string>

</property> </widget> </item> + <item row="8" column="1"> + <widget class="QRadioButton" name="numGuess"> + <property name="text"> + <string>Guess</string> + </property> + </widget> + </item> </layout> </item> <item row="2" column="0" colspan="2">