diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/combiner/Combiner.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/combiner/Combiner.java index 450866ac67..3d3803e8b2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/combiner/Combiner.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/combiner/Combiner.java @@ -18,6 +18,7 @@ package ghidra.features.base.memsearch.combiner; import java.util.*; import java.util.function.BiFunction; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.program.model.address.Address; @@ -35,10 +36,10 @@ public enum Combiner { B_MINUS_A("B-A", Combiner::reverseSubtract); private String name; - private BiFunction, List, Collection> function; + private BiFunction>, List>, Collection>> function; private Combiner(String name, - BiFunction, List, Collection> function) { + BiFunction>, List>, Collection>> function) { this.name = name; this.function = function; } @@ -51,23 +52,25 @@ public enum Combiner { return name; } - public Collection combine(List matches1, List matches2) { + public Collection> combine(List> matches1, + List> matches2) { return function.apply(matches1, matches2); } - private static Collection replace(List matches1, - List matches2) { + private static Collection> replace( + List> matches1, + List> matches2) { return matches2; } - private static Collection union(List matches1, - List matches2) { + private static Collection> union(List> matches1, + List> matches2) { - Map matches1Map = createMap(matches1); - for (MemoryMatch match2 : matches2) { + Map> matches1Map = createMap(matches1); + for (MemoryMatch match2 : matches2) { Address address = match2.getAddress(); - MemoryMatch match1 = matches1Map.get(address); + MemoryMatch match1 = matches1Map.get(address); if (match1 == null || match2.getLength() > match1.getLength()) { matches1Map.put(address, match2); } @@ -75,50 +78,56 @@ public enum Combiner { return matches1Map.values(); } - private static Collection intersect(List matches1, - List matches2) { + private static Collection> intersect( + List> matches1, + List> matches2) { - List intersection = new ArrayList<>(); - Map matches1Map = createMap(matches1); + List> intersection = new ArrayList<>(); + Map> matches1Map = createMap(matches1); - for (MemoryMatch match2 : matches2) { + for (MemoryMatch match2 : matches2) { Address address = match2.getAddress(); - MemoryMatch match1 = matches1Map.get(address); + MemoryMatch match1 = matches1Map.get(address); if (match1 != null) { - MemoryMatch best = match2.getLength() > match1.getLength() ? match2 : match1; + MemoryMatch best = + match2.getLength() > match1.getLength() ? match2 : match1; intersection.add(best); } } return intersection; } - private static List xor(List matches1, List matches2) { - List results = new ArrayList<>(); + private static List> xor(List> matches1, + List> matches2) { + List> results = new ArrayList<>(); results.addAll(subtract(matches1, matches2)); results.addAll(subtract(matches2, matches1)); return results; } - private static Collection subtract(List matches1, - List matches2) { + private static Collection> subtract( + List> matches1, + List> matches2) { - Map matches1Map = createMap(matches1); + Map> matches1Map = createMap(matches1); - for (MemoryMatch match2 : matches2) { + for (MemoryMatch match2 : matches2) { Address address = match2.getAddress(); matches1Map.remove(address); } return matches1Map.values(); } - private static Collection reverseSubtract(List matches1, - List matches2) { + private static Collection> reverseSubtract( + List> matches1, + List> matches2) { return subtract(matches2, matches1); } - private static Map createMap(List matches) { - Map map = new HashMap<>(); - for (MemoryMatch result : matches) { + private static Map> createMap( + List> matches) { + Map> map = new HashMap<>(); + for (MemoryMatch result : matches) { map.put(result.getAddress(), result); } return map; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/BinarySearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/BinarySearchFormat.java index c1d425dcd3..e11d27a32a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/BinarySearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/BinarySearchFormat.java @@ -34,7 +34,7 @@ class BinarySearchFormat extends SearchFormat { } @Override - public ByteMatcher parse(String input, SearchSettings settings) { + public UserInputByteMatcher parse(String input, SearchSettings settings) { input = input.trim(); if (input.isBlank()) { return new InvalidByteMatcher(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/DecimalSearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/DecimalSearchFormat.java index ff5ae7d709..bd544e167e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/DecimalSearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/DecimalSearchFormat.java @@ -35,7 +35,7 @@ class DecimalSearchFormat extends SearchFormat { } @Override - public ByteMatcher parse(String input, SearchSettings settings) { + public UserInputByteMatcher parse(String input, SearchSettings settings) { input = input.trim(); if (input.isBlank()) { return new InvalidByteMatcher(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/FloatSearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/FloatSearchFormat.java index f212147e7f..f5378c7bd0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/FloatSearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/FloatSearchFormat.java @@ -38,7 +38,7 @@ class FloatSearchFormat extends SearchFormat { } @Override - public ByteMatcher parse(String input, SearchSettings settings) { + public UserInputByteMatcher parse(String input, SearchSettings settings) { input = input.trim(); if (input.isBlank()) { return new InvalidByteMatcher(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/HexSearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/HexSearchFormat.java index 9c56ba244b..4956eacf5d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/HexSearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/HexSearchFormat.java @@ -36,7 +36,7 @@ class HexSearchFormat extends SearchFormat { } @Override - public ByteMatcher parse(String input, SearchSettings settings) { + public UserInputByteMatcher parse(String input, SearchSettings settings) { input = input.trim(); if (input.isBlank()) { return new InvalidByteMatcher(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/RegExSearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/RegExSearchFormat.java index 6b4f9a6045..66804fe921 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/RegExSearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/RegExSearchFormat.java @@ -30,7 +30,7 @@ class RegExSearchFormat extends SearchFormat { } @Override - public ByteMatcher parse(String input, SearchSettings settings) { + public UserInputByteMatcher parse(String input, SearchSettings settings) { input = input.trim(); if (input.isBlank()) { return new InvalidByteMatcher(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/SearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/SearchFormat.java index 5dc29b7e5f..3d794db599 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/SearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/SearchFormat.java @@ -17,6 +17,7 @@ package ghidra.features.base.memsearch.format; import ghidra.features.base.memsearch.gui.SearchSettings; import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; /** * SearchFormats are responsible for parsing user input data into a {@link ByteMatcher} that @@ -57,7 +58,7 @@ public abstract class SearchFormat { * @param settings the current search/parse settings * @return a ByteMatcher that can be used for searching bytes (or an error version of a matcher) */ - public abstract ByteMatcher parse(String input, SearchSettings settings); + public abstract UserInputByteMatcher parse(String input, SearchSettings settings); /** * Returns a tool tip describing this search format @@ -152,7 +153,7 @@ public abstract class SearchFormat { } protected boolean isValidText(String text, SearchSettings settings) { - ByteMatcher byteMatcher = parse(text, settings); + UserInputByteMatcher byteMatcher = parse(text, settings); return byteMatcher.isValidSearch(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/StringSearchFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/StringSearchFormat.java index af246248cd..2ed5294f0d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/StringSearchFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/format/StringSearchFormat.java @@ -36,7 +36,7 @@ class StringSearchFormat extends SearchFormat { } @Override - public ByteMatcher parse(String input, SearchSettings settings) { + public UserInputByteMatcher parse(String input, SearchSettings settings) { input = input.trim(); if (input.isBlank()) { return new InvalidByteMatcher(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java index 07950fbca2..1f5978ae20 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.List; import ghidra.features.base.memsearch.combiner.Combiner; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.features.base.memsearch.searcher.MemorySearcher; import ghidra.util.datastruct.Accumulator; @@ -29,26 +30,27 @@ import ghidra.util.task.TaskMonitor; * Table loader that performs a search and then combines the new results with existing results. */ public class CombinedMatchTableLoader implements MemoryMatchTableLoader { - private MemorySearcher memSearcher; - private List previousResults; + private MemorySearcher memSearcher; + private List> previousResults; private Combiner combiner; private boolean completedSearch; - private MemoryMatch firstMatch; + private MemoryMatch firstMatch; - public CombinedMatchTableLoader(MemorySearcher memSearcher, - List previousResults, Combiner combiner) { + public CombinedMatchTableLoader(MemorySearcher memSearcher, + List> previousResults, Combiner combiner) { this.memSearcher = memSearcher; this.previousResults = previousResults; this.combiner = combiner; } @Override - public void loadResults(Accumulator accumulator, TaskMonitor monitor) { - ListAccumulator listAccumulator = new ListAccumulator<>(); + public void loadResults(Accumulator> accumulator, TaskMonitor monitor) { + ListAccumulator> listAccumulator = new ListAccumulator<>(); completedSearch = memSearcher.findAll(listAccumulator, monitor); - List followOnResults = listAccumulator.asList(); + List> followOnResults = listAccumulator.asList(); firstMatch = followOnResults.isEmpty() ? null : followOnResults.get(0); - Collection results = combiner.combine(previousResults, followOnResults); + Collection> results = + combiner.combine(previousResults, followOnResults); accumulator.addAll(results); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java index 3c58ee5eab..7888153638 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java @@ -15,6 +15,7 @@ */ package ghidra.features.base.memsearch.gui; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.util.datastruct.Accumulator; import ghidra.util.task.TaskMonitor; @@ -25,7 +26,7 @@ import ghidra.util.task.TaskMonitor; public class EmptyMemoryMatchTableLoader implements MemoryMatchTableLoader { @Override - public void loadResults(Accumulator accumulator, TaskMonitor monitor) { + public void loadResults(Accumulator> accumulator, TaskMonitor monitor) { return; } @@ -40,7 +41,7 @@ public class EmptyMemoryMatchTableLoader implements MemoryMatchTableLoader { } @Override - public MemoryMatch getFirstMatch() { + public MemoryMatch getFirstMatch() { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java index a6602e7287..1d36f1742b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java @@ -17,6 +17,7 @@ package ghidra.features.base.memsearch.gui; import java.util.List; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.features.base.memsearch.searcher.MemorySearcher; import ghidra.program.model.address.Address; @@ -29,15 +30,16 @@ import ghidra.util.task.TaskMonitor; */ public class FindOnceTableLoader implements MemoryMatchTableLoader { - private MemorySearcher searcher; + private MemorySearcher searcher; private Address address; - private List previousResults; + private List> previousResults; private MemorySearchResultsPanel panel; - private MemoryMatch match; + private MemoryMatch match; private boolean forward; - public FindOnceTableLoader(MemorySearcher searcher, Address address, - List previousResults, MemorySearchResultsPanel panel, boolean forward) { + public FindOnceTableLoader(MemorySearcher searcher, Address address, + List> previousResults, MemorySearchResultsPanel panel, + boolean forward) { this.searcher = searcher; this.address = address; this.previousResults = previousResults; @@ -46,13 +48,13 @@ public class FindOnceTableLoader implements MemoryMatchTableLoader { } @Override - public void loadResults(Accumulator accumulator, TaskMonitor monitor) { + public void loadResults(Accumulator> accumulator, TaskMonitor monitor) { accumulator.addAll(previousResults); match = searcher.findOnce(address, forward, monitor); if (match != null) { - MemoryMatch existing = findExisingMatch(match.getAddress()); + MemoryMatch existing = findExisingMatch(match.getAddress()); if (existing != null) { existing.updateBytes(match.getBytes()); } @@ -62,8 +64,8 @@ public class FindOnceTableLoader implements MemoryMatchTableLoader { } } - private MemoryMatch findExisingMatch(Address newMatchAddress) { - for (MemoryMatch memoryMatch : previousResults) { + private MemoryMatch findExisingMatch(Address newMatchAddress) { + for (MemoryMatch memoryMatch : previousResults) { if (newMatchAddress.equals(memoryMatch.getAddress())) { return memoryMatch; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchHighlighter.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchHighlighter.java index d36df87fb3..b962946bc9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchHighlighter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchHighlighter.java @@ -27,6 +27,7 @@ import ghidra.app.util.ListingHighlightProvider; import ghidra.app.util.SearchConstants; import ghidra.app.util.viewer.field.*; import ghidra.app.util.viewer.proxy.ProxyObj; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.program.model.address.Address; import ghidra.program.model.listing.CodeUnit; @@ -38,10 +39,10 @@ import ghidra.program.model.listing.Program; public class MemoryMatchHighlighter implements ListingHighlightProvider { private Navigatable navigatable; private Program program; - private List sortedResults; + private List> sortedResults; private MemoryMatchTableModel model; private MemorySearchOptions options; - private MemoryMatch selectedMatch; + private MemoryMatch selectedMatch; public MemoryMatchHighlighter(Navigatable navigatable, MemoryMatchTableModel model, MemorySearchOptions options) { @@ -92,7 +93,7 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { Address minAddr = cu.getMinAddress(); Address maxAddr = cu.getMaxAddress(); - List results = getMatchesInRange(minAddr, maxAddr); + List> results = getMatchesInRange(minAddr, maxAddr); if (results.isEmpty()) { return NO_HIGHLIGHTS; } @@ -100,13 +101,14 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return getHighlights(text, minAddr, results); } - private Highlight[] getHighlights(String text, Address minAddr, List results) { + private Highlight[] getHighlights(String text, Address minAddr, + List> results) { Highlight[] highlights = new Highlight[results.size()]; int selectedMatchIndex = -1; for (int i = 0; i < highlights.length; i++) { - MemoryMatch match = results.get(i); + MemoryMatch match = results.get(i); Color highlightColor = SearchConstants.SEARCH_HIGHLIGHT_COLOR; if (match == selectedMatch) { selectedMatchIndex = i; @@ -124,7 +126,8 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return highlights; } - private Highlight createHighlight(MemoryMatch match, Address start, String text, Color color) { + private Highlight createHighlight(MemoryMatch match, Address start, String text, + Color color) { int highlightLength = match.getLength(); Address address = match.getAddress(); int startByteOffset = (int) address.subtract(start); @@ -152,7 +155,7 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return Math.min(text.length() - 1, pos); } - List getMatches() { + List> getMatches() { if (sortedResults != null) { return sortedResults; @@ -162,7 +165,7 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return Collections.emptyList(); } - List modelData = model.getModelData(); + List> modelData = model.getModelData(); if (model.isSortedOnAddress()) { return modelData; } @@ -173,8 +176,8 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return sortedResults; } - private List getMatchesInRange(Address start, Address end) { - List matches = getMatches(); + private List> getMatchesInRange(Address start, Address end) { + List> matches = getMatches(); int startIndex = findFirstIndex(matches, start, end); if (startIndex < 0) { return Collections.emptyList(); @@ -185,15 +188,15 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { endIndex++; // end index is non-inclusive and we want to include direct hit } - List resultList = matches.subList(startIndex, endIndex); + List> resultList = matches.subList(startIndex, endIndex); return resultList; } - private int findFirstIndex(List matches, Address start, Address end) { + private int findFirstIndex(List> matches, Address start, Address end) { int startIndex = findIndexAtOrGreater(matches, start); if (startIndex > 0) { // see if address before extends into this range. - MemoryMatch resultBefore = matches.get(startIndex - 1); + MemoryMatch resultBefore = matches.get(startIndex - 1); Address beforeAddr = resultBefore.getAddress(); int length = resultBefore.getLength(); if (start.hasSameAddressSpace(beforeAddr) && start.subtract(beforeAddr) < length) { @@ -205,7 +208,7 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return -1; } - MemoryMatch result = matches.get(startIndex); + MemoryMatch result = matches.get(startIndex); Address addr = result.getAddress(); if (end.compareTo(addr) >= 0) { return startIndex; @@ -213,9 +216,9 @@ public class MemoryMatchHighlighter implements ListingHighlightProvider { return -1; } - private int findIndexAtOrGreater(List matches, Address address) { + private int findIndexAtOrGreater(List> matches, Address address) { - MemoryMatch key = new MemoryMatch(address); + MemoryMatch key = new MemoryMatch<>(address); int index = Collections.binarySearch(matches, key); if (index < 0) { index = -index - 1; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java index 6756a3cf5e..29de239188 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java @@ -15,6 +15,7 @@ */ package ghidra.features.base.memsearch.gui; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.util.datastruct.Accumulator; import ghidra.util.task.TaskMonitor; @@ -32,7 +33,7 @@ public interface MemoryMatchTableLoader { * @param accumulator the accumulator to store results that will appear in the results table * @param monitor the task monitor */ - public void loadResults(Accumulator accumulator, TaskMonitor monitor); + public void loadResults(Accumulator> accumulator, TaskMonitor monitor); /** * Returns true if the search/loading did not fully complete. (Search limit reached, cancelled diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableModel.java index 0b23004906..45f34036f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableModel.java @@ -21,7 +21,7 @@ import docking.widgets.table.*; import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.docking.settings.Settings; import ghidra.features.base.memsearch.format.SearchFormat; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.*; @@ -39,7 +39,7 @@ import ghidra.util.task.TaskMonitor; /** * Table model for memory search results. */ -public class MemoryMatchTableModel extends AddressBasedTableModel { +public class MemoryMatchTableModel extends AddressBasedTableModel> { private Color CHANGED_COLOR = Tables.ERROR_UNSELECTED; private Color CHANGED_SELECTED_COLOR = Tables.ERROR_SELECTED; @@ -50,8 +50,8 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } @Override - protected TableColumnDescriptor createTableColumnDescriptor() { - TableColumnDescriptor descriptor = new TableColumnDescriptor<>(); + protected TableColumnDescriptor> createTableColumnDescriptor() { + TableColumnDescriptor> descriptor = new TableColumnDescriptor<>(); descriptor.addVisibleColumn( DiscoverableTableUtils.adaptColumForModel(this, new AddressTableColumn()), 1, true); @@ -66,7 +66,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } @Override - protected void doLoad(Accumulator accumulator, TaskMonitor monitor) + protected void doLoad(Accumulator> accumulator, TaskMonitor monitor) throws CancelledException { if (loader == null) { return; @@ -92,7 +92,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } ColumnSortState primaryState = sortState.getAllSortStates().get(0); - DynamicTableColumn column = + DynamicTableColumn, ?, ?> column = getColumn(primaryState.getColumnModelIndex()); String name = column.getColumnName(); if (AddressTableColumn.NAME.equals(name)) { @@ -108,7 +108,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { return null; // we've been disposed } - DynamicTableColumn column = getColumn(modelColumn); + DynamicTableColumn, ?, ?> column = getColumn(modelColumn); Class columnClass = column.getClass(); if (column instanceof MappedTableColumn mappedColumn) { columnClass = mappedColumn.getMappedColumnClass(); @@ -147,7 +147,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } public class MatchBytesColumn - extends DynamicTableColumnExtensionPoint { + extends DynamicTableColumnExtensionPoint, String, Program> { private ByteArrayRenderer renderer = new ByteArrayRenderer(); @@ -157,7 +157,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } @Override - public String getValue(MemoryMatch match, Settings settings, Program pgm, + public String getValue(MemoryMatch match, Settings settings, Program pgm, ServiceProvider service) throws IllegalArgumentException { return getByteString(match.getBytes()); @@ -188,7 +188,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } public class MatchValueColumn - extends DynamicTableColumnExtensionPoint { + extends DynamicTableColumnExtensionPoint, String, Program> { private ValueRenderer renderer = new ValueRenderer(); @@ -198,11 +198,11 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { } @Override - public String getValue(MemoryMatch match, Settings settings, Program pgm, + public String getValue(MemoryMatch match, Settings settings, Program pgm, ServiceProvider service) throws IllegalArgumentException { - ByteMatcher byteMatcher = match.getByteMatcher(); - SearchSettings searchSettings = byteMatcher.getSettings(); + SearchData searchData = match.getPattern(); + SearchSettings searchSettings = searchData.getSettings(); SearchFormat format = searchSettings.getSearchFormat(); return format.getValueString(match.getBytes(), searchSettings); } @@ -231,7 +231,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { super.getTableCellRendererComponent(data); - MemoryMatch match = (MemoryMatch) data.getRowObject(); + MemoryMatch match = (MemoryMatch) data.getRowObject(); String text = data.getValue().toString(); if (match.isChanged()) { text = getHtmlColoredString(match, data.isSelected()); @@ -240,7 +240,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { return this; } - private String getHtmlColoredString(MemoryMatch match, boolean isSelected) { + private String getHtmlColoredString(MemoryMatch match, boolean isSelected) { Color color = isSelected ? Tables.ERROR_SELECTED : Tables.ERROR_UNSELECTED; StringBuilder b = new StringBuilder(); @@ -277,7 +277,7 @@ public class MemoryMatchTableModel extends AddressBasedTableModel { super.getTableCellRendererComponent(data); setText((String) data.getValue()); - MemoryMatch match = (MemoryMatch) data.getRowObject(); + MemoryMatch match = (MemoryMatch) data.getRowObject(); if (match.isChanged()) { setForeground(data.isSelected() ? CHANGED_SELECTED_COLOR : CHANGED_COLOR); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToAddressTableRowMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToAddressTableRowMapper.java index 8430b703f8..0f8a707088 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToAddressTableRowMapper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToAddressTableRowMapper.java @@ -15,6 +15,7 @@ */ package ghidra.features.base.memsearch.gui; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; @@ -26,10 +27,10 @@ import ghidra.util.table.ProgramLocationTableRowMapper; * table columns. */ public class MemoryMatchToAddressTableRowMapper - extends ProgramLocationTableRowMapper { + extends ProgramLocationTableRowMapper, Address> { @Override - public Address map(MemoryMatch rowObject, Program data, ServiceProvider serviceProvider) { + public Address map(MemoryMatch rowObject, Program data, ServiceProvider serviceProvider) { return rowObject.getAddress(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToProgramLocationTableRowMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToProgramLocationTableRowMapper.java index 4959d8a7cb..320f413616 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToProgramLocationTableRowMapper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchToProgramLocationTableRowMapper.java @@ -15,6 +15,7 @@ */ package ghidra.features.base.memsearch.gui; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.listing.Program; @@ -26,10 +27,10 @@ import ghidra.util.table.ProgramLocationTableRowMapper; * program location based table columns. */ public class MemoryMatchToProgramLocationTableRowMapper - extends ProgramLocationTableRowMapper { + extends ProgramLocationTableRowMapper, ProgramLocation> { @Override - public ProgramLocation map(MemoryMatch rowObject, Program program, + public ProgramLocation map(MemoryMatch rowObject, Program program, ServiceProvider serviceProvider) { return new ProgramLocation(program, rowObject.getAddress()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchtToFunctionTableRowMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchtToFunctionTableRowMapper.java index 92b7bf8257..40fb524c85 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchtToFunctionTableRowMapper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchtToFunctionTableRowMapper.java @@ -15,9 +15,12 @@ */ package ghidra.features.base.memsearch.gui; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.framework.plugintool.ServiceProvider; -import ghidra.program.model.listing.*; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.listing.Program; import ghidra.util.table.ProgramLocationTableRowMapper; /** @@ -25,10 +28,10 @@ import ghidra.util.table.ProgramLocationTableRowMapper; * table columns. */ public class MemoryMatchtToFunctionTableRowMapper - extends ProgramLocationTableRowMapper { + extends ProgramLocationTableRowMapper, Function> { @Override - public Function map(MemoryMatch rowObject, Program program, + public Function map(MemoryMatch rowObject, Program program, ServiceProvider serviceProvider) { FunctionManager functionManager = program.getFunctionManager(); return functionManager.getFunctionContaining(rowObject.getAddress()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java index cf6c1180d3..0e9a148b96 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java @@ -39,8 +39,8 @@ import docking.widgets.list.GComboBoxCellRenderer; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.features.base.memsearch.combiner.Combiner; import ghidra.features.base.memsearch.format.SearchFormat; -import ghidra.features.base.memsearch.matcher.ByteMatcher; import ghidra.features.base.memsearch.matcher.InvalidByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; import ghidra.util.HTMLUtilities; import ghidra.util.Swing; import ghidra.util.layout.PairLayout; @@ -54,10 +54,10 @@ import ghidra.util.timer.GTimerMonitor; */ class MemorySearchControlPanel extends JPanel { private MultiStateButton searchButton; - private GhidraComboBox searchInputField; + private GhidraComboBox searchInputField; private GDLabel hexSearchSequenceField; private boolean hasResults; - private ByteMatcher currentMatcher = new InvalidByteMatcher(""); + private UserInputByteMatcher currentMatcher = new InvalidByteMatcher(""); private SearchHistory searchHistory; private SearchGuiModel model; private JCheckBox selectionCheckbox; @@ -145,7 +145,7 @@ class MemorySearchControlPanel extends JPanel { String text = searchInputField.getText(); String convertedText = searchFormat.convertText(text, oldSettings, model.getSettings()); searchInputField.setText(convertedText); - ByteMatcher byteMatcher = searchFormat.parse(convertedText, model.getSettings()); + UserInputByteMatcher byteMatcher = searchFormat.parse(convertedText, model.getSettings()); setByteMatcher(byteMatcher); } @@ -209,7 +209,7 @@ class MemorySearchControlPanel extends JPanel { // our data model is ByteMatcher, not strings return; } - ByteMatcher matcher = (ByteMatcher) obj; + UserInputByteMatcher matcher = (UserInputByteMatcher) obj; model.setSettings(matcher.getSettings()); super.setSelectedItem(obj); } @@ -286,7 +286,7 @@ class MemorySearchControlPanel extends JPanel { return newFormat.convertText(text, oldSettings, newSettings); } - private void setByteMatcher(ByteMatcher byteMatcher) { + private void setByteMatcher(UserInputByteMatcher byteMatcher) { clearInputError(); currentMatcher = byteMatcher; String text = currentMatcher.getDescription(); @@ -404,7 +404,7 @@ class MemorySearchControlPanel extends JPanel { } private void updateCombo() { - ByteMatcher[] historyArray = searchHistory.getHistoryAsArray(); + UserInputByteMatcher[] historyArray = searchHistory.getHistoryAsArray(); searchInputField.setModel(new DefaultComboBoxModel<>(historyArray)); } @@ -428,7 +428,7 @@ class MemorySearchControlPanel extends JPanel { String afterOffset = currentText.substring(offs, currentText.length()); String proposedText = beforeOffset + str + afterOffset; - ByteMatcher byteMatcher = model.parse(proposedText); + UserInputByteMatcher byteMatcher = model.parse(proposedText); if (!byteMatcher.isValidInput()) { reportInputError(byteMatcher.getDescription()); return; @@ -457,7 +457,7 @@ class MemorySearchControlPanel extends JPanel { return; } - ByteMatcher byteMatcher = model.parse(proposedResult); + UserInputByteMatcher byteMatcher = model.parse(proposedResult); if (!byteMatcher.isValidInput()) { reportInputError(byteMatcher.getDescription()); return; @@ -503,14 +503,14 @@ class MemorySearchControlPanel extends JPanel { searchInputField.setText(initialInput); } - private class SearchHistoryRenderer extends GComboBoxCellRenderer { + private class SearchHistoryRenderer extends GComboBoxCellRenderer { { setHTMLRenderingEnabled(true); } @Override - public Component getListCellRendererComponent(JList list, - ByteMatcher matcher, int index, + public Component getListCellRendererComponent(JList list, + UserInputByteMatcher matcher, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, matcher, index, isSelected, cellHasFocus); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchPlugin.java index ac6dc79024..692b65d180 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchPlugin.java @@ -30,7 +30,8 @@ import ghidra.app.services.*; import ghidra.app.util.HelpTopics; import ghidra.app.util.query.TableService; import ghidra.features.base.memsearch.bytesource.AddressableByteSource; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.SearchData; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.features.base.memsearch.searcher.MemorySearcher; import ghidra.framework.options.SaveState; @@ -68,7 +69,7 @@ public class MemorySearchPlugin extends Plugin implements MemorySearchService { private static final String SHOW_OPTIONS_PANEL = "Show Options Panel"; private static final String SHOW_SCAN_PANEL = "Show Scan Panel"; - private ByteMatcher lastByteMatcher; + private UserInputByteMatcher lastByteMatcher; private MemorySearchOptions options; private SearchHistory searchHistory = new SearchHistory(MAX_HISTORY); private Address lastSearchAddress; @@ -133,7 +134,7 @@ public class MemorySearchPlugin extends Plugin implements MemorySearchService { TaskLauncher.launch(task); } - void updateByteMatcher(ByteMatcher matcher) { + void updateByteMatcher(UserInputByteMatcher matcher) { lastByteMatcher = matcher; searchHistory.addSearch(matcher); } @@ -207,8 +208,9 @@ public class MemorySearchPlugin extends Plugin implements MemorySearchService { return; } - MemorySearcher searcher = new MemorySearcher(source, lastByteMatcher, addresses, 1); - MemoryMatch match = searcher.findOnce(start, forward, monitor); + MemorySearcher searcher = + new MemorySearcher<>(source, lastByteMatcher, addresses, 1); + MemoryMatch match = searcher.findOnce(start, forward, monitor); Swing.runLater(() -> navigateToMatch(match)); } @@ -227,7 +229,7 @@ public class MemorySearchPlugin extends Plugin implements MemorySearchService { return forward ? start.next() : start.previous(); } - private void navigateToMatch(MemoryMatch match) { + private void navigateToMatch(MemoryMatch match) { if (match != null) { lastSearchAddress = match.getAddress(); Program program = navigatable.getProgram(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchProvider.java index 356de33c3b..cb97ae40fd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchProvider.java @@ -15,13 +15,24 @@ */ package ghidra.features.base.memsearch.gui; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Toolkit; import java.time.Duration; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Predicate; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JSeparator; import docking.ActionContext; import docking.DockingContextListener; @@ -35,16 +46,22 @@ import docking.widgets.OptionDialogBuilder; import docking.widgets.table.actions.DeleteTableRowAction; import generic.theme.GIcon; import ghidra.app.context.NavigatableActionContext; -import ghidra.app.nav.*; +import ghidra.app.nav.Navigatable; +import ghidra.app.nav.NavigatableRegistry; +import ghidra.app.nav.NavigatableRemovalListener; import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; import ghidra.app.script.AskDialog; import ghidra.app.util.HelpTopics; import ghidra.features.base.memsearch.bytesource.AddressableByteSource; import ghidra.features.base.memsearch.bytesource.SearchRegion; import ghidra.features.base.memsearch.combiner.Combiner; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.SearchData; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; import ghidra.features.base.memsearch.scan.Scanner; -import ghidra.features.base.memsearch.searcher.*; +import ghidra.features.base.memsearch.searcher.AlignmentFilter; +import ghidra.features.base.memsearch.searcher.CodeUnitFilter; +import ghidra.features.base.memsearch.searcher.MemoryMatch; +import ghidra.features.base.memsearch.searcher.MemorySearcher; import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObjectClosedListener; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -52,7 +69,9 @@ import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.Program; -import ghidra.program.util.*; +import ghidra.program.util.BytesFieldLocation; +import ghidra.program.util.ProgramLocation; +import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.layout.VerticalLayout; @@ -96,7 +115,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter private DockingAction nextAction; private DockingAction refreshAction; - private ByteMatcher byteMatcher; + private UserInputByteMatcher byteMatcher; private Address lastMatchingAddress; private boolean isBusy; @@ -188,7 +207,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter return mainComponent; } - void setByteMatcher(ByteMatcher byteMatcher) { + void setByteMatcher(UserInputByteMatcher byteMatcher) { this.byteMatcher = byteMatcher; tool.contextChanged(this); } @@ -216,7 +235,8 @@ public class MemorySearchProvider extends ComponentProviderAdapter Address start = getSearchStartAddress(forward); AddressSet addresses = getSearchAddresses(); - MemorySearcher searcher = new MemorySearcher(byteSource, byteMatcher, addresses, 1); + MemorySearcher searcher = + new MemorySearcher<>(byteSource, byteMatcher, addresses, 1); searcher.setMatchFilter(createFilter()); setBusy(true); @@ -238,7 +258,8 @@ public class MemorySearchProvider extends ComponentProviderAdapter updateTitle(); int limit = options.getSearchLimit(); AddressSet addresses = getSearchAddresses(); - MemorySearcher searcher = new MemorySearcher(byteSource, byteMatcher, addresses, limit); + MemorySearcher searcher = + new MemorySearcher<>(byteSource, byteMatcher, addresses, limit); searcher.setMatchFilter(createFilter()); setBusy(true); @@ -312,7 +333,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter tool.contextChanged(this); } - private Predicate createFilter() { + private Predicate> createFilter() { AlignmentFilter alignmentFilter = new AlignmentFilter(model.getAlignment()); CodeUnitFilter codeUnitFilter = new CodeUnitFilter(program, model.includeInstructions(), @@ -375,7 +396,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter } } - void searchOnceCompleted(MemoryMatch match, boolean cancelled) { + void searchOnceCompleted(MemoryMatch match, boolean cancelled) { setBusy(false); updateSubTitle(); if (match != null) { @@ -387,7 +408,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter } } - void refreshAndScanCompleted(MemoryMatch match) { + void refreshAndScanCompleted(MemoryMatch match) { setBusy(false); updateSubTitle(); if (match != null) { @@ -645,7 +666,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter } void tableSelectionChanged() { - MemoryMatch selectedMatch = resultsPanel.getSelectedMatch(); + MemoryMatch selectedMatch = resultsPanel.getSelectedMatch(); matchHighlighter.setSelectedMatch(selectedMatch); if (selectedMatch != null) { lastMatchingAddress = selectedMatch.getAddress(); @@ -673,7 +694,7 @@ public class MemorySearchProvider extends ComponentProviderAdapter return isBusy; } - public List getSearchResults() { + public List> getSearchResults() { return resultsPanel.getTableModel().getModelData(); } @@ -751,13 +772,13 @@ public class MemorySearchProvider extends ComponentProviderAdapter nextProvider.setSearchInput(this.getSearchInput()); nextProvider.showScanPanel(true); - List searchResults = getSearchResults(); - List rebasedResults = new ArrayList<>(); - for (MemoryMatch match : searchResults) { + List> searchResults = getSearchResults(); + List> rebasedResults = new ArrayList<>(); + for (MemoryMatch match : searchResults) { ProgramLocation canonicalLocation = byteSource.getCanonicalLocation(match.getAddress()); Address rebase = nextByteSource.rebaseFromCanonical(canonicalLocation); if (rebase != null) { - MemoryMatch nextMatch = new MemoryMatch(rebase, match.getBytes(), match.getByteMatcher()); + MemoryMatch nextMatch = new MemoryMatch<>(rebase, match.getBytes(), match.getPattern()); rebasedResults.add(nextMatch); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchResultsPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchResultsPanel.java index e07d711f1f..ebdd6d227a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchResultsPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchResultsPanel.java @@ -26,6 +26,7 @@ import javax.swing.event.TableModelEvent; import ghidra.app.nav.Navigatable; import ghidra.features.base.memsearch.bytesource.AddressableByteSource; import ghidra.features.base.memsearch.combiner.Combiner; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.scan.Scanner; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.features.base.memsearch.searcher.MemorySearcher; @@ -42,8 +43,8 @@ import ghidra.util.task.*; * table for showing the results. */ public class MemorySearchResultsPanel extends JPanel { - private GhidraThreadedTablePanel threadedTablePanel; - private GhidraTableFilterPanel tableFilterPanel; + private GhidraThreadedTablePanel> threadedTablePanel; + private GhidraTableFilterPanel> tableFilterPanel; private GhidraTable table; private MemoryMatchTableModel tableModel; private MemorySearchProvider provider; @@ -101,7 +102,7 @@ public class MemorySearchResultsPanel extends JPanel { return tableFilterPanel; } - public void search(MemorySearcher searcher, Combiner combiner) { + public void search(MemorySearcher searcher, Combiner combiner) { MemoryMatchTableLoader loader = createLoader(searcher, combiner); tableModel.addInitialLoadListener( cancelled -> provider.searchAllCompleted(loader.hasResults(), cancelled, @@ -109,7 +110,7 @@ public class MemorySearchResultsPanel extends JPanel { tableModel.setLoader(loader); } - public void searchOnce(MemorySearcher searcher, Address address, boolean forward) { + public void searchOnce(MemorySearcher searcher, Address address, boolean forward) { SearchOnceTask task = new SearchOnceTask(forward, searcher, address); TaskLauncher.launch(task); } @@ -119,12 +120,14 @@ public class MemorySearchResultsPanel extends JPanel { TaskLauncher.launch(task); } - public void refreshAndMaybeScanForChanges(AddressableByteSource byteSource, Scanner scanner, List previousResults) { + public void refreshAndMaybeScanForChanges(AddressableByteSource byteSource, Scanner scanner, + List> previousResults) { RefreshAndScanTask task = new RefreshAndScanTask(byteSource, scanner, previousResults); TaskLauncher.launch(task); } - private MemoryMatchTableLoader createLoader(MemorySearcher searcher, Combiner combiner) { + private MemoryMatchTableLoader createLoader(MemorySearcher searcher, + Combiner combiner) { if (!hasResults()) { hasDeleted = false; return new NewSearchTableLoader(searcher); @@ -141,7 +144,7 @@ public class MemorySearchResultsPanel extends JPanel { // loader as if doing an initial search because you get incremental loading and also // don't need to copy the existing results to feed to a combiner. hasCombined = true; - List previousResults = tableModel.getModelData(); + List> previousResults = tableModel.getModelData(); return new CombinedMatchTableLoader(searcher, previousResults, combiner); } @@ -164,7 +167,7 @@ public class MemorySearchResultsPanel extends JPanel { return tableModel.getRowCount(); } - void select(MemoryMatch match) { + void select(MemoryMatch match) { int rowIndex = tableModel.getRowIndex(match); if (rowIndex >= 0) { threadedTablePanel.getTable().selectRow(rowIndex); @@ -175,7 +178,7 @@ public class MemorySearchResultsPanel extends JPanel { return table; } - public MemoryMatch getSelectedMatch() { + public MemoryMatch getSelectedMatch() { int row = table.getSelectedRow(); return row < 0 ? null : tableModel.getRowObject(row); } @@ -192,17 +195,17 @@ public class MemorySearchResultsPanel extends JPanel { private class SearchOnceTask extends Task { private boolean forward; - private MemorySearcher searcher; + private MemorySearcher searcher; private Address start; - public SearchOnceTask(boolean forward, MemorySearcher searcher, Address start) { + public SearchOnceTask(boolean forward, MemorySearcher searcher, Address start) { super(forward ? "Search Next" : "Search Previous", true, true, true); this.forward = forward; this.searcher = searcher; this.start = start; } - private void tableLoadComplete(MemoryMatch match, boolean wasCancelled) { + private void tableLoadComplete(MemoryMatch match, boolean wasCancelled) { int rowIndex = tableModel.getRowIndex(match); if (rowIndex >= 0) { table.selectRow(rowIndex); @@ -214,7 +217,7 @@ public class MemorySearchResultsPanel extends JPanel { @Override public void run(TaskMonitor monitor) throws CancelledException { try { - MemoryMatch match = searcher.findOnce(start, forward, monitor); + MemoryMatch match = searcher.findOnce(start, forward, monitor); if (match != null) { tableModel.addInitialLoadListener(b -> tableLoadComplete(match, b)); tableModel.addObject(match); @@ -234,20 +237,21 @@ public class MemorySearchResultsPanel extends JPanel { private AddressableByteSource byteSource; private Scanner scanner; - private List matchList; + private List> matchList; public RefreshAndScanTask(AddressableByteSource byteSource, Scanner scanner) { this(byteSource, scanner, tableModel.getModelData()); } - public RefreshAndScanTask(AddressableByteSource byteSource, Scanner scanner, List matches) { + public RefreshAndScanTask(AddressableByteSource byteSource, Scanner scanner, + List> matches) { super("Refreshing", true, true, true); this.byteSource = byteSource; this.scanner = scanner; this.matchList = matches; } - private void tableLoadComplete(MemoryMatch match) { + private void tableLoadComplete(MemoryMatch match) { if (match == null) { provider.refreshAndScanCompleted(null); } @@ -270,11 +274,12 @@ public class MemorySearchResultsPanel extends JPanel { } } - private boolean refreshByteValues(TaskMonitor monitor, List matches) { + private boolean refreshByteValues(TaskMonitor monitor, + List> matches) { try { byteSource.invalidate(); // clear any caches before refreshing byte values monitor.initialize(matches.size(), "Refreshing..."); - for (MemoryMatch match : matches) { + for (MemoryMatch match : matches) { byte[] bytes = new byte[match.getLength()]; byteSource.getBytes(match.getAddress(), bytes, bytes.length); match.updateBytes(bytes); @@ -293,10 +298,11 @@ public class MemorySearchResultsPanel extends JPanel { return false; } - private void performScanFiltering(TaskMonitor monitor, List matches) { + private void performScanFiltering(TaskMonitor monitor, + List> matches) { monitor.initialize(matches.size(), "Scanning for changes..."); - List scanResults = new ArrayList<>(); - for (MemoryMatch match : matches) { + List> scanResults = new ArrayList<>(); + for (MemoryMatch match : matches) { if (scanner.accept(match)) { scanResults.add(match); } @@ -305,14 +311,15 @@ public class MemorySearchResultsPanel extends JPanel { } } - MemoryMatch firstIfReduced = getFirstMatchIfReduced(matches, scanResults); + MemoryMatch firstIfReduced = getFirstMatchIfReduced(matches, scanResults); tableModel.addInitialLoadListener(b -> tableLoadComplete(firstIfReduced)); tableModel.setLoader(new RefreshResultsTableLoader(scanResults)); } - private MemoryMatch getFirstMatchIfReduced(List matches, - List scanResults) { - MemoryMatch firstIfReduced = null; + private MemoryMatch getFirstMatchIfReduced( + List> matches, + List> scanResults) { + MemoryMatch firstIfReduced = null; if (!scanResults.isEmpty() && scanResults.size() != matches.size()) { firstIfReduced = scanResults.isEmpty() ? null : scanResults.getFirst(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java index 164eda3b2c..e07227f1b2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java @@ -17,6 +17,7 @@ package ghidra.features.base.memsearch.gui; import java.util.Iterator; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.features.base.memsearch.searcher.MemorySearcher; import ghidra.util.datastruct.Accumulator; @@ -27,18 +28,18 @@ import ghidra.util.task.TaskMonitor; */ public class NewSearchTableLoader implements MemoryMatchTableLoader { - private MemorySearcher memSearcher; + private MemorySearcher memSearcher; private boolean completedSearch; - private MemoryMatch firstMatch; + private MemoryMatch firstMatch; - NewSearchTableLoader(MemorySearcher memSearcher) { + NewSearchTableLoader(MemorySearcher memSearcher) { this.memSearcher = memSearcher; } @Override - public void loadResults(Accumulator accumulator, TaskMonitor monitor) { + public void loadResults(Accumulator> accumulator, TaskMonitor monitor) { completedSearch = memSearcher.findAll(accumulator, monitor); - Iterator iterator = accumulator.iterator(); + Iterator> iterator = accumulator.iterator(); if (iterator.hasNext()) { firstMatch = iterator.next(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java index fcc5ffce7b..d27a8725f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java @@ -17,6 +17,7 @@ package ghidra.features.base.memsearch.gui; import java.util.List; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.util.datastruct.Accumulator; import ghidra.util.task.TaskMonitor; @@ -27,15 +28,15 @@ import ghidra.util.task.TaskMonitor; */ public class RefreshResultsTableLoader implements MemoryMatchTableLoader { - private List matches; + private List> matches; private boolean hasResults; - public RefreshResultsTableLoader(List matches) { + public RefreshResultsTableLoader(List> matches) { this.matches = matches; } @Override - public void loadResults(Accumulator accumulator, TaskMonitor monitor) { + public void loadResults(Accumulator> accumulator, TaskMonitor monitor) { accumulator.addAll(matches); hasResults = !accumulator.isEmpty(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchGuiModel.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchGuiModel.java index 6cd6331a43..655372a3a8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchGuiModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchGuiModel.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import ghidra.features.base.memsearch.bytesource.SearchRegion; import ghidra.features.base.memsearch.combiner.Combiner; import ghidra.features.base.memsearch.format.SearchFormat; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; /** * Maintains the state of all the settings and controls for the memory search window. @@ -133,7 +133,7 @@ public class SearchGuiModel { notifySettingsChanged(oldSettings); } - public ByteMatcher parse(String proposedText) { + public UserInputByteMatcher parse(String proposedText) { return settings.getSearchFormat().parse(proposedText, settings); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchHistory.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchHistory.java index 5341dbc958..7e153cbdb7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchHistory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchHistory.java @@ -18,7 +18,7 @@ package ghidra.features.base.memsearch.gui; import java.util.*; import ghidra.features.base.memsearch.format.SearchFormat; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; /** * Class for managing memory search history. It maintains a list of previously used ByteMatchers to @@ -26,7 +26,7 @@ import ghidra.features.base.memsearch.matcher.ByteMatcher; * to create it. */ public class SearchHistory { - private List history = new LinkedList<>(); + private List history = new LinkedList<>(); private int maxHistory; public SearchHistory(int maxHistory) { @@ -38,18 +38,18 @@ public class SearchHistory { this.maxHistory = other.maxHistory; } - public void addSearch(ByteMatcher matcher) { + public void addSearch(UserInputByteMatcher matcher) { removeSimilarMatchers(matcher); history.addFirst(matcher); truncateHistoryAsNeeded(); } - private void removeSimilarMatchers(ByteMatcher matcher) { - Iterator it = history.iterator(); + private void removeSimilarMatchers(UserInputByteMatcher matcher) { + Iterator it = history.iterator(); String newInput = matcher.getInput(); SearchFormat newFormat = matcher.getSettings().getSearchFormat(); while (it.hasNext()) { - ByteMatcher historyMatch = it.next(); + UserInputByteMatcher historyMatch = it.next(); SearchFormat historyFormat = historyMatch.getSettings().getSearchFormat(); String historyInput = historyMatch.getInput(); if (historyFormat.equals(newFormat) && historyInput.equals(newInput)) { @@ -70,8 +70,8 @@ public class SearchHistory { } } - public ByteMatcher[] getHistoryAsArray() { - ByteMatcher[] historyArray = new ByteMatcher[history.size()]; + public UserInputByteMatcher[] getHistoryAsArray() { + UserInputByteMatcher[] historyArray = new UserInputByteMatcher[history.size()]; history.toArray(historyArray); return historyArray; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchMarkers.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchMarkers.java index 9fec961756..475ed87060 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchMarkers.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/SearchMarkers.java @@ -22,6 +22,7 @@ import javax.swing.Icon; import generic.theme.GIcon; import ghidra.app.services.*; import ghidra.app.util.SearchConstants; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.listing.Program; @@ -68,7 +69,7 @@ public class SearchMarkers { service.setMarkerForGroup(MarkerService.HIGHLIGHT_GROUP, markerSet, program); } - void loadMarkers(String title, List matches) { + void loadMarkers(String title, List> matches) { if (service == null) { return; } @@ -92,7 +93,7 @@ public class SearchMarkers { } markerSet.clearAll(); - for (MemoryMatch match : matches) { + for (MemoryMatch match : matches) { markerSet.add(match.getAddress()); } service.setMarkerForGroup(MarkerService.HIGHLIGHT_GROUP, markerSet, program); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/ByteMatcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/ByteMatcher.java index 5bf837a2e2..47467fb610 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/ByteMatcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/ByteMatcher.java @@ -15,124 +15,19 @@ */ package ghidra.features.base.memsearch.matcher; -import java.util.Objects; - import ghidra.features.base.memsearch.bytesequence.ExtendedByteSequence; -import ghidra.features.base.memsearch.gui.SearchSettings; +import ghidra.util.bytesearch.Match; /** * ByteMatcher is the base class for an object that be used to scan bytes looking for sequences * that match some criteria. As a convenience, it also stores the input string and settings that * were used to generated this ByteMatcher. + * @param The type of object used by the client to identify the matched pattern */ -public abstract class ByteMatcher { +public interface ByteMatcher { - private final String name; - private final String input; - private final SearchSettings settings; + public Iterable> match(ExtendedByteSequence bytes); - protected ByteMatcher(String name, String input, SearchSettings settings) { - this.name = name; - this.input = input; - this.settings = settings; - } - - /** - * {@return the name of this byte matcher.} - */ - public String getName() { - return name; - } - - /** - * Returns the original input text that generated this ByteMatacher. - * @return the original input text that generated this BytesMatcher - */ - public final String getInput() { - return input == null ? "" : input; - } - - /** - * Returns the settings used to generate this ByteMatcher. - * @return the settings used to generate this ByteMatcher - */ - public SearchSettings getSettings() { - return settings; - } - - /** - * Returns an {@link Iterable} for returning matches within the given byte sequence. - * @param bytes the byte sequence to search - * @return an iterable for return matches in the given sequence - */ - public abstract Iterable match(ExtendedByteSequence bytes); - - /** - * Returns a description of what this byte matcher matches. (Typically a sequence of bytes) - * @return a description of what this byte matcher matches - */ - public abstract String getDescription(); - - /** - * Returns additional information about this byte matcher. (Typically the mask bytes) - * @return additional information about this byte matcher - */ - public abstract String getToolTip(); - - /** - * Returns true if this byte matcher is valid and can be used to perform a search. If false, - * the description will return an error message explaining why this byte matcher is - * invalid. - * @return true if this byte matcher is valid and can be used to perform a search. - */ - public boolean isValidSearch() { - return true; - } - - /** - * Returns true if this byte matcher has valid (but possibly incomplete) input text. For - * example, when entering decimal values, the input could be just "-" as the user starts - * to enter a negative number. In this case the input is valid, but the {@link #isValidSearch()} - * would return false. - * @return true if this byte matcher has valid text - */ - public boolean isValidInput() { - return true; - } - - @Override - public String toString() { - return input; - } - - @Override - public int hashCode() { - return input.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - - if (getClass() != obj.getClass()) { - return false; - } - ByteMatcher other = (ByteMatcher) obj; - return Objects.equals(input, other.input) && - settings.getSearchFormat() == other.settings.getSearchFormat(); - } - - /** - * Record class to contain a match specification. - * @param start the offset in the buffer where the match starts - * @param length the length of the match - * @param matcher the matcher the found the match - */ - public record ByteMatch(int start, int length, ByteMatcher matcher) {} + public String getDescription(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/CombinedByteMatcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/CombinedByteMatcher.java deleted file mode 100644 index 5a78a596db..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/CombinedByteMatcher.java +++ /dev/null @@ -1,98 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.features.base.memsearch.matcher; - -import java.util.Iterator; -import java.util.List; - -import ghidra.features.base.memsearch.bytesequence.ExtendedByteSequence; -import ghidra.features.base.memsearch.gui.SearchSettings; -import ghidra.features.base.memsearch.searcher.MemorySearcher; - -/** - * A ByteMatcher that searches an input sequence for matches from multiple patterns. This is - * useful for using with the {@link MemorySearcher} so that multiple patterns can be searched with - * only one pass through memory, thus paying the memory I/O costs only once. The resulting matches - * will contain the sub ByteMatcher that matched so that it is easy to know which of the multiple - * patterns matched. - */ -public class CombinedByteMatcher extends ByteMatcher { - - private List matchers; - - public CombinedByteMatcher(List matchers, SearchSettings settings) { - super("Multi-Pattern Matcher", null, settings); - this.matchers = matchers; - } - - @Override - public Iterable match(ExtendedByteSequence bytes) { - return new MultiMatcherIterator(bytes); - } - - @Override - public String getDescription() { - return getName(); - } - - @Override - public String getToolTip() { - return null; - } - - private class MultiMatcherIterator implements Iterable, Iterator { - - private Iterator matcherIterator; - private Iterator currentMatchIterator; - private ExtendedByteSequence bytes; - - MultiMatcherIterator(ExtendedByteSequence bytes) { - this.bytes = bytes; - matcherIterator = matchers.iterator(); - currentMatchIterator = getNextMatchIterator(); - } - - @Override - public boolean hasNext() { - while (currentMatchIterator != null && !currentMatchIterator.hasNext()) { - currentMatchIterator = getNextMatchIterator(); - } - return currentMatchIterator != null; - } - - private Iterator getNextMatchIterator() { - if (matcherIterator.hasNext()) { - ByteMatcher matcher = matcherIterator.next(); - return matcher.match(bytes).iterator(); - } - return null; - } - - @Override - public ByteMatch next() { - if (hasNext()) { - return currentMatchIterator.next(); - } - return null; - } - - @Override - public Iterator iterator() { - return this; - } - - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/InvalidByteMatcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/InvalidByteMatcher.java index ae0d741f24..ac9d86cd7b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/InvalidByteMatcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/InvalidByteMatcher.java @@ -19,6 +19,7 @@ import org.apache.commons.collections4.iterators.EmptyIterator; import ghidra.features.base.memsearch.bytesequence.ExtendedByteSequence; import ghidra.features.base.memsearch.format.SearchFormat; +import ghidra.util.bytesearch.Match; import util.CollectionUtils; /** @@ -29,7 +30,7 @@ import util.CollectionUtils; * but not complete so that a fully valid byte matcher could not be created. In this case, the * search is still invalid, but the input is valid. The description will reflect this situation. */ -public class InvalidByteMatcher extends ByteMatcher { +public class InvalidByteMatcher extends UserInputByteMatcher { private final String errorMessage; private final boolean isValidInput; @@ -50,13 +51,13 @@ public class InvalidByteMatcher extends ByteMatcher { * a negative number. */ public InvalidByteMatcher(String errorMessage, boolean isValidInput) { - super("Invalid", null, null); + super("Invalid", "", null); this.errorMessage = errorMessage; this.isValidInput = isValidInput; } @Override - public Iterable match(ExtendedByteSequence bytes) { + public Iterable> match(ExtendedByteSequence bytes) { return CollectionUtils.asIterable(EmptyIterator.emptyIterator()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/MaskedByteSequenceByteMatcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/MaskedByteSequenceByteMatcher.java index b63451556e..65f50ee8d0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/MaskedByteSequenceByteMatcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/MaskedByteSequenceByteMatcher.java @@ -22,12 +22,13 @@ import org.bouncycastle.util.Arrays; import ghidra.features.base.memsearch.bytesequence.ByteSequence; import ghidra.features.base.memsearch.bytesequence.ExtendedByteSequence; import ghidra.features.base.memsearch.gui.SearchSettings; +import ghidra.util.bytesearch.Match; /** * {@link ByteMatcher} where the user search input has been parsed into a sequence of bytes and * masks to be used for searching a byte sequence. */ -public class MaskedByteSequenceByteMatcher extends ByteMatcher { +public class MaskedByteSequenceByteMatcher extends UserInputByteMatcher { private final byte[] searchBytes; private final byte[] masks; @@ -68,7 +69,7 @@ public class MaskedByteSequenceByteMatcher extends ByteMatcher { } @Override - public Iterable match(ExtendedByteSequence byteSequence) { + public Iterable> match(ExtendedByteSequence byteSequence) { return new MatchIterator(byteSequence); } @@ -109,11 +110,12 @@ public class MaskedByteSequenceByteMatcher extends ByteMatcher { //================================================================================================== // Inner classes //================================================================================================== - private class MatchIterator implements Iterator, Iterable { + private class MatchIterator + implements Iterator>, Iterable> { private ByteSequence byteSequence; private int startIndex = 0; - private ByteMatch nextMatch; + private Match nextMatch; public MatchIterator(ByteSequence byteSequence) { this.byteSequence = byteSequence; @@ -121,7 +123,7 @@ public class MaskedByteSequenceByteMatcher extends ByteMatcher { } @Override - public Iterator iterator() { + public Iterator> iterator() { return this; } @@ -131,22 +133,21 @@ public class MaskedByteSequenceByteMatcher extends ByteMatcher { } @Override - public ByteMatch next() { + public Match next() { if (nextMatch == null) { return null; } - ByteMatch returnValue = nextMatch; + Match returnValue = nextMatch; nextMatch = findNextMatch(); return returnValue; } - private ByteMatch findNextMatch() { + private Match findNextMatch() { int nextPossibleStart = findNextPossibleStart(startIndex); while (nextPossibleStart >= 0) { startIndex = nextPossibleStart + 1; if (isValidMatch(nextPossibleStart)) { - return new ByteMatch(nextPossibleStart, searchBytes.length, - MaskedByteSequenceByteMatcher.this); + return new Match<>(searchData, nextPossibleStart, searchBytes.length); } nextPossibleStart = findNextPossibleStart(startIndex); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/RegExByteMatcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/RegExByteMatcher.java index 21a7449682..2aa9841200 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/RegExByteMatcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/RegExByteMatcher.java @@ -23,11 +23,12 @@ import javax.help.UnsupportedOperationException; import ghidra.features.base.memsearch.bytesequence.ExtendedByteSequence; import ghidra.features.base.memsearch.gui.SearchSettings; +import ghidra.util.bytesearch.Match; /** * {@link ByteMatcher} where the user search input has been parsed as a regular expression. */ -public class RegExByteMatcher extends ByteMatcher { +public class RegExByteMatcher extends UserInputByteMatcher { private final Pattern pattern; @@ -43,7 +44,7 @@ public class RegExByteMatcher extends ByteMatcher { } @Override - public Iterable match(ExtendedByteSequence byteSequence) { + public Iterable> match(ExtendedByteSequence byteSequence) { return new PatternMatchIterator(byteSequence); } @@ -93,12 +94,13 @@ public class RegExByteMatcher extends ByteMatcher { /** * Adapter class for converting java {@link Pattern} matching into an iterator of - * {@link ByteMatch}s. + * {@link Match}s. */ - private class PatternMatchIterator implements Iterable, Iterator { + private class PatternMatchIterator + implements Iterable>, Iterator> { private Matcher matcher; - private ByteMatch nextMatch; + private Match nextMatch; private ExtendedByteSequence byteSequence; public PatternMatchIterator(ExtendedByteSequence byteSequence) { @@ -113,22 +115,22 @@ public class RegExByteMatcher extends ByteMatcher { } @Override - public ByteMatch next() { + public Match next() { if (nextMatch == null) { return null; } - ByteMatch returnValue = nextMatch; + Match returnValue = nextMatch; nextMatch = findNextMatch(); return returnValue; } @Override - public Iterator iterator() { + public Iterator> iterator() { return this; } - private ByteMatch findNextMatch() { + private Match findNextMatch() { if (!matcher.find()) { return null; } @@ -137,7 +139,7 @@ public class RegExByteMatcher extends ByteMatcher { if (start >= byteSequence.getLength()) { return null; } - return new ByteMatch(start, end - start, RegExByteMatcher.this); + return new Match<>(searchData, start, end - start); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/SearchData.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/SearchData.java new file mode 100644 index 0000000000..0e5f679a20 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/SearchData.java @@ -0,0 +1,65 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.features.base.memsearch.matcher; + +import java.util.Objects; + +import ghidra.features.base.memsearch.gui.SearchSettings; + +public class SearchData { + private final String name; + private final String input; + private final SearchSettings settings; + + public SearchData(String name, String input, SearchSettings settings) { + this.name = name; + this.input = input == null ? "" : input; + this.settings = settings; + } + + public String getName() { + return name; + } + + public String getInput() { + return input; + } + + public SearchSettings getSettings() { + return settings; + } + + @Override + public int hashCode() { + return Objects.hash(input, settings); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + SearchData other = (SearchData) obj; + return Objects.equals(input, other.input) && Objects.equals(settings, other.settings); + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/UserInputByteMatcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/UserInputByteMatcher.java new file mode 100644 index 0000000000..5a2caf8d0f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/matcher/UserInputByteMatcher.java @@ -0,0 +1,118 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.features.base.memsearch.matcher; + +import java.util.Objects; + +import ghidra.features.base.memsearch.bytesequence.ExtendedByteSequence; +import ghidra.features.base.memsearch.gui.SearchSettings; +import ghidra.util.bytesearch.Match; + +public abstract class UserInputByteMatcher implements ByteMatcher { + + protected final SearchData searchData; + + protected UserInputByteMatcher(String name, String input, SearchSettings settings) { + searchData = new SearchData(name, input, settings); + } + + /** + * {@return the name of this byte matcher.} + */ + public String getName() { + return searchData.getName(); + } + + /** + * Returns an {@link Iterable} for returning matches within the given byte sequence. + * @param bytes the byte sequence to search + * @return an iterable for return matches in the given sequence + */ + @Override + public abstract Iterable> match(ExtendedByteSequence bytes); + + /** + * Returns a description of what this byte matcher matches. (Typically a sequence of bytes) + * @return a description of what this byte matcher matches + */ + @Override + public abstract String getDescription(); + + /** + * Returns additional information about this byte matcher. (Typically the mask bytes) + * @return additional information about this byte matcher + */ + public abstract String getToolTip(); + + /** + * Returns true if this byte matcher is valid and can be used to perform a search. If false, + * the description will return an error message explaining why this byte matcher is + * invalid. + * @return true if this byte matcher is valid and can be used to perform a search. + */ + public boolean isValidSearch() { + return true; + } + + /** + * Returns true if this byte matcher has valid (but possibly incomplete) input text. For + * example, when entering decimal values, the input could be just "-" as the user starts + * to enter a negative number. In this case the input is valid, but the {@link #isValidSearch()} + * would return false. + * @return true if this byte matcher has valid text + */ + public boolean isValidInput() { + return true; + } + + @Override + public String toString() { + return searchData.getInput(); + } + + @Override + public int hashCode() { + return searchData.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + UserInputByteMatcher other = (UserInputByteMatcher) obj; + return Objects.equals(searchData, other.searchData); + } + + public SearchSettings getSettings() { + return searchData.getSettings(); + } + + public String getInput() { + return searchData.getInput(); + } + + public SearchData getSearchData() { + return searchData; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/scan/Scanner.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/scan/Scanner.java index fdb823fcaa..e03f2dae1a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/scan/Scanner.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/scan/Scanner.java @@ -19,7 +19,7 @@ import java.util.function.Predicate; import ghidra.features.base.memsearch.format.SearchFormat; import ghidra.features.base.memsearch.gui.SearchSettings; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; /** @@ -37,10 +37,10 @@ public enum Scanner { DECREASED("Decreased", mm -> compareBytes(mm) < 0, "Keep results whose values decreased"); private final String name; - private final Predicate acceptCondition; + private final Predicate> acceptCondition; private final String description; - private Scanner(String name, Predicate condition, String description) { + private Scanner(String name, Predicate> condition, String description) { this.name = name; this.acceptCondition = condition; this.description = description; @@ -54,16 +54,16 @@ public enum Scanner { return description; } - public boolean accept(MemoryMatch match) { + public boolean accept(MemoryMatch match) { return acceptCondition.test(match); } - private static int compareBytes(MemoryMatch match) { + private static int compareBytes(MemoryMatch match) { byte[] bytes = match.getBytes(); byte[] originalBytes = match.getPreviousBytes(); - ByteMatcher matcher = match.getByteMatcher(); - SearchSettings settings = matcher.getSettings(); + SearchData matchInfo = match.getPattern(); + SearchSettings settings = matchInfo.getSettings(); SearchFormat searchFormat = settings.getSearchFormat(); return searchFormat.compareValues(bytes, originalBytes, settings); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/AlignmentFilter.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/AlignmentFilter.java index cc0fa05804..d812d79979 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/AlignmentFilter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/AlignmentFilter.java @@ -17,11 +17,13 @@ package ghidra.features.base.memsearch.searcher; import java.util.function.Predicate; +import ghidra.features.base.memsearch.matcher.SearchData; + /** * Search filter that can test a search result and determine if that result is at an address * whose offset matches the given alignment (i.e. its offset is a multiple of the alignment value) */ -public class AlignmentFilter implements Predicate { +public class AlignmentFilter implements Predicate> { private int alignment; @@ -30,7 +32,7 @@ public class AlignmentFilter implements Predicate { } @Override - public boolean test(MemoryMatch match) { + public boolean test(MemoryMatch match) { return match.getAddress().getOffset() % alignment == 0; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/CodeUnitFilter.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/CodeUnitFilter.java index 62e5eb84cf..5659b4e9ef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/CodeUnitFilter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/CodeUnitFilter.java @@ -17,13 +17,18 @@ package ghidra.features.base.memsearch.searcher; import java.util.function.Predicate; -import ghidra.program.model.listing.*; +import ghidra.features.base.memsearch.matcher.SearchData; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.Listing; +import ghidra.program.model.listing.Program; /** * Search filter that can test a search result and determine if that result starts at or inside * a code unit that matches one of the selected types. */ -public class CodeUnitFilter implements Predicate { +public class CodeUnitFilter implements Predicate> { private boolean includeInstructions; private boolean includeUndefinedData; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemoryMatch.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemoryMatch.java index 366ed32cda..ab057d513f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemoryMatch.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemoryMatch.java @@ -18,34 +18,34 @@ package ghidra.features.base.memsearch.searcher; import java.util.Arrays; import java.util.Objects; -import ghidra.features.base.memsearch.matcher.ByteMatcher; import ghidra.program.model.address.Address; /** * A class that represents a memory search hit at an address. Matches can also be updated with * new byte values (from a scan or refresh action). The original bytes that matched the original * search are maintained in addition to the "refreshed" bytes. + * @param The client object type that identifies the matching pattern */ -public class MemoryMatch implements Comparable { +public class MemoryMatch implements Comparable> { private final Address address; private byte[] bytes; private byte[] previousBytes; - private final ByteMatcher matcher; + private final T pattern; - public MemoryMatch(Address address, byte[] bytes, ByteMatcher matcher) { + public MemoryMatch(Address address, byte[] bytes, T pattern) { if (bytes == null || bytes.length < 1) { throw new IllegalArgumentException("Must provide at least 1 byte"); } this.address = Objects.requireNonNull(address); this.bytes = bytes; this.previousBytes = bytes; - this.matcher = matcher; + this.pattern = pattern; } public MemoryMatch(Address address) { this.address = address; - this.matcher = null; + this.pattern = null; } public void updateBytes(byte[] newBytes) { @@ -71,12 +71,12 @@ public class MemoryMatch implements Comparable { return previousBytes; } - public ByteMatcher getByteMatcher() { - return matcher; + public T getPattern() { + return pattern; } @Override - public int compareTo(MemoryMatch o) { + public int compareTo(MemoryMatch o) { return address.compareTo(o.address); } @@ -97,7 +97,7 @@ public class MemoryMatch implements Comparable { return false; } - MemoryMatch other = (MemoryMatch) obj; + MemoryMatch other = (MemoryMatch) obj; // just compare addresses. The bytes are mutable and we want matches to be equal even // if the bytes are different return Objects.equals(address, other.address); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java index 30a46bd018..92888aaf62 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java @@ -20,8 +20,8 @@ import java.util.function.Predicate; import ghidra.features.base.memsearch.bytesequence.*; import ghidra.features.base.memsearch.bytesource.AddressableByteSource; import ghidra.features.base.memsearch.matcher.ByteMatcher; -import ghidra.features.base.memsearch.matcher.ByteMatcher.ByteMatch; import ghidra.program.model.address.*; +import ghidra.util.bytesearch.Match; import ghidra.util.datastruct.Accumulator; import ghidra.util.task.TaskMonitor; @@ -34,17 +34,18 @@ import ghidra.util.task.TaskMonitor; * then either call the {@link #findAll(Accumulator, TaskMonitor)} method or use it to incrementally * search using {@link #findNext(Address, TaskMonitor)}, * {@link #findPrevious(Address, TaskMonitor)}, or {@link #findOnce(Address, boolean, TaskMonitor)}. + * @param The client object type used to identify matching patterns */ -public class MemorySearcher { +public class MemorySearcher { private static final int DEFAULT_CHUNK_SIZE = 16 * 1024; private static final int OVERLAP_SIZE = 100; private final AddressableByteSequence bytes1; private final AddressableByteSequence bytes2; - private final ByteMatcher matcher; + private final ByteMatcher matcher; private final int chunkSize; - private Predicate filter = r -> true; + private Predicate> filter = r -> true; private final int searchLimit; private final AddressSetView searchSet; @@ -55,7 +56,7 @@ public class MemorySearcher { * @param addresses the address in the byte source to search * @param searchLimit the max number of hits before stopping */ - public MemorySearcher(AddressableByteSource byteSource, ByteMatcher matcher, + public MemorySearcher(AddressableByteSource byteSource, ByteMatcher matcher, AddressSetView addresses, int searchLimit) { this(byteSource, matcher, addresses, searchLimit, DEFAULT_CHUNK_SIZE); } @@ -68,7 +69,7 @@ public class MemorySearcher { * @param searchLimit the max number of hits before stopping * @param chunkSize the maximum number of bytes to feed to the matcher at any one time. */ - public MemorySearcher(AddressableByteSource byteSource, ByteMatcher matcher, + public MemorySearcher(AddressableByteSource byteSource, ByteMatcher matcher, AddressSetView addresses, int searchLimit, int chunkSize) { this.matcher = matcher; this.searchSet = addresses; @@ -84,7 +85,7 @@ public class MemorySearcher { * criteria that is not captured in the byte matcher such as alignment and code unit type. * @param filter the predicate to use to filter search results */ - public void setMatchFilter(Predicate filter) { + public void setMatchFilter(Predicate> filter) { this.filter = filter; } @@ -97,7 +98,7 @@ public class MemorySearcher { * @param monitor the task monitor * @return true if the search completed searching through the entire address set. */ - public boolean findAll(Accumulator accumulator, TaskMonitor monitor) { + public boolean findAll(Accumulator> accumulator, TaskMonitor monitor) { monitor.initialize(searchSet.getNumAddresses(), "Searching..."); for (AddressRange range : searchSet.getAddressRanges()) { @@ -116,7 +117,7 @@ public class MemorySearcher { * @param monitor the task monitor * @return the first match found or null if no match found. */ - public MemoryMatch findOnce(Address start, boolean forward, TaskMonitor monitor) { + public MemoryMatch findOnce(Address start, boolean forward, TaskMonitor monitor) { if (forward) { return findNext(start, monitor); } @@ -130,14 +131,14 @@ public class MemorySearcher { * @param monitor the task monitor * @return the first match found or null if no match found. */ - public MemoryMatch findNext(Address start, TaskMonitor monitor) { + public MemoryMatch findNext(Address start, TaskMonitor monitor) { long numAddresses = searchSet.getNumAddresses() - searchSet.getAddressCountBefore(start); monitor.initialize(numAddresses, "Searching...."); for (AddressRange range : searchSet.getAddressRanges(start, true)) { range = range.intersectRange(start, range.getMaxAddress()); - MemoryMatch match = findFirst(range, monitor); + MemoryMatch match = findFirst(range, monitor); if (match != null) { return match; } @@ -155,12 +156,12 @@ public class MemorySearcher { * @param monitor the task monitor * @return the first match found or null if no match found. */ - public MemoryMatch findPrevious(Address start, TaskMonitor monitor) { + public MemoryMatch findPrevious(Address start, TaskMonitor monitor) { monitor.initialize(searchSet.getAddressCountBefore(start) + 1, "Searching...."); for (AddressRange range : searchSet.getAddressRanges(start, false)) { - MemoryMatch match = findLast(range, start, monitor); + MemoryMatch match = findLast(range, start, monitor); if (match != null) { return match; } @@ -171,7 +172,7 @@ public class MemorySearcher { return null; } - private MemoryMatch findFirst(AddressRange range, TaskMonitor monitor) { + private MemoryMatch findFirst(AddressRange range, TaskMonitor monitor) { AddressableByteSequence searchBytes = bytes1; AddressableByteSequence extra = bytes2; @@ -183,7 +184,7 @@ public class MemorySearcher { AddressRange next = it.next(); extra.setRange(next); - MemoryMatch match = findFirst(searchBytes, extra, monitor); + MemoryMatch match = findFirst(searchBytes, extra, monitor); if (match != null) { return match; } @@ -202,7 +203,7 @@ public class MemorySearcher { return findFirst(searchBytes, extra, monitor); } - private MemoryMatch findLast(AddressRange range, Address start, TaskMonitor monitor) { + private MemoryMatch findLast(AddressRange range, Address start, TaskMonitor monitor) { AddressableByteSequence searchBytes = bytes1; AddressableByteSequence extra = bytes2; extra.clear(); @@ -221,7 +222,7 @@ public class MemorySearcher { while (it.hasNext()) { AddressRange next = it.next(); searchBytes.setRange(next); - MemoryMatch match = findLast(searchBytes, extra, monitor); + MemoryMatch match = findLast(searchBytes, extra, monitor); if (match != null) { return match; } @@ -237,16 +238,17 @@ public class MemorySearcher { return null; } - private MemoryMatch findFirst(AddressableByteSequence searchBytes, ByteSequence extra, + private MemoryMatch findFirst(AddressableByteSequence searchBytes, ByteSequence extra, TaskMonitor monitor) { ExtendedByteSequence searchSequence = new ExtendedByteSequence(searchBytes, extra, OVERLAP_SIZE); - for (ByteMatch byteMatch : matcher.match(searchSequence)) { - Address address = searchBytes.getAddress(byteMatch.start()); - byte[] bytes = searchSequence.getBytes(byteMatch.start(), byteMatch.length()); - MemoryMatch match = new MemoryMatch(address, bytes, byteMatch.matcher()); + for (Match byteMatch : matcher.match(searchSequence)) { + Address address = searchBytes.getAddress((int) byteMatch.getStart()); + byte[] bytes = + searchSequence.getBytes((int) byteMatch.getStart(), byteMatch.getLength()); + MemoryMatch match = new MemoryMatch<>(address, bytes, byteMatch.getPattern()); if (filter.test(match)) { return match; } @@ -258,18 +260,19 @@ public class MemorySearcher { return null; } - private MemoryMatch findLast(AddressableByteSequence searchBytes, ByteSequence extra, + private MemoryMatch findLast(AddressableByteSequence searchBytes, ByteSequence extra, TaskMonitor monitor) { - MemoryMatch last = null; + MemoryMatch last = null; ExtendedByteSequence searchSequence = new ExtendedByteSequence(searchBytes, extra, OVERLAP_SIZE); - for (ByteMatch byteMatch : matcher.match(searchSequence)) { - Address address = searchBytes.getAddress(byteMatch.start()); - byte[] bytes = searchSequence.getBytes(byteMatch.start(), byteMatch.length()); - MemoryMatch match = new MemoryMatch(address, bytes, byteMatch.matcher()); + for (Match byteMatch : matcher.match(searchSequence)) { + Address address = searchBytes.getAddress((int) byteMatch.getStart()); + byte[] bytes = + searchSequence.getBytes((int) byteMatch.getStart(), byteMatch.getLength()); + MemoryMatch match = new MemoryMatch<>(address, bytes, byteMatch.getPattern()); if (filter.test(match)) { last = match; } @@ -281,7 +284,7 @@ public class MemorySearcher { return last; } - private boolean findAll(Accumulator accumulator, AddressRange range, + private boolean findAll(Accumulator> accumulator, AddressRange range, TaskMonitor monitor) { AddressableByteSequence searchBytes = bytes1; AddressableByteSequence extra = bytes2; @@ -303,7 +306,7 @@ public class MemorySearcher { return findAll(accumulator, searchBytes, extra, monitor); } - private boolean findAll(Accumulator accumulator, + private boolean findAll(Accumulator> accumulator, AddressableByteSequence searchBytes, ByteSequence extra, TaskMonitor monitor) { if (monitor.isCancelled()) { @@ -313,15 +316,15 @@ public class MemorySearcher { ExtendedByteSequence searchSequence = new ExtendedByteSequence(searchBytes, extra, OVERLAP_SIZE); - for (ByteMatch byteMatch : matcher.match(searchSequence)) { - Address address = searchBytes.getAddress(byteMatch.start()); - byte[] bytes = searchSequence.getBytes(byteMatch.start(), byteMatch.length()); - MemoryMatch match = new MemoryMatch(address, bytes, byteMatch.matcher()); - if (filter.test(match)) { + for (Match match : matcher.match(searchSequence)) { + Address address = searchBytes.getAddress((int) match.getStart()); + byte[] bytes = searchSequence.getBytes((int) match.getStart(), match.getLength()); + MemoryMatch memMatch = new MemoryMatch<>(address, bytes, match.getPattern()); + if (filter.test(memMatch)) { if (accumulator.size() >= searchLimit) { return false; } - accumulator.add(match); + accumulator.add(memMatch); } if (monitor.isCancelled()) { return false; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Match.java b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Match.java index 59dac95a56..5a91c69f05 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Match.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Match.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,109 +15,76 @@ */ package ghidra.util.bytesearch; +import java.util.Objects; + /** - * Represents a match of a DittedBitSequence at a given offset in a byte sequence. + * Represents a match of a BytePattern at a given offset in a byte sequence. * - * There is a hidden assumption that the sequence is actually a Pattern - * that might have a ditted-bit-sequence, a set of match actions, - * and post match rules/checks + * @param The specific implementation of the BytePattern that was used to create this match * */ -public class Match { - private DittedBitSequence sequence; // Pattern that matched - private long offset; // Offset within bytestream where the match occurred +public class Match { + private T pattern; // Pattern that matched + private long start; // position in the input byte sequence where this pattern matched + private int length; /** - * Construct a Match of a DittedBitSequence at an offset within a byte stream. - * Object normally used when a match occurs during a MemoryBytePatternSearch. - * @param sequence that matched - * @param offset from the start of byte stream where the matched occured + * Construct a Match of a BytePattern that matched at a position in the input byte sequence. + * @param pattern the byte pattern that matched + * @param start the location in the input byte sequence where the pattern match begins + * @param length the length of the matching sequence */ - public Match(DittedBitSequence sequence, long offset) { - this.sequence = sequence; - this.offset = offset; + public Match(T pattern, long start, int length) { + this.pattern = pattern; + this.start = start; + this.length = length; } /** - * If the sequence corresponds to a PatternPair, return the number of postbits - * @return the number of post bits + * @return length in bytes of the matched pattern */ - public int getNumPostBits() { - if (!(sequence instanceof Pattern)) { - return 0; - } - int marked = ((Pattern) sequence).getMarkOffset(); - if (marked == 0) { - return sequence.getNumFixedBits(); - } - return sequence.getNumFixedBits() - sequence.getNumInitialFixedBits(marked); - } - - /** - * @return actions associated with this match - */ - public MatchAction[] getMatchActions() { - return ((Pattern) sequence).getMatchActions(); - } - - /** - * @return size in bytes of sequence - */ - public int getSequenceSize() { - return sequence.getSize(); - } - - /** - * @return index of sequence in a possibly longer set of sequences - */ - public int getSequenceIndex() { - return sequence.getIndex(); - } - - /** - * @return the offset of the match within a longer byte sequence - */ - public long getMarkOffset() { - return offset + ((Pattern) sequence).getMarkOffset(); + public int getLength() { + return length; } /** * @return offset of match in sequence of bytes */ - public long getMatchStart() { - return offset; - } - - /** - * Check that the possible post rules are satisfied - * - * @param streamoffset offset within from match location to check postrules. - * - * @return true if post rules are satisfied - */ - public boolean checkPostRules(long streamoffset) { - long curoffset = streamoffset + offset; - Pattern pattern = (Pattern) sequence; - PostRule[] postRules = pattern.getPostRules(); - for (PostRule postRule : postRules) { - if (!postRule.apply(pattern, curoffset)) { - return false; - } - } - return true; - } - - /** - * @return ditted bit sequence as a string - */ - public String getHexString() { - return sequence.getHexString(); + public long getStart() { + return start; } /** * @return the sequence that was matched */ - public DittedBitSequence getSequence() { - return sequence; + public T getPattern() { + return pattern; } + + @Override + public String toString() { + return pattern.toString() + " @ " + start; + } + + @Override + public int hashCode() { + return Objects.hash(pattern, start, length); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Match other = (Match) obj; + return Objects.equals(pattern, other.pattern) && start == other.start && + length == other.length; + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MatchAction.java b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MatchAction.java index 6c81bfe9a9..94d43bcec5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MatchAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MatchAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,7 +30,7 @@ public interface MatchAction { * @param addr where the match occured * @param match information about the match that occurred */ - public void apply(Program program, Address addr, Match match); + public void apply(Program program, Address addr, Match match); /** * Action can be constructed from XML diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MemoryBytePatternSearcher.java b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MemoryBytePatternSearcher.java index 9d2ae060b0..47da2c19a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MemoryBytePatternSearcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MemoryBytePatternSearcher.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,7 +36,7 @@ import ghidra.util.task.TaskMonitor; public class MemoryBytePatternSearcher { private static final long RESTRICTED_PATTERN_BYTE_RANGE = 32; - SequenceSearchState root = null; + SequenceSearchState root = null; ArrayList patternList; @@ -62,7 +62,7 @@ public class MemoryBytePatternSearcher { * @param searchName name of search * @param root search state pre-initialized */ - public MemoryBytePatternSearcher(String searchName, SequenceSearchState root) { + public MemoryBytePatternSearcher(String searchName, SequenceSearchState root) { this.searchName = searchName; this.root = root; } @@ -164,7 +164,7 @@ public class MemoryBytePatternSearcher { * @throws IOException exception during read of memory * @throws CancelledException canceled search */ - private void searchBlock(SequenceSearchState rootState, Program program, MemoryBlock block, + private void searchBlock(SequenceSearchState rootState, Program program, MemoryBlock block, AddressSetView restrictSet, TaskMonitor monitor) throws IOException, CancelledException { @@ -193,7 +193,7 @@ public class MemoryBytePatternSearcher { AddressRange addressRange = addressRanges.next(); long numAddressesInRange = addressRange.getLength(); - ArrayList mymatches = new ArrayList<>(); + ArrayList> mymatches = new ArrayList<>(); long streamoffset = blockStartAddr.getOffset(); @@ -228,13 +228,15 @@ public class MemoryBytePatternSearcher { monitor.checkCancelled(); monitor.setProgress( matchProgress + (long) (numAddressesInRange * ((float) i / mymatches.size()))); - Match match = mymatches.get(i); - Address addr = blockStartAddr.add(match.getMarkOffset() + blockOffset); - if (!match.checkPostRules(streamoffset + blockOffset)) { + Match match = mymatches.get(i); + Pattern pattern = match.getPattern(); + Address addr = blockStartAddr.add(pattern.getMarkOffset()+match.getStart() + blockOffset); + long totalOffset = streamoffset + blockOffset + match.getStart(); + if (!pattern.checkPostRules(totalOffset)) { continue; } - MatchAction[] matchactions = match.getMatchActions(); + MatchAction[] matchactions = pattern.getMatchActions(); preMatchApply(matchactions, addr); for (MatchAction matchaction : matchactions) { matchaction.apply(program, addr, match); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Pattern.java b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Pattern.java index 03893ebfa5..192ca14efa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Pattern.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/Pattern.java @@ -227,4 +227,20 @@ public class Pattern extends DittedBitSequence { parser.end(); } + + /** + * Check that the possible post rules are satisfied + * + * @param offset offset in stream to check postrules. + * + * @return true if post rules are satisfied + */ + public boolean checkPostRules(long offset) { + for (PostRule postRule : postrule) { + if (!postRule.apply(this, offset)) { + return false; + } + } + return true; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/SequenceSearchState.java b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/SequenceSearchState.java index fe32063619..c3df31db86 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/SequenceSearchState.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/SequenceSearchState.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,6 +17,7 @@ package ghidra.util.bytesearch; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Array; import java.util.*; import ghidra.util.task.TaskMonitor; @@ -25,22 +26,22 @@ import ghidra.util.task.TaskMonitor; * SeqenceSearchState holds the state of a search for a DittedBitSequence within a byte * sequence. */ -public class SequenceSearchState implements Comparable { +public class SequenceSearchState implements Comparable> { private static final int PATTERN_ENDED = Integer.MAX_VALUE; - private SequenceSearchState parent; - private ArrayList possible; // Patterns that could still match in this state - private ArrayList success; // Patterns that have matched successfully if we reached this state - private SequenceSearchState[] trans; // State transitions based on next byte + private SequenceSearchState parent; + private ArrayList possible; // Patterns that could still match in this state + private ArrayList success; // Patterns that have matched successfully if we reached this state + private SequenceSearchState[] trans; // State transitions based on next byte /** * Construct a sub sequence state with a parent sequence * * @param parent parent SequenceSearchState */ - public SequenceSearchState(SequenceSearchState parent) { + public SequenceSearchState(SequenceSearchState parent) { this.parent = parent; - possible = new ArrayList(); + possible = new ArrayList(); success = null; trans = null; } @@ -65,11 +66,11 @@ public class SequenceSearchState implements Comparable { * @param pat pattern to add * @param pos position within the current set of patterns to add this pattern */ - public void addSequence(DittedBitSequence pat, int pos) { + public void addSequence(T pat, int pos) { possible.add(pat); if (pos == pat.getSize()) { if (success == null) { - success = new ArrayList(); + success = new ArrayList(); } success.add(pat); } @@ -92,7 +93,7 @@ public class SequenceSearchState implements Comparable { } @Override - public int compareTo(SequenceSearchState o) { + public int compareTo(SequenceSearchState o) { int i = 0; for (;;) { if (possible.size() <= i) { @@ -113,12 +114,12 @@ public class SequenceSearchState implements Comparable { } } - private void buildSingleTransition(ArrayList all, int pos, int val) { - SequenceSearchState newstate = null; - for (DittedBitSequence curpat : possible) { + private void buildSingleTransition(ArrayList> all, int pos, int val) { + SequenceSearchState newstate = null; + for (T curpat : possible) { if (curpat.isMatch(pos, val)) { if (newstate == null) { - newstate = new SequenceSearchState(this); + newstate = new SequenceSearchState<>(this); } newstate.addSequence(curpat, pos + 1); } @@ -130,9 +131,9 @@ public class SequenceSearchState implements Comparable { } } - private void exportSuccess(ArrayList match, int offset) { - for (DittedBitSequence succes : success) { // If we found matches - Match newmatch = new Match(succes, offset); + private void exportSuccess(ArrayList> match, int offset) { + for (T succes : success) { // If we found matches + Match newmatch = new Match(succes, offset, succes.getSize()); match.add(newmatch); } } @@ -141,8 +142,8 @@ public class SequenceSearchState implements Comparable { * Merge in -op- and this as a single state * @param op */ - private void merge(SequenceSearchState op) { - SequenceSearchState parent = op.parent; + private void merge(SequenceSearchState op) { + SequenceSearchState parent = op.parent; for (int i = 0; i < 256; ++i) { if (parent.trans[i] == op) { parent.trans[i] = this; // Should be replaced with this @@ -153,7 +154,7 @@ public class SequenceSearchState implements Comparable { success = op.success; } else { - ArrayList tmp = new ArrayList(); + ArrayList tmp = new ArrayList<>(); int i = 0; int j = 0; int curpat = -1; @@ -200,9 +201,9 @@ public class SequenceSearchState implements Comparable { * @param numbytes retrict number of bytes to allow to match * @param match list of matches, the result */ - public void sequenceMatch(byte[] bytearray, int numbytes, ArrayList match) { + public void sequenceMatch(byte[] bytearray, int numbytes, ArrayList> match) { int subindex = 0; - SequenceSearchState curstate = this; + SequenceSearchState curstate = this; do { if (curstate.success != null) { @@ -223,8 +224,8 @@ public class SequenceSearchState implements Comparable { * @param buffer is the array of bytes to search * @param match is populated with a Match object for each pattern and position that matches */ - public void apply(byte[] buffer, ArrayList match) { - SequenceSearchState curstate; + public void apply(byte[] buffer, ArrayList> match) { + SequenceSearchState curstate; int subindex; for (int offset = 0; offset < buffer.length; ++offset) { curstate = this; // New starting offset -> Root state @@ -250,7 +251,7 @@ public class SequenceSearchState implements Comparable { * @param monitor - if non-null, check for user cancel, and maintain progress info * @throws IOException */ - public void apply(InputStream in, ArrayList match, TaskMonitor monitor) + public void apply(InputStream in, ArrayList> match, TaskMonitor monitor) throws IOException { apply(in, -1L, match, monitor); } @@ -263,7 +264,7 @@ public class SequenceSearchState implements Comparable { * @param monitor - if non-null, check for user cancel, and maintain progress info * @throws IOException */ - public void apply(InputStream in, long maxBytes, ArrayList match, TaskMonitor monitor) + public void apply(InputStream in, long maxBytes, ArrayList> match, TaskMonitor monitor) throws IOException { long progress = monitor.getProgress(); @@ -277,7 +278,7 @@ public class SequenceSearchState implements Comparable { byte[] firstBuf = new byte[maxSize]; byte[] secondBuf = new byte[maxSize]; byte[] curBuf; - SequenceSearchState curState; + SequenceSearchState curState; int fullBuffers; // Number of buffers that are completely full int ra = in.read(firstBuf); if (ra == firstBuf.length) { @@ -405,13 +406,14 @@ public class SequenceSearchState implements Comparable { * @param pos position within the search sequence state for this level * @return list of possible new search states to be added to the state machine */ - static ArrayList buildTransitionLevel(ArrayList prev, + @SuppressWarnings("unchecked") + static ArrayList> buildTransitionLevel(ArrayList> prev, int pos) { - ArrayList res = new ArrayList(); - Iterator iterator = prev.iterator(); + ArrayList> res = new ArrayList>(); + Iterator> iterator = prev.iterator(); while (iterator.hasNext()) { // For each current state - SequenceSearchState next = iterator.next(); - next.trans = new SequenceSearchState[256]; + SequenceSearchState next = iterator.next(); + next.trans = (SequenceSearchState[]) Array.newInstance(next.getClass(), 256); for (int i = 0; i < 256; ++i) { // Try every byte transition next.buildSingleTransition(res, pos, i); } @@ -421,12 +423,12 @@ public class SequenceSearchState implements Comparable { } // Prepare to dedup the states Collections.sort(res); - ArrayList finalres = new ArrayList(); - Iterator iter = res.iterator(); - SequenceSearchState curpat = iter.next(); + ArrayList> finalres = new ArrayList>(); + Iterator> iter = res.iterator(); + SequenceSearchState curpat = iter.next(); finalres.add(curpat); while (iter.hasNext()) { - SequenceSearchState nextpat = iter.next(); + SequenceSearchState nextpat = iter.next(); int comp = curpat.compareTo(nextpat); if (comp == 0) { // Identical states curpat.merge(nextpat); @@ -444,16 +446,16 @@ public class SequenceSearchState implements Comparable { * @param patterns bit sequence patterns * @return search state the will match the given sequences */ - static public SequenceSearchState buildStateMachine( - ArrayList patterns) { - SequenceSearchState root = new SequenceSearchState(null); + static public SequenceSearchState buildStateMachine( + ArrayList patterns) { + SequenceSearchState root = new SequenceSearchState<>(null); for (int i = 0; i < patterns.size(); ++i) { - DittedBitSequence pat = patterns.get(i); + T pat = patterns.get(i); pat.setIndex(i); root.addSequence(pat, 0); } root.sortSequences(); - ArrayList statelevel = new ArrayList(); + ArrayList> statelevel = new ArrayList>(); statelevel.add(root); int level = 0; do { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/features/base/memsearch/AbstractMemSearchTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/features/base/memsearch/AbstractMemSearchTest.java index 2237c273bc..30b3b0b72a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/features/base/memsearch/AbstractMemSearchTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/features/base/memsearch/AbstractMemSearchTest.java @@ -35,6 +35,7 @@ import ghidra.app.util.viewer.format.FormatManager; import ghidra.features.base.memsearch.bytesource.SearchRegion; import ghidra.features.base.memsearch.format.SearchFormat; import ghidra.features.base.memsearch.gui.*; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; @@ -122,7 +123,7 @@ public abstract class AbstractMemSearchTest extends AbstractProgramBasedTest { assertEquals("The inner-class has been renamed", "MemoryMatchHighlighter", highlightProvider.getClass().getSimpleName()); - List data = searchProvider.getSearchResults(); + List> data = searchProvider.getSearchResults(); return data.stream().map(result -> result.getAddress()).collect(Collectors.toList()); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/CombinedByteMatcherTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/CombinedByteMatcherTest.java deleted file mode 100644 index 10662bf8e7..0000000000 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/CombinedByteMatcherTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.features.base.memsearch.bytesequence; - -import static org.junit.Assert.*; - -import java.util.List; -import java.util.stream.StreamSupport; - -import org.junit.Before; -import org.junit.Test; - -import ghidra.features.base.memsearch.matcher.*; -import ghidra.features.base.memsearch.matcher.ByteMatcher.ByteMatch; - -public class CombinedByteMatcherTest { - private ByteMatcher xxxByteMatcher; - private ByteMatcher yyyByteMatcher; - private ByteMatcher zzzByteMatcher; - private CombinedByteMatcher multiMatcher; - - @Before - public void setUp() { - - xxxByteMatcher = new RegExByteMatcher("xxx", null); - yyyByteMatcher = new RegExByteMatcher("yyy", null); - zzzByteMatcher = new RegExByteMatcher("zzz", null); - multiMatcher = - new CombinedByteMatcher(List.of(xxxByteMatcher, yyyByteMatcher, zzzByteMatcher), null); - } - - @Test - public void textFindsOneEachPatterns() { - List results = match("fooxxxbar, fooyyybar, foozzzbar"); - assertEquals(3, results.size()); - assertEquals(new ByteMatch(3, 3, xxxByteMatcher), results.get(0)); - assertEquals(new ByteMatch(15, 3, yyyByteMatcher), results.get(1)); - assertEquals(new ByteMatch(26, 3, zzzByteMatcher), results.get(2)); - } - - @Test - public void textFindsMutliplePatterns() { - List results = match("xxxyyyzzzxxxyyyzzz"); - assertEquals(6, results.size()); - assertEquals(new ByteMatch(0, 3, xxxByteMatcher), results.get(0)); - assertEquals(new ByteMatch(9, 3, xxxByteMatcher), results.get(1)); - assertEquals(new ByteMatch(3, 3, yyyByteMatcher), results.get(2)); - assertEquals(new ByteMatch(12, 3, yyyByteMatcher), results.get(3)); - assertEquals(new ByteMatch(6, 3, zzzByteMatcher), results.get(4)); - assertEquals(new ByteMatch(15, 3, zzzByteMatcher), results.get(5)); - } - - @Test - public void testNoMatches() { - List results = match("There are no matches here!"); - assertEquals(0, results.size()); - } - - private List match(String s) { - ExtendedByteSequence sequence = createByteSequence(s); - Iterable match = multiMatcher.match(sequence); - return StreamSupport.stream(match.spliterator(), false).toList(); - } - - private ExtendedByteSequence createByteSequence(String s) { - ByteSequence main = new ByteArrayByteSequence(makeBytes(s)); - ByteSequence extra = new ByteArrayByteSequence(makeBytes("")); - return new ExtendedByteSequence(main, extra, 0); - } - - private byte[] makeBytes(String string) { - byte[] bytes = new byte[string.length()]; - for (int i = 0; i < bytes.length; i++) { - bytes[i] = (byte) string.charAt(i); - } - return bytes; - } - -} diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/MaskedBytesSequenceByteMatcherTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/MaskedBytesSequenceByteMatcherTest.java index 2999857918..ff9e19deee 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/MaskedBytesSequenceByteMatcherTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/MaskedBytesSequenceByteMatcherTest.java @@ -22,9 +22,8 @@ import java.util.Iterator; import org.junit.Before; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; -import ghidra.features.base.memsearch.matcher.ByteMatcher.ByteMatch; -import ghidra.features.base.memsearch.matcher.MaskedByteSequenceByteMatcher; +import ghidra.features.base.memsearch.matcher.*; +import ghidra.util.bytesearch.Match; public class MaskedBytesSequenceByteMatcherTest { @@ -44,15 +43,17 @@ public class MaskedBytesSequenceByteMatcherTest { public void testSimplePatterWithOneMatchCrossingBoundary() { byte[] searchBytes = makeBytes(3, 2, 4); - ByteMatcher byteMatcher = new MaskedByteSequenceByteMatcher("", searchBytes, null); + MaskedByteSequenceByteMatcher byteMatcher = + new MaskedByteSequenceByteMatcher("", searchBytes, null); + SearchData searchData = byteMatcher.getSearchData(); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); assertTrue(it.hasNext()); - assertEquals(new ByteMatch(2, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchData, 2, 3), it.next()); assertTrue(it.hasNext()); - assertEquals(new ByteMatch(9, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchData, 9, 3), it.next()); assertFalse(it.hasNext()); @@ -62,12 +63,14 @@ public class MaskedBytesSequenceByteMatcherTest { public void testSimplePatterWithOneMatchCrossingBoundaryNoHasNextCalls() { byte[] searchBytes = makeBytes(3, 2, 4); - ByteMatcher byteMatcher = new MaskedByteSequenceByteMatcher("", searchBytes, null); + MaskedByteSequenceByteMatcher byteMatcher = + new MaskedByteSequenceByteMatcher("", searchBytes, null); + SearchData searchData = byteMatcher.getSearchData(); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); - assertEquals(new ByteMatch(2, 3, byteMatcher), it.next()); - assertEquals(new ByteMatch(9, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchData, 2, 3), it.next()); + assertEquals(new Match<>(searchData, 9, 3), it.next()); assertNull(it.next()); } @@ -76,14 +79,15 @@ public class MaskedBytesSequenceByteMatcherTest { byte[] searchBytes = makeBytes(2, 0, 2); byte[] masks = makeBytes(0xff, 0x00, 0xff); - ByteMatcher byteMatcher = + MaskedByteSequenceByteMatcher byteMatcher = new MaskedByteSequenceByteMatcher("", searchBytes, masks, null); + SearchData searchdata = byteMatcher.getSearchData(); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); - assertEquals(new ByteMatch(1, 3, byteMatcher), it.next()); - assertEquals(new ByteMatch(6, 3, byteMatcher), it.next()); - assertEquals(new ByteMatch(8, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchdata, 1, 3), it.next()); + assertEquals(new Match<>(searchdata, 6, 3), it.next()); + assertEquals(new Match<>(searchdata, 8, 3), it.next()); assertNull(it.next()); } @@ -91,17 +95,17 @@ public class MaskedBytesSequenceByteMatcherTest { public void testPatternStartButNotEnoughExtraBytes() { byte[] searchBytes = makeBytes(6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); byte[] masks = makeBytes(0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - ByteMatcher byteMatcher = + MaskedByteSequenceByteMatcher byteMatcher = new MaskedByteSequenceByteMatcher("", searchBytes, masks, null); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); assertFalse(it.hasNext()); } @Test public void testGetDescription() { byte[] searchBytes = makeBytes(1, 2, 3, 0xaa); - ByteMatcher byteMatcher = new MaskedByteSequenceByteMatcher("", searchBytes, null); + UserInputByteMatcher byteMatcher = new MaskedByteSequenceByteMatcher("", searchBytes, null); assertEquals("01 02 03 aa", byteMatcher.getDescription()); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/RegExByteMatcherTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/RegExByteMatcherTest.java index 4c949db118..1c91a714a1 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/RegExByteMatcherTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/bytesequence/RegExByteMatcherTest.java @@ -22,9 +22,8 @@ import java.util.Iterator; import org.junit.Before; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; -import ghidra.features.base.memsearch.matcher.ByteMatcher.ByteMatch; -import ghidra.features.base.memsearch.matcher.RegExByteMatcher; +import ghidra.features.base.memsearch.matcher.*; +import ghidra.util.bytesearch.Match; public class RegExByteMatcherTest { private ExtendedByteSequence byteSequence; @@ -40,15 +39,16 @@ public class RegExByteMatcherTest { @Test public void testSimplePatternWithOneMatchCrossingBoundary() { - ByteMatcher byteMatcher = new RegExByteMatcher("two", null); + RegExByteMatcher byteMatcher = new RegExByteMatcher("two", null); + SearchData searchData = byteMatcher.getSearchData(); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); assertTrue(it.hasNext()); - assertEquals(new ByteMatch(4, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchData, 4, 3), it.next()); assertTrue(it.hasNext()); - assertEquals(new ByteMatch(14, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchData, 14, 3), it.next()); assertFalse(it.hasNext()); @@ -57,21 +57,22 @@ public class RegExByteMatcherTest { @Test public void testSimplePatternWithOneMatchCrossingBoundaryNoHasNextCalls() { - ByteMatcher byteMatcher = new RegExByteMatcher("two", null); + RegExByteMatcher byteMatcher = new RegExByteMatcher("two", null); + SearchData searchData = byteMatcher.getSearchData(); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); - assertEquals(new ByteMatch(4, 3, byteMatcher), it.next()); - assertEquals(new ByteMatch(14, 3, byteMatcher), it.next()); + assertEquals(new Match<>(searchData, 4, 3), it.next()); + assertEquals(new Match<>(searchData, 14, 3), it.next()); assertNull(it.next()); } @Test public void testNoMatch() { - ByteMatcher byteMatcher = new RegExByteMatcher("apple", null); + ByteMatcher byteMatcher = new RegExByteMatcher("apple", null); - Iterator it = byteMatcher.match(byteSequence).iterator(); + Iterator> it = byteMatcher.match(byteSequence).iterator(); assertFalse(it.hasNext()); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/combiner/MemoryMatchCombinerTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/combiner/MemoryMatchCombinerTest.java index 7c20715e4b..077092d6c5 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/combiner/MemoryMatchCombinerTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/combiner/MemoryMatchCombinerTest.java @@ -22,6 +22,7 @@ import java.util.*; import org.junit.Before; import org.junit.Test; +import ghidra.features.base.memsearch.matcher.SearchData; import ghidra.features.base.memsearch.searcher.MemoryMatch; import ghidra.program.model.address.*; @@ -29,18 +30,18 @@ public class MemoryMatchCombinerTest { private GenericAddressSpace space; - private MemoryMatch m1; - private MemoryMatch m2; - private MemoryMatch m3; - private MemoryMatch m4; - private MemoryMatch m5; - private MemoryMatch m6; - private MemoryMatch m7; - private MemoryMatch m8; + private MemoryMatch m1; + private MemoryMatch m2; + private MemoryMatch m3; + private MemoryMatch m4; + private MemoryMatch m5; + private MemoryMatch m6; + private MemoryMatch m7; + private MemoryMatch m8; - List list1; - List list2; - List result; + List> list1; + List> list2; + List> result; @Before public void setUp() { @@ -88,8 +89,8 @@ public class MemoryMatchCombinerTest { @Test public void testUnionWithDupsKeepsLonger() { - MemoryMatch m3_short = createMatch(3, 2); - MemoryMatch m3_long = createMatch(3, 8); + MemoryMatch m3_short = createMatch(3, 2); + MemoryMatch m3_long = createMatch(3, 8); list1 = list(m1, m2, m3); list2 = list(m3_short, m4, m5); @@ -127,8 +128,8 @@ public class MemoryMatchCombinerTest { @Test public void testIntersectionKeepsLonger() { - MemoryMatch m4_long = createMatch(4, 8); - MemoryMatch m3_long = createMatch(3, 8); + MemoryMatch m4_long = createMatch(4, 8); + MemoryMatch m3_long = createMatch(3, 8); list1 = list(m1, m2, m3, m4_long); list2 = list(m1, m2, m3_long, m4); result = intersect(list1, list2); @@ -174,8 +175,8 @@ public class MemoryMatchCombinerTest { @Test public void testXorLengthDontMatter() { - MemoryMatch m4_long = createMatch(4, 8); - MemoryMatch m3_short = createMatch(3, 2); + MemoryMatch m4_long = createMatch(4, 8); + MemoryMatch m3_short = createMatch(3, 2); list1 = list(m1, m2, m3, m4); list2 = list(m3_short, m4_long, m5); @@ -227,8 +228,8 @@ public class MemoryMatchCombinerTest { @Test public void testAMinusBLengthDontMatter() { - MemoryMatch m4_long = createMatch(4, 8); - MemoryMatch m3_short = createMatch(3, 2); + MemoryMatch m4_long = createMatch(4, 8); + MemoryMatch m3_short = createMatch(3, 2); list1 = list(m1, m2, m3, m4); list2 = list(m3_short, m4_long, m5); @@ -280,8 +281,8 @@ public class MemoryMatchCombinerTest { @Test public void testBMinusALengthDontMatter() { - MemoryMatch m4_long = createMatch(4, 8); - MemoryMatch m3_short = createMatch(3, 2); + MemoryMatch m4_long = createMatch(4, 8); + MemoryMatch m3_short = createMatch(3, 2); list1 = list(m1, m2, m3, m4); list2 = list(m3_short, m4_long, m5); @@ -294,42 +295,53 @@ public class MemoryMatchCombinerTest { assertEquals(list(m5), result); } - private List xor(List matches1, List matches2) { + private List> xor(List> matches1, + List> matches2) { Combiner combiner = Combiner.XOR; - List results = new ArrayList<>(combiner.combine(matches1, matches2)); + List> results = + new ArrayList<>(combiner.combine(matches1, matches2)); Collections.sort(results); return results; } - private List union(List matches1, List matches2) { + private List> union(List> matches1, + List> matches2) { Combiner combiner = Combiner.UNION; - List results = new ArrayList<>(combiner.combine(matches1, matches2)); + List> results = + new ArrayList<>(combiner.combine(matches1, matches2)); Collections.sort(results); return results; } - private List intersect(List matches1, List matches2) { + private List> intersect(List> matches1, + List> matches2) { Combiner combiner = Combiner.INTERSECT; - List results = new ArrayList<>(combiner.combine(matches1, matches2)); + List> results = + new ArrayList<>(combiner.combine(matches1, matches2)); Collections.sort(results); return results; } - private List aMinusB(List matches1, List matches2) { + private List> aMinusB(List> matches1, + List> matches2) { Combiner combiner = Combiner.A_MINUS_B; - List results = new ArrayList<>(combiner.combine(matches1, matches2)); + List> results = + new ArrayList<>(combiner.combine(matches1, matches2)); Collections.sort(results); return results; } - private List BMinusA(List matches1, List matches2) { + private List> BMinusA(List> matches1, + List> matches2) { Combiner combiner = Combiner.B_MINUS_A; - List results = new ArrayList<>(combiner.combine(matches1, matches2)); + List> results = + new ArrayList<>(combiner.combine(matches1, matches2)); Collections.sort(results); return results; } - private List list(MemoryMatch... matches) { + @SafeVarargs + private List> list(MemoryMatch... matches) { return Arrays.asList(matches); } @@ -337,9 +349,9 @@ public class MemoryMatchCombinerTest { return space.getAddress(offset); } - private MemoryMatch createMatch(int offset, int length) { + private MemoryMatch createMatch(int offset, int length) { Address address = addr(offset); byte[] bytes = new byte[length]; - return new MemoryMatch(address, bytes, null); + return new MemoryMatch<>(address, bytes, null); } } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/BinarySearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/BinarySearchFormatTest.java index 5650259a7d..cf32fb9c1f 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/BinarySearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/BinarySearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class BinarySearchFormatTest extends AbstractSearchFormatTest { public BinarySearchFormatTest() { @@ -47,14 +47,14 @@ public class BinarySearchFormatTest extends AbstractSearchFormatTest { @Test public void testGroupTooBig() { - ByteMatcher bad = format.parse("111111111", settings); + UserInputByteMatcher bad = format.parse("111111111", settings); assertFalse(bad.isValidInput()); assertEquals("Max group size exceeded. Enter to add more.", bad.getDescription()); } @Test public void testInvalidChars() { - ByteMatcher bad = format.parse("012", settings); + UserInputByteMatcher bad = format.parse("012", settings); assertFalse(bad.isValidInput()); assertEquals("Invalid character", bad.getDescription()); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/DoubleSearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/DoubleSearchFormatTest.java index 8855a6dca1..c0ce12d831 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/DoubleSearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/DoubleSearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class DoubleSearchFormatTest extends AbstractSearchFormatTest { public DoubleSearchFormatTest() { @@ -58,7 +58,7 @@ public class DoubleSearchFormatTest extends AbstractSearchFormatTest { @Test public void testDotOnly() { - ByteMatcher byteMatcher = format.parse(".", settings); + UserInputByteMatcher byteMatcher = format.parse(".", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete floating point number", byteMatcher.getDescription()); @@ -66,7 +66,7 @@ public class DoubleSearchFormatTest extends AbstractSearchFormatTest { @Test public void testEndE() { - ByteMatcher byteMatcher = format.parse("2.1e", settings); + UserInputByteMatcher byteMatcher = format.parse("2.1e", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete floating point number", byteMatcher.getDescription()); @@ -74,7 +74,7 @@ public class DoubleSearchFormatTest extends AbstractSearchFormatTest { @Test public void testEndNegativeE() { - ByteMatcher byteMatcher = format.parse("2.1-e", settings); + UserInputByteMatcher byteMatcher = format.parse("2.1-e", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete floating point number", byteMatcher.getDescription()); @@ -82,7 +82,7 @@ public class DoubleSearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative floating point number", byteMatcher.getDescription()); @@ -90,7 +90,7 @@ public class DoubleSearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeDotSignOnly() { - ByteMatcher byteMatcher = format.parse("-.", settings); + UserInputByteMatcher byteMatcher = format.parse("-.", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative floating point number", byteMatcher.getDescription()); @@ -98,7 +98,7 @@ public class DoubleSearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12.z", settings); + UserInputByteMatcher byteMatcher = format.parse("12.z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Floating point parse error: For input string: \"12.z\"", diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/FloatSearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/FloatSearchFormatTest.java index 70d8c7bc2b..1ff9286e82 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/FloatSearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/FloatSearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class FloatSearchFormatTest extends AbstractSearchFormatTest { public FloatSearchFormatTest() { @@ -56,7 +56,7 @@ public class FloatSearchFormatTest extends AbstractSearchFormatTest { @Test public void testDotOnly() { - ByteMatcher byteMatcher = format.parse(".", settings); + UserInputByteMatcher byteMatcher = format.parse(".", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete floating point number", byteMatcher.getDescription()); @@ -64,7 +64,7 @@ public class FloatSearchFormatTest extends AbstractSearchFormatTest { @Test public void testEndE() { - ByteMatcher byteMatcher = format.parse("2.1e", settings); + UserInputByteMatcher byteMatcher = format.parse("2.1e", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete floating point number", byteMatcher.getDescription()); @@ -72,7 +72,7 @@ public class FloatSearchFormatTest extends AbstractSearchFormatTest { @Test public void testEndNegativeE() { - ByteMatcher byteMatcher = format.parse("2.1-e", settings); + UserInputByteMatcher byteMatcher = format.parse("2.1-e", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete floating point number", byteMatcher.getDescription()); @@ -80,7 +80,7 @@ public class FloatSearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative floating point number", byteMatcher.getDescription()); @@ -88,7 +88,7 @@ public class FloatSearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeDotSignOnly() { - ByteMatcher byteMatcher = format.parse("-.", settings); + UserInputByteMatcher byteMatcher = format.parse("-.", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative floating point number", byteMatcher.getDescription()); @@ -96,7 +96,7 @@ public class FloatSearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12.z", settings); + UserInputByteMatcher byteMatcher = format.parse("12.z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Floating point parse error: For input string: \"12.z\"", diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/HexSearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/HexSearchFormatTest.java index 544ddef6cc..01e3083e8b 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/HexSearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/HexSearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class HexSearchFormatTest extends AbstractSearchFormatTest { @@ -147,14 +147,14 @@ public class HexSearchFormatTest extends AbstractSearchFormatTest { @Test public void testGroupTooBig() { - ByteMatcher bad = format.parse("0123456789abcdef0", settings); + UserInputByteMatcher bad = format.parse("0123456789abcdef0", settings); assertFalse(bad.isValidInput()); assertEquals("Max group size exceeded. Enter to add more.", bad.getDescription()); } @Test public void testInvalidChars() { - ByteMatcher bad = format.parse("01z3", settings); + UserInputByteMatcher bad = format.parse("01z3", settings); assertFalse(bad.isValidInput()); assertEquals("Invalid character", bad.getDescription()); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int1SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int1SearchFormatTest.java index c47c287c2f..fea5ff24d4 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int1SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int1SearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class Int1SearchFormatTest extends AbstractSearchFormatTest { public Int1SearchFormatTest() { @@ -49,7 +49,7 @@ public class Int1SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x80); value -= 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-128, 127]", byteMatcher.getDescription()); @@ -62,7 +62,7 @@ public class Int1SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x7f); value += 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-128, 127]", byteMatcher.getDescription()); @@ -70,7 +70,7 @@ public class Int1SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative number", byteMatcher.getDescription()); @@ -78,7 +78,7 @@ public class Int1SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int2SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int2SearchFormatTest.java index 757b59658a..fd95170172 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int2SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int2SearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class Int2SearchFormatTest extends AbstractSearchFormatTest { public Int2SearchFormatTest() { @@ -49,7 +49,7 @@ public class Int2SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x80, 0); value -= 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-32768, 32767]", byteMatcher.getDescription()); @@ -62,7 +62,7 @@ public class Int2SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x7f, 0xff); value += 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-32768, 32767]", byteMatcher.getDescription()); @@ -70,7 +70,7 @@ public class Int2SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative number", byteMatcher.getDescription()); @@ -78,7 +78,7 @@ public class Int2SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int4SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int4SearchFormatTest.java index 8f7e1711ae..7f7dc206af 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int4SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int4SearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class Int4SearchFormatTest extends AbstractSearchFormatTest { public Int4SearchFormatTest() { @@ -49,7 +49,7 @@ public class Int4SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x80, 0, 0, 0); value -= 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-2147483648, 2147483647]", byteMatcher.getDescription()); @@ -62,7 +62,7 @@ public class Int4SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x7f, 0xff, 0xff, 0xff); value += 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-2147483648, 2147483647]", byteMatcher.getDescription()); @@ -70,7 +70,7 @@ public class Int4SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative number", byteMatcher.getDescription()); @@ -78,7 +78,7 @@ public class Int4SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int8SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int8SearchFormatTest.java index 982e7bea90..feb5857f1c 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int8SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/Int8SearchFormatTest.java @@ -21,7 +21,7 @@ import java.math.BigInteger; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class Int8SearchFormatTest extends AbstractSearchFormatTest { public Int8SearchFormatTest() { @@ -54,7 +54,7 @@ public class Int8SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x80, 0, 0, 0, 0, 0, 0, 0); BigInteger bigValue = BigInteger.valueOf(value).subtract(BigInteger.ONE); - ByteMatcher byteMatcher = format.parse(bigValue.toString(), settings); + UserInputByteMatcher byteMatcher = format.parse(bigValue.toString(), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-9223372036854775808, 9223372036854775807]", byteMatcher.getDescription()); @@ -67,7 +67,7 @@ public class Int8SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); BigInteger bigValue = BigInteger.valueOf(value).add(BigInteger.ONE); - ByteMatcher byteMatcher = format.parse(bigValue.toString(), settings); + UserInputByteMatcher byteMatcher = format.parse(bigValue.toString(), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [-9223372036854775808, 9223372036854775807]", byteMatcher.getDescription()); @@ -75,7 +75,7 @@ public class Int8SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertTrue(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Incomplete negative number", byteMatcher.getDescription()); @@ -83,7 +83,7 @@ public class Int8SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/RegExSearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/RegExSearchFormatTest.java index 7f2af90a3f..9fe195fd44 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/RegExSearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/RegExSearchFormatTest.java @@ -19,10 +19,10 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class RegExSearchFormatTest extends AbstractSearchFormatTest { - private ByteMatcher byteMatcher; + private UserInputByteMatcher byteMatcher; public RegExSearchFormatTest() { super(SearchFormat.REG_EX); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt1SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt1SearchFormatTest.java index 6dfa0d87d9..37a4965c7e 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt1SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt1SearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class UInt1SearchFormatTest extends AbstractSearchFormatTest { public UInt1SearchFormatTest() { @@ -48,7 +48,7 @@ public class UInt1SearchFormatTest extends AbstractSearchFormatTest { matcher = parse("0"); assertBytes(0); - ByteMatcher byteMatcher = format.parse("-1", settings); + UserInputByteMatcher byteMatcher = format.parse("-1", settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 255]", byteMatcher.getDescription()); @@ -61,7 +61,7 @@ public class UInt1SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0xff); value += 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 255]", byteMatcher.getDescription()); @@ -69,7 +69,7 @@ public class UInt1SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Negative numbers not allowed for unsigned values", @@ -78,7 +78,7 @@ public class UInt1SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt2SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt2SearchFormatTest.java index 0ed64f5d82..a6c430b3b4 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt2SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt2SearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class UInt2SearchFormatTest extends AbstractSearchFormatTest { public UInt2SearchFormatTest() { @@ -48,7 +48,7 @@ public class UInt2SearchFormatTest extends AbstractSearchFormatTest { matcher = parse("0"); assertBytes(0, 0); - ByteMatcher byteMatcher = format.parse("-1", settings); + UserInputByteMatcher byteMatcher = format.parse("-1", settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 65535]", byteMatcher.getDescription()); @@ -61,7 +61,7 @@ public class UInt2SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0xff, 0xff); value += 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 65535]", byteMatcher.getDescription()); @@ -69,7 +69,7 @@ public class UInt2SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Negative numbers not allowed for unsigned values", @@ -78,7 +78,7 @@ public class UInt2SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt4SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt4SearchFormatTest.java index 34051186f8..3613a7cbd3 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt4SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt4SearchFormatTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class UInt4SearchFormatTest extends AbstractSearchFormatTest { public UInt4SearchFormatTest() { @@ -48,7 +48,7 @@ public class UInt4SearchFormatTest extends AbstractSearchFormatTest { matcher = parse("0"); assertBytes(0, 0, 0, 0); - ByteMatcher byteMatcher = format.parse("-1", settings); + UserInputByteMatcher byteMatcher = format.parse("-1", settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 4294967295]", byteMatcher.getDescription()); @@ -61,7 +61,7 @@ public class UInt4SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0xff, 0xff, 0xff, 0xff); value += 1; - ByteMatcher byteMatcher = format.parse(Long.toString(value), settings); + UserInputByteMatcher byteMatcher = format.parse(Long.toString(value), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 4294967295]", byteMatcher.getDescription()); @@ -69,7 +69,7 @@ public class UInt4SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Negative numbers not allowed for unsigned values", @@ -78,7 +78,7 @@ public class UInt4SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt8SearchFormatTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt8SearchFormatTest.java index 2ba5142353..9cf3520cce 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt8SearchFormatTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/format/UInt8SearchFormatTest.java @@ -21,7 +21,7 @@ import java.math.BigInteger; import org.junit.Test; -import ghidra.features.base.memsearch.matcher.ByteMatcher; +import ghidra.features.base.memsearch.matcher.UserInputByteMatcher; public class UInt8SearchFormatTest extends AbstractSearchFormatTest { public UInt8SearchFormatTest() { @@ -52,7 +52,7 @@ public class UInt8SearchFormatTest extends AbstractSearchFormatTest { matcher = parse("0"); assertBytes(0, 0, 0, 0, 0, 0, 0, 0); - ByteMatcher byteMatcher = format.parse("-1", settings); + UserInputByteMatcher byteMatcher = format.parse("-1", settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 18446744073709551615]", byteMatcher.getDescription()); @@ -65,7 +65,7 @@ public class UInt8SearchFormatTest extends AbstractSearchFormatTest { assertBytes(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); BigInteger bigValue = value.add(BigInteger.ONE); - ByteMatcher byteMatcher = format.parse(bigValue.toString(), settings); + UserInputByteMatcher byteMatcher = format.parse(bigValue.toString(), settings); assertFalse(byteMatcher.isValidInput()); assertEquals("Number must be in the range [0, 18446744073709551615]", byteMatcher.getDescription()); @@ -74,7 +74,7 @@ public class UInt8SearchFormatTest extends AbstractSearchFormatTest { @Test public void testNegativeSignOnly() { - ByteMatcher byteMatcher = format.parse("-", settings); + UserInputByteMatcher byteMatcher = format.parse("-", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Negative numbers not allowed for unsigned values", @@ -83,7 +83,7 @@ public class UInt8SearchFormatTest extends AbstractSearchFormatTest { @Test public void testBadChars() { - ByteMatcher byteMatcher = format.parse("12z", settings); + UserInputByteMatcher byteMatcher = format.parse("12z", settings); assertFalse(byteMatcher.isValidInput()); assertFalse(byteMatcher.isValidSearch()); assertEquals("Number parse error: For input string: \"12z\"", byteMatcher.getDescription()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java index ef96d38e49..03a561ce62 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java @@ -24,8 +24,7 @@ import org.junit.Test; import ghidra.features.base.memsearch.bytesource.AddressableByteSource; import ghidra.features.base.memsearch.bytesource.SearchRegion; -import ghidra.features.base.memsearch.matcher.ByteMatcher; -import ghidra.features.base.memsearch.matcher.RegExByteMatcher; +import ghidra.features.base.memsearch.matcher.*; import ghidra.program.model.address.*; import ghidra.program.util.ProgramLocation; import ghidra.util.datastruct.Accumulator; @@ -38,8 +37,8 @@ public class MemSearcherTest { private TestByteSource bytes; private AddressSpace space; private TaskMonitor monitor = TaskMonitor.DUMMY; - private ByteMatcher bobMatcher = new RegExByteMatcher("bob", null); - private Accumulator accumulator = new ListAccumulator<>(); + private ByteMatcher bobMatcher = new RegExByteMatcher("bob", null); + private Accumulator> accumulator = new ListAccumulator<>(); @Before public void setUp() { @@ -49,27 +48,30 @@ public class MemSearcherTest { @Test public void testFindNext() { bytes = new TestByteSource(addr(0), "xxbobxxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(2, "bob", match); } @Test public void testFindNextStartingAtMatch() { bytes = new TestByteSource(addr(0), "xxbobxxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findNext(addr(2), monitor); + MemoryMatch match = searcher.findNext(addr(2), monitor); assertMatch(2, "bob", match); } @Test public void testFindNextNoMatch() { bytes = new TestByteSource(addr(0), "xxjoexxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertNull(match); } @@ -77,30 +79,30 @@ public class MemSearcherTest { public void testFindNextInSecondChunk() { bytes = new TestByteSource(addr(0), "xxxx xbob x"); // spaces are removed by bytes call AddressSet addresses = bytes.getAddressSet(); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addresses, SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addresses, SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(5, "bob", match); } @Test public void testFindNextInLaterChunk() { bytes = new TestByteSource(addr(0), "xxxx xxxx xxxx xxxx xbob x"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(17, "bob", match); } @Test public void testFindNextMatchSpansChunks() { bytes = new TestByteSource(addr(0), "xxxb obxx"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(3, "bob", match); } @@ -109,76 +111,80 @@ public class MemSearcherTest { bytes = new TestByteSource(addr(0), "xxxxx"); bytes.addBytes(addr(100), "xxxxxboxxbxx"); bytes.addBytes(addr(200), "xxxbobxxxxbobxxxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(203, "bob", match); } @Test public void testFindPrevious() { bytes = new TestByteSource(addr(0), "xxbobxxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findPrevious(addr(100), monitor); + MemoryMatch match = searcher.findPrevious(addr(100), monitor); assertMatch(2, "bob", match); } @Test public void testFindPreviousNoMatch() { bytes = new TestByteSource(addr(0), "xxjoexxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findPrevious(addr(100), monitor); + MemoryMatch match = searcher.findPrevious(addr(100), monitor); assertNull(match); } @Test public void testFindPreviousStartingAtMatch() { bytes = new TestByteSource(addr(0), "xxbobxxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findPrevious(addr(2), monitor); + MemoryMatch match = searcher.findPrevious(addr(2), monitor); assertMatch(2, "bob", match); } @Test public void testFindPreviousInFirstChunk() { bytes = new TestByteSource(addr(0), "xxxx xbob"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findPrevious(addr(100), monitor); + MemoryMatch match = searcher.findPrevious(addr(100), monitor); assertMatch(5, "bob", match); } @Test public void testFindPreviousInSecondChunk() { bytes = new TestByteSource(addr(0), "xbob xxxx"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findPrevious(addr(100), monitor); + MemoryMatch match = searcher.findPrevious(addr(100), monitor); assertMatch(1, "bob", match); } @Test public void testFindPreviousInLaterChunk() { bytes = new TestByteSource(addr(0), "xbob xxxx xxxx xxxx xxxx xxxx x"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findPrevious(addr(100), monitor); + MemoryMatch match = searcher.findPrevious(addr(100), monitor); assertMatch(1, "bob", match); } @Test public void testFindPreviousSpansChunk() { bytes = new TestByteSource(addr(0), "xxbo bxxx"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); - MemoryMatch match = searcher.findPrevious(addr(100), monitor); + MemoryMatch match = searcher.findPrevious(addr(100), monitor); assertMatch(2, "bob", match); } @@ -187,20 +193,21 @@ public class MemSearcherTest { bytes = new TestByteSource(addr(0), "xxbobxxx"); bytes.addBytes(addr(100), "xxxxxboxxbxx"); bytes.addBytes(addr(200), "xxxxxxxbbxxxx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(2, "bob", match); } @Test public void testFindAll() { bytes = new TestByteSource(addr(0), "xbob xxxb obxx xxxx xxbo b"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); searcher.findAll(accumulator, monitor); assertEquals(3, accumulator.size()); - Iterator it = accumulator.iterator(); + Iterator> it = accumulator.iterator(); assertMatch(1, "bob", it.next()); assertMatch(7, "bob", it.next()); assertMatch(18, "bob", it.next()); @@ -212,11 +219,11 @@ public class MemSearcherTest { bytes.addBytes(addr(100), "bobxxxxxx"); bytes.addBytes(addr(200), "xxxxxx"); bytes.addBytes(addr(300), "xxxx xxbo bxxx bob"); - MemorySearcher searcher = - new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT, TINY_CHUNK_SIZE); searcher.findAll(accumulator, monitor); assertEquals(4, accumulator.size()); - Iterator it = accumulator.iterator(); + Iterator> it = accumulator.iterator(); assertMatch(1, "bob", it.next()); assertMatch(100, "bob", it.next()); assertMatch(306, "bob", it.next()); @@ -226,10 +233,11 @@ public class MemSearcherTest { @Test public void testNextWithFilter() { bytes = new TestByteSource(addr(0), "xxbobxxxbob"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); searcher.setMatchFilter(r -> r.getAddress().getOffset() != 2); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(8, "bob", match); } @@ -237,10 +245,11 @@ public class MemSearcherTest { @Test public void testPreviousWithFilter() { bytes = new TestByteSource(addr(0), "xxbobxxxbob"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); searcher.setMatchFilter(r -> r.getAddress().getOffset() != 8); - MemoryMatch match = searcher.findNext(addr(0), monitor); + MemoryMatch match = searcher.findNext(addr(0), monitor); assertMatch(2, "bob", match); } @@ -248,13 +257,14 @@ public class MemSearcherTest { @Test public void testAllWithFilter() { bytes = new TestByteSource(addr(0), "bobx xxbo bxxx xxxx xbob xxxx bobx"); - MemorySearcher searcher = new MemorySearcher(bytes, bobMatcher, addrs(), SEARCH_LIMIT); + MemorySearcher searcher = + new MemorySearcher<>(bytes, bobMatcher, addrs(), SEARCH_LIMIT); searcher.setMatchFilter(r -> r.getAddress().getOffset() % 2 == 0); // only even addresses searcher.findAll(accumulator, monitor); assertEquals(3, accumulator.size()); - Iterator it = accumulator.iterator(); + Iterator> it = accumulator.iterator(); assertMatch(0, "bob", it.next()); assertMatch(6, "bob", it.next()); assertMatch(24, "bob", it.next()); @@ -264,7 +274,7 @@ public class MemSearcherTest { return bytes.getAddressSet(); } - private void assertMatch(int address, String matchString, MemoryMatch match) { + private void assertMatch(int address, String matchString, MemoryMatch match) { assertNotNull(match); assertEquals(addr(address), match.getAddress()); assertEquals(matchString.length(), match.getLength()); diff --git a/Ghidra/Features/BytePatterns/ghidra_scripts/PatternStats.java b/Ghidra/Features/BytePatterns/ghidra_scripts/PatternStats.java index 0cef5597e2..61f15c4846 100644 --- a/Ghidra/Features/BytePatterns/ghidra_scripts/PatternStats.java +++ b/Ghidra/Features/BytePatterns/ghidra_scripts/PatternStats.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -52,7 +52,7 @@ public class PatternStats extends GhidraScript implements PatternFactory { private MatchActionMarker codeBoundary = new MatchActionMarker(MatchActionMarker.CODE_BOUNDARY); private MatchActionMarker context = new MatchActionMarker(MatchActionMarker.CONTEXT); - private SequenceSearchState root; + private SequenceSearchState root; private ArrayList accumList; private FunctionManager functionManager; private Listing listing; @@ -75,7 +75,7 @@ public class PatternStats extends GhidraScript implements PatternFactory { } @Override - public void apply(Program program, Address addr, Match match) { + public void apply(Program program, Address addr, Match match) { } @Override @@ -327,7 +327,7 @@ public class PatternStats extends GhidraScript implements PatternFactory { taskMonitor.setMessage("Byte Search"); taskMonitor.setMaximum((int) block.getSize()); taskMonitor.setProgress(0); - ArrayList mymatches = new ArrayList<>(); + ArrayList> mymatches = new ArrayList<>(); long streamoffset = block.getStart().getOffset(); root.apply(block.getData(), mymatches, taskMonitor); if (taskMonitor.isCancelled()) { @@ -335,13 +335,15 @@ public class PatternStats extends GhidraScript implements PatternFactory { } Address start = block.getStart(); for (int i = 0; i < mymatches.size(); ++i) { - Match match = mymatches.get(i); - Address addr = start.add(match.getMarkOffset()); - if (!match.checkPostRules(streamoffset)) { + Match match = mymatches.get(i); + Pattern pattern = match.getPattern(); + Address addr = start.add(match.getStart() + pattern.getMarkOffset()); + long totalOffset = streamoffset + match.getStart(); + if (!pattern.checkPostRules(totalOffset)) { continue; } - PatternAccumulate accum = accumList.get(match.getSequenceIndex()); - MatchAction[] matchActions = match.getMatchActions(); + PatternAccumulate accum = accumList.get(pattern.getIndex()); + MatchAction[] matchActions = pattern.getMatchActions(); for (MatchAction matchAction : matchActions) { boolean isFalse = collectStats(accum, (MatchActionMarker) matchAction, addr); if (isFalse) { diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java index a19668ff81..83eec4921c 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java @@ -61,8 +61,8 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa private static ProgramDecisionTree patternDecisitionTree; // always need to initialize the root. - SequenceSearchState rootState = null; - SequenceSearchState explicitState = null; //for use during dynamic function start pattern discovery + SequenceSearchState rootState = null; + SequenceSearchState explicitState = null; //for use during dynamic function start pattern discovery private boolean executableBlocksOnly = true; // true if we only analyze executable blocks @@ -120,7 +120,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa * {@link SequenceSearchState#initialize} * @param explicit */ - public void setExplicitState(SequenceSearchState explicit) { + public void setExplicitState(SequenceSearchState explicit) { explicitState = explicit; } @@ -173,7 +173,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa public class CodeBoundaryAction implements MatchAction { @Override - public void apply(Program program, Address addr, Match match) { + public void apply(Program program, Address addr, Match match) { Listing listing = program.getListing(); CodeUnit cu = listing.getCodeUnitContaining(addr); if (cu != null) { @@ -215,7 +215,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa private boolean contiguous = true; // require validcode instructions be contiguous @Override - public void apply(Program program, Address addr, Match match) { + public void apply(Program program, Address addr, Match match) { if (!checkPreRequisites(program, addr)) { // didn't match, get rid of contextValueList contextValueList = null; @@ -291,7 +291,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa } protected void applyActionToSet(Program program, Address addr, AddressSet resultSet, - Match match) { + Match match) { if ((addr.getOffset() % program.getLanguage().getInstructionAlignment()) != 0) { return; // addr is not properly aligned @@ -548,11 +548,11 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa return func; } - void bookmarkAction(Program program, Address addr, Match match) { + void bookmarkAction(Program program, Address addr, Match match) { if (setbookmark) { BookmarkManager bookmarkManager = program.getBookmarkManager(); bookmarkManager.setBookmark(addr, BookmarkType.ANALYSIS, getName(), - "Match pattern " + match.getSequenceIndex()); + "Match pattern " + match.getPattern().getIndex()); } } @@ -682,7 +682,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa public class PossibleFunctionStartAction extends FunctionStartAction { @Override - public void apply(Program program, Address addr, Match match) { + public void apply(Program program, Address addr, Match match) { if (!checkPreRequisites(program, addr)) { return; } @@ -690,11 +690,11 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa } @Override - void bookmarkAction(Program program, Address addr, Match match) { + void bookmarkAction(Program program, Address addr, Match match) { if (setbookmark) { BookmarkManager bookmarkManager = program.getBookmarkManager(); bookmarkManager.setBookmark(addr, BookmarkType.ANALYSIS, "Possible " + getName(), - "Match pattern " + match.getSequenceIndex()); + "Match pattern " + match.getPattern().getIndex()); } } @@ -720,7 +720,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa } @Override - public void apply(Program program, Address addr, Match match) { + public void apply(Program program, Address addr, Match match) { Listing listing = program.getListing(); CodeUnit cu = listing.getCodeUnitContaining(addr); if (cu != null) { @@ -795,7 +795,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { - SequenceSearchState root = initialize(program); + SequenceSearchState root = initialize(program); if (root == null) { String message = "Could not initialize a search state."; log.appendMsg(getName(), message); @@ -930,7 +930,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa return null; } - SequenceSearchState root = SequenceSearchState.buildStateMachine(patternlist); + SequenceSearchState root = SequenceSearchState.buildStateMachine(patternlist); return root; } diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClipboardPanel.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClipboardPanel.java index b42ee0c644..fa96fc2466 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClipboardPanel.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClipboardPanel.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -121,7 +121,7 @@ public class ClipboardPanel extends JPanel { MatchAction[] actions = getMatchActions(funcStartAnalyzer, pattern); pattern.setMatchActions(actions); } - SequenceSearchState root = SequenceSearchState.buildStateMachine(patternList); + SequenceSearchState root = SequenceSearchState.buildStateMachine(patternList); funcStartAnalyzer.setExplicitState(root); AutoAnalysisManager autoManager = AutoAnalysisManager.getAnalysisManager(currentProgram); @@ -214,7 +214,7 @@ public class ClipboardPanel extends JPanel { Msg.showWarn(this, this, "Only Pre-Patterns", "Only Pre-Patterns in selection: no true/false positive information will be calculated."); } - SequenceSearchState root = SequenceSearchState.buildStateMachine(patternList); + SequenceSearchState root = SequenceSearchState.buildStateMachine(patternList); indexToSize.clear(); for (Pattern pattern : patternList) { indexToSize.put(pattern.getIndex(), pattern.getSize()); @@ -235,9 +235,9 @@ public class ClipboardPanel extends JPanel { return matchStats; } - private void searchBlock(SequenceSearchState root, MemoryBlock block, + private void searchBlock(SequenceSearchState root, MemoryBlock block, PatternEvaluationStats matchStats, Program program, TaskMonitor monitor) { - ArrayList mymatches = new ArrayList<>(); + ArrayList> mymatches = new ArrayList<>(); try { root.apply(block.getData(), mymatches, monitor); @@ -250,7 +250,7 @@ public class ClipboardPanel extends JPanel { } for (int i = 0; i < mymatches.size(); ++i) { - Match match = mymatches.get(i); + Match match = mymatches.get(i); if (onlyPrePatterns) { evaluatePrePatternMatch(match, program, block, matchStats); } @@ -262,16 +262,17 @@ public class ClipboardPanel extends JPanel { //Only pre-patterns: don't compute the various kinds of false positives //just show where all of the matches are and warn the user - private void evaluatePrePatternMatch(Match match, Program program, MemoryBlock block, + private void evaluatePrePatternMatch(Match match, Program program, MemoryBlock block, PatternEvaluationStats matchStats) { Address blockStart = block.getStart(); - Address matchStart = blockStart.add(match.getMatchStart()); - Address funcStart = matchStart.add(indexToSize.get(match.getSequenceIndex())); + Pattern pattern = match.getPattern(); + Address matchStart = blockStart.add(match.getStart()); + Address funcStart = matchStart.add(indexToSize.get(pattern.getIndex())); Address patternEnd = funcStart.add(-1); - int totalBits = match.getSequence().getNumFixedBits(); + int totalBits = pattern.getNumFixedBits(); int postBits = 0; PatternEvalRowObject rowObject = new PatternEvalRowObject(PatternMatchType.PRE_PATTERN_HIT, - new AddressSet(matchStart, patternEnd), match.getHexString(), funcStart, postBits, + new AddressSet(matchStart, patternEnd), pattern.getHexString(), funcStart, postBits, totalBits); matchStats.addRowObject(rowObject); return; @@ -280,34 +281,41 @@ public class ClipboardPanel extends JPanel { //if something falls through to it: not a function start //if there is just a jump to it: possibly a function start - private void evaluateMatch(Match match, Program program, MemoryBlock block, + private void evaluateMatch(Match match, Program program, MemoryBlock block, PatternEvaluationStats matchStats) { Address blockStart = block.getStart(); int alignment = program.getLanguage().getInstructionAlignment(); - Address matchStart = blockStart.add(match.getMatchStart()); + Address matchStart = blockStart.add(match.getStart()); if (matchStart.getOffset() % alignment != 0) { return; //inconsistent with instruction alignment for language } long streamoffset = blockStart.getOffset(); - if (!match.checkPostRules(streamoffset)) { + Pattern pattern = match.getPattern(); + if (!pattern.checkPostRules(streamoffset)) { return; } - Address matchEnd = matchStart.add(indexToSize.get(match.getSequenceIndex()) - 1); - Address funcStart = blockStart.add(match.getMarkOffset()); + Address matchEnd = matchStart.add(indexToSize.get(pattern.getIndex()) - 1); + Address funcStart = blockStart.add(match.getStart() + pattern.getMarkOffset()); //see whether the pattern conflict with any existing context //perhaps this should be after? - ContextRegisterFilter cRegFilter = sequenceToCRegFilter.get(match.getSequence()); - int totalBits = match.getSequence().getNumFixedBits(); - int postBits = match.getNumPostBits(); + ContextRegisterFilter cRegFilter = sequenceToCRegFilter.get(pattern); + int totalBits = pattern.getNumFixedBits(); + int postBits = getNumPostBits(pattern); int index = (totalBits - postBits) / BITS_PER_BYTE - 1; PatternMatchType type = getMatchType(program, funcStart, cRegFilter); PatternEvalRowObject rowObject = new PatternEvalRowObject(type, new AddressSet(matchStart, matchEnd), - addSeparator(match.getHexString(), index), funcStart, postBits, totalBits); + addSeparator(pattern.getHexString(), index), funcStart, postBits, totalBits); matchStats.addRowObject(rowObject); } - + private int getNumPostBits(Pattern pattern) { + int marked = pattern.getMarkOffset(); + if (marked == 0) { + return pattern.getNumFixedBits(); + } + return pattern.getNumFixedBits() - pattern.getNumInitialFixedBits(marked); + } private PatternMatchType getMatchType(Program program, Address funcStart, ContextRegisterFilter cRegFilter) { if (cRegFilter != null) { diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java index 7ad5223236..b69e128b1c 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java @@ -127,13 +127,13 @@ public class AARCH64PltThunkAnalyzer extends AbstractAnalyzer { return true; } - SequenceSearchState sequenceSearchState = SequenceSearchState.buildStateMachine( + SequenceSearchState sequenceSearchState = SequenceSearchState.buildStateMachine( leThunkPatterns); monitor.setIndeterminate(true); monitor.setProgress(0); - ArrayList matches = new ArrayList<>(); + ArrayList> matches = new ArrayList<>(); try { for (AddressRange range : set.getAddressRanges()) { @@ -147,9 +147,10 @@ public class AARCH64PltThunkAnalyzer extends AbstractAnalyzer { matches.clear(); sequenceSearchState.apply(bytes, matches); - for (Match match : matches) { - Address addr = range.getMinAddress().add(match.getMarkOffset()); - analyzePltThunk(program, addr, match.getSequenceSize(), monitor); + for (Match match : matches) { + Pattern pattern = match.getPattern(); + Address addr = range.getMinAddress().add(match.getStart() + pattern.getMarkOffset()); + analyzePltThunk(program, addr, match.getLength(), monitor); } }