mirror of https://github.com/mgba-emu/mgba.git
Core: Add memory delta search
This commit is contained in:
parent
591ab468e9
commit
db9725a563
|
@ -18,24 +18,31 @@ enum mCoreMemorySearchType {
|
|||
mCORE_MEMORY_SEARCH_GUESS,
|
||||
};
|
||||
|
||||
enum mCoreMemorySearchOp {
|
||||
mCORE_MEMORY_SEARCH_FIXED,
|
||||
mCORE_MEMORY_SEARCH_DELTA,
|
||||
};
|
||||
|
||||
struct mCoreMemorySearchParams {
|
||||
int memoryFlags;
|
||||
enum mCoreMemorySearchType type;
|
||||
enum mCoreMemorySearchOp op;
|
||||
int align;
|
||||
int width;
|
||||
union {
|
||||
const char* valueStr;
|
||||
uint32_t valueInt;
|
||||
int32_t valueInt;
|
||||
};
|
||||
};
|
||||
|
||||
struct mCoreMemorySearchResult {
|
||||
uint32_t address;
|
||||
int segment;
|
||||
uint64_t guessDivisor;
|
||||
uint64_t guessMultiplier;
|
||||
uint32_t guessDivisor;
|
||||
uint32_t guessMultiplier;
|
||||
enum mCoreMemorySearchType type;
|
||||
int width;
|
||||
int32_t oldValue;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult);
|
||||
|
|
|
@ -34,6 +34,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value32;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 2) && (!limit || found < limit)) {
|
||||
|
@ -44,6 +45,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value32;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 4) && (!limit || found < limit)) {
|
||||
|
@ -54,6 +56,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value32;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 8) && (!limit || found < limit)) {
|
||||
|
@ -64,6 +67,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value32;
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +103,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 2) && (!limit || found < limit)) {
|
||||
|
@ -109,6 +114,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 4) && (!limit || found < limit)) {
|
||||
|
@ -119,6 +125,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 8) && (!limit || found < limit)) {
|
||||
|
@ -129,6 +136,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 16) && (!limit || found < limit)) {
|
||||
|
@ -139,6 +147,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 32) && (!limit || found < limit)) {
|
||||
|
@ -149,6 +158,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 64) && (!limit || found < limit)) {
|
||||
|
@ -159,6 +169,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 128) && (!limit || found < limit)) {
|
||||
|
@ -169,6 +180,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
@ -203,6 +215,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 2) && (!limit || found < limit)) {
|
||||
|
@ -213,6 +226,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 4) && (!limit || found < limit)) {
|
||||
|
@ -223,6 +237,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 8) && (!limit || found < limit)) {
|
||||
|
@ -233,6 +248,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 16) && (!limit || found < limit)) {
|
||||
|
@ -243,6 +259,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 32) && (!limit || found < limit)) {
|
||||
|
@ -253,6 +270,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 64) && (!limit || found < limit)) {
|
||||
|
@ -263,6 +281,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
if ((mask & 128) && (!limit || found < limit)) {
|
||||
|
@ -273,6 +292,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +337,7 @@ static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemor
|
|||
// TODO: As str
|
||||
|
||||
char* end;
|
||||
uint64_t value;
|
||||
int64_t value;
|
||||
|
||||
size_t found = 0;
|
||||
|
||||
|
@ -325,7 +345,7 @@ static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemor
|
|||
mCoreMemorySearchResultsInit(&tmp, 0);
|
||||
|
||||
// Decimal:
|
||||
value = strtoull(valueStr, &end, 10);
|
||||
value = strtoll(valueStr, &end, 10);
|
||||
if (end && !end[0]) {
|
||||
if (value > 0x10000) {
|
||||
found += _search32(mem, size, block, value, out, limit ? limit - found : 0);
|
||||
|
@ -358,7 +378,7 @@ static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemor
|
|||
}
|
||||
|
||||
// Hex:
|
||||
value = strtoull(valueStr, &end, 16);
|
||||
value = strtoll(valueStr, &end, 16);
|
||||
if (end && !end[0]) {
|
||||
if (value > 0x10000) {
|
||||
found += _search32(mem, size, block, value, out, limit ? limit - found : 0);
|
||||
|
@ -428,34 +448,42 @@ void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams*
|
|||
}
|
||||
}
|
||||
|
||||
bool _testGuess(struct mCore* core, const struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
|
||||
uint64_t value;
|
||||
bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
|
||||
int64_t value;
|
||||
int32_t offset = 0;
|
||||
char* end;
|
||||
|
||||
value = strtoull(params->valueStr, &end, 10);
|
||||
if (end) {
|
||||
if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
|
||||
return true;
|
||||
}
|
||||
if (params->op == mCORE_MEMORY_SEARCH_DELTA) {
|
||||
offset = res->oldValue;
|
||||
}
|
||||
|
||||
value = strtoull(params->valueStr, &end, 16);
|
||||
value = strtoll(params->valueStr, &end, 10);
|
||||
if (end) {
|
||||
if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
|
||||
res->oldValue += value;
|
||||
if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
|
||||
if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
|
||||
if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
|
||||
return true;
|
||||
}
|
||||
res->oldValue -= value;
|
||||
}
|
||||
|
||||
value = strtoll(params->valueStr, &end, 16);
|
||||
if (end) {
|
||||
res->oldValue += value;
|
||||
if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
|
||||
return true;
|
||||
}
|
||||
res->oldValue -= value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -466,33 +494,36 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
|
|||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(inout, i);
|
||||
switch (res->type) {
|
||||
case mCORE_MEMORY_SEARCH_INT:
|
||||
switch (params->width) {
|
||||
case 1:
|
||||
if (core->rawRead8(core, res->address, res->segment) != params->valueInt) {
|
||||
mCoreMemorySearchResultsShift(inout, i, 1);
|
||||
--i;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (core->rawRead8(core, res->address, res->segment) != params->valueInt) {
|
||||
mCoreMemorySearchResultsShift(inout, i, 1);
|
||||
--i;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (core->rawRead32(core, res->address, res->segment) != params->valueInt) {
|
||||
mCoreMemorySearchResultsShift(inout, i, 1);
|
||||
--i;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
if (params->type == mCORE_MEMORY_SEARCH_GUESS) {
|
||||
if (!_testGuess(core, res, params)) {
|
||||
mCoreMemorySearchResultsShift(inout, i, 1);
|
||||
--i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} else if (params->type == mCORE_MEMORY_SEARCH_INT) {
|
||||
int32_t oldValue = params->valueInt;
|
||||
if (params->op == mCORE_MEMORY_SEARCH_DELTA) {
|
||||
oldValue += res->oldValue;
|
||||
}
|
||||
int32_t value = 0;
|
||||
switch (params->width) {
|
||||
case 1:
|
||||
value = core->rawRead8(core, res->address, res->segment);
|
||||
break;
|
||||
case 2:
|
||||
value = core->rawRead16(core, res->address, res->segment);
|
||||
break;
|
||||
case 4:
|
||||
value = core->rawRead32(core, res->address, res->segment);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (value != oldValue) {
|
||||
mCoreMemorySearchResultsShift(inout, i, 1);
|
||||
--i;
|
||||
} else {
|
||||
res->oldValue = value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mCORE_MEMORY_SEARCH_STRING:
|
||||
|
|
|
@ -40,8 +40,9 @@ bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
|
|||
|
||||
QByteArray string;
|
||||
bool ok = false;
|
||||
if (m_ui.typeNum->isChecked()) {
|
||||
if (m_ui.typeNum->isChecked() || m_ui.typeDelta->isChecked()) {
|
||||
params->type = mCORE_MEMORY_SEARCH_INT;
|
||||
params->op = m_ui.typeDelta->isChecked() ? mCORE_MEMORY_SEARCH_DELTA : mCORE_MEMORY_SEARCH_FIXED;
|
||||
params->align = -1;
|
||||
if (m_ui.bits8->isChecked()) {
|
||||
params->width = 1;
|
||||
|
@ -140,6 +141,7 @@ void MemorySearch::refresh() {
|
|||
|
||||
m_ui.results->clearContents();
|
||||
m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
|
||||
m_ui.typeDelta->setEnabled(false);
|
||||
for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) {
|
||||
mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
|
||||
QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0')));
|
||||
|
@ -200,6 +202,10 @@ void MemorySearch::refresh() {
|
|||
}
|
||||
m_ui.results->setItem(i, 1, item);
|
||||
m_ui.results->setItem(i, 2, type);
|
||||
m_ui.typeDelta->setEnabled(true);
|
||||
}
|
||||
if (m_ui.typeDelta->isChecked() && !m_ui.typeDelta->isEnabled()) {
|
||||
m_ui.typeNum->setChecked(true);
|
||||
}
|
||||
m_ui.results->sortItems(0);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>631</width>
|
||||
<height>378</height>
|
||||
<width>639</width>
|
||||
<height>397</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
|
@ -89,7 +89,7 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QRadioButton" name="typeStr">
|
||||
<property name="text">
|
||||
<string>Text</string>
|
||||
|
@ -99,14 +99,14 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QRadioButton" name="bits8">
|
||||
<property name="text">
|
||||
<string>1 Byte (8-bit)</string>
|
||||
|
@ -116,7 +116,7 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QRadioButton" name="bits16">
|
||||
<property name="text">
|
||||
<string>2 Bytes (16-bit)</string>
|
||||
|
@ -126,7 +126,7 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QRadioButton" name="bits32">
|
||||
<property name="text">
|
||||
<string>4 Bytes (32-bit)</string>
|
||||
|
@ -139,14 +139,14 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Number type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QRadioButton" name="numHex">
|
||||
<property name="text">
|
||||
<string>Hexadecimal</string>
|
||||
|
@ -156,20 +156,47 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QRadioButton" name="numDec">
|
||||
<property name="text">
|
||||
<string>Decimal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="11" column="1">
|
||||
<widget class="QRadioButton" name="numGuess">
|
||||
<property name="text">
|
||||
<string>Guess</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="typeDelta">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delta</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">type</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
|
|
Loading…
Reference in New Issue