Merge remote-tracking branch 'origin/GP-145_ghidra1_RemoveObsoleteCode'

This commit is contained in:
ghidra1 2020-09-08 13:34:19 -04:00
commit 2fdfc217c1
22 changed files with 1 additions and 2733 deletions

View File

@ -49,10 +49,9 @@ public enum AnalyzerType {
FUNCTION_ANALYZER("Function Analyzer", "Triggered when functions are created."),
FUNCTION_MODIFIERS_ANALYZER("Function-modifiers Analyzer", "Triggered when a function's modifier changes"),
FUNCTION_SIGNATURES_ANALYZER("Function-Signatures Analyzer", "Triggered when a function's signature changes."),
DATA_ANALYZER("Data Analyzer", "Triggered when data is created."),
DATA_ANALYZER("Data Analyzer", "Triggered when data is created.");
// TODO: Add Symbol analyzer type
// SYMBOL_ANALYZER("Symbol Analyzer", "Triggered when non-default primary symbol is added or changed"),
ONE_SHOT_ANALYZER("One Shot Analzyer", "Not triggered by any event, only executed when analysis is run manually (One shots run before all others)");
private String name;
private String description;

View File

@ -1,208 +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.framework.analysis;
import java.util.*;
import org.apache.commons.collections4.map.HashedMap;
import ghidra.app.services.Analyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.model.UndoableDomainObject;
import ghidra.framework.task.*;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class AnalysisManager {
private AnalysisRecipe recipe;
private Map<AnalyzerType, List<AnalyzerScheduler>> triggerMap;
private List<AnalyzerScheduler> schedulers = new ArrayList<AnalyzerScheduler>();
private GTaskManager taskManager;
private AnalysisPhase currentPhase;
private MessageLog messageLog = new MessageLog();
public AnalysisManager(Program program) {
this(program, AnalysisRecipeBuilder.getRecipe(program));
}
public AnalysisManager(Program program, AnalysisRecipe recipe) {
this.recipe = recipe;
taskManager = GTaskManagerFactory.getTaskManager(program);
triggerMap = new HashedMap<AnalyzerType, List<AnalyzerScheduler>>();
initialize();
}
private void initialize() {
List<Analyzer> analyzerList = recipe.getAnalyzers();
for (int rank = 0; rank < analyzerList.size(); rank++) {
Analyzer analyzer = analyzerList.get(rank);
AnalyzerScheduler scheduler = new AnalyzerScheduler(this, analyzer, rank);
AnalyzerType analyzerType = analyzer.getAnalysisType();
addScheduler(analyzerType, scheduler);
}
setPhase(recipe.getLastPhase());
}
private void setPhase(AnalysisPhase phase) {
currentPhase = phase;
for (AnalyzerScheduler scheduler : schedulers) {
scheduler.setPhase(phase);
}
}
private void addScheduler(AnalyzerType analysisType, AnalyzerScheduler analyzerScheduler) {
schedulers.add(analyzerScheduler);
List<AnalyzerScheduler> list = triggerMap.get(analysisType);
if (list == null) {
list = new ArrayList<AnalyzerScheduler>();
triggerMap.put(analysisType, list);
}
list.add(analyzerScheduler);
}
public void runAnalysis(AddressSet addressSet) {
if (!currentPhase.equals(recipe.getLastPhase())) {
Msg.showWarn(this, null, "Analysis Already Running!",
"Please wait for the current analysis to complete before running analysis again.");
return;
}
List<AnalysisPhase> analysisPhases = recipe.getAnalysisPhases();
boolean isFirstPhase = true;
taskManager.setSuspended(true);
for (AnalysisPhase analysisPhase : analysisPhases) {
taskManager.scheduleTask(new StartPhaseTask(analysisPhase), 0, analysisPhase.getName());
if (isFirstPhase) {
isFirstPhase = false;
taskManager.scheduleTask(new KickStartAnalyzersTask(addressSet), 1,
analysisPhase.getName());
}
}
taskManager.setSuspended(false);
}
public void addTaskListener(GTaskListener listener) {
taskManager.addTaskListener(listener);
}
public void removeTaskListener(GTaskListener listener) {
taskManager.removeTaskListener(listener);
}
public void waitForAnalysis(long timeoutMillis) {
taskManager.waitWhileBusy(timeoutMillis);
}
void scheduleAnalysisTask(AnalysisTask task) {
taskManager.scheduleTask(task, 1000 + task.getPriority() * 10, task.getPhase().getName());
}
public List<AnalysisPhase> getPhases() {
return recipe.getAnalysisPhases();
}
void triggerAnalysis(AnalyzerType analyzerType, AddressSetView addressSet) {
List<AnalyzerScheduler> list = triggerMap.get(analyzerType);
if (list == null) {
return;
}
for (AnalyzerScheduler analyzerScheduler : list) {
analyzerScheduler.added(addressSet);
}
}
private class StartPhaseTask implements GTask {
private AnalysisPhase phase;
public StartPhaseTask(AnalysisPhase phase) {
this.phase = phase;
}
@Override
public String getName() {
return phase.getName();
}
@Override
public void run(UndoableDomainObject domainObject, TaskMonitor monitor)
throws CancelledException {
Msg.debug(this, "Starting phase " + phase);
setPhase(phase);
}
}
private class KickStartAnalyzersTask implements GTask {
private AddressSetView restrictSet;
public KickStartAnalyzersTask(AddressSet addressSet) {
this.restrictSet = addressSet;
}
@Override
public String getName() {
return "Analysis Address Set Primer Task";
}
@Override
public void run(UndoableDomainObject domainObject, TaskMonitor monitor)
throws CancelledException {
Program program = (Program) domainObject;
if (restrictSet == null || restrictSet.isEmpty()) {
analyzeExternalSpace(program);
restrictSet = program.getMemory(); // process entire program
}
triggerAnalysis(AnalyzerType.BYTE_ANALYZER, restrictSet);
if (program.getListing().getNumInstructions() != 0) {
triggerAnalysis(AnalyzerType.INSTRUCTION_ANALYZER, restrictSet);
}
if (program.getListing().getNumDefinedData() != 0) {
triggerAnalysis(AnalyzerType.DATA_ANALYZER, restrictSet);
}
if (program.getFunctionManager().getFunctions(true).hasNext()) {
triggerAnalysis(AnalyzerType.FUNCTION_ANALYZER, restrictSet);
triggerAnalysis(AnalyzerType.FUNCTION_SIGNATURES_ANALYZER, restrictSet);
}
}
private void analyzeExternalSpace(Program program) {
triggerAnalysis(AnalyzerType.BYTE_ANALYZER,
new AddressSet(AddressSpace.EXTERNAL_SPACE.getMinAddress(),
AddressSpace.EXTERNAL_SPACE.getMaxAddress()));
}
@Override
public String toString() {
return getName() + ": " + restrictSet;
}
}
public MessageLog getMessageLog() {
return messageLog;
}
}

View File

@ -1,98 +0,0 @@
/* ###
* 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.framework.analysis;
import ghidra.app.services.Analyzer;
import org.jdom.Element;
public class AnalysisPhase implements Comparable<AnalysisPhase> {
static final String XML_ELEMENT_NAME = "ANALYSIS_PHASE";
private AnalysisRecipe recipe;
private int index;
private boolean isCheckPoint;
public AnalysisPhase(AnalysisRecipe recipe, int index, boolean isCheckPoint) {
this.recipe = recipe;
this.index = index;
this.isCheckPoint = isCheckPoint;
}
AnalysisPhase(Element element) {
this.index = Integer.parseInt(element.getAttributeValue("INDEX"));
this.isCheckPoint = Boolean.parseBoolean(element.getAttributeValue("CHECKPOINT"));
}
@Override
final public boolean equals(Object obj) {
return this == obj;
}
@Override
final public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return getName();
}
public String getName() {
return Integer.toString(index + 1);
}
public Element toXML() {
Element element = new Element(XML_ELEMENT_NAME);
element.setAttribute("INDEX", Integer.toString(index));
element.setAttribute("CHECKPOINT", Boolean.toString(isCheckPoint));
return element;
}
public int getIndex() {
return index;
}
void setIndex(int i) {
index = i;
}
public boolean isEnabled(Analyzer analyzer) {
return recipe.isAnalyzerEnabled(analyzer);
}
public AnalysisPhase getExecutionPhase(Analyzer analyzer) {
return recipe.getExecutionPhase(analyzer, this);
}
@Override
public int compareTo(AnalysisPhase o) {
return index - o.index;
}
public boolean isCheckPoint() {
return isCheckPoint;
}
public void setIsCheckPoint(boolean b) {
if (recipe.getLastPhase() == this) {
return; // can't change state of last phase - it is always a checkpoint
}
this.isCheckPoint = b;
}
}

View File

@ -1,264 +0,0 @@
/* ###
* 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.framework.analysis;
import generic.jar.ResourceFile;
import ghidra.app.services.Analyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.listing.Program;
import java.util.*;
import javax.swing.event.ChangeListener;
import org.jdom.Element;
public class AnalysisRecipe {
private List<AnalysisPhase> phases = new ArrayList<AnalysisPhase>();
private Map<Analyzer, AnalyzerInfo> analyzerMap = new HashMap<Analyzer, AnalyzerInfo>();
private List<AnalyzerInfo> analyzerInfoList = new ArrayList<AnalyzerInfo>();
private ToolOptions options = new ToolOptions("Analysis Options");
private String name;
private ChangeListener listener;
public AnalysisRecipe(String name, Collection<Analyzer> analyzers, Program program) {
this.name = name;
phases.add(new AnalysisPhase(this, 0, true));
for (Analyzer analyzer : analyzers) {
if (!analyzer.canAnalyze(program)) {
continue;
}
boolean defaultEnablement = analyzer.getDefaultEnablement(program);
AnalyzerInfo info = new AnalyzerInfo(this, analyzer, defaultEnablement);
analyzerMap.put(analyzer, info);
analyzerInfoList.add(info);
}
Collections.sort(analyzerInfoList);
for (Analyzer analyzer : analyzers) {
analyzer.registerOptions(options.getOptions(analyzer.getName()), program);
}
}
public Options getOptions(Analyzer analyzer) {
return options.getOptions(analyzer.getName());
}
public String getName() {
return name;
}
Element toXML() {
Element root = new Element("Analysis_Recipe");
root.setAttribute("Name", name);
for (AnalysisPhase phase : phases) {
root.addContent(phase.toXML());
}
for (AnalyzerInfo info : analyzerMap.values()) {
root.addContent(info.toXML());
}
Element optionsElement = options.getXmlRoot(false);
root.addContent(optionsElement);
return root;
}
void loadFromXML(Element root) {
phases.clear();
this.name = root.getAttributeValue("Name");
List<?> phaseChildren = root.getChildren(AnalysisPhase.XML_ELEMENT_NAME);
for (Object object : phaseChildren) {
Element child = (Element) object;
phases.add(new AnalysisPhase(child));
}
Collections.sort(phases);
List<?> infoChildren = root.getChildren(AnalyzerInfo.XML_ELEMENT_NAME);
for (Object object : infoChildren) {
processAnalyzerInfoElement((Element) object);
}
Element optionsElement = root.getChild(ToolOptions.XML_ELEMENT_NAME);
options = new ToolOptions(optionsElement);
}
private void processAnalyzerInfoElement(Element element) {
String className = element.getAttributeValue(AnalyzerInfo.CLASS_NAME);
if (GhidraScriptAnalyzerAdapter.class.getName().equals(className)) {
AnalyzerInfo info = AnalyzerInfo.createInfoForWrappedAnalzyer(this, element);
info.setStartPhase(getFirstPhase());
analyzerMap.put(info.getAnalyzer(), info);
analyzerInfoList.add(info);
Collections.sort(analyzerInfoList);
}
AnalyzerInfo info = findInfoForAnalyzerClass(className);
if (info != null) {
info.loadFromXML(element);
}
}
private AnalyzerInfo findInfoForAnalyzerClass(String className) {
for (AnalyzerInfo info : analyzerInfoList) {
if (className.equals(info.getAnalyzer().getClass().getName())) {
return info;
}
}
return null;
}
public List<AnalysisPhase> getAnalysisPhases() {
return phases;
}
public AnalysisPhase getLastPhase() {
return phases.get(phases.size() - 1);
}
public AnalysisPhase getFirstPhase() {
return phases.get(0);
}
public AnalysisPhase createPhase() {
AnalysisPhase newPhase = new AnalysisPhase(this, 0, false);
phases.add(0, newPhase);
for (int i = 0; i < phases.size(); i++) {
phases.get(i).setIndex(i);
}
notifyChanged();
return newPhase;
}
public void deletePhase() {
if (phases.size() <= 1) {
return;
}
AnalysisPhase removedPhase = phases.remove(0);
AnalysisPhase firstPhase = phases.get(0);
for (int i = 0; i < phases.size(); i++) {
phases.get(i).setIndex(i);
}
for (AnalyzerInfo info : analyzerInfoList) {
if (info.getAnalyzerStartPhase() == removedPhase) {
info.setStartPhase(firstPhase);
}
}
notifyChanged();
}
/**
* returns a list of all analyzers in priority order.
* @return a list of all analyzers in priority order.
*/
public List<Analyzer> getAnalyzers() {
List<Analyzer> list = new ArrayList<Analyzer>(analyzerMap.size());
for (AnalyzerInfo info : analyzerInfoList) {
list.add(info.getAnalyzer());
}
return list;
}
public AnalysisPhase getPhase(int i) {
return phases.get(i);
}
// AnalyzerInfo getAnalyzerInfo(Analyzer analyzer) {
// return analyzerMap.get(analyzer);
// }
// public AnalyzerStatus getAnalyzerStatus(Analyzer analyzer, AnalysisPhase phase) {
// AnalyzerInfo analyzerInfo = analyzerMap.get(analyzer);
// return analyzerInfo.getStatus(phase);
// }
public boolean isAnalyzerEnabled(Analyzer analyzer) {
AnalyzerInfo analyzerInfo = analyzerMap.get(analyzer);
return analyzerInfo.isEnabled();
}
public AnalysisPhase getExecutionPhase(Analyzer analyzer, AnalysisPhase currentPhase) {
AnalyzerInfo analyzerInfo = analyzerMap.get(analyzer);
return analyzerInfo.getNextEnabledPhaseAtOrAfter(currentPhase);
}
// public void setAnalyzerStatus(Analyzer analyzer, AnalysisPhase phase, AnalyzerStatus status) {
// AnalyzerInfo info = analyzerMap.get(analyzer);
// info.setStatus(phase, status);
// notifyChanged();
// }
private void notifyChanged() {
if (listener != null) {
listener.stateChanged(null);
}
}
public void setAnalyzerEnablement(Analyzer analyzer, boolean b) {
AnalyzerInfo info = analyzerMap.get(analyzer);
info.setEnabled(b);
notifyChanged();
}
public void setChangeListener(ChangeListener listener) {
this.listener = listener;
}
public List<Analyzer> getAnalyzers(AnalysisPhase phase) {
if (phase == null) {
return getAnalyzers();
}
List<Analyzer> list = new ArrayList<Analyzer>();
for (AnalyzerInfo info : analyzerInfoList) {
if (info.getNextEnabledPhaseAtOrAfter(phase) == phase) {
list.add(info.getAnalyzer());
}
}
return list;
}
public void setAnalyzerStartPhase(Analyzer analyzer, AnalysisPhase phase) {
AnalyzerInfo info = analyzerMap.get(analyzer);
info.setStartPhase(phase);
notifyChanged();
}
public AnalysisPhase getAnalyzerStartPhase(Analyzer analyzer) {
AnalyzerInfo info = analyzerMap.get(analyzer);
return info.getAnalyzerStartPhase();
}
public void addScriptAnalyzer(ResourceFile file, AnalyzerType analyzerType, int priority) {
Analyzer analyzer = new GhidraScriptAnalyzerAdapter(file, analyzerType, priority);
AnalyzerInfo info = new AnalyzerInfo(this, analyzer, true);
info.setStartPhase(getFirstPhase());
analyzerMap.put(analyzer, info);
analyzerInfoList.add(info);
Collections.sort(analyzerInfoList);
notifyChanged();
}
public void deleteScriptAnalyzer(Analyzer analyzer) {
AnalyzerInfo removedInfo = analyzerMap.remove(analyzer);
if (removedInfo != null) {
analyzerInfoList.remove(removedInfo);
}
notifyChanged();
}
}

View File

@ -1,56 +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.framework.analysis;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.services.Analyzer;
import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ClassSearcher;
public class AnalysisRecipeBuilder {
private static List<Class<? extends Analyzer>> classes;
public static AnalysisRecipe getRecipe(Program program) {
AnalysisRecipe recipe = findRecipe(program);
if (recipe == null) {
recipe = buildDefaultRecipe(program);
}
return recipe;
}
private static AnalysisRecipe buildDefaultRecipe(Program program) {
List<Analyzer> analyzerList = new ArrayList<Analyzer>();
List<Analyzer> anayzers = ClassSearcher.getInstances(Analyzer.class);
for (Analyzer analyzer : anayzers) {
if (analyzer.canAnalyze(program)) {
analyzerList.add(analyzer);
}
}
return new AnalysisRecipe("Default", analyzerList, program);
}
private static AnalysisRecipe findRecipe(Program program) {
return new AnalysisRecipe("Default", ClassSearcher.getInstances(Analyzer.class), program);
}
}

View File

@ -1,227 +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.framework.analysis;
import java.awt.*;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ChangeListener;
import docking.DockingUtils;
import docking.options.editor.ScrollableOptionsEditor;
import docking.widgets.label.GDLabel;
import generic.jar.ResourceFile;
import ghidra.app.services.Analyzer;
import ghidra.framework.analysis.gui.AnalyzerListPanel;
import ghidra.framework.analysis.gui.GhidraScriptSelectionDialog;
import ghidra.framework.options.EditorStateFactory;
import ghidra.framework.options.Options;
import ghidra.util.layout.MiddleLayout;
public class AnalysisRecipeEditor {
private JComponent mainComponent;
private AnalysisRecipe recipe;
private JTextArea descriptionComponent;
private JPanel analyzerOptionsPanel;
private Analyzer selectedAnalyzer;
private JPanel noOptionsPanel;
private ChangeListener changeListener = e -> refresh();
private JTabbedPane tabbedPane;
private ChangeListener tabListener;
public AnalysisRecipeEditor(AnalysisRecipe recipe) {
this.recipe = recipe;
mainComponent = buildComponent();
recipe.setChangeListener(changeListener);
buildNoOptionsPanel();
}
private void buildNoOptionsPanel() {
noOptionsPanel = new JPanel(new MiddleLayout());
noOptionsPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
JLabel label = new GDLabel("No options available.");
label.setFont(label.getFont().deriveFont(20f));
noOptionsPanel.add(label);
}
private void refresh() {
refreshAnalyzerPanel();
}
private JComponent buildComponent() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(buildLeftPanel(), BorderLayout.WEST);
panel.add(buildRightPanel(), BorderLayout.CENTER);
panel.add(buildButtonPanel(), BorderLayout.SOUTH);
return panel;
}
private Component buildButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
JButton addScriptButton = new JButton("Add script");
JButton addPhaseButton = new JButton("Add Phase");
JButton removePhaseButton = new JButton("Remove Phase");
addPhaseButton.addActionListener(e -> {
if (recipe.getAnalysisPhases().size() < 9) {
recipe.createPhase();
}
});
removePhaseButton.addActionListener(e -> recipe.deletePhase());
addScriptButton.addActionListener(e -> {
GhidraScriptSelectionDialog dialog = new GhidraScriptSelectionDialog();
ResourceFile file = dialog.show(mainComponent);
if (file != null) {
recipe.addScriptAnalyzer(file, dialog.getAnalyzerType(), dialog.getPriority());
}
});
panel.add(addScriptButton);
panel.add(addPhaseButton);
panel.add(removePhaseButton);
return panel;
}
private Component buildRightPanel() {
analyzerOptionsPanel = new JPanel(new BorderLayout());
configureBorder(analyzerOptionsPanel, "Analyzer Options");
/*
JPanel panel = new JPanel(new BorderLayout());
panel.add(buildDescriptionPanel(), BorderLayout.NORTH);
panel.add(analyzerOptionsPanel, BorderLayout.CENTER);
return panel;
*/
JSplitPane splitpane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, buildDescriptionPanel(),
analyzerOptionsPanel);
splitpane.setResizeWeight(.2);
splitpane.setBorder(BorderFactory.createEmptyBorder(10, 6, 8, 6));
splitpane.setDividerLocation(0.50);
return splitpane;
}
/**
* Sets a compound border around the component consisting
* of a titled border and a 10 pixel wide empty border.
*/
private void configureBorder(JComponent component, String title) {
Border emptyBorder = BorderFactory.createEmptyBorder(10, 10, 10, 10);
Border titleBorder =
BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), title);
Border compoundBorder = BorderFactory.createCompoundBorder(titleBorder, emptyBorder);
component.setBorder(compoundBorder);
}
private JPanel buildDescriptionPanel() {
descriptionComponent = buildTextArea();
JScrollPane descriptionScrollPane = new JScrollPane(descriptionComponent);
DockingUtils.setTransparent(descriptionScrollPane);
JPanel descriptionPanel = new JPanel(new BorderLayout());
configureBorder(descriptionScrollPane, "Analyzer Description");
descriptionPanel.add(descriptionScrollPane, BorderLayout.CENTER);
return descriptionPanel;
}
private JTextArea buildTextArea() {
JTextArea textarea = new JTextArea(3, 60);
textarea.setEditable(false);
textarea.setWrapStyleWord(true);
textarea.setLineWrap(true);
textarea.setFont(textarea.getFont().deriveFont(18f));
return textarea;
}
private Component buildLeftPanel() {
tabbedPane = new JTabbedPane();
tabListener = e -> {
AnalyzerListPanel panel = (AnalyzerListPanel) tabbedPane.getSelectedComponent();
List<Analyzer> selectedAnalyzers = panel.getSelectedAnalyzers();
setSelectedAnalyzer(selectedAnalyzers.size() == 1 ? selectedAnalyzers.get(0) : null);
};
populateTabs();
tabbedPane.addChangeListener(tabListener);
return tabbedPane;
}
private void populateTabs() {
tabbedPane.addTab("All", new AnalyzerListPanel(this, recipe, null));
List<AnalysisPhase> phases = recipe.getAnalysisPhases();
for (int i = 0; i < phases.size(); i++) {
AnalysisPhase phase = phases.get(i);
tabbedPane.addTab("Phase " + (i + 1), new AnalyzerListPanel(this, recipe, phase));
}
tabbedPane.setSelectedIndex(0);
}
private void refreshAnalyzerPanel() {
tabbedPane.removeChangeListener(tabListener);
List<AnalysisPhase> phases = recipe.getAnalysisPhases();
int tabCount = tabbedPane.getTabCount();
if (tabCount != phases.size() + 1) {
tabbedPane.removeAll();
populateTabs();
return;
}
for (int i = 0; i < tabCount; i++) {
AnalyzerListPanel comp = (AnalyzerListPanel) tabbedPane.getComponentAt(i);
comp.refresh();
}
tabbedPane.addChangeListener(tabListener);
mainComponent.validate();
mainComponent.repaint();
}
public JComponent getComponent() {
return mainComponent;
}
public void setSelectedAnalyzer(Analyzer analyzer) {
selectedAnalyzer = analyzer;
String description = analyzer != null ? analyzer.getDescription() : "";
descriptionComponent.setText(description);
descriptionComponent.setCaretPosition(0);
updateOptionsPanel();
mainComponent.validate();
analyzerOptionsPanel.repaint();
}
private void updateOptionsPanel() {
analyzerOptionsPanel.removeAll();
analyzerOptionsPanel.invalidate();
if (selectedAnalyzer == null) {
return;
}
Options options = recipe.getOptions(selectedAnalyzer);
List<String> optionNames = options.getLeafOptionNames();
if (optionNames.isEmpty()) {
analyzerOptionsPanel.add(noOptionsPanel);
return;
}
ScrollableOptionsEditor editorPanel =
new ScrollableOptionsEditor("Options For " + selectedAnalyzer.getName(), options,
optionNames, new EditorStateFactory());
editorPanel.setBorder(BorderFactory.createEmptyBorder());
analyzerOptionsPanel.add(editorPanel);
}
}

View File

@ -1,65 +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.framework.analysis;
import ghidra.app.services.Analyzer;
import ghidra.framework.model.UndoableDomainObject;
import ghidra.framework.task.GTask;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class AnalysisTask implements GTask {
private AnalyzerScheduler analyzerScheduler;
private AnalysisPhase executionPhase;
private AnalysisManager analysisManager;
public AnalysisTask(AnalysisPhase executionPhase, AnalyzerScheduler analyzerScheduler) {
this.executionPhase = executionPhase;
this.analyzerScheduler = analyzerScheduler;
analysisManager = analyzerScheduler.getAnalysisManager();
}
@Override
public String getName() {
return analyzerScheduler.getAnalyzer().getName();
}
@Override
public void run(UndoableDomainObject domainObject, TaskMonitor monitor)
throws CancelledException {
Program program = (Program) domainObject;
Analyzer analyzer = analyzerScheduler.getAnalyzer();
AddressSetView addressSet = analyzerScheduler.getAddressSet();
analyzer.added(program, addressSet, monitor, analysisManager.getMessageLog());
}
public int getPriority() {
return analyzerScheduler.getPriority();
}
public AnalysisPhase getPhase() {
return executionPhase;
}
@Override
public String toString() {
return getName();
}
}

View File

@ -1,138 +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.framework.analysis;
import org.jdom.Element;
import generic.jar.ResourceFile;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.services.*;
class AnalyzerInfo implements Comparable<AnalyzerInfo> {
static final String XML_ELEMENT_NAME = "ANALYZER";
static final String CLASS_NAME = "CLASS_NAME";
private boolean enabled;
private final boolean defaultEnablement;
private Analyzer analyzer;
private AnalysisPriority analysisPriority;
private AnalysisPhase startPhase;
private AnalysisRecipe recipe;
AnalyzerInfo(AnalysisRecipe analysisRecipe, Analyzer analyzer, boolean defaultEnablement) {
this.recipe = analysisRecipe;
this.analyzer = analyzer;
this.startPhase = recipe.getLastPhase();
this.analysisPriority = analyzer.getPriority();
this.defaultEnablement = defaultEnablement;
this.enabled = defaultEnablement;
}
@Override
public int compareTo(AnalyzerInfo o) {
// first make all One-Shot Analyzers sort before all other types.
AnalyzerType myType = analyzer.getAnalysisType();
AnalyzerType otherType = o.analyzer.getAnalysisType();
if (myType == AnalyzerType.ONE_SHOT_ANALYZER &&
otherType != AnalyzerType.ONE_SHOT_ANALYZER) {
return -1;
}
if (myType != AnalyzerType.ONE_SHOT_ANALYZER &&
otherType == AnalyzerType.ONE_SHOT_ANALYZER) {
return 1;
}
int diff = analysisPriority.priority() - o.analysisPriority.priority();
if (diff == 0) {
return analyzer.getName().compareTo(o.analyzer.getName());
}
return diff;
}
public void setEnabled(boolean b) {
enabled = b;
}
public boolean isEnabled() {
return enabled;
}
public AnalysisPhase getNextEnabledPhaseAtOrAfter(AnalysisPhase phase) {
if (!enabled) {
return null;
}
// if the given phase is less than the start phase, report the start phase
if (phase.compareTo(startPhase) <= 0) {
return startPhase;
}
if (analyzer.getAnalysisType() == AnalyzerType.ONE_SHOT_ANALYZER) {
// one shots only run once, so return null for all phases after start phase
return null;
}
// all other analyzers will run in all phases at or after their start phase.
return phase;
}
public Analyzer getAnalyzer() {
return analyzer;
}
public void setStartPhase(AnalysisPhase phase) {
this.startPhase = phase;
}
Element toXML() {
Element element = new Element(XML_ELEMENT_NAME);
element.setAttribute(CLASS_NAME, analyzer.getClass().getName());
if (analyzer instanceof GhidraScriptAnalyzerAdapter) {
GhidraScriptAnalyzerAdapter wrappedAnalyzer = (GhidraScriptAnalyzerAdapter) analyzer;
element.setAttribute("SCRIPT_NAME", wrappedAnalyzer.getScriptName());
element.setAttribute("ANALYZER_TYPE", wrappedAnalyzer.getAnalysisType().name());
element.setAttribute("PRIORITY",
Integer.toString(wrappedAnalyzer.getPriority().priority()));
}
element.setAttribute("START_PHASE", Integer.toString(startPhase.getIndex()));
if (enabled != defaultEnablement) {
element.setAttribute("ENABLED", Boolean.toString(enabled));
}
return element;
}
void loadFromXML(Element element) {
String enabledValue = element.getAttributeValue("ENABLED"); // defaults are not saved, so could be null
if (enabledValue != null) {
enabled = Boolean.parseBoolean(enabledValue);
}
int startPhaseIndex = Integer.parseInt(element.getAttributeValue("START_PHASE"));
startPhase = recipe.getPhase(startPhaseIndex);
}
public AnalysisPhase getAnalyzerStartPhase() {
return startPhase;
}
public static AnalyzerInfo createInfoForWrappedAnalzyer(AnalysisRecipe recipe,
Element element) {
String scriptName = element.getAttributeValue("SCRIPT_NAME");
String type = element.getAttributeValue("ANALYZER_TYPE");
AnalyzerType analyzerType = AnalyzerType.valueOf(type);
int priority = Integer.parseInt(element.getAttributeValue("PRIORITY"));
ResourceFile file = GhidraScriptUtil.findScriptByName(scriptName);
Analyzer analyzer = new GhidraScriptAnalyzerAdapter(file, analyzerType, priority);
return new AnalyzerInfo(recipe, analyzer, true);
}
}

View File

@ -1,23 +0,0 @@
/* ###
* 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.framework.analysis;
import ghidra.framework.options.Options;
public class AnalyzerPhaseConfiguration {
private Options options;
}

View File

@ -1,81 +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.framework.analysis;
import ghidra.app.services.Analyzer;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
public class AnalyzerScheduler {
private final AnalysisManager analysisManager;
private final Analyzer analyzer;
private int rank;
private boolean enabled;
private AddressSet addressSet = new AddressSet();
/**
* The phase to execute this scheduler's analyzer - may be current phase or a future phase
* if current status is delayed.
*/
private AnalysisPhase executionPhase;
public AnalyzerScheduler(AnalysisManager analysisMgr, Analyzer analyzer, int rank) {
this.analysisManager = analysisMgr;
this.rank = rank;
this.analyzer = analyzer;
}
synchronized void setPhase(AnalysisPhase phase) {
executionPhase = phase.getExecutionPhase(analyzer);
enabled = executionPhase != null;
}
synchronized void added(AddressSetView set) {
if (!enabled) {
return;
}
boolean alreadyScheduled = !addressSet.isEmpty();
addressSet.add(set);
if (!alreadyScheduled) {
analysisManager.scheduleAnalysisTask(new AnalysisTask(executionPhase, this));
}
}
public Analyzer getAnalyzer() {
return analyzer;
}
public int getPriority() {
return rank;
}
public AnalysisManager getAnalysisManager() {
return analysisManager;
}
public synchronized AddressSetView getAddressSet() {
AddressSetView set = addressSet;
addressSet = new AddressSet();
return set;
}
@Override
public String toString() {
return analyzer.getName();
}
}

View File

@ -1,21 +0,0 @@
/* ###
* 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.framework.analysis;
public enum AnalyzerStatus {
ENABLED, DELAYED, DISABLED
}

View File

@ -1,113 +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.framework.analysis;
import java.io.PrintWriter;
import generic.jar.ResourceFile;
import ghidra.app.script.*;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.model.Project;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg;
import ghidra.util.classfinder.ExtensionPointProperties;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ExtensionPointProperties(exclude = true) // exclude class from extension point discovery because it has to be directly instantiated in order to wrap the supplied script
public class GhidraScriptAnalyzerAdapter extends AbstractAnalyzer {
private ResourceFile scriptFile;
private GhidraScript script;
private PrintWriter writer;
public GhidraScriptAnalyzerAdapter(ResourceFile file, AnalyzerType analyzerType, int priority) {
super("Script: " + file.getName(), getDescription(file), analyzerType);
this.scriptFile = file;
setDefaultEnablement(true);
setPriority(new AnalysisPriority(priority));
writer = new PrintWriter(System.out);
script = getGhidraScript();
}
private static String getDescription(ResourceFile file) {
return GhidraScriptUtil.newScriptInfo(file).getDescription();
}
public void setPrintWriter(PrintWriter writer) {
this.writer = writer;
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
if (script == null) {
return false;
}
ProgramLocation loc = new ProgramLocation(program, set.getMinAddress());
ProgramSelection selection = new ProgramSelection(set);
// TODO if this API is ever used, then we need a project passed for scripts that
// may need it
Project project = null;
GhidraState scriptState = new GhidraState(null, project, program, loc, selection, null);
return runScript(scriptState, monitor);
}
private boolean runScript(GhidraState scriptState, TaskMonitor monitor) {
ResourceFile srcFile = script.getSourceFile();
String scriptName =
srcFile != null ? srcFile.getAbsolutePath() : (script.getClass().getName() + ".class");
try {
Msg.info(this, "SCRIPT: " + scriptName);
script.execute(scriptState, monitor, writer);
writer.flush();
}
catch (Exception exc) {
Program prog = scriptState.getCurrentProgram();
String path = (prog != null ? prog.getExecutablePath() : "Current program is null.");
String logErrorMsg =
path + "\nREPORT SCRIPT ERROR: " + scriptName + " : " + exc.getMessage();
Msg.error(this, logErrorMsg, exc);
return false;
}
return true;
}
private GhidraScript getGhidraScript() {
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptFile);
try {
return provider.getScriptInstance(scriptFile, writer);
}
catch (Exception e) {
Msg.error(this, "Error compiling script: " + e.getMessage(), e);
}
return null;
}
public String getScriptName() {
return scriptFile.getName();
}
}

View File

@ -1,41 +0,0 @@
/* ###
* 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.framework.analysis;
import docking.DialogComponentProvider;
public class RecipeEditorDialog extends DialogComponentProvider {
private AnalysisRecipe recipe;
public RecipeEditorDialog(AnalysisRecipe recipe) {
super("Recipe Editor", true);
this.recipe = recipe;
AnalysisRecipeEditor editor = new AnalysisRecipeEditor(recipe);
addWorkPanel(editor.getComponent());
addOKButton();
}
@Override
protected void okCallback() {
close();
}
public static void main(String[] args) throws Exception {
}
}

View File

@ -1,319 +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.framework.analysis.gui;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.label.GLabel;
import ghidra.app.services.Analyzer;
import ghidra.framework.analysis.*;
public class AnalyzerListPanel extends JPanel {
private AnalysisRecipe recipe;
private AnalysisPhase relevantPhase;
private JList<Analyzer> jList;
private AnalysisRecipeEditor editor;
private AnalyzerListModel model;
public AnalyzerListPanel(AnalysisRecipeEditor editor, AnalysisRecipe recipe,
AnalysisPhase phase) {
super(new BorderLayout());
this.editor = editor;
this.recipe = recipe;
this.relevantPhase = phase;
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JScrollPane jScrollPane = new JScrollPane(buildAnalyzerList());
jScrollPane.setColumnHeaderView(buildHeader());
jScrollPane.setCorner("UPPER_RIGHT_CORNER", new JPanel());
// jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
add(jScrollPane, BorderLayout.CENTER);
if (phase != null) {
GCheckBox checkbox =
new GCheckBox("Create Checkpoint When Phase Completed", phase.isCheckPoint());
checkbox.addActionListener(e -> relevantPhase.setIsCheckPoint(checkbox.isSelected()));
add(checkbox, BorderLayout.SOUTH);
if (phase == recipe.getLastPhase()) {
checkbox.setEnabled(false);
}
}
}
public List<Analyzer> getSelectedAnalyzers() {
int[] selectedIndices = jList.getSelectedIndices();
List<Analyzer> analyzers = new ArrayList<>();
for (int i : selectedIndices) {
analyzers.add(model.getElementAt(i));
}
return analyzers;
}
private JList<Analyzer> buildAnalyzerList() {
model = new AnalyzerListModel(recipe.getAnalyzers(relevantPhase));
jList = new JList<>(model) {
@Override
public String getToolTipText(MouseEvent e) {
Point p = e.getPoint();
int row = jList.locationToIndex(p);
Rectangle b = jList.getCellBounds(row, row);
p.x -= b.x;
p.y -= b.y;
ListCellRenderer<? super Analyzer> cellRenderer = jList.getCellRenderer();
Analyzer analyzer = jList.getModel().getElementAt(row);
JComponent comp = (JComponent) cellRenderer.getListCellRendererComponent(jList,
analyzer, row, true, true);
comp.setBounds(b.x, b.y, b.width, b.height);
JComponent c = (JComponent) SwingUtilities.getDeepestComponentAt(comp, p.x, p.y);
return c.getToolTipText();
}
};
jList.setCellRenderer(new AnalyzerCellRenderer());
jList.setPrototypeCellValue(getAnalyzerWithLongestName());
jList.setVisibleRowCount(14);
jList.addMouseListener(new AnalyzerListMouseListener());
jList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
List<Analyzer> selectedValues = jList.getSelectedValuesList();
if (selectedValues.size() == 1) {
editor.setSelectedAnalyzer(selectedValues.iterator().next());
}
else {
editor.setSelectedAnalyzer(null);
}
}
});
jList.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
char keyChar = e.getKeyChar();
if (keyChar == ' ') {
List<Analyzer> selectedValues = jList.getSelectedValuesList();
if (selectedValues.size() == 1) {
Analyzer analyzer = selectedValues.iterator().next();
recipe.setAnalyzerEnablement(analyzer, !recipe.isAnalyzerEnabled(analyzer));
}
}
else if (keyChar >= '1' && keyChar <= '9') {
setPhaseForSelectedAnalyzers(keyChar - '1');
}
}
});
return jList;
}
private Component buildHeader() {
JPanel panel = new JPanel(new BorderLayout());
// panel.setBackground(HEADER_COLOR);
//panel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
panel.add(new GLabel("ANALYZERS", SwingConstants.CENTER), BorderLayout.CENTER);
panel.add(buildPhaseHeader(), BorderLayout.EAST);
return panel;
}
private Component buildPhaseHeader() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(6, 0, 0, 0));
// panel.add(new GLabel("START", SwingConstants.CENTER), BorderLayout.NORTH);
panel.add(new GLabel("PHASE", SwingConstants.CENTER), BorderLayout.SOUTH);
Dimension dim = panel.getPreferredSize();
dim.width = getAnalysisPanelPhaseWidth();
panel.setPreferredSize(dim);
return panel;
}
private int getAnalysisPanelPhaseWidth() {
AnalyzerPanel panel = new AnalyzerPanel(recipe.getAnalyzers().get(0), recipe, null);
return panel.getPhasePanelWidth();
}
private Analyzer getAnalyzerWithLongestName() {
List<Analyzer> analyzers = recipe.getAnalyzers();
Analyzer longestAnalyzer = analyzers.get(0);
AnalyzerPanel panel = new AnalyzerPanel(longestAnalyzer, recipe, null);
int longestWidth = panel.getPreferredSize().width;
for (Analyzer analyzer : analyzers) {
panel.setAnalyzer(analyzer);
if (panel.getPreferredSize().width > longestWidth) {
longestWidth = panel.getPreferredSize().width;
longestAnalyzer = analyzer;
}
}
return longestAnalyzer;
}
protected void popupMenu(Point p) {
JPopupMenu menu = new JPopupMenu("Set Phase");
List<AnalysisPhase> phases = recipe.getAnalysisPhases();
for (AnalysisPhase analysisPhase : phases) {
menu.add(createMenuItem(analysisPhase));
}
addMenuItemToDeleteWrappedAnalyzerScripts(menu);
menu.show(jList, p.x, p.y);
}
private void addMenuItemToDeleteWrappedAnalyzerScripts(JPopupMenu menu) {
List<Analyzer> selectedValues = jList.getSelectedValuesList();
if (selectedValues.size() != 1) {
return;
}
final Analyzer analyzer = selectedValues.iterator().next();
if (analyzer instanceof GhidraScriptAnalyzerAdapter) {
JMenuItem jMenuItem = new JMenuItem("Delete Script Analyzer: " + analyzer.getName());
jMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
recipe.deleteScriptAnalyzer(analyzer);
}
});
menu.addSeparator();
menu.add(jMenuItem);
}
}
private JMenuItem createMenuItem(final AnalysisPhase analysisPhase) {
JMenuItem jMenuItem = new JMenuItem("Set Start Phase to " + analysisPhase);
jMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setPhaseForSelectedAnalyzers(analysisPhase.getIndex());
}
});
return jMenuItem;
}
public void refresh() {
model.setAnalyzers(recipe.getAnalyzers(relevantPhase));
}
protected void setPhaseForSelectedAnalyzers(int phaseIndex) {
List<AnalysisPhase> phases = recipe.getAnalysisPhases();
if (phaseIndex >= phases.size()) {
return;
}
AnalysisPhase phase = phases.get(phaseIndex);
for (Object object : jList.getSelectedValuesList()) {
Analyzer analyzer = (Analyzer) object;
recipe.setAnalyzerStartPhase(analyzer, phase);
}
}
private class AnalyzerCellRenderer implements ListCellRenderer<Analyzer> {
private AnalyzerPanel analyzerPanel;
AnalyzerCellRenderer() {
analyzerPanel = new AnalyzerPanel(recipe.getAnalyzers().get(0), recipe, relevantPhase);
}
@Override
public Component getListCellRendererComponent(JList<? extends Analyzer> list,
Analyzer value, int index, boolean isSelected, boolean cellHasFocus) {
Analyzer analyzer = value;
analyzerPanel.setAnalyzer(analyzer);
analyzerPanel.setSelected(isSelected);
return analyzerPanel;
}
}
private static class AnalyzerListModel extends AbstractListModel<Analyzer> {
private List<Analyzer> list;
AnalyzerListModel(List<Analyzer> list) {
this.list = list;
}
public void setAnalyzers(List<Analyzer> analyzers) {
if (analyzersChanged(analyzers)) {
list = analyzers;
fireContentsChanged(this, 0, list.size());
}
}
private boolean analyzersChanged(List<Analyzer> analyzers) {
if (analyzers.size() != list.size()) {
return true;
}
for (int i = 0; i < list.size(); i++) {
if (analyzers.get(i) != list.get(i)) {
return true;
}
}
return false;
}
@Override
public int getSize() {
return list.size();
}
@Override
public Analyzer getElementAt(int index) {
return (list.get(index));
}
}
private class AnalyzerListMouseListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
int row = jList.locationToIndex(p);
if (e.getButton() == MouseEvent.BUTTON1) {
Rectangle b = jList.getCellBounds(row, row);
p.x -= b.x;
p.y -= b.y;
ListCellRenderer<? super Analyzer> cellRenderer = jList.getCellRenderer();
Analyzer analyzer = jList.getModel().getElementAt(row);
Component comp =
cellRenderer.getListCellRendererComponent(jList, analyzer, row, true, true);
comp.setBounds(0, 0, b.width, b.height);
Component c = SwingUtilities.getDeepestComponentAt(comp, p.x, p.y);
if (c instanceof JCheckBox) {
((JCheckBox) c).doClick();
jList.repaint();
}
}
else if (e.getButton() == MouseEvent.BUTTON3) {
if (jList.isSelectedIndex(row)) {
popupMenu(p);
}
}
}
}
}

View File

@ -1,211 +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.framework.analysis.gui;
import java.awt.*;
import java.util.List;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.label.GDLabel;
import ghidra.app.services.Analyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.framework.analysis.AnalysisPhase;
import ghidra.framework.analysis.AnalysisRecipe;
import ghidra.util.layout.MiddleLayout;
import resources.ResourceManager;
public class AnalyzerPanel extends JPanel {
/**
* A raised beveled border that works with a white background.
*/
private static final Border RAISED_BUTTON_BORDER = BorderFactory.createCompoundBorder(
BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.LIGHT_GRAY, Color.DARK_GRAY),
BorderFactory.createEmptyBorder(1, 1, 1, 1));
/**
* A lowered beveled border that works with a white background.
*/
private static final Border LOWERED_BUTTON_BORDER = BorderFactory.createCompoundBorder(
BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.LIGHT_GRAY, Color.DARK_GRAY),
BorderFactory.createEmptyBorder(1, 1, 1, 1));
public static final Icon DELAYED_ICON = ResourceManager.loadImage("images/ledyellow.png");
public static final Icon DISABLED_ICON = ResourceManager.loadImage("images/ledred.png");
public static final Icon ENABLED_ICON = ResourceManager.loadImage("images/ledgreen.png");
private Analyzer analyzer;
private AnalysisRecipe recipe;
private JCheckBox enabledCheckbox;
private JLabel analyzerNameLabel;
private JLabel priorityLabel;
private JLabel iconLabel;
private JPanel phasePanel;
private JLabel phaseLabel;
private AnalysisPhase relevantPhase;
public AnalyzerPanel(Analyzer analyzer, AnalysisRecipe recipe, AnalysisPhase relevantPhase) {
super(new BorderLayout());
this.analyzer = analyzer;
this.recipe = recipe;
this.relevantPhase = relevantPhase;
add(buildInfoPanel(), BorderLayout.CENTER);
add(buildPhasePanel(), BorderLayout.EAST);
setBackground(Color.WHITE);
}
public int getPhasePanelWidth() {
return phasePanel.getPreferredSize().width;
}
private Component buildInfoPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
panel.setBorder(BorderFactory.createEtchedBorder());
panel.add(buildCheckboxAndIconPanel(), BorderLayout.WEST);
panel.add(buildLabelPanel(), BorderLayout.CENTER);
return panel;
}
private Component buildCheckboxAndIconPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
panel.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10));
enabledCheckbox = new GCheckBox();
enabledCheckbox.addActionListener(
e -> recipe.setAnalyzerEnablement(analyzer, enabledCheckbox.isSelected()));
enabledCheckbox.setSelected(recipe.isAnalyzerEnabled(analyzer));
panel.add(enabledCheckbox, BorderLayout.WEST);
iconLabel = new GDLabel();
updateIconLabel();
iconLabel.setBorder(BorderFactory.createEmptyBorder(2, 15, 2, 5));
panel.add(iconLabel, BorderLayout.EAST);
return panel;
}
private Component buildLabelPanel() {
JPanel panel = new JPanel(new BorderLayout());
// panel.setBorder(BorderFactory.createEtchedBorder());
panel.setBorder(BorderFactory.createEmptyBorder(4, 10, 2, 5));
panel.setOpaque(false);
analyzerNameLabel = new GDLabel(analyzer.getName());
analyzerNameLabel.setFont(analyzerNameLabel.getFont().deriveFont(18f));
panel.add(analyzerNameLabel, BorderLayout.CENTER);
priorityLabel = new GDLabel(analyzer.getPriority().toString());
priorityLabel.setHorizontalAlignment(SwingConstants.RIGHT);
priorityLabel.setFont(priorityLabel.getFont().deriveFont(10f));
priorityLabel.setForeground(Color.GRAY);
panel.add(priorityLabel, BorderLayout.SOUTH);
return panel;
}
private void updateIconLabel() {
AnalyzerType analyzerType = analyzer.getAnalysisType();
iconLabel.setToolTipText(analyzerType.getDescription());
iconLabel.setIcon(AnalyzerUtil.getIcon(analyzerType));
}
private Component buildPhasePanel() {
phasePanel = new JPanel(new MiddleLayout());
Border empty = BorderFactory.createEmptyBorder(0, 20, 0, 20);
Border etched = BorderFactory.createEtchedBorder();
phasePanel.setBorder(BorderFactory.createCompoundBorder(etched, empty));
phasePanel.setOpaque(false);
phasePanel.setPreferredSize(new Dimension(60, 0));
phaseLabel = new GDLabel("");
//@formatter:off
String text = analyzer.getAnalysisType() == AnalyzerType.ONE_SHOT_ANALYZER ?
"Phase when this analyzer runs. (Select and press number to change)"
: "Phase when this analyzer first becomes active. (Select and press number to change)";
//@formatter:on
phaseLabel.setToolTipText(text);
phasePanel.setToolTipText(text);
updatePhaseLabel();
phasePanel.add(phaseLabel);
return phasePanel;
}
public void setAnalyzer(Analyzer analyzer) {
if (this.analyzer != analyzer) {
this.analyzer = analyzer;
updateInfoFields();
}
updateAnalyzerStatus();
updateLabelColor();
}
private void updateLabelColor() {
boolean enabled = recipe.isAnalyzerEnabled(analyzer);
Color foreground = Color.BLACK;
if (!enabled) {
foreground = Color.LIGHT_GRAY;
}
else if (relevantPhase != null) {
if (recipe.getAnalyzerStartPhase(analyzer) == relevantPhase) {
foreground = Color.blue;
}
}
analyzerNameLabel.setForeground(foreground);
phaseLabel.setForeground(foreground);
}
private void updateAnalyzerStatus() {
boolean enabled = recipe.isAnalyzerEnabled(analyzer);
enabledCheckbox.setSelected(enabled);
List<AnalysisPhase> analysisPhases = recipe.getAnalysisPhases();
int nPhases = analysisPhases.size();
int nPanels = phasePanel.getComponentCount();
// if too many panels, remove extras
for (int i = nPanels; i > nPhases; i--) {
phasePanel.remove(i - 1);
}
updatePhaseLabel();
}
private void updatePhaseLabel() {
if (recipe.isAnalyzerEnabled(analyzer)) {
phaseLabel.setText(recipe.getAnalyzerStartPhase(analyzer).toString());
}
else {
phaseLabel.setText("");
}
}
private void updateInfoFields() {
analyzerNameLabel.setText(analyzer.getName());
priorityLabel.setText(analyzer.getPriority().toString());
updateIconLabel();
}
public void setSelected(boolean b) {
setBackground(b ? Color.YELLOW : Color.WHITE);
repaint();
}
}

View File

@ -1,79 +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.framework.analysis.gui;
import javax.swing.Icon;
import ghidra.app.services.AnalyzerType;
import ghidra.util.exception.AssertException;
import resources.MultiIcon;
import resources.ResourceManager;
import resources.icons.TranslateIcon;
public class AnalyzerUtil {
private static final Icon BYTES_ICON = ResourceManager.loadImage("images/mem_chip3.png");
private static final Icon DATA_ICON = ResourceManager.loadImage("images/Data_32.png");
private static final Icon FUNCTION_ICON = new MultiIcon(ResourceManager.getScaledIcon(
ResourceManager.loadImage("images/FunctionScope.gif"), 28, 28), false, 32, 32);
private static final Icon FUNCTION_MODIFIER_ICON = getIconForFunctionModifiersChanged();
private static final Icon FUNCTION_SIGNATURE_ICON = getIconForFunctionSignatureChanged();
private static final Icon INSTRUCTION_ICON =
ResourceManager.loadImage("images/Instructions_32.png");
private static final Icon MANUAL_ICON = new MultiIcon(
new TranslateIcon(ResourceManager.loadImage("images/play.png"), 5, 5), false, 32, 32);
private static Icon getIconForFunctionModifiersChanged() {
Icon baseIcon = new TranslateIcon(ResourceManager.getScaledIcon(
ResourceManager.loadImage("images/FunctionScope.gif"), 22, 22), 10, 5);
Icon hammerIcon = ResourceManager.loadImage("images/applications-development16.png");
MultiIcon multiIcon = new MultiIcon(baseIcon, false, 32, 32);
multiIcon.addIcon(hammerIcon);
return multiIcon;
}
private static Icon getIconForFunctionSignatureChanged() {
Icon baseIcon = new TranslateIcon(ResourceManager.getScaledIcon(
ResourceManager.loadImage("images/FunctionScope.gif"), 22, 22), 10, 5);
Icon pencilIcon = ResourceManager.loadImage("images/pencil.png");
MultiIcon multiIcon = new MultiIcon(baseIcon, false, 32, 32);
multiIcon.addIcon(pencilIcon);
return multiIcon;
}
public static Icon getIcon(AnalyzerType type) {
switch (type) {
case BYTE_ANALYZER:
return BYTES_ICON;
case DATA_ANALYZER:
return DATA_ICON;
case FUNCTION_ANALYZER:
return FUNCTION_ICON;
case FUNCTION_MODIFIERS_ANALYZER:
return FUNCTION_MODIFIER_ICON;
case FUNCTION_SIGNATURES_ANALYZER:
return FUNCTION_SIGNATURE_ICON;
case INSTRUCTION_ANALYZER:
return INSTRUCTION_ICON;
case ONE_SHOT_ANALYZER:
return MANUAL_ICON;
default:
throw new AssertException("Missing case statement for icons");
}
}
}

View File

@ -1,123 +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.framework.analysis.gui;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.Border;
import docking.widgets.*;
import docking.widgets.button.GRadioButton;
import docking.widgets.label.GLabel;
import docking.widgets.textfield.IntegerTextField;
import generic.jar.ResourceFile;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.services.AnalyzerType;
import ghidra.util.layout.HorizontalLayout;
import ghidra.util.layout.VerticalLayout;
public class GhidraScriptSelectionDialog extends ListSelectionDialog<ResourceFile> {
private ButtonGroup buttonGroup;
private IntegerTextField priorityField;
public GhidraScriptSelectionDialog() {
super("Create Script Based Analyzer", "Script Name:",
GhidraScriptUtil.getScriptSourceDirectories(), new ScriptNameConverter(),
new ScriptDescriptionConverter());
}
@Override
protected JComponent buildWorkPanel(String label,
DropDownTextFieldDataModel<ResourceFile> model) {
JPanel panel = new JPanel(new VerticalLayout(5));
panel.add(super.buildWorkPanel(label, model));
panel.add(buildTypePanel());
panel.add(buildPriorityPanel());
return panel;
}
private Component buildPriorityPanel() {
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(0, 40, 20, 0));
panel.add(new GLabel("Priority: "));
priorityField = new IntegerTextField(5, 0L);
panel.add(priorityField.getComponent());
return panel;
}
private JComponent createButtonComponent(AnalyzerType type) {
JPanel panel = new JPanel(new HorizontalLayout(1));
Icon icon = AnalyzerUtil.getIcon(type);
GRadioButton button = new GRadioButton();
button.setActionCommand(type.name());
button.setToolTipText(type.getDescription());
if (buttonGroup == null) {
buttonGroup = new ButtonGroup();
}
buttonGroup.add(button);
panel.add(button, BorderLayout.WEST);
JLabel label = new GLabel(type.getName(), icon, SwingConstants.LEFT);
label.setToolTipText(type.getDescription());
panel.add(label);
return panel;
}
private JComponent buildTypePanel() {
JPanel panel = new JPanel(new GridLayout(0, 2, 10, 10));
panel.add(createButtonComponent(AnalyzerType.ONE_SHOT_ANALYZER));
buttonGroup.setSelected(buttonGroup.getElements().nextElement().getModel(), true);
panel.add(createButtonComponent(AnalyzerType.FUNCTION_ANALYZER));
panel.add(createButtonComponent(AnalyzerType.BYTE_ANALYZER));
panel.add(createButtonComponent(AnalyzerType.FUNCTION_MODIFIERS_ANALYZER));
panel.add(createButtonComponent(AnalyzerType.INSTRUCTION_ANALYZER));
panel.add(createButtonComponent(AnalyzerType.FUNCTION_SIGNATURES_ANALYZER));
panel.add(createButtonComponent(AnalyzerType.DATA_ANALYZER));
Border inner = BorderFactory.createTitledBorder("Analyzer Type");
Border outer = BorderFactory.createEmptyBorder(0, 20, 20, 20);
panel.setBorder(BorderFactory.createCompoundBorder(outer, inner));
return panel;
}
public AnalyzerType getAnalyzerType() {
ButtonModel selection = buttonGroup.getSelection();
String actionCommand = selection.getActionCommand();
return AnalyzerType.valueOf(actionCommand);
}
public int getPriority() {
return priorityField.getIntValue();
}
public ResourceFile getScriptFile() {
return getSelectedItem();
}
private static class ScriptNameConverter implements DataToStringConverter<ResourceFile> {
@Override
public String getString(ResourceFile resourceFile) {
return resourceFile.getName();
}
}
private static class ScriptDescriptionConverter implements DataToStringConverter<ResourceFile> {
@Override
public String getString(ResourceFile resourceFile) {
return GhidraScriptUtil.newScriptInfo(resourceFile).getDescription();
}
}
}

View File

@ -1,121 +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.framework.analysis;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.services.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.listing.Program;
public class AnalyzerSchedulerTest extends AbstractGenericTest {
private static final int HIGHEST_RANK = 0;
private AnalyzerScheduler scheduler;
private ProgramDB program;
private AnalysisManagerSpy analysisMgrSpy;
private List<Analyzer> analyzers = new ArrayList<Analyzer>();
private Analyzer1 scheduledAnalyzer;
private AnalysisRecipe recipe;
public AnalyzerSchedulerTest() {
super();
}
@Before
public void setUp() throws Exception {
ProgramBuilder programBuilder = new ProgramBuilder();
programBuilder.createMemory("AAA", "0x100", 0x1000);
program = programBuilder.getProgram();
analysisMgrSpy = new AnalysisManagerSpy(program);
scheduledAnalyzer = new Analyzer1();
analyzers.add(scheduledAnalyzer);
recipe = new AnalysisRecipe("Test", analyzers, program);
scheduler = new AnalyzerScheduler(analysisMgrSpy, scheduledAnalyzer, HIGHEST_RANK);
}
@Test
public void testDisabledState() {
recipe.setAnalyzerEnablement(scheduledAnalyzer, false);
scheduler.setPhase(recipe.getLastPhase());
scheduler.added(program.getMemory());
assertEquals(0, analysisMgrSpy.getScheduledTaskCount());
}
@Test
public void testDelayedState() {
AnalysisPhase phase = recipe.createPhase();
scheduler.setPhase(phase);
scheduler.added(program.getMemory());
assertEquals(1, analysisMgrSpy.getScheduledTaskCount());
assertEquals(recipe.getLastPhase(), analysisMgrSpy.getTask().getPhase());
}
@Test
public void testEnabledState() {
AnalysisPhase phase = recipe.createPhase();
recipe.setAnalyzerStartPhase(scheduledAnalyzer, phase);
scheduler.setPhase(phase);
scheduler.added(program.getMemory());
assertEquals(1, analysisMgrSpy.getScheduledTaskCount());
assertEquals(phase, analysisMgrSpy.getTask().getPhase());
}
// private AnalysisPhase createPhase(AnalyzerStatus status) {
// AnalysisPhase phase = recipe.createPhaseBefore(recipe.getLastPhase(), "Phase 1");
// recipe.setAnalyzerStatus(scheduledAnalyzer, phase, status);
// return phase;
// }
private class AnalysisManagerSpy extends AnalysisManager {
private List<AnalysisTask> tasks = new ArrayList<AnalysisTask>();
public AnalysisManagerSpy(Program program) {
super(program);
}
AnalysisTask getTask() {
return tasks.get(0);
}
@Override
void scheduleAnalysisTask(AnalysisTask task) {
tasks.add(task);
}
int getScheduledTaskCount() {
return tasks.size();
}
}
public static class Analyzer1 extends AnalyzerTestStub {
Analyzer1() {
super("Analyzer1", AnalyzerType.BYTE_ANALYZER, true, new AnalysisPriority("1", 1));
}
}
}

View File

@ -1,42 +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.framework.analysis;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class AnalyzerTestStub extends AbstractAnalyzer {
AnalyzerTestStub(String name, AnalyzerType type, boolean defaultEnablement,
AnalysisPriority priority) {
super(name, name + " Description", type);
setPriority(priority);
setDefaultEnablement(defaultEnablement);
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
Msg.debug(this, "Ran " + getName());
return true;
}
}

View File

@ -1,278 +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.framework.analysis;
import static org.junit.Assert.*;
import java.io.*;
import java.util.ArrayList;
import org.junit.*;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.osgi.BundleHost;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.services.*;
import ghidra.framework.task.GScheduledTask;
import ghidra.framework.task.GTaskListener;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.symbol.Symbol;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import mockit.*;
public class AnalysisManagerTest extends AbstractGhidraHeadlessIntegrationTest {
@Mocked
GTaskListener listener;
private ProgramBuilder programBuilder;
private ProgramDB program;
private AnalysisManager analysisManager;
private ArrayList<Analyzer> analyzers;
class TaskTypeDelegate implements Delegate<GScheduledTask> {
private String name;
TaskTypeDelegate(String name) {
this.name = name;
}
void validate(GScheduledTask scheduledTask) {
String clazz = scheduledTask.getTask().getClass().getSimpleName();
if (!clazz.equals(name)) {
assertEquals("Found unexpected class. Found task with name '" +
scheduledTask.getTask().getName() + "'", name, clazz);
}
}
}
class TaskNameDelegate implements Delegate<GScheduledTask> {
private String name;
TaskNameDelegate(String name) {
this.name = name;
}
void validate(GScheduledTask scheduledTask) {
Assert.assertEquals(name, scheduledTask.getTask().getName());
}
}
@Before
public void setUp() throws Exception {
programBuilder = new ProgramBuilder();
programBuilder.createMemory("AAA", "0x100", 0x1000);
program = programBuilder.getProgram();
analyzers = new ArrayList<>();
// make sure the user scripts subdirectory exists for createScriptFile
File userScriptsDir = new File(GhidraScriptUtil.USER_SCRIPTS_DIR);
userScriptsDir.mkdirs();
GhidraScriptUtil.initialize(new BundleHost(), null);
}
@After
public void cleanup() {
GhidraScriptUtil.dispose();
}
@Test
public void testTwoAnalyzersWithOnePhases() {
analyzers.add(new Analyzer1());
analyzers.add(new Analyzer2());
AnalysisRecipe recipe = new AnalysisRecipe("Test Recipe", analyzers, program);
analysisManager = new AnalysisManager(program, recipe);
analysisManager.addTaskListener(listener);
analysisManager.runAnalysis(null);
analysisManager.waitForAnalysis(1000);
new VerificationsInOrder() {
{
listener.initialize();
listener.taskStarted(with(new TaskTypeDelegate("StartPhaseTask")));
listener.taskCompleted(with(new TaskTypeDelegate("StartPhaseTask")), null);
listener.taskStarted(with(new TaskTypeDelegate("KickStartAnalyzersTask")));
listener.taskCompleted(with(new TaskTypeDelegate("KickStartAnalyzersTask")), null);
listener.taskStarted(with(new TaskNameDelegate("Analyzer1")));
listener.taskCompleted(with(new TaskNameDelegate("Analyzer1")), null);
listener.taskStarted(with(new TaskNameDelegate("Analyzer2")));
listener.taskCompleted(with(new TaskNameDelegate("Analyzer2")), null);
}
};
}
@Test
public void testTwoAnalyzersWithTwoPhases() {
analyzers.add(new Analyzer1());
analyzers.add(new Analyzer2());
AnalysisRecipe recipe = new AnalysisRecipe("Test Recipe", analyzers, program);
AnalysisPhase firstPhase = recipe.createPhase();
recipe.setAnalyzerStartPhase(analyzers.get(0), firstPhase);
analysisManager = new AnalysisManager(program, recipe);
analysisManager.addTaskListener(listener);
analysisManager.runAnalysis(null);
analysisManager.waitForAnalysis(1000);
new VerificationsInOrder() {
{
listener.initialize();
listener.taskStarted(with(new TaskTypeDelegate("StartPhaseTask")));
listener.taskCompleted(with(new TaskTypeDelegate("StartPhaseTask")), null);
listener.taskStarted(with(new TaskTypeDelegate("KickStartAnalyzersTask")));
listener.taskCompleted(with(new TaskTypeDelegate("KickStartAnalyzersTask")), null);
listener.taskStarted(with(new TaskNameDelegate("Analyzer1")));
listener.taskCompleted(with(new TaskNameDelegate("Analyzer1")), null);
listener.taskStarted(with(new TaskTypeDelegate("StartPhaseTask")));
listener.taskCompleted(with(new TaskTypeDelegate("StartPhaseTask")), null);
listener.taskStarted(with(new TaskNameDelegate("Analyzer2")));
listener.taskCompleted(with(new TaskNameDelegate("Analyzer2")), null);
}
};
}
@Test
public void testTwoAnalyzersWithTwoPhasesAnalyzerInSecondPhaseOff() {
analyzers.add(new Analyzer1());
analyzers.add(new Analyzer2());
AnalysisRecipe recipe = new AnalysisRecipe("Test Recipe", analyzers, program);
AnalysisPhase firstPhase = recipe.createPhase();
recipe.setAnalyzerStartPhase(analyzers.get(0), firstPhase);
recipe.setAnalyzerEnablement(analyzers.get(1), false);
analysisManager = new AnalysisManager(program, recipe);
analysisManager.addTaskListener(listener);
analysisManager.runAnalysis(null);
analysisManager.waitForAnalysis(1000);
new VerificationsInOrder() {
{
listener.initialize();
listener.taskStarted(with(new TaskTypeDelegate("StartPhaseTask")));
listener.taskCompleted(with(new TaskTypeDelegate("StartPhaseTask")), null);
listener.taskStarted(with(new TaskTypeDelegate("KickStartAnalyzersTask")));
listener.taskCompleted(with(new TaskTypeDelegate("KickStartAnalyzersTask")), null);
listener.taskStarted(with(new TaskNameDelegate("Analyzer1")));
listener.taskCompleted(with(new TaskNameDelegate("Analyzer1")), null);
listener.taskStarted(with(new TaskTypeDelegate("StartPhaseTask")));
listener.taskCompleted(with(new TaskTypeDelegate("StartPhaseTask")), null);
listener.taskStarted((GScheduledTask) any);
times = 0; // make sure no more taskStarted calls are mode
}
};
}
@Test
public void testSciptAnalyzer() throws Exception {
final ResourceFile scriptFile = createScriptFile();
analyzers.add(new Analyzer1());
GhidraScriptAnalyzerAdapter analyzer =
new GhidraScriptAnalyzerAdapter(scriptFile, AnalyzerType.BYTE_ANALYZER, 10000);
analyzers.add(analyzer);
AnalysisRecipe recipe = new AnalysisRecipe("Test Recipe", analyzers, program);
analysisManager = new AnalysisManager(program, recipe);
analysisManager.addTaskListener(listener);
analysisManager.runAnalysis(null);
analysisManager.waitForAnalysis(10000);
// verify that the script ran
Symbol symbol = getUniqueSymbol(program, "TEST_SYMBOL");
assertNotNull(symbol);
new VerificationsInOrder() {
{
listener.initialize();
listener.taskStarted(with(new TaskTypeDelegate("StartPhaseTask")));
listener.taskCompleted(with(new TaskTypeDelegate("StartPhaseTask")), null);
listener.taskStarted(with(new TaskTypeDelegate("KickStartAnalyzersTask")));
listener.taskCompleted(with(new TaskTypeDelegate("KickStartAnalyzersTask")), null);
listener.taskStarted(with(new TaskNameDelegate("Analyzer1")));
listener.taskCompleted(with(new TaskNameDelegate("Analyzer1")), null);
listener.taskStarted(with(new TaskNameDelegate("Script: " + scriptFile.getName())));
listener.taskCompleted(
with(new TaskNameDelegate("Script: " + scriptFile.getName())), null);
listener.taskStarted((GScheduledTask) any);
times = 0; // make sure no more taskStarted calls are mode
}
};
}
private ResourceFile createScriptFile() throws Exception {
ResourceFile newScriptFile = createTempScriptFile("TestAnalyzerScript");
String filename = newScriptFile.getName();
String className = filename.replaceAll("\\.java", "");
//@formatter:off
String newScript =
"import ghidra.app.script.GhidraScript;\n\n"+
"import ghidra.program.model.address.Address;\n"+
"import ghidra.program.model.symbol.SourceType;\n"+
"public class "+className+" extends GhidraScript {\n\n"+
" @Override\n"+
" protected void run() throws Exception {\n"+
" Address minAddress = currentProgram.getMinAddress();\n"+
" currentProgram.getSymbolTable().createLabel(minAddress, \"TEST_SYMBOL\",\n"+
" SourceType.USER_DEFINED);\n"+
" }\n\n"+
"}\n";
//@formatter:on
writeStringToFile(newScriptFile, newScript);
return newScriptFile;
}
private void writeStringToFile(ResourceFile file, String string) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(file.getFile(false)));
writer.write(string);
writer.close();
}
private ResourceFile createTempScriptFile(String name) throws IOException {
File userScriptsDir = new File(GhidraScriptUtil.USER_SCRIPTS_DIR);
if (name.length() > 50) {
// too long and the script manager complains
name = name.substring(name.length() - 50);
}
File tempFile = File.createTempFile(name, ".java", userScriptsDir);
tempFile.deleteOnExit();
return new ResourceFile(tempFile);
}
public static class Analyzer1 extends AnalyzerTestStub {
Analyzer1() {
super("Analyzer1", AnalyzerType.BYTE_ANALYZER, true, new AnalysisPriority("1", 1));
}
}
public static class Analyzer2 extends AnalyzerTestStub {
Analyzer2() {
super("Analyzer2", AnalyzerType.BYTE_ANALYZER, true, new AnalysisPriority("2", 2));
}
}
}

View File

@ -1,158 +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.framework.analysis;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.jdom.Element;
import org.junit.*;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.osgi.BundleHost;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.services.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class AnalysisRecipeTest extends AbstractGhidraHeadlessIntegrationTest {
private AnalysisRecipe recipe;
private ProgramBuilder programBuilder;
private ProgramDB program;
private ArrayList<Analyzer> analyzers;
@Before
public void setUp() throws Exception {
programBuilder = new ProgramBuilder();
programBuilder.createMemory("AAA", "0x100", 0x1000);
program = programBuilder.getProgram();
analyzers = new ArrayList<>();
GhidraScriptUtil.initialize(new BundleHost(), null);
}
@After
public void cleanup() {
GhidraScriptUtil.dispose();
}
@Test
public void testXML() {
Analyzer1 analyzer1 = new Analyzer1();
Analyzer2 analyzer2 = new Analyzer2();
analyzers.add(analyzer1);
analyzers.add(analyzer2);
recipe = new AnalysisRecipe("Test Recipe", analyzers, program);
AnalysisPhase lastPhase = recipe.getLastPhase();
AnalysisPhase firstPhase = recipe.createPhase();
recipe.setAnalyzerStartPhase(analyzer1, firstPhase);
assertEquals(firstPhase, recipe.getAnalyzerStartPhase(analyzer1));
assertEquals(lastPhase, recipe.getAnalyzerStartPhase(analyzer2));
Element xml = recipe.toXML();
AnalysisRecipe savedRecipe = new AnalysisRecipe("FOO", analyzers, program);
savedRecipe.loadFromXML(xml);
List<AnalysisPhase> analysisPhases = savedRecipe.getAnalysisPhases();
assertEquals(2, analysisPhases.size());
AnalysisPhase phase1 = analysisPhases.get(0);
AnalysisPhase phase2 = analysisPhases.get(1);
assertEquals("Test Recipe", savedRecipe.getName());
assertEquals("1", phase1.getName());
assertEquals("2", phase2.getName());
assertEquals(firstPhase, recipe.getAnalyzerStartPhase(analyzer1));
assertEquals(lastPhase, recipe.getAnalyzerStartPhase(analyzer2));
}
@Test
public void testXMLWithScriptAnalzyers() {
Analyzer1 analyzer1 = new Analyzer1();
Analyzer2 analyzer2 = new Analyzer2();
analyzers.add(analyzer1);
analyzers.add(analyzer2);
recipe = new AnalysisRecipe("Test Recipe", analyzers, program);
ResourceFile sourceFile = GhidraScriptUtil.findScriptByName("HelloWorldScript.java");
assertNotNull(sourceFile);
recipe.addScriptAnalyzer(sourceFile, AnalyzerType.INSTRUCTION_ANALYZER, 15);
AnalysisPhase lastPhase = recipe.getLastPhase();
AnalysisPhase firstPhase = recipe.createPhase();
recipe.setAnalyzerStartPhase(analyzer1, firstPhase);
assertEquals(firstPhase, recipe.getAnalyzerStartPhase(analyzer1));
assertEquals(lastPhase, recipe.getAnalyzerStartPhase(analyzer2));
Element xml = recipe.toXML();
AnalysisRecipe savedRecipe = new AnalysisRecipe("FOO", analyzers, program);
savedRecipe.loadFromXML(xml);
List<AnalysisPhase> analysisPhases = savedRecipe.getAnalysisPhases();
assertEquals(2, analysisPhases.size());
AnalysisPhase phase1 = analysisPhases.get(0);
AnalysisPhase phase2 = analysisPhases.get(1);
assertEquals("Test Recipe", savedRecipe.getName());
List<Analyzer> analyzerList = savedRecipe.getAnalyzers();
assertEquals(3, analyzerList.size());
Analyzer scriptAnalyzer = analyzerList.get(0);
assertEquals(GhidraScriptAnalyzerAdapter.class, scriptAnalyzer.getClass());
assertEquals("Script: HelloWorldScript.java", scriptAnalyzer.getName());
assertEquals(AnalyzerType.INSTRUCTION_ANALYZER, scriptAnalyzer.getAnalysisType());
assertEquals(15, scriptAnalyzer.getPriority().priority());
}
public static class Analyzer1 extends AnalyzerTestStub {
Analyzer1() {
super("Analyzer1", AnalyzerType.BYTE_ANALYZER, true, new AnalysisPriority("1", 100));
}
}
public static class Analyzer2 extends AnalyzerTestStub {
Analyzer2() {
super("Analyzer2", AnalyzerType.BYTE_ANALYZER, true, new AnalysisPriority("2", 200));
}
}
public Namespace get(Program program, Namespace otherNamespace) {
Program source = otherNamespace.getSymbol().getProgram();
if (source == program) {
return otherNamespace;
}
getCorrespondingNamespace(source, otherNamespace, program);
return null;
}
private Namespace getCorrespondingNamespace(Program source, Namespace ns, Program p) {
Namespace parent = ns.getParentNamespace();
if (parent == source.getGlobalNamespace()) {
return p.getGlobalNamespace();
}
Namespace other = getCorrespondingNamespace(source, parent, p);
Symbol symbol = getUniqueSymbol(p, ns.getName(), other);
return (Namespace) symbol.getObject();
}
}

View File

@ -1,65 +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.framework.analysis;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import docking.DockingWindowManager;
import ghidra.SwingExceptionHandler;
import ghidra.program.database.ProgramBuilder;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
public class RecipeDialogTest extends AbstractGhidraHeadedIntegrationTest {
private ProgramBuilder builder;
private AnalysisRecipe recipe;
public RecipeDialogTest() {
super();
}
@Before
public void setUp() throws Exception {
builder = new ProgramBuilder();
recipe = AnalysisRecipeBuilder.getRecipe(builder.getProgram());
recipe.createPhase();
recipe.createPhase();
recipe.createPhase();
}
@Test
public void testNothing() {
//
}
public void dontTestDialog() {
RecipeEditorDialog dialog = new RecipeEditorDialog(recipe);
DockingWindowManager.showDialog(null, dialog);
assertNotNull(dialog);
}
public static void main(String[] args) throws Exception {
SwingExceptionHandler.registerHandler();
RecipeDialogTest test = new RecipeDialogTest();
test.setUp();
test.dontTestDialog();
System.exit(0);
}
}