Closed rompgadgets closed 2 years ago
You are talking about the version control checks I assume? This is indeed something I never tested, highly likely that I missed something there. My gut feeling is that there is probably some other event that the plugin should handle, instead of doing this in the locationChanged callback. Will look into this and see if your fix is the best solution. Thank you very much for reporting this!
Yeah, exactly during the version control checks. Agreed, it seems like there should be another explicit event to handle file check-ins.
Sure, no problem.
Okay, I finally got around to properly looking into this. I am using Ghidra 10.1 and the ghidra-server.org Server which is also Ghidra 10.1. What happens is that when a program is opened (i.e. the Codebrowser tool is open), something is changed and the binary is checked in while the code browser is running the events seem to fire in the following order:
INFO Checkin completed for xochitl (GhidraFileData)
INFO Program opened (JupyterKotlinPlugin)
INFO Program deactivated (JupyterKotlinPlugin)
INFO Selection changed to null (JupyterKotlinPlugin)
INFO Highlight changed (JupyterKotlinPlugin)
INFO Program activated (JupyterKotlinPlugin)
INFO Location changed to MemoryBlockStartFieldLocation@00010000, row=0, col=0, charOffset=0, Comment Type = -1 (JupyterKotlinPlugin)
INFO Program closed (JupyterKotlinPlugin)
Afterwards clicking anywhere (and changing the location) will result in an error titled Null program passed to ProgramLocation. Trace and remove this problem
with the traceback:
Null program passed to ProgramLocation
java.lang.NullPointerException: Null program passed to ProgramLocation
at ghidra.program.util.ProgramLocation.<init>(ProgramLocation.java:72)
at ghidra.program.util.ProgramLocation.<init>(ProgramLocation.java:128)
at ghidra.app.script.GhidraState.setCurrentAddress(GhidraState.java:141)
at ghidra.app.script.GhidraScript.setCurrentLocation(GhidraScript.java:501)
at GhidraJupyterKotlin.JupyterKotlinPlugin.locationChanged(JupyterKotlinPlugin.java:317)
at ghidra.app.plugin.ProgramPlugin.processEvent(ProgramPlugin.java:173)
at ghidra.framework.plugintool.Plugin.eventSent(Plugin.java:329)
at ghidra.framework.plugintool.mgr.EventManager.sendEvents(EventManager.java:286)
at ghidra.framework.plugintool.mgr.EventManager.lambda$new$3(EventManager.java:49)
at ghidra.util.Swing.doRun(Swing.java:292)
at ghidra.util.Swing.runNow(Swing.java:208)
at ghidra.util.Swing.runNow(Swing.java:163)
at ghidra.framework.plugintool.mgr.EventManager.fireEvent(EventManager.java:216)
at ghidra.framework.plugintool.PluginTool.firePluginEvent(PluginTool.java:475)
at ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin.locationChanged(CodeBrowserPlugin.java:276)
at ghidra.app.plugin.core.codebrowser.CodeViewerProvider.programLocationChanged(CodeViewerProvider.java:521)
at ghidra.app.util.viewer.listingpanel.ListingPanel.fieldLocationChanged(ListingPanel.java:797)
at docking.widgets.fieldpanel.FieldPanel$CursorHandler.notifyCursorChanged(FieldPanel.java:2133)
at docking.widgets.fieldpanel.FieldPanel$CursorHandler.setCursorPos(FieldPanel.java:1928)
at docking.widgets.fieldpanel.FieldPanel$FieldPanelMouseAdapter.mousePressed(FieldPanel.java:1316)
at java.desktop/java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:287)
at java.desktop/java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:287)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6632)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
at java.desktop/java.awt.Component.processEvent(Component.java:6400)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4544)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
So for some reason there is a program closed event after all the other program opening and activation.
I think the actual root cause was that we weren't implementing programClosed
properly. The argument to it isn't necessarily the program that was set opened and activated earlier. For example FunctionGraphPlugin.programClosed
explicitly checks if the passed argument is even the program that is considered "current"
@Override
protected void programClosed(Program program) {
if (currentProgram == program) {
currentProgram = null;
}
connectedProvider.programClosed(program);
Iterator<FGProvider> iterator = disconnectedProviders.iterator();
while (iterator.hasNext()) {
FGProvider provider = iterator.next();
if (provider.getProgram() == program) {
iterator.remove();
removeProvider(provider);
}
}
adding the same kind of check to the JupyterKotlinPlugin.programClosed
seems to work, because the argument is the old program being closed, while the new one was activated earlier already.
Currently the Kotlin Kernel plugin doesn't really manage multiple programs, so this fix should be sufficient and fixes the addresses the actual root cause. Still, your PR might have been an acceptable workaround ( I guess it at least worked for you), so I am kinda sorry that I let perfect be the enemy of good here, and only addressed this 8 months later :/
I noticed after installing the plug-in for Ghidra 9.2.2 that after checking in a file the CodeBrowser reports Null Program Location set repeatedly until the CodeBrowser window is closed and re-opened. Made a quick fix as I believe the root issue is that after a check-in the program closed event is triggered nulling out the state variables, but the program activation event is never called again.