mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
191 lines
No EOL
5.4 KiB
C++
191 lines
No EOL
5.4 KiB
C++
#include "pch.h"
|
|
#include "Debugger/Disassembler.h"
|
|
#include "Debugger/DisassemblySearch.h"
|
|
#include "Debugger/LabelManager.h"
|
|
|
|
DisassemblySearch::DisassemblySearch(Disassembler* disassembler, LabelManager* labelManager)
|
|
{
|
|
_disassembler = disassembler;
|
|
_labelManager = labelManager;
|
|
}
|
|
|
|
int32_t DisassemblySearch::SearchDisassembly(CpuType cpuType, const char* searchString, int32_t startAddress, DisassemblySearchOptions options)
|
|
{
|
|
CodeLineData results[1] = {};
|
|
uint32_t resultCount = SearchDisassembly(cpuType, searchString, startAddress, options, results, 1);
|
|
return resultCount > 0 ? results[0].Address : -1;
|
|
}
|
|
|
|
uint32_t DisassemblySearch::FindOccurrences(CpuType cpuType, const char* searchString, DisassemblySearchOptions options, CodeLineData output[], uint32_t maxResultCount)
|
|
{
|
|
return SearchDisassembly(cpuType, searchString, 0, options, output, maxResultCount);
|
|
}
|
|
|
|
uint32_t DisassemblySearch::SearchDisassembly(CpuType cpuType, const char* searchString, int32_t startAddress, DisassemblySearchOptions options, CodeLineData searchResults[], uint32_t maxResultCount)
|
|
{
|
|
MemoryType memType = DebugUtilities::GetCpuMemoryType(cpuType);
|
|
uint16_t bank = startAddress >> 16;
|
|
uint16_t maxBank = _disassembler->GetMaxBank(cpuType);
|
|
|
|
vector<DisassemblyResult> rows = _disassembler->Disassemble(cpuType, bank);
|
|
if(rows.empty()) {
|
|
return -1;
|
|
}
|
|
int step = options.SearchBackwards ? -1 : 1;
|
|
|
|
string searchStr = searchString;
|
|
|
|
int32_t startRow = _disassembler->GetMatchingRow(rows, startAddress, options.SearchBackwards);
|
|
if(options.SearchBackwards) {
|
|
startRow--;
|
|
} else if(options.SkipFirstLine) {
|
|
startRow++;
|
|
}
|
|
|
|
if(startRow >= 0 && startRow < rows.size()) {
|
|
startAddress = rows[startRow].CpuAddress;
|
|
}
|
|
|
|
uint32_t resultCount = 0;
|
|
|
|
int32_t prevAddress = -1;
|
|
|
|
CodeLineData lineData = {};
|
|
int rowCounter = 0;
|
|
|
|
string txt;
|
|
|
|
do {
|
|
for(int i = startRow; i >= 0 && i < rows.size(); i += step) {
|
|
if(rows[i].CpuAddress < 0) {
|
|
continue;
|
|
}
|
|
|
|
if(
|
|
(!options.SearchBackwards && prevAddress < startAddress && rows[i].CpuAddress >= startAddress) ||
|
|
(options.SearchBackwards && prevAddress > startAddress && rows[i].CpuAddress <= startAddress) ||
|
|
rowCounter > 500000
|
|
) {
|
|
if(rowCounter > 0) {
|
|
//Checked entire memory space without finding a match (or checked over 500k rows), give up
|
|
return resultCount;
|
|
}
|
|
}
|
|
|
|
rowCounter++;
|
|
|
|
prevAddress = rows[i].CpuAddress;
|
|
|
|
_disassembler->GetLineData(rows[i], cpuType, memType, lineData);
|
|
|
|
if(TextContains(searchStr, lineData.Text, 1000, options)) {
|
|
searchResults[resultCount] = lineData;
|
|
if(maxResultCount == ++resultCount) {
|
|
return resultCount;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(TextContains(searchStr, lineData.Comment, 1000, options)) {
|
|
searchResults[resultCount] = lineData;
|
|
if(maxResultCount == ++resultCount) {
|
|
return resultCount;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(lineData.EffectiveAddress.ShowAddress && lineData.EffectiveAddress.Address >= 0) {
|
|
txt = _labelManager->GetLabel({ lineData.EffectiveAddress.Address, memType });
|
|
if(txt.empty()) {
|
|
txt = "[$" + DebugUtilities::AddressToHex(lineData.LineCpuType, lineData.EffectiveAddress.Address) + "]";
|
|
} else {
|
|
txt = "[" + txt + "]";
|
|
}
|
|
|
|
if(TextContains(searchStr, txt.c_str(), (int)txt.size(), options)) {
|
|
searchResults[resultCount] = lineData;
|
|
if(maxResultCount == ++resultCount) {
|
|
return resultCount;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if(maxResultCount == 1 && lineData.EffectiveAddress.ValueSize > 0) {
|
|
txt = "$" + (lineData.EffectiveAddress.ValueSize == 2 ? HexUtilities::ToHex((uint16_t)lineData.Value) : HexUtilities::ToHex((uint8_t)lineData.Value));
|
|
if(TextContains(searchStr, txt.c_str(), (int)txt.size(), options)) {
|
|
searchResults[resultCount] = lineData;
|
|
if(maxResultCount == ++resultCount) {
|
|
return resultCount;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//No match found, go to next/previous bank
|
|
int nextBank = (int)bank + step;
|
|
if(nextBank < 0) {
|
|
nextBank = maxBank;
|
|
} else if(nextBank > maxBank) {
|
|
if(startAddress == 0) {
|
|
return resultCount;
|
|
}
|
|
nextBank = 0;
|
|
}
|
|
bank = (uint16_t)nextBank;
|
|
rows = _disassembler->Disassemble(cpuType, bank);
|
|
if(rows.empty()) {
|
|
return resultCount;
|
|
}
|
|
startRow = options.SearchBackwards ? (int32_t)rows.size() - 1 : 0;
|
|
} while(true);
|
|
|
|
return resultCount;
|
|
}
|
|
|
|
bool DisassemblySearch::TextContains(string& needle, const char* hay, int size, DisassemblySearchOptions& options)
|
|
{
|
|
if(options.MatchCase) {
|
|
return TextContains<true>(needle, hay, size, options);
|
|
} else {
|
|
return TextContains<false>(needle, hay, size, options);
|
|
}
|
|
}
|
|
|
|
template<bool matchCase>
|
|
bool DisassemblySearch::TextContains(string& needle, const char* hay, int size, DisassemblySearchOptions& options)
|
|
{
|
|
int pos = 0;
|
|
for(int j = 0; j < size; j++) {
|
|
char c = hay[j];
|
|
if(c <= 0) {
|
|
break;
|
|
}
|
|
|
|
if(needle[pos] == (matchCase ? c : tolower(c))) {
|
|
if(options.MatchWholeWord && pos == 0 && j > 0 && !IsWordSeparator(hay[j - 1])) {
|
|
continue;
|
|
}
|
|
|
|
pos++;
|
|
if(pos == needle.size()) {
|
|
if(options.MatchWholeWord && j < size - 1 && !IsWordSeparator(hay[j + 1])) {
|
|
j -= pos - 1;
|
|
pos = 0;
|
|
continue;
|
|
}
|
|
return true;
|
|
}
|
|
} else {
|
|
j -= pos;
|
|
pos = 0;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool DisassemblySearch::IsWordSeparator(char c)
|
|
{
|
|
return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '@' || c == '$' || c == '#');
|
|
} |