mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 13:11:47 +00:00
Merge remote-tracking branch 'origin/GP-145_ghidra1_RemoveObsoleteCode'
This commit is contained in:
commit
2fdfc217c1
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user