GP-2835 addressing code review comments

This commit is contained in:
James 2022-11-22 09:11:16 -05:00
parent 88b7734608
commit 74040472fb
9 changed files with 118 additions and 104 deletions

View file

@ -113,7 +113,8 @@ public class FindFunctionsRFExampleScript extends GhidraScript {
//show the true function starts most similar to one of the false positives //show the true function starts most similar to one of the false positives
if (!falsePositives.isEmpty()) { if (!falsePositives.isEmpty()) {
SimilarStartsFinder finder = new SimilarStartsFinder(currentProgram, best); SimilarStartsFinder finder =
new SimilarStartsFinder(currentProgram, currentProgram, best);
List<SimilarStartRowObject> neighbors = List<SimilarStartRowObject> neighbors =
finder.getSimilarFunctionStarts(falsePositives.get(0).getKey(), 10); finder.getSimilarFunctionStarts(falsePositives.get(0).getKey(), 10);
printf("\nClosest function starts to false positive at %s :\n", printf("\nClosest function starts to false positive at %s :\n",

View file

@ -181,8 +181,8 @@
is measured using <b>random forest proximity</b>. Given a potential start <i>p</i> and is measured using <b>random forest proximity</b>. Given a potential start <i>p</i> and
a known start <i>s</i>, the similarity of <i>p</i> and <i>s</i> is the proportion of trees a known start <i>s</i>, the similarity of <i>p</i> and <i>s</i> is the proportion of trees
which end up in the same leaf node when processing <i>p</i> and <i>s</i>. </P> which end up in the same leaf node when processing <i>p</i> and <i>s</i>. </P>
<P> For convenience, the potential start is also displayed as a row in the table. In <P> For convenience, the potential start is displayed in a table with a single row directly
the Address column, its address is surrounded by asterisks.</P> above the similar starts table.</P>
<H2><A name="DebugModelTable"></A> Debug Model Table </H2> <H2><A name="DebugModelTable"></A> Debug Model Table </H2>
<P> This table has the same format as the <A href="#FunctionStartTable">Potential Functions Table</A> <P> This table has the same format as the <A href="#FunctionStartTable">Potential Functions Table</A>

View file

@ -16,7 +16,6 @@
package ghidra.machinelearning.functionfinding; package ghidra.machinelearning.functionfinding;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.LongStream; import java.util.stream.LongStream;
@ -35,13 +34,12 @@ import docking.widgets.table.threaded.GThreadedTablePanel;
import docking.widgets.textfield.IntegerTextField; import docking.widgets.textfield.IntegerTextField;
import ghidra.app.services.ProgramManager; import ghidra.app.services.ProgramManager;
import ghidra.framework.main.DataTreeDialog; import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.model.DomainFile;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.layout.PairLayout; import ghidra.util.layout.PairLayout;
import ghidra.util.table.SelectionNavigationAction; import ghidra.util.table.SelectionNavigationAction;
import ghidra.util.table.actions.MakeProgramSelectionAction; import ghidra.util.table.actions.MakeProgramSelectionAction;
@ -145,7 +143,6 @@ public class FunctionStartRFParamsDialog extends DialogComponentProvider {
private RandomForestTableModel tableModel; private RandomForestTableModel tableModel;
private Program trainingSource; private Program trainingSource;
private FunctionStartRFParams params; private FunctionStartRFParams params;
private Set<Program> openPrograms;
private Vector<Long> moduli = new Vector<>(Arrays.asList(new Long[] { 4l, 8l, 16l, 32l })); private Vector<Long> moduli = new Vector<>(Arrays.asList(new Long[] { 4l, 8l, 16l, 32l }));
private GComboBox<Long> modBox; private GComboBox<Long> modBox;
private JButton trainButton; private JButton trainButton;
@ -164,7 +161,6 @@ public class FunctionStartRFParamsDialog extends DialogComponentProvider {
true, true); true, true);
this.plugin = plugin; this.plugin = plugin;
rowObjects = new ArrayList<>(); rowObjects = new ArrayList<>();
openPrograms = new HashSet<>();
trainingSource = plugin.getCurrentProgram(); trainingSource = plugin.getCurrentProgram();
JPanel panel = createPanel(); JPanel panel = createPanel();
addWorkPanel(panel); addWorkPanel(panel);
@ -487,24 +483,37 @@ public class FunctionStartRFParamsDialog extends DialogComponentProvider {
} }
private void searchOtherProgram(RandomForestRowObject modelRow) { private void searchOtherProgram(RandomForestRowObject modelRow) {
Program p = selectProgram(); DataTreeDialog dtd = new DataTreeDialog(null, "Select Program", DataTreeDialog.OPEN, f -> {
if (p == null) { Class<?> c = f.getDomainObjectClass();
return Program.class.isAssignableFrom(c);
});
dtd.show();
DomainFile dFile = dtd.getDomainFile();
if (dFile == null) {
return; return;
} }
ProgramManager pm = plugin.getTool().getService(ProgramManager.class); ProgramManager pm = plugin.getTool().getService(ProgramManager.class);
pm.openProgram(p, ProgramManager.OPEN_VISIBLE); Program p = pm.openProgram(dFile, DomainFile.DEFAULT_VERSION, ProgramManager.OPEN_VISIBLE);
if (p == null) {
return;
}
if (!isProgramCompatible(p)) {
Msg.showWarn(this, null, "Incompatible Program", p.getName() +
" is not compatible with training source program " + trainingSource.getName());
return;
}
searchProgram(p, modelRow); searchProgram(p, modelRow);
} }
private void showTestErrors(RandomForestRowObject modelRow) { private void showTestErrors(RandomForestRowObject modelRow) {
FunctionStartTableProvider provider = new FunctionStartTableProvider(plugin, trainingSource, FunctionStartTableProvider provider = new FunctionStartTableProvider(plugin, trainingSource,
modelRow.getTestErrors(), modelRow, true); modelRow.getTestErrors(), modelRow, true);
addGeneralActions(provider); addGeneralActions(provider, trainingSource);
} }
private void searchProgram(Program prog, RandomForestRowObject modelRow) { private void searchProgram(Program targetProgram, RandomForestRowObject modelRow) {
GetAddressesToClassifyTask getTask = GetAddressesToClassifyTask getTask =
new GetAddressesToClassifyTask(prog, plugin.getMinUndefinedRangeSize()); new GetAddressesToClassifyTask(targetProgram, plugin.getMinUndefinedRangeSize());
//don't want to use the dialog's progress bar //don't want to use the dialog's progress bar
TaskLauncher.launchModal("Gathering Addresses To Classify", getTask); TaskLauncher.launchModal("Gathering Addresses To Classify", getTask);
if (getTask.isCancelled()) { if (getTask.isCancelled()) {
@ -518,25 +527,25 @@ public class FunctionStartRFParamsDialog extends DialogComponentProvider {
execNonFunc = getTask.getAddressesToClassify(); execNonFunc = getTask.getAddressesToClassify();
} }
FunctionStartTableProvider provider = FunctionStartTableProvider provider =
new FunctionStartTableProvider(plugin, prog, execNonFunc, modelRow, false); new FunctionStartTableProvider(plugin, targetProgram, execNonFunc, modelRow, false);
addGeneralActions(provider); addGeneralActions(provider, targetProgram);
DisassembleFunctionStartsAction disassembleAction = null; DisassembleFunctionStartsAction disassembleAction = null;
if (params.isRestrictedByContext()) { if (params.isRestrictedByContext()) {
disassembleAction = new DisassembleAndApplyContextAction(plugin, prog, disassembleAction = new DisassembleAndApplyContextAction(plugin, targetProgram,
provider.getTable(), provider.getTableModel()); provider.getTable(), provider.getTableModel());
} }
else { else {
disassembleAction = new DisassembleFunctionStartsAction(plugin, prog, disassembleAction = new DisassembleFunctionStartsAction(plugin, targetProgram,
provider.getTable(), provider.getTableModel()); provider.getTable(), provider.getTableModel());
} }
plugin.getTool().addLocalAction(provider, disassembleAction); plugin.getTool().addLocalAction(provider, disassembleAction);
CreateFunctionsAction createActions = CreateFunctionsAction createActions = new CreateFunctionsAction(plugin, targetProgram,
new CreateFunctionsAction(plugin, prog, provider.getTable(), provider.getTableModel()); provider.getTable(), provider.getTableModel());
plugin.getTool().addLocalAction(provider, createActions); plugin.getTool().addLocalAction(provider, createActions);
} }
private void addGeneralActions(FunctionStartTableProvider provider) { private void addGeneralActions(FunctionStartTableProvider provider, Program targetProgram) {
plugin.addProvider(provider); plugin.addProvider(provider);
DockingAction programSelectAction = DockingAction programSelectAction =
new MakeProgramSelectionAction(plugin, provider.getTable()); new MakeProgramSelectionAction(plugin, provider.getTable());
@ -545,35 +554,11 @@ public class FunctionStartRFParamsDialog extends DialogComponentProvider {
DockingAction selectNavigationAction = DockingAction selectNavigationAction =
new SelectionNavigationAction(plugin, provider.getTable()); new SelectionNavigationAction(plugin, provider.getTable());
plugin.getTool().addLocalAction(provider, selectNavigationAction); plugin.getTool().addLocalAction(provider, selectNavigationAction);
ShowSimilarStartsAction similarStarts = new ShowSimilarStartsAction(plugin, ShowSimilarStartsAction similarStarts = new ShowSimilarStartsAction(plugin, trainingSource,
plugin.getCurrentProgram(), provider.getTable(), provider.getTableModel()); targetProgram, provider.getTable(), provider.getTableModel());
plugin.getTool().addLocalAction(provider, similarStarts); plugin.getTool().addLocalAction(provider, similarStarts);
} }
private Program selectProgram() {
DataTreeDialog dtd = new DataTreeDialog(null, "Select Program", DataTreeDialog.OPEN, f -> {
Class<?> c = f.getDomainObjectClass();
return Program.class.isAssignableFrom(c);
});
dtd.show();
if (dtd.wasCancelled()) {
return null;
}
Program otherProgram = null;
try {
otherProgram = (Program) dtd.getDomainFile()
.getDomainObject(plugin, true, true, getTaskMonitorComponent());
openPrograms.add(otherProgram);
}
catch (VersionException | CancelledException | IOException e) {
return null;
}
if (isProgramCompatible(otherProgram)) {
return otherProgram;
}
return null;
}
//checks whether otherProgram contains any specified context registers //checks whether otherProgram contains any specified context registers
//at some point might be worth adding more restrictions //at some point might be worth adding more restrictions
private boolean isProgramCompatible(Program otherProgram) { private boolean isProgramCompatible(Program otherProgram) {

View file

@ -30,6 +30,7 @@ import ghidra.app.events.ProgramLocationPluginEvent;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin; import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.GoToService; import ghidra.app.services.GoToService;
import ghidra.app.services.ProgramManager;
import ghidra.framework.options.OptionsChangeListener; import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginInfo; import ghidra.framework.plugintool.PluginInfo;
@ -43,12 +44,12 @@ import ghidra.util.bean.opteditor.OptionsVetoException;
//@formatter:off //@formatter:off
@PluginInfo( @PluginInfo(
status = PluginStatus.UNSTABLE, status = PluginStatus.RELEASED,
packageName = MiscellaneousPluginPackage.NAME, packageName = MiscellaneousPluginPackage.NAME,
category = PluginCategoryNames.ANALYSIS, category = PluginCategoryNames.ANALYSIS,
shortDescription = "Function Finder", shortDescription = "Function Finder",
description = "Trains a random forest model to find function starts.", description = "Trains a random forest model to find function starts.",
servicesRequired = { GoToService.class}, servicesRequired = { GoToService.class, ProgramManager.class},
eventsProduced = { ProgramLocationPluginEvent.class }, eventsProduced = { ProgramLocationPluginEvent.class },
eventsConsumed = { ProgramClosedPluginEvent.class} eventsConsumed = { ProgramClosedPluginEvent.class}
) )
@ -212,10 +213,6 @@ public class RandomForestFunctionFinderPlugin extends ProgramPlugin
if (paramsDialog == null) { if (paramsDialog == null) {
paramsDialog = new FunctionStartRFParamsDialog(this); paramsDialog = new FunctionStartRFParamsDialog(this);
} }
if (!paramsDialog.getTrainingSource().equals(this.getCurrentProgram())) {
paramsDialog.dismissCallback();
paramsDialog = new FunctionStartRFParamsDialog(this);
}
tool.showDialog(paramsDialog, c.getComponentProvider()); tool.showDialog(paramsDialog, c.getComponentProvider());
} }

View file

@ -33,7 +33,8 @@ public class ShowSimilarStartsAction extends DockingAction {
private static final String MENU_TEXT = "Show Similar Function Starts"; private static final String MENU_TEXT = "Show Similar Function Starts";
private static final String ACTION_NAME = "ShowSimilarStartsAction"; private static final String ACTION_NAME = "ShowSimilarStartsAction";
private static final int NUM_NEIGHBORS = 10; private static final int NUM_NEIGHBORS = 10;
private Program program; private Program trainingSource;
private Program targetProgram;
private FunctionStartTableModel model; private FunctionStartTableModel model;
private GhidraTable table; private GhidraTable table;
private RandomForestRowObject modelAndParams; private RandomForestRowObject modelAndParams;
@ -43,20 +44,22 @@ public class ShowSimilarStartsAction extends DockingAction {
/** /**
* Constructs an action display similar function starts * Constructs an action display similar function starts
* @param plugin plugin * @param plugin plugin
* @param program source program * @param trainingSource source of training data
* @param targetProgram program being searched
* @param table table * @param table table
* @param model table with action * @param model table with action
*/ */
public ShowSimilarStartsAction(RandomForestFunctionFinderPlugin plugin, Program program, public ShowSimilarStartsAction(RandomForestFunctionFinderPlugin plugin, Program trainingSource,
GhidraTable table, FunctionStartTableModel model) { Program targetProgram, GhidraTable table, FunctionStartTableModel model) {
super(ACTION_NAME, plugin.getName()); super(ACTION_NAME, plugin.getName());
this.program = program; this.trainingSource = trainingSource;
this.targetProgram = targetProgram;
this.model = model; this.model = model;
this.table = table; this.table = table;
this.plugin = plugin; this.plugin = plugin;
this.modelAndParams = model.getRandomForestRowObject(); this.modelAndParams = model.getRandomForestRowObject();
init(); init();
finder = new SimilarStartsFinder(program, modelAndParams); finder = new SimilarStartsFinder(trainingSource, targetProgram, modelAndParams);
} }
@Override @Override
@ -74,8 +77,8 @@ public class ShowSimilarStartsAction extends DockingAction {
Address potential = model.getAddress(table.getSelectedRow()); Address potential = model.getAddress(table.getSelectedRow());
List<SimilarStartRowObject> closeNeighbors = List<SimilarStartRowObject> closeNeighbors =
finder.getSimilarFunctionStarts(potential, NUM_NEIGHBORS); finder.getSimilarFunctionStarts(potential, NUM_NEIGHBORS);
SimilarStartsTableProvider provider = new SimilarStartsTableProvider(plugin, program, SimilarStartsTableProvider provider = new SimilarStartsTableProvider(plugin, trainingSource,
potential, closeNeighbors, modelAndParams); targetProgram, potential, closeNeighbors, modelAndParams);
plugin.addProvider(provider); plugin.addProvider(provider);
} }

View file

@ -35,11 +35,13 @@ import ghidra.program.model.listing.Program;
* function starts, this class is used to find the function starts in the training set * function starts, this class is used to find the function starts in the training set
* most similar to {@code S}. Here "similar" is defined in terms of proximity in a * most similar to {@code S}. Here "similar" is defined in terms of proximity in a
* random forest (i.e., proportion of trees which agree on two feature vectors). * random forest (i.e., proportion of trees which agree on two feature vectors).
* Note that {@code S} may or may not be in the training source program.
*/ */
public class SimilarStartsFinder { public class SimilarStartsFinder {
private RandomForestRowObject modelAndParams; private RandomForestRowObject modelAndParams;
private Program program; private Program trainingSource;
private Program targetProgram;
private int preBytes; private int preBytes;
private int initialBytes; private int initialBytes;
private boolean includeBitFeatures; private boolean includeBitFeatures;
@ -48,11 +50,14 @@ public class SimilarStartsFinder {
/** /**
* Creates a {@link SimilarStartsFinder} for the given program and model * Creates a {@link SimilarStartsFinder} for the given program and model
* @param program program * @param trainingSource source of training data
* @param targetProgram program being searched
* @param modelAndParams model and params * @param modelAndParams model and params
*/ */
public SimilarStartsFinder(Program program, RandomForestRowObject modelAndParams) { public SimilarStartsFinder(Program trainingSource, Program targetProgram,
this.program = program; RandomForestRowObject modelAndParams) {
this.trainingSource = trainingSource;
this.targetProgram = targetProgram;
this.modelAndParams = modelAndParams; this.modelAndParams = modelAndParams;
preBytes = modelAndParams.getNumPreBytes(); preBytes = modelAndParams.getNumPreBytes();
initialBytes = modelAndParams.getNumInitialBytes(); initialBytes = modelAndParams.getNumInitialBytes();
@ -69,7 +74,7 @@ public class SimilarStartsFinder {
* @return similar starts (in descending order) * @return similar starts (in descending order)
*/ */
public List<SimilarStartRowObject> getSimilarFunctionStarts(Address potential, int numStarts) { public List<SimilarStartRowObject> getSimilarFunctionStarts(Address potential, int numStarts) {
List<Node<Label>> leafNodes = getLeafNodes(potential); List<Node<Label>> leafNodes = getLeafNodes(potential, targetProgram);
List<SimilarStartRowObject> neighbors = new ArrayList<>(startsToLeafList.size()); List<SimilarStartRowObject> neighbors = new ArrayList<>(startsToLeafList.size());
for (Entry<Address, List<Node<Label>>> entry : startsToLeafList.entrySet()) { for (Entry<Address, List<Node<Label>>> entry : startsToLeafList.entrySet()) {
Address start = entry.getKey(); Address start = entry.getKey();
@ -99,7 +104,7 @@ public class SimilarStartsFinder {
AddressIterator addrIter = knownStarts.getAddresses(true); AddressIterator addrIter = knownStarts.getAddresses(true);
while (addrIter.hasNext()) { while (addrIter.hasNext()) {
Address start = addrIter.next(); Address start = addrIter.next();
List<Node<Label>> nodeList = getLeafNodes(start); List<Node<Label>> nodeList = getLeafNodes(start, trainingSource);
startsToLeafList.put(start, nodeList); startsToLeafList.put(start, nodeList);
} }
} }
@ -107,10 +112,11 @@ public class SimilarStartsFinder {
/** /**
* Creates a feature vector for {@code addr}, runs it down each tree in the forest, * Creates a feature vector for {@code addr}, runs it down each tree in the forest,
* and records the leaf node reached. * and records the leaf node reached.
* @param addr potential function start * @param addr (potential) function start
* @param program program containing {@code addr}
* @return list of leaf nodes * @return list of leaf nodes
*/ */
List<Node<Label>> getLeafNodes(Address addr) { List<Node<Label>> getLeafNodes(Address addr, Program program) {
List<Node<Label>> leafNodes = new ArrayList<>(randomForest.getNumModels()); List<Node<Label>> leafNodes = new ArrayList<>(randomForest.getNumModels());
List<Feature> potentialFeatureVector = ModelTrainingUtils.getFeatureVector(program, addr, List<Feature> potentialFeatureVector = ModelTrainingUtils.getFeatureVector(program, addr,
preBytes, initialBytes, includeBitFeatures); preBytes, initialBytes, includeBitFeatures);

View file

@ -41,7 +41,6 @@ import ghidra.util.task.TaskMonitor;
*/ */
public class SimilarStartsTableModel extends AddressBasedTableModel<SimilarStartRowObject> { public class SimilarStartsTableModel extends AddressBasedTableModel<SimilarStartRowObject> {
private Address potentialStart;
private List<SimilarStartRowObject> rows; private List<SimilarStartRowObject> rows;
private RandomForestRowObject randomForestRow; private RandomForestRowObject randomForestRow;
@ -50,14 +49,12 @@ public class SimilarStartsTableModel extends AddressBasedTableModel<SimilarStart
* a potential function start * a potential function start
* @param plugin owning program * @param plugin owning program
* @param program program * @param program program
* @param potentialStart address of potential start
* @param rows similar function starts * @param rows similar function starts
* @param randomForestRow model and params * @param randomForestRow model and params
*/ */
public SimilarStartsTableModel(PluginTool plugin, Program program, Address potentialStart, public SimilarStartsTableModel(PluginTool plugin, Program program,
List<SimilarStartRowObject> rows, RandomForestRowObject randomForestRow) { List<SimilarStartRowObject> rows, RandomForestRowObject randomForestRow) {
super("test", plugin, program, null, false); super("Similar Starts", plugin, program, null, false);
this.potentialStart = potentialStart;
this.rows = rows; this.rows = rows;
this.randomForestRow = randomForestRow; this.randomForestRow = randomForestRow;
} }
@ -70,10 +67,6 @@ public class SimilarStartsTableModel extends AddressBasedTableModel<SimilarStart
@Override @Override
protected void doLoad(Accumulator<SimilarStartRowObject> accumulator, TaskMonitor monitor) protected void doLoad(Accumulator<SimilarStartRowObject> accumulator, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
//add a special row corresponding to the potential function start
//want it in the table to facilitate (visual) byte string comparisons
accumulator.add(new SimilarStartRowObject(potentialStart,
randomForestRow.getRandomForest().getNumModels()));
accumulator.addAll(rows); accumulator.addAll(rows);
} }
@ -99,11 +92,6 @@ public class SimilarStartsTableModel extends AddressBasedTableModel<SimilarStart
public String getValue(SimilarStartRowObject rowObject, Settings settings, Object data, public String getValue(SimilarStartRowObject rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException { ServiceProvider services) throws IllegalArgumentException {
String addrString = rowObject.funcStart().toString(); String addrString = rowObject.funcStart().toString();
//address corresponding to the potential start should stand out in the table
//so surround it with asterisks
if (rowObject.funcStart().equals(potentialStart)) {
addrString = "*" + addrString + "*";
}
return addrString; return addrString;
} }
} }

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.machinelearning.functionfinding; package ghidra.machinelearning.functionfinding;
import java.awt.BorderLayout;
import java.awt.Dimension; import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.*; import javax.swing.*;
@ -33,29 +33,35 @@ import ghidra.util.table.GhidraThreadedTablePanel;
* set to a potential function start * set to a potential function start
*/ */
public class SimilarStartsTableProvider extends ProgramAssociatedComponentProviderAdapter { public class SimilarStartsTableProvider extends ProgramAssociatedComponentProviderAdapter {
private Program program; private Program trainingSource;
private Program targetProgram;
private Address potentialStart; private Address potentialStart;
private List<SimilarStartRowObject> rows; private List<SimilarStartRowObject> rows;
private JComponent component; private JSplitPane component;
private RandomForestRowObject randomForestRow; private RandomForestRowObject randomForestRow;
/** /**
* Create a table provider * Create a table provider
* @param plugin owning plugin * @param plugin owning plugin
* @param program program being search * @param trainingSource source of training data
* @param targetProgram program being searched
* @param potentialStart address of potential start * @param potentialStart address of potential start
* @param rows closest potential starts * @param rows closest potential starts
* @param randomForestRow model and params * @param randomForestRow model and params
*/ */
public SimilarStartsTableProvider(RandomForestFunctionFinderPlugin plugin, Program program, public SimilarStartsTableProvider(RandomForestFunctionFinderPlugin plugin,
Address potentialStart, List<SimilarStartRowObject> rows, Program trainingSource, Program targetProgram, Address potentialStart,
RandomForestRowObject randomForestRow) { List<SimilarStartRowObject> rows, RandomForestRowObject randomForestRow) {
super(program.getName() + ": Similar Function Starts", plugin.getName(), program, plugin); super("Potential Start in " + targetProgram.getName(), plugin.getName(), targetProgram,
this.program = program; plugin);
this.trainingSource = trainingSource;
this.targetProgram = targetProgram;
this.potentialStart = potentialStart; this.potentialStart = potentialStart;
this.rows = rows; this.rows = rows;
this.randomForestRow = randomForestRow; this.randomForestRow = randomForestRow;
this.setSubTitle("Function Starts Similar to " + potentialStart.toString()); this.setSubTitle(
potentialStart.toString() + " compared to closest known starts in training set (from " +
trainingSource.getName() + ")");
build(); build();
setHelpLocation(new HelpLocation(plugin.getName(), "SimilarStartsTable")); setHelpLocation(new HelpLocation(plugin.getName(), "SimilarStartsTable"));
} }
@ -65,23 +71,51 @@ public class SimilarStartsTableProvider extends ProgramAssociatedComponentProvid
return component; return component;
} }
/**
* Builds the main component for this provider.
* <P>
* The component is a {@code JSplitPanel} with two {@link GhidraTable}s. The upper
* table consists of a single row containing the potential function start. The rows
* of the lower table contain the function starts in the training source program closest to
* the potential function start. Both tables are navigable; note that the potential
* function start may or may not be in training source program.
*/
private void build() { private void build() {
component = new JPanel(new BorderLayout()); SimilarStartsTableModel similarStartsModel =
SimilarStartsTableModel model = new SimilarStartsTableModel(tool, trainingSource, rows, randomForestRow);
new SimilarStartsTableModel(tool, program, potentialStart, rows, randomForestRow);
GhidraThreadedTablePanel<SimilarStartRowObject> similarStartsPanel = GhidraThreadedTablePanel<SimilarStartRowObject> similarStartsPanel =
new GhidraThreadedTablePanel<>(model, 1000); new GhidraThreadedTablePanel<>(similarStartsModel, 1000);
GhidraTable similarStartsTable = similarStartsPanel.getTable(); GhidraTable similarStartsTable = similarStartsPanel.getTable();
similarStartsTable.setName( similarStartsPanel.setName(
program.getName() + ": Known Starts Similar to " + potentialStart.toString()); targetProgram.getName() + ": Known Starts Similar to " + potentialStart.toString());
GoToService goToService = tool.getService(GoToService.class); GoToService goToService = tool.getService(GoToService.class);
if (goToService != null) { if (goToService != null) {
similarStartsTable.installNavigation(goToService, goToService.getDefaultNavigatable()); similarStartsTable.installNavigation(goToService, goToService.getDefaultNavigatable());
} }
similarStartsTable.setNavigateOnSelectionEnabled(true); similarStartsTable.setNavigateOnSelectionEnabled(true);
similarStartsTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); similarStartsTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
similarStartsTable.setPreferredScrollableViewportSize(new Dimension(900, 300)); similarStartsTable.setPreferredScrollableViewportSize(new Dimension(700, 200));
component.add(similarStartsPanel, BorderLayout.CENTER); similarStartsTable.setToolTipText("Known Starts in " + trainingSource.getName());
List<SimilarStartRowObject> singleton = new ArrayList<>();
singleton.add(new SimilarStartRowObject(potentialStart,
randomForestRow.getRandomForest().getNumModels()));
SimilarStartsTableModel potentialStartSingletonModel =
new SimilarStartsTableModel(tool, targetProgram, singleton, randomForestRow);
GhidraThreadedTablePanel<SimilarStartRowObject> potentialStartPanel =
new GhidraThreadedTablePanel<>(potentialStartSingletonModel, 1000);
GhidraTable potentialStartTable = potentialStartPanel.getTable();
potentialStartTable
.setToolTipText("Potential Function Start in " + targetProgram.getName());
if (goToService != null) {
potentialStartTable.installNavigation(goToService, goToService.getDefaultNavigatable());
}
potentialStartTable.setNavigateOnSelectionEnabled(true);
potentialStartTable.setPreferredScrollableViewportSize(new Dimension(700, 30));
potentialStartTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
component =
new JSplitPane(JSplitPane.VERTICAL_SPLIT, potentialStartPanel, similarStartsPanel);
component.setResizeWeight(.1);
} }
} }

View file

@ -117,7 +117,7 @@ public class RandomForestTrainingTaskTest extends AbstractProgramBasedTest {
RandomForestFunctionFinderPlugin.NON_START, 1, 1, true, TaskMonitor.DUMMY)); RandomForestFunctionFinderPlugin.NON_START, 1, 1, true, TaskMonitor.DUMMY));
LabelFactory lf = new LabelFactory(); LabelFactory lf = new LabelFactory();
ListDataSource<Label> trainingSource = ListDataSource<Label> trainingSource =
new ListDataSource<Label>(trainingData, lf, new SimpleDataSourceProvenance("test", lf)); new ListDataSource<>(trainingData, lf, new SimpleDataSourceProvenance("test", lf));
MutableDataset<Label> trainingSet = new MutableDataset<>(trainingSource); MutableDataset<Label> trainingSet = new MutableDataset<>(trainingSource);
//create ensemble with two models which always report FUNC_START //create ensemble with two models which always report FUNC_START
@ -199,7 +199,7 @@ public class RandomForestTrainingTaskTest extends AbstractProgramBasedTest {
new RandomForestTrainingTask(program, params, x -> rows.add(x), 100); new RandomForestTrainingTask(program, params, x -> rows.add(x), 100);
TaskLauncher.launchModal("test", task); TaskLauncher.launchModal("test", task);
assertEquals(1, rows.size()); assertEquals(1, rows.size());
SimilarStartsFinder finder = new SimilarStartsFinder(program, rows.get(0)); SimilarStartsFinder finder = new SimilarStartsFinder(program, program, rows.get(0));
Address entryAddr = program.getSymbolTable().getSymbols("entry").next().getAddress(); Address entryAddr = program.getSymbolTable().getSymbols("entry").next().getAddress();
List<SimilarStartRowObject> res = finder.getSimilarFunctionStarts(entryAddr, 7); List<SimilarStartRowObject> res = finder.getSimilarFunctionStarts(entryAddr, 7);
//just verify that the number of elements is correct, each element is a function start, //just verify that the number of elements is correct, each element is a function start,