/* ### * 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.feature.vt.gui.task; import static ghidra.feature.vt.gui.util.VTOptionDefines.*; import java.util.Collection; import java.util.List; import ghidra.app.plugin.core.analysis.AnalysisWorker; import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.feature.vt.api.main.*; import ghidra.feature.vt.api.markuptype.FunctionNameMarkupType; import ghidra.feature.vt.api.markuptype.LabelMarkupType; import ghidra.feature.vt.api.util.VTAssociationStatusException; import ghidra.feature.vt.api.util.VersionTrackingApplyException; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.util.VTMatchApplyChoices.FunctionNameChoices; import ghidra.feature.vt.gui.util.VTMatchApplyChoices.LabelChoices; import ghidra.framework.options.Options; import ghidra.framework.options.ToolOptions; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; public class AcceptMatchTask extends VtTask { protected final VTController controller; private final List<VTMatch> matches; private boolean doApplyFunctionNames = true; private boolean doApplyDataNames = true; public AcceptMatchTask(VTController controller, List<VTMatch> matches) { super("Accept Matches", controller.getSession()); this.controller = controller; this.matches = matches; Options options = controller.getOptions(); doApplyFunctionNames = options.getBoolean(APPLY_FUNCTION_NAME_ON_ACCEPT, true); doApplyDataNames = options.getBoolean(APPLY_DATA_NAME_ON_ACCEPT, true); } @Override protected boolean shouldSuspendSessionEvents() { return matches.size() > 20; } @Override protected boolean doWork(TaskMonitor monitor) { Program destinationProgram = controller.getDestinationProgram(); AutoAnalysisManager manager = AutoAnalysisManager.getAnalysisManager(destinationProgram); try { return manager.scheduleWorker(new AnalysisWorker() { @Override public String getWorkerName() { return getTaskTitle(); } @Override public boolean analysisWorkerCallback(Program program, Object workerContext, TaskMonitor tm) throws CancelledException { // accept matches without triggering auto-analysis on changes made acceptMatches(tm); return true; } }, null, false, monitor); } catch (CancelledException e) { // don't care } catch (Exception e) { reportError(e); } return false; } private void acceptMatches(TaskMonitor monitor) throws CancelledException { monitor.setMessage("Processing matches"); monitor.initialize(matches.size()); for (VTMatch match : matches) { monitor.checkCanceled(); VTAssociation association = match.getAssociation(); VTAssociationStatus status = association.getStatus(); if (status != VTAssociationStatus.AVAILABLE) { continue; } acceptMatch(match); if (match.getAssociation().getType() == VTAssociationType.FUNCTION) { if (doApplyFunctionNames) { applyFunctionNames(match, monitor); } } else if (doApplyDataNames) { applyDataNames(match, monitor); } monitor.incrementProgress(1); } monitor.setProgress(matches.size()); } private void applyDataNames(VTMatch match, TaskMonitor monitor) throws CancelledException { VTAssociation association = match.getAssociation(); Collection<VTMarkupItem> markupItems = association.getMarkupItems(monitor); VTMarkupItem vtMarkupItem = getDataLabelMarkupItem(association.getSourceAddress(), markupItems); if (vtMarkupItem == null) { return; } // since this markup item is always at the match destination, we can set it simply without // using a correlator. if (vtMarkupItem.getDestinationAddress() == null) { vtMarkupItem.setDestinationAddress(match.getAssociation().getDestinationAddress()); } ToolOptions options = controller.getOptions(); ToolOptions copyOfOptions = options.copy(); // Force the label to be applied. if (copyOfOptions.getEnum(LABELS, DEFAULT_OPTION_FOR_LABELS) == LabelChoices.EXCLUDE) { copyOfOptions.setEnum(LABELS, DEFAULT_OPTION_FOR_LABELS); } try { vtMarkupItem.apply(VTMarkupItemApplyActionType.REPLACE, copyOfOptions); } catch (VersionTrackingApplyException e) { reportError(e); } } private void applyFunctionNames(VTMatch match, TaskMonitor monitor) throws CancelledException { VTAssociation association = match.getAssociation(); Collection<VTMarkupItem> markupItems = association.getMarkupItems(monitor); VTMarkupItem vtMarkupItem = getFunctionNameMarkupItem(markupItems); if (vtMarkupItem == null) { return; } // since this markup item is always at the match destination, we can set it simply without // using a correlator. if (vtMarkupItem.getDestinationAddress() == null) { vtMarkupItem.setDestinationAddress(match.getAssociation().getDestinationAddress()); } ToolOptions options = controller.getOptions(); ToolOptions copyOfOptions = options.copy(); // Force the function name to be applied. if (copyOfOptions.getEnum(FUNCTION_NAME, DEFAULT_OPTION_FOR_FUNCTION_NAME) == FunctionNameChoices.EXCLUDE) { copyOfOptions.setEnum(FUNCTION_NAME, DEFAULT_OPTION_FOR_FUNCTION_NAME); } try { vtMarkupItem.apply(VTMarkupItemApplyActionType.REPLACE, copyOfOptions); } catch (VersionTrackingApplyException e) { reportError(e); } } private VTMarkupItem getFunctionNameMarkupItem(Collection<VTMarkupItem> markupItems) { for (VTMarkupItem vtMarkupItem : markupItems) { if (vtMarkupItem.getMarkupType() == FunctionNameMarkupType.INSTANCE) { return vtMarkupItem; } } return null; } private VTMarkupItem getDataLabelMarkupItem(Address source, Collection<VTMarkupItem> markupItems) { for (VTMarkupItem vtMarkupItem : markupItems) { if (vtMarkupItem.getMarkupType() == LabelMarkupType.INSTANCE && vtMarkupItem.getSourceAddress().equals(source)) { return vtMarkupItem; } } return null; } private void acceptMatch(VTMatch match) { VTAssociation association = match.getAssociation(); VTAssociationStatus status = association.getStatus(); if (status == VTAssociationStatus.ACCEPTED) { return; } try { association.setAccepted(); } catch (VTAssociationStatusException e) { throw new AssertException("Should have been given an association that is not " + "blocked - current status: " + association.getStatus()); } } }