Candidate release of source code.

This commit is contained in:
Dan 2019-03-26 13:45:32 -04:00
parent db81e6b3b0
commit 79d8f164f8
12449 changed files with 2800756 additions and 16 deletions

View file

@ -0,0 +1,10 @@
apply plugin: 'eclipse'
eclipse.project.name = 'Xtra SampleTablePlugin'
apply from: "$rootProject.projectDir/gradleScripts/buildHelp.gradle"
project.ext.includeExtensionInInstallation = true
dependencies {
compile project(':Base')
}

View file

@ -0,0 +1,23 @@
##VERSION: 2.0
##MODULE IP: FAMFAMFAM Icons - CC 2.5
##MODULE IP: Oxygen Icons - LGPL 3.0
.classpath||GHIDRA||||END|
.project||GHIDRA||||END|
Module.manifest||GHIDRA||reviewed||END|
build.gradle||GHIDRA||||END|
data/ExtensionPoint.manifest||GHIDRA||||END|
extension.properties||GHIDRA||||END|
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END|
src/main/help/help/shared/close16.gif||GHIDRA||reviewed||END|
src/main/help/help/shared/menu16.gif||GHIDRA||reviewed||END|
src/main/help/help/shared/note-red.png||Oxygen Icons - LGPL 3.0||||END|
src/main/help/help/shared/note.png||Oxygen Icons - LGPL 3.0||||END|
src/main/help/help/shared/note.yellow.png||Oxygen Icons - LGPL 3.0||||END|
src/main/help/help/shared/redo.png||GHIDRA||reviewed||END|
src/main/help/help/shared/tip.png||Oxygen Icons - LGPL 3.0||||END|
src/main/help/help/shared/undo.png||GHIDRA||reviewed||END|
src/main/help/help/shared/warning.png||Oxygen Icons - LGPL 3.0||||END|
src/main/help/help/topics/SampleHelpTopic/SampleHelpFile.htm||GHIDRA||reviewed||END|
src/main/resources/images/erase16.png||GHIDRA||reviewed||END|
src/main/resources/images/information.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|

View file

@ -0,0 +1 @@
FunctionAlgorithm

View file

@ -0,0 +1,5 @@
name=SampleTablePlugin
description=Sample plugin for creating and manipulating a table
author=Ghidra Team
createdOn=pre-4/6/2015
version=@extversion@

View file

@ -0,0 +1,53 @@
<?xml version='1.0' encoding='ISO-8859-1' ?>
<!--
This is an XML file intended to be parsed by the Ghidra help system. It is loosely based
upon the JavaHelp table of contents document format. The Ghidra help system uses a
TOC_Source.xml file to allow a module with help to define how its contents appear in the
Ghidra help viewer's table of contents. The main document (in the Base module)
defines a basic structure for the
Ghidra table of contents system. Other TOC_Source.xml files may use this structure to insert
their files directly into this structure (and optionally define a substructure).
In this document, a tag can be either a <tocdef> or a <tocref>. The former is a definition
of an XML item that may have a link and may contain other <tocdef> and <tocref> children.
<tocdef> items may be referred to in other documents by using a <tocref> tag with the
appropriate id attribute value. Using these two tags allows any module to define a place
in the table of contents system (<tocdef>), which also provides a place for
other TOC_Source.xml files to insert content (<tocref>).
During the help build time, all TOC_Source.xml files will be parsed and validated to ensure
that all <tocref> tags point to valid <tocdef> tags. From these files will be generated
<module name>_TOC.xml files, which are table of contents files written in the format
desired by the JavaHelp system. Additionally, the genated files will be merged together
as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra
help GUI, there will be on table of contents that has been created from the definitions in
all of the modules' TOC_Source.xml files.
Tags and Attributes
<tocdef>
-id - the name of the definition (this must be unique across all TOC_Source.xml files)
-text - the display text of the node, as seen in the help GUI
-target** - the file to display when the node is clicked in the GUI
-sortgroup - this is a string that defines where a given node should appear under a given
parent. The string values will be sorted by the JavaHelp system using
a javax.text.RulesBasedCollator. If this attribute is not specified, then
the text of attribute will be used.
<tocref>
-id - The id of the <tocdef> that this reference points to
**The URL for the target is relative and should start with 'help/topics'. This text is
used by the Ghidra help system to provide a universal starting point for all links so that
they can be resolved at runtime, across modules.
-->
<tocroot>
</tocroot>

View file

@ -0,0 +1,58 @@
/* ###
* 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.
*/
/*
WARNING!
This file is copied to all help directories. If you change this file, you must copy it
to each src/main/help/help/shared directory.
Java Help Note: JavaHelp does not accept sizes (like in 'margin-top') in anything but
px (pixel) or with no type marking.
*/
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */
li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/*
P tag code. Most of the help files nest P tags inside of blockquote tags (the was the
way it had been done in the beginning). The net effect is that the text is indented. In
modern HTML we would use CSS to do this. We need to support the Ghidra P tags, nested in
blockquote tags, as well as naked P tags. The following two lines accomplish this. Note
that the 'blockquote p' definition will inherit from the first 'p' definition.
*/
p { margin-left: 40px; font-family:times new roman; font-size:14pt; }
blockquote p { margin-left: 10px; }
p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; }
p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; }
/*
We wish for a tables to have space between it and the preceding element, so that text
is not too close to the top of the table. Also, nest the table a bit so that it is clear
the table relates to the preceding text.
*/
table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,58 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<META http-equiv="Content-Language" content="en-us">
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<META name="GENERATOR" content="Microsoft FrontPage 4.0">
<META name="ProgId" content="FrontPage.Editor.Document">
<TITLE>Sample Help File for a Plugin</TITLE>
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD>
<BODY>
<H1><a name="SampleHelpTopic_Anchor_Name"></a>Sample Help File for a Plugin</H1>
<P>The first paragraph should describe the purpose of the plugin and explain <I>why</I> a user
would want to add this plugin to a tool. The Hello World plugin is a sample plugin to
demonstrate the how to set up an action and how to add a listener to the Project. The listener
is notified when a project is opened and closed. The Hello World plugin implements the <FONT
face="Courier New" size="3">FrontEndable</FONT> interface so that it becomes eligible to be
added to the Ghidra Project Window, which is also a tool. Finally, it shows how to add a help
URL to the action so that when the user presses the &lt;F1&gt; or &lt;Help&gt; key, this page
will be displayed in the Ghidra Help Browser.</P>
<P>If the plugin pops up a dialog, the display elements and input fields should be explained in
detail, as well as any resulting changes which may be made to the current program.<BR>
</P>
<P><B>Note on the Style Sheet</B>: This sample help file uses a style sheet that is consistent
with Ghidra Help. Specify <I>Frontpage.css</I> as the style sheet for your help page if you
would like to maintain the same "look and feel." The <I>Frontpage.css</I> file is in the
<I>help/shared/</I> directory.</P>
<P>Here are some sample bookmarks for the actions in the sample plugins (see the <FONT face=
"Courier New"><FONT size="3">setupActions()</FONT></FONT> method in <FONT size="3" face=
"Courier New">ghidra.examples.KitchenSinkPlugin</FONT> for how to specify a bookmark in the
URL that is used as the help URL for the action):</P>
<UL>
<LI><A name="KS_Hello_World"></A>The Hello world action displays a dialog to say "Hello
World."</LI>
</UL>
<UL>
<LI><A name="KS_Hello_Program"></A>The Hello program action displays a dialog to say "Hello
Program."</LI>
</UL>
<P class="relatedtopic">Related Topics: add links to related pages</P>
<P class="providedbyplugin">Provided By: the <I>Hello World</I> and <I>Kitchen Sink</I>
plugins</P>
<BR>
</BODY>
</HTML>

View file

@ -0,0 +1,64 @@
/* ###
* 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.examples;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.block.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class BasicBlockCounterFunctionAlgorithm implements FunctionAlgorithm {
@Override
public String getName() {
return "Basic Block Count";
}
@Override
public int score(Function function, TaskMonitor monitor) throws CancelledException {
Program program = function.getProgram();
CodeBlockModel blockModel = new BasicBlockModel(program);
AddressSetView body = function.getBody();
long maxIterations = body.getNumAddresses();
monitor.initialize(maxIterations);
CodeBlockIterator iterator = blockModel.getCodeBlocksContaining(body, monitor);
int blockCount = 0;
while (iterator.hasNext()) {
monitor.checkCanceled();
iterator.next();
blockCount++;
monitor.incrementProgress(1);
artificialSleepForDemoPurposes();
}
return blockCount;
}
private void artificialSleepForDemoPurposes() {
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
// don't care; we tried
}
}
}

View file

@ -0,0 +1,30 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.examples;
import ghidra.program.model.listing.Function;
import ghidra.util.classfinder.ExtensionPoint;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public interface FunctionAlgorithm extends ExtensionPoint {
public int score(Function function, TaskMonitor monitor) throws CancelledException;
public String getName();
}

View file

@ -0,0 +1,50 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.examples;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
public class FunctionStatsRowObject {
private final Function function;
private final String algorithmName;
private int score;
FunctionStatsRowObject(Function function, String algorithmName, int score) {
this.function = function;
this.algorithmName = algorithmName;
this.score = score;
}
public Address getAddress() {
return function.getEntryPoint();
}
public String getFunctionName() {
return function.getName();
}
public String getAlgorithmName() {
return algorithmName;
}
public Integer getScore() {
return score;
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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.examples;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceManager;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class ReferenceFunctionAlgorithm implements FunctionAlgorithm {
@Override
public String getName() {
return "Reference Counter";
}
@Override
public int score(Function function, TaskMonitor monitor) throws CancelledException {
Program program = function.getProgram();
ReferenceManager referenceManager = program.getReferenceManager();
AddressSetView body = function.getBody();
long maxIterations = body.getNumAddresses();
monitor.initialize(maxIterations);
AddressIterator iterator = referenceManager.getReferenceSourceIterator(body, true);
int referenceCount = 0;
while (iterator.hasNext()) {
monitor.checkCanceled();
Address address = iterator.next();
Reference[] referencesFrom = referenceManager.getReferencesFrom(address);
referenceCount += referencesFrom.length;
monitor.incrementProgress(1);
artificialSleepForDemoPurposes();
}
return referenceCount;
}
private void artificialSleepForDemoPurposes() {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
// don't care; we tried
}
}
}

View file

@ -0,0 +1,142 @@
/* ###
* 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.examples;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.util.datastruct.Accumulator;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorSplitter;
import java.util.List;
import docking.widgets.table.*;
import docking.widgets.table.threaded.ThreadedTableModelStub;
class SampleTableModel extends ThreadedTableModelStub<FunctionStatsRowObject> {
private SampleTablePlugin plugin;
SampleTableModel(SampleTablePlugin plugin) {
super("Sample Table Model", plugin.getTool());
this.plugin = plugin;
}
@Override
protected TableColumnDescriptor<FunctionStatsRowObject> createTableColumnDescriptor() {
TableColumnDescriptor<FunctionStatsRowObject> descriptor =
new TableColumnDescriptor<FunctionStatsRowObject>();
descriptor.addVisibleColumn(new FunctionNameTableColumn());
descriptor.addVisibleColumn(new AlgorithmTableColumn());
descriptor.addVisibleColumn(new ScoreTableColumn(), 0, true); // default sorted column
descriptor.addHiddenColumn(new AddressTableColumn()); // hidden by default
return descriptor;
}
@Override
protected void doLoad(Accumulator<FunctionStatsRowObject> accumulator, TaskMonitor monitor)
throws CancelledException {
if (!plugin.resetExisingTableData()) {
accumulator.addAll(getModelData());
}
Function function = plugin.getFunction();
if (function == null) {
return; // not inside a function
}
List<FunctionAlgorithm> algorithms = plugin.getAlgorithms();
TaskMonitor[] taskMonitors =
TaskMonitorSplitter.splitTaskMonitor(monitor, algorithms.size());
for (int i = 0; i < algorithms.size(); i++) {
FunctionAlgorithm algorithm = algorithms.get(i);
TaskMonitor subMonitor = taskMonitors[i];
subMonitor.setMessage("Computing score using " + algorithm.getName());
int score = algorithm.score(function, subMonitor);
String name = algorithm.getName();
accumulator.add(new FunctionStatsRowObject(function, name, score));
}
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class FunctionNameTableColumn extends
AbstractDynamicTableColumn<FunctionStatsRowObject, String, Object> {
@Override
public String getColumnName() {
return "Name";
}
@Override
public String getValue(FunctionStatsRowObject rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException {
return rowObject.getFunctionName();
}
}
private class AlgorithmTableColumn extends
AbstractDynamicTableColumn<FunctionStatsRowObject, String, Object> {
@Override
public String getColumnName() {
return "Algorithm";
}
@Override
public String getValue(FunctionStatsRowObject rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException {
return rowObject.getAlgorithmName();
}
}
private class ScoreTableColumn extends
AbstractDynamicTableColumn<FunctionStatsRowObject, Integer, Object> {
@Override
public String getColumnName() {
return "Score";
}
@Override
public Integer getValue(FunctionStatsRowObject rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException {
return rowObject.getScore();
}
}
private class AddressTableColumn extends
AbstractDynamicTableColumn<FunctionStatsRowObject, Address, Object> {
@Override
public String getColumnName() {
return "Address";
}
@Override
public Address getValue(FunctionStatsRowObject rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException {
return rowObject.getAddress();
}
}
}

View file

@ -0,0 +1,84 @@
/* ###
* 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.examples;
import java.util.List;
import ghidra.app.ExamplesPluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg;
//@formatter:off
@PluginInfo(
status = PluginStatus.RELEASED,
packageName = ExamplesPluginPackage.NAME,
category = PluginCategoryNames.EXAMPLES,
shortDescription = "Sample Table Plugin",
description = "Sample plugin for creating and manipulating a table"
)
//@formatter:on
public class SampleTablePlugin extends ProgramPlugin {
private SampleTableProvider provider;
private Function currentFunction;
public SampleTablePlugin(PluginTool tool) {
super(tool, true /*location changes*/, true/*selection changes*/);
provider = new SampleTableProvider(this);
provider.addToTool();
}
@Override
protected void locationChanged(ProgramLocation location) {
if (location == null) {
currentFunction = null;
return;
}
FunctionManager functionManager = currentProgram.getFunctionManager();
currentFunction = functionManager.getFunctionContaining(location.getAddress());
}
@Override
protected void selectionChanged(ProgramSelection selection) {
Msg.info(this, "selectionChanged(): " + selection);
}
public Function getFunction() {
return currentFunction;
}
public List<FunctionAlgorithm> getAlgorithms() {
return provider.getAlgorithms();
}
public boolean resetExisingTableData() {
return provider.resetExistingTableData();
}
@Override
protected void dispose() {
provider.dispose();
}
}

View file

@ -0,0 +1,247 @@
/* ###
* 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.examples;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import docking.ActionContext;
import docking.action.*;
import docking.widgets.filechooser.GhidraFileChooserPanel;
import docking.widgets.table.GFilterTable;
import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.plugintool.util.OptionsService;
import ghidra.util.*;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.layout.MiddleLayout;
import resources.ResourceManager;
public class SampleTableProvider extends ComponentProviderAdapter implements OptionsChangeListener {
private static final String OPTIONS_TITLE = "Sample Table";
private static final String RESET_TABLE_DATA_OPTION = "Reset Table Data";
private SampleTablePlugin plugin;
private JComponent component;
private GFilterTable<FunctionStatsRowObject> filterTable;
private SampleTableModel model;
private List<FunctionAlgorithm> discoveredAlgorithms;
private JCheckBox[] checkBoxes;
private GhidraFileChooserPanel fileChooserPanel;
private boolean resetTableData;
public SampleTableProvider(SampleTablePlugin plugin) {
super(plugin.getTool(), "Sample Table Provider", plugin.getName());
this.plugin = plugin;
discoveredAlgorithms = findAlgorithms();
component = build();
createActions();
initializeOptions();
}
void dispose() {
filterTable.dispose();
removeFromTool();
}
private JComponent build() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(buildTablePanel(), BorderLayout.CENTER);
panel.add(buildControlPanel(), BorderLayout.NORTH);
return panel;
}
private Component buildControlPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(buildAlgorithmsPanel(), BorderLayout.WEST);
panel.add(buildButtonsPanel(), BorderLayout.CENTER); // run button
return panel;
}
private JPanel buildAlgorithmsPanel() {
JPanel checkBoxPanel = new JPanel(new GridLayout(0, 1));
checkBoxPanel.setBorder(BorderFactory.createTitledBorder("Discovered Algorithms"));
checkBoxes = new JCheckBox[discoveredAlgorithms.size()];
for (int i = 0; i < discoveredAlgorithms.size(); i++) {
checkBoxes[i] = new JCheckBox(discoveredAlgorithms.get(i).getName());
checkBoxPanel.add(checkBoxes[i]);
}
return checkBoxPanel;
}
private JPanel buildButtonsPanel() {
JPanel buttonPanel = new JPanel(new BorderLayout());
String defaultOuptutFilePath =
System.getProperty("user.home") + File.separator + "SampleTablePluginOutput.txt";
String preferencesKey = "sample.table.plugin.output.file";
fileChooserPanel = new GhidraFileChooserPanel("Output File", preferencesKey,
defaultOuptutFilePath, true, GhidraFileChooserPanel.OUTPUT_MODE);
JButton runButton = new JButton("Run Algorithms");
runButton.addActionListener(e -> model.reload());
JPanel runButtonPanel = new JPanel(new MiddleLayout());
runButtonPanel.add(runButton);
buttonPanel.add(fileChooserPanel, BorderLayout.NORTH);
buttonPanel.add(runButtonPanel, BorderLayout.CENTER);
return buttonPanel;
}
private List<FunctionAlgorithm> findAlgorithms() {
return new ArrayList<>(ClassSearcher.getInstances(FunctionAlgorithm.class));
}
private Component buildTablePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
model = new SampleTableModel(plugin);
filterTable = new GFilterTable<>(model);
panel.add(filterTable);
return panel;
}
private void createActions() {
DockingAction optionsAction = new DockingAction("Sample Table Options", plugin.getName()) {
@Override
public void actionPerformed(ActionContext context) {
OptionsService service = tool.getService(OptionsService.class);
service.showOptionsDialog(OPTIONS_TITLE, "Sample");
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return tool.getService(OptionsService.class) != null;
}
};
ImageIcon icon = ResourceManager.loadImage("images/table.png");
optionsAction.setToolBarData(new ToolBarData(icon));
DockingAction saveTableDataAction = new DockingAction("Save Table Data", plugin.getName()) {
@Override
public void actionPerformed(ActionContext context) {
StringBuilder buffer = new StringBuilder();
buffer.append("Writing the following objects to file: ");
buffer.append(fileChooserPanel.getFileName());
List<FunctionStatsRowObject> selectedObjects = filterTable.getSelectedRowObjects();
for (FunctionStatsRowObject stats : selectedObjects) {
buffer.append("\nData: " + stats.getAlgorithmName());
}
Msg.showInfo(this, filterTable, "Example Dialog",
HTMLUtilities.toHTML(buffer.toString()));
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return filterTable.getSelectedRowObjects().size() > 0;
}
@Override
public boolean isAddToPopup(ActionContext context) {
Object sourceObject = context.getSourceObject();
if (sourceObject instanceof JTable) {
return true;
}
return SwingUtilities.isDescendingFrom((Component) sourceObject, filterTable);
}
};
icon = ResourceManager.loadImage("images/disk.png");
saveTableDataAction.setToolBarData(new ToolBarData(icon));
saveTableDataAction.setPopupMenuData(new MenuData(new String[] { "Save Data" }));
addLocalAction(optionsAction);
addLocalAction(saveTableDataAction);
}
@Override
public JComponent getComponent() {
return component;
}
public List<FunctionAlgorithm> getAlgorithms() {
List<FunctionAlgorithm> list = new ArrayList<>();
for (int i = 0; i < checkBoxes.length; i++) {
JCheckBox checkBox = checkBoxes[i];
if (checkBox.isSelected()) {
list.add(discoveredAlgorithms.get(i));
}
}
return list;
}
public boolean resetExistingTableData() {
return resetTableData;
}
//==================================================================================================
// Options Methods
//==================================================================================================
private void initializeOptions() {
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
HelpLocation help = new HelpLocation("SampleTablePlugin", "Reset_Options");
opt.registerOption(RESET_TABLE_DATA_OPTION, true, help,
"When toggled on the sample table will clear " +
"any existing data before showing algorithm results");
resetTableData = opt.getBoolean(RESET_TABLE_DATA_OPTION, true);
opt.addOptionsChangeListener(this);
}
// Options changed callback
@Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) {
if (RESET_TABLE_DATA_OPTION.equals(optionName)) {
resetTableData = (Boolean) newValue;
}
}
}

View file

@ -0,0 +1,35 @@
/* ###
* 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.examples;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Function;
import ghidra.util.task.TaskMonitor;
public class SizeFunctionAlgorithm implements FunctionAlgorithm {
@Override
public String getName() {
return "Function Size";
}
@Override
public int score(Function function, TaskMonitor monitor) {
AddressSetView body = function.getBody();
return (int) body.getNumAddresses();
}
}

View file

@ -0,0 +1,88 @@
/* ###
* 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.examples2;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.util.datastruct.Accumulator;
import ghidra.util.exception.CancelledException;
import ghidra.util.table.AddressBasedTableModel;
import ghidra.util.task.TaskMonitor;
import docking.widgets.table.AbstractDynamicTableColumn;
import docking.widgets.table.TableColumnDescriptor;
public class SampleSearchTableModel extends AddressBasedTableModel<SearchResults> {
private SampleSearcher searcher;
public SampleSearchTableModel(SampleSearcher searcher, PluginTool tool) {
super("Sample Search Results", tool, searcher.getProgram(), null);
this.searcher = searcher;
}
@Override
protected void doLoad(Accumulator<SearchResults> accumulator, TaskMonitor monitor)
throws CancelledException {
searcher.search(accumulator, monitor);
}
@Override
protected TableColumnDescriptor<SearchResults> createTableColumnDescriptor() {
TableColumnDescriptor<SearchResults> descriptor =
new TableColumnDescriptor<SearchResults>();
descriptor.addVisibleColumn(new MyAddressColumn());
descriptor.addVisibleColumn(new MyValueColumn());
return descriptor;
}
private class MyAddressColumn extends
AbstractDynamicTableColumn<SearchResults, Address, Object> {
@Override
public String getColumnName() {
return "Address";
}
@Override
public Address getValue(SearchResults rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException {
return rowObject.getAddress();
}
}
private class MyValueColumn extends AbstractDynamicTableColumn<SearchResults, String, Object> {
@Override
public String getColumnName() {
return "Value";
}
@Override
public String getValue(SearchResults rowObject, Settings settings, Object data,
ServiceProvider services) throws IllegalArgumentException {
return rowObject.getDisplayValue();
}
}
@Override
public Address getAddress(int row) {
return getRowObject(row).getAddress();
}
}

View file

@ -0,0 +1,76 @@
/* ###
* 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.examples2;
import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.DockingAction;
import docking.action.MenuData;
import ghidra.app.ExamplesPluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
//@formatter:off
@PluginInfo(
status = PluginStatus.RELEASED,
packageName = ExamplesPluginPackage.NAME,
category = PluginCategoryNames.EXAMPLES,
shortDescription = "Sample Search Table Plugin",
description = "Sample plugin for searching and creating a table for the results"
)
//@formatter:on
public class SampleSearchTablePlugin extends ProgramPlugin {
private SampleSearchTableProvider provider;
public SampleSearchTablePlugin(PluginTool tool) {
super(tool, false, false);
createActions();
}
@Override
protected void dispose() {
if (provider != null) {
provider.dispose();
}
}
private void createActions() {
DockingAction action = new DockingAction("Search Stuff", getName()) {
@Override
public void actionPerformed(ActionContext context) {
search();
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return currentProgram != null;
}
};
action.setMenuBarData(
new MenuData(new String[] { "Search", "No Arg Functions" }, "MyGroup"));
tool.addAction(action);
}
protected void search() {
SampleSearcher searcher = new SampleSearcher(currentProgram);
provider = new SampleSearchTableProvider(this, searcher);
tool.addComponentProvider(provider, true);
}
}

View file

@ -0,0 +1,83 @@
/* ###
* 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.examples2;
import java.awt.BorderLayout;
import javax.swing.*;
import docking.widgets.table.GFilterTable;
import ghidra.app.services.GoToService;
import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.util.table.GhidraFilterTable;
import ghidra.util.table.GhidraTable;
public class SampleSearchTableProvider extends ComponentProviderAdapter
implements OptionsChangeListener {
private SampleSearchTablePlugin plugin;
private JComponent component;
private GFilterTable<SearchResults> filterTable;
private SampleSearchTableModel model;
public SampleSearchTableProvider(SampleSearchTablePlugin plugin, SampleSearcher searcher) {
super(plugin.getTool(), "Sample Table Provider", plugin.getName());
this.plugin = plugin;
component = build(searcher);
setTransient();
// createActions();
}
private JComponent build(SampleSearcher searcher) {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
model = new SampleSearchTableModel(searcher, plugin.getTool());
filterTable = new GhidraFilterTable<>(model);
GhidraTable table = ((GhidraTable) filterTable.getTable());
GoToService goToService = tool.getService(GoToService.class);
if (goToService != null) {
table.installNavigation(goToService, goToService.getDefaultNavigatable());
}
table.setNavigateOnSelectionEnabled(true);
panel.add(filterTable);
return panel;
}
public void dispose() {
filterTable.dispose();
filterTable.getTable().dispose();
removeFromTool();
}
@Override
public JComponent getComponent() {
return component;
}
@Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) {
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,53 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.examples2;
import ghidra.program.model.listing.*;
import ghidra.util.datastruct.Accumulator;
import ghidra.util.task.TaskMonitor;
public class SampleSearcher {
private Program program;
public SampleSearcher(Program program) {
this.program = program;
}
public void search(Accumulator<SearchResults> accumulator, TaskMonitor monitor) {
FunctionIterator it = program.getFunctionManager().getFunctions(true);
monitor.initialize(program.getFunctionManager().getFunctionCount());
while (it.hasNext()) {
if (monitor.isCancelled()) {
monitor.clearCanceled(); //otherwise the partial results won't be shown
break;
}
Function fun = it.next();
monitor.incrementProgress(1);
if (fun.getParameterCount() == 0) {
accumulator.add(new SearchResults(fun.getEntryPoint(), fun.getName()));
}
}
}
public Program getProgram() {
return program;
}
}

View file

@ -0,0 +1,40 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.examples2;
import ghidra.program.model.address.Address;
public class SearchResults {
private Address address;
private String displayValue;
public SearchResults(Address address, String displayValue) {
this.address = address;
this.displayValue = displayValue;
}
public String getDisplayValue() {
return displayValue;
}
public Address getAddress() {
return address;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B