diff --git a/CHANGES b/CHANGES index a871d8693..699967c61 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Features: - 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 diff --git a/include/mgba/core/mem-search.h b/include/mgba/core/mem-search.h index ded5bc44f..57084b4ae 100644 --- a/include/mgba/core/mem-search.h +++ b/include/mgba/core/mem-search.h @@ -34,6 +34,7 @@ struct mCoreMemorySearchParams { struct mCoreMemorySearchResult { uint32_t address; int segment; + uint64_t guessDivisor; enum mCoreMemorySearchType type; }; diff --git a/src/core/mem-search.c b/src/core/mem-search.c index 68b6cb0b1..db52e8651 100644 --- a/src/core/mem-search.c +++ b/src/core/mem-search.c @@ -31,6 +31,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl res->address = start + i + 12; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } } @@ -84,6 +88,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl 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 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl res->address = start + i + 14; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } } @@ -164,6 +176,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo 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 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo res->address = start + i + 7; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO + res->guessDivisor = 1; ++found; } } @@ -240,11 +260,84 @@ static size_t _searchStr(const void* mem, size_t size, const struct mCoreMemoryB } 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 @@ void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* } } +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 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP 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 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP --i; } break; + case mCORE_MEMORY_SEARCH_GUESS: + if (!_testGuess(core, res, params)) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; default: break; } @@ -318,7 +448,6 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP 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 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP --i; } break; + case mCORE_MEMORY_SEARCH_GUESS: + if (!_testGuess(core, res, params)) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; default: break; } @@ -337,12 +472,17 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP case mCORE_MEMORY_SEARCH_32: switch (params->type) { case mCORE_MEMORY_SEARCH_32: - case mCORE_MEMORY_SEARCH_GUESS: if (core->rawRead32(core, res->address, res->segment) != params->value32) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; + case mCORE_MEMORY_SEARCH_GUESS: + if (!_testGuess(core, res, params)) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; default: break; } diff --git a/src/platform/qt/MemorySearch.cpp b/src/platform/qt/MemorySearch.cpp index b5de7c95a..82dae23be 100644 --- a/src/platform/qt/MemorySearch.cpp +++ b/src/platform/qt/MemorySearch.cpp @@ -87,6 +87,12 @@ bool MemorySearch::createParams(mCoreMemorySearchParams* params) { } } } + 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; diff --git a/src/platform/qt/MemorySearch.ui b/src/platform/qt/MemorySearch.ui index ce000b55f..9b8e57460 100644 --- a/src/platform/qt/MemorySearch.ui +++ b/src/platform/qt/MemorySearch.ui @@ -160,6 +160,13 @@ + + + + Guess + + +