diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/Navigatable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/Navigatable.java index 64fb41d58c..caba88008c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/Navigatable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/Navigatable.java @@ -35,9 +35,9 @@ public interface Navigatable { /** * Commands this navigatable to goto (display) the given program and location - * + * * @param program the program - * + * * @param location the location in that program to display * @return true if the goto was successful */ @@ -45,35 +45,35 @@ public interface Navigatable { /** * Returns the current location of this Navigatable - * + * * @return the current location of this Navigatable */ public ProgramLocation getLocation(); /** * Returns the current Program of this Navigatable - * + * * @return the current Program of this Navigatable */ public Program getProgram(); /** * Returns the view state for this navigatable - * + * * @return the view state for this navigatable */ public LocationMemento getMemento(); /** * Sets the view state for this navigatable. This is used later to restore the view state. - * + * * @param memento the state of this navigatable */ public void setMemento(LocationMemento memento); /** * Returns an icon that represents this Navigatable - * + * * @return the icon */ public Icon getNavigatableIcon(); @@ -81,7 +81,7 @@ public interface Navigatable { /** * Returns true if this Navigatable is "connected". Navigatables are connected if they produce * and consume location and selection events. - * + * * @return true if this Navigatable is "connected" */ public boolean isConnected(); @@ -89,8 +89,8 @@ public interface Navigatable { /** * Return true if this Navigatable is part of the "dynamic analysis" or "debugger" user * interface. - * - * @return tre if this Navigatable is "dynamic" + * + * @return true if this Navigatable is "dynamic" */ default public boolean isDynamic() { return false; @@ -98,7 +98,7 @@ public interface Navigatable { /** * Currently only the 'connected' windows support markers - * + * * @return true if this navigatable supports markers */ public boolean supportsMarkers(); @@ -110,78 +110,78 @@ public interface Navigatable { /** * Returns true if this provider is visible - * + * * @return true if visible */ public boolean isVisible(); /** * Tells this Navigatable to set its selection to the given selection - * + * * @param selection the selection to set. */ public void setSelection(ProgramSelection selection); /** * Tells this Navigatable to set its highlight to the given highlight - * + * * @param highlight the highlight to set. */ public void setHighlight(ProgramSelection highlight); /** * Returns the current selection of this Navigatable - * + * * @return the current selection of this Navigatable */ public ProgramSelection getSelection(); /** * Returns the current highlight of this Navigatable - * + * * @return the current highlight of this Navigatable */ public ProgramSelection getHighlight(); /** * Returns the current text selection or null - * + * * @return the text selection */ public String getTextSelection(); /** * Adds a listener to be notified if this Navigatable is terminated - * + * * @param listener the listener to be notified when this Navigatable is closed */ public void addNavigatableListener(NavigatableRemovalListener listener); /** * Removes a listener to be notified if this Navigatable is terminated. - * + * * @param listener the listener that no longer should be notified when this Navigatable is * closed. */ public void removeNavigatableListener(NavigatableRemovalListener listener); /** - * Returns true if this navigatable is no longer valid, false if it is still good - * - * @return true if this navigatable is no longer valid, false if it is still good + * Returns true if this navigatable is no longer valid + * + * @return true if this navigatable is no longer valid */ public boolean isDisposed(); /** * Returns true if this navigatable supports highlighting - * + * * @return true if this navigatable supports highlighting */ public boolean supportsHighlight(); /** * Set the highlight provider for the given program - * + * * @param highlightProvider the provider * @param program the program */ @@ -189,7 +189,7 @@ public interface Navigatable { /** * Removes the given highlight provider for the given program - * + * * @param highlightProvider the provider * @param program the program */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NavigationHistoryPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NavigationHistoryPlugin.java index ce10f964a6..8c220cc162 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NavigationHistoryPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NavigationHistoryPlugin.java @@ -41,7 +41,7 @@ import ghidra.util.bean.opteditor.OptionsVetoException; * viewer plugins to change their focus to a certain address. As viewer plugins are directed to one * or more addresses it maintains information about where the viewers have been to support ability * for the viewers to go back to a previous "focus" point. - * + * * Services Provided: NavigationHistoryService Events Consumed: ProgramLocationPluginEvent, * ProgramPluginEvent Event Produced: HistoryChangePluginEvent Actions: None. */ @@ -447,7 +447,7 @@ public class NavigationHistoryPlugin extends Plugin //================================================================================================== // Inner Classes -//================================================================================================== +//================================================================================================== private static class HistoryList { private List list = new ArrayList<>(); @@ -551,7 +551,7 @@ public class NavigationHistoryPlugin extends Plugin /** * Find the next history LocationMemento that contains a different function. If no such * LocationMemento is found, null is returned. - * + * * @param navigatable the navigatable being navigated * @param moveTo true means after finding, get current location to it. false to just find * and do nothing @@ -595,7 +595,7 @@ public class NavigationHistoryPlugin extends Plugin /** * Find the previous history LocationMemento that contains a different function. If no such * LocationMemento is found, null is returned. - * + * * @param navigatable the navigatable being navigated * @param moveTo true means after finding, get current location to it. false to just find * and do nothing @@ -627,35 +627,71 @@ public class NavigationHistoryPlugin extends Plugin } private Function getPreviousStartFunction(Navigatable navigatable) { - ProgramLocation location = navigatable.getLocation(); + ProgramLocation location = getProgramLocation(navigatable); if (location == null) { return null; } Address currentAddress = location.getAddress(); + Program program = location.getProgram(); + FunctionManager functionManager = program.getFunctionManager(); + return functionManager.getFunctionContaining(currentAddress); + } + + private ProgramLocation getProgramLocation(Navigatable navigatable) { // // The active component may still be showing the previously loaded function, instead - // of the current location when that location is not in a function. In that case, + // of the current location when that location is not in a function. In that case, // when that provider is focused, prefer its notion of the current function so that // users navigating from that view will go to the function before the one that is // on the history stack. This should feel more intuitive to the user, with the risk // that the navigation actions will sometimes feel inconsistent, depending upon // what view is focused. // - DockingWindowManager manager = DockingWindowManager.getActiveInstance(); - ComponentProvider provider = manager.getActiveComponentProvider(); - if (provider instanceof Navigatable) { - LocationMemento memento = ((Navigatable) provider).getMemento(); - ProgramLocation otherLocation = memento.getProgramLocation(); - if (otherLocation != null) { - currentAddress = otherLocation.getAddress(); + DockingWindowManager dwm = DockingWindowManager.getActiveInstance(); + ComponentProvider activeProvider = dwm.getActiveComponentProvider(); + if (activeProvider instanceof Navigatable) { + Navigatable activeNavigatable = (Navigatable) activeProvider; + LocationMemento memento = activeNavigatable.getMemento(); + ProgramLocation location = + validateProgramLocation(activeNavigatable, memento.getProgramLocation()); + if (location != null) { + // prefer the active natigatable's location + return location; } } + ProgramLocation location = navigatable.getLocation(); + return validateProgramLocation(navigatable, location); + } + + private ProgramLocation validateProgramLocation(Navigatable navigatable, + ProgramLocation location) { + if (location == null) { + return null; + } + if (isClosedProgram(navigatable, location)) { + return null; + } + return location; + } + + // TODO debug code that can go away if we find the source of the lingering program location + // being used that causes the program closed exception + private boolean isClosedProgram(Navigatable navigatable, ProgramLocation location) { Program program = location.getProgram(); - FunctionManager functionManager = program.getFunctionManager(); - return functionManager.getFunctionContaining(currentAddress); + if (program.isClosed()) { + + Msg.showError(this, null, "Closed Program", + "The Navigation History Plugin is using a closed program.\n" + "Program: " + + program.getName() + "Navigatable: " + + navigatable.getClass().getSimpleName() + "\n" + "Location: " + + location.getClass().getSimpleName() + " @ " + location.getAddress()); + return true; + } + + return false; } void remove(LocationMemento location) { diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin.java index b348305783..9e8417af2c 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin.java @@ -30,28 +30,17 @@ import ghidra.util.SystemUtilities; /** * Visible Plugin to show ByteBlock data in various formats. */ -@PluginInfo( - status = PluginStatus.RELEASED, - packageName = CorePluginPackage.NAME, - category = PluginCategoryNames.BYTE_VIEWER, - shortDescription = "Displays bytes in memory", - description = "Provides a component for showing the bytes in memory. " + - "Additional plugins provide capabilites for this plugin" + - " to show the bytes in various formats (e.g., hex, octal, decimal)." + - " The hex format plugin is loaded by default when this plugin is loaded.", - servicesRequired = { +@PluginInfo(status = PluginStatus.RELEASED, packageName = CorePluginPackage.NAME, category = PluginCategoryNames.BYTE_VIEWER, shortDescription = "Displays bytes in memory", description = "Provides a component for showing the bytes in memory. " + + "Additional plugins provide capabilites for this plugin" + + " to show the bytes in various formats (e.g., hex, octal, decimal)." + + " The hex format plugin is loaded by default when this plugin is loaded.", servicesRequired = { ProgramManager.class, GoToService.class, NavigationHistoryService.class, - ClipboardService.class, - }, - eventsConsumed = { - ProgramLocationPluginEvent.class, ProgramActivatedPluginEvent.class, - ProgramSelectionPluginEvent.class, ProgramHighlightPluginEvent.class, - ProgramClosedPluginEvent.class, ByteBlockChangePluginEvent.class, - }, - eventsProduced = { - ProgramLocationPluginEvent.class, ProgramSelectionPluginEvent.class, - ByteBlockChangePluginEvent.class, - }) + ClipboardService.class, }, eventsConsumed = { ProgramLocationPluginEvent.class, + ProgramActivatedPluginEvent.class, ProgramSelectionPluginEvent.class, + ProgramHighlightPluginEvent.class, ProgramClosedPluginEvent.class, + ByteBlockChangePluginEvent.class, }, eventsProduced = { + ProgramLocationPluginEvent.class, ProgramSelectionPluginEvent.class, + ByteBlockChangePluginEvent.class, }) public class ByteViewerPlugin extends AbstractByteViewerPlugin { public ByteViewerPlugin(PluginTool tool) { @@ -73,6 +62,7 @@ public class ByteViewerPlugin extends AbstractByteViewerPlugin { - if (currentLocation != null) { - connectedProvider.setLocation(currentLocation, null); + if (currentLocation == null) { + return; } + + Program locationProgram = currentLocation.getProgram(); + if (locationProgram.isClosed()) { + return; // not sure if this can happen + } + connectedProvider.setLocation(currentLocation, null); }); public DecompilePlugin(PluginTool tool) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java index 3d7ae2e706..fd60ea164c 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java @@ -4,9 +4,9 @@ * 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. diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java index d3a386c458..328ba8acb3 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java @@ -135,7 +135,7 @@ public class FGProvider extends VisualGraphComponentProviderexternal to the function graph (e.g., + * Called when for location changes that are external to the function graph (e.g., * when the user clicks in Ghidra's Listing window) - * - * @param newLocation the new location + * + * @param newLocation the new location */ void setLocation(ProgramLocation newLocation) { pendingLocation = newLocation; @@ -497,6 +497,13 @@ public class FGProvider extends VisualGraphComponentProvider graph = functionGraph; Collection inEdgesForDestination = graph.getInEdges(destinationVertex); @@ -895,7 +902,7 @@ public class FGProvider extends VisualGraphComponentProvider