mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Task Launcher - updated timeout feature to ignore interruptions
This commit is contained in:
parent
fb2a4a0363
commit
2cf9f7dded
11 changed files with 240 additions and 344 deletions
|
@ -115,10 +115,9 @@ public class DomainFileArchiveNode extends ArchiveNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Icon getIcon(boolean expanded) {
|
public Icon getIcon(boolean expanded) {
|
||||||
DomainFile df = ((DomainFileArchive) archive).getDomainFile();
|
|
||||||
ImageIcon baseIcon = archive.getIcon(expanded);
|
|
||||||
|
|
||||||
BackgroundIcon bgIcon = new BackgroundIcon(24, 16, df.isVersioned());
|
ImageIcon baseIcon = archive.getIcon(expanded);
|
||||||
|
BackgroundIcon bgIcon = new BackgroundIcon(24, 16, isVersioned);
|
||||||
MultiIcon multiIcon = new MultiIcon(bgIcon);
|
MultiIcon multiIcon = new MultiIcon(bgIcon);
|
||||||
multiIcon.addIcon(baseIcon);
|
multiIcon.addIcon(baseIcon);
|
||||||
|
|
||||||
|
|
|
@ -497,6 +497,16 @@ public class DummyTool implements Tool {
|
||||||
//do nothing
|
//do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStatusInfo(String text, boolean beep) {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearStatusInfo() {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAction(DockingActionIf action) {
|
public void addAction(DockingActionIf action) {
|
||||||
//do nothing
|
//do nothing
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.Frame;
|
import java.awt.*;
|
||||||
import java.awt.Window;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
|
@ -78,6 +78,20 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
winMgr.setStatusText(text);
|
winMgr.setStatusText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStatusInfo(String text, boolean beep) {
|
||||||
|
winMgr.setStatusText(text);
|
||||||
|
if (beep) {
|
||||||
|
Toolkit tk = getToolFrame().getToolkit();
|
||||||
|
tk.beep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearStatusInfo() {
|
||||||
|
winMgr.setStatusText("");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAction(DockingActionIf action) {
|
public void addAction(DockingActionIf action) {
|
||||||
actionMgr.addToolAction(action);
|
actionMgr.addToolAction(action);
|
||||||
|
|
|
@ -83,6 +83,18 @@ public interface DockingTool {
|
||||||
*/
|
*/
|
||||||
public void setStatusInfo(String text);
|
public void setStatusInfo(String text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the status information
|
||||||
|
* @param text string to be displayed in the Status display area
|
||||||
|
* @param beep whether to be or not
|
||||||
|
*/
|
||||||
|
public void setStatusInfo(String text, boolean beep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the status information
|
||||||
|
*/
|
||||||
|
public void clearStatusInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the action to the tool.
|
* Adds the action to the tool.
|
||||||
* @param action the action to be added.
|
* @param action the action to be added.
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
package generic.test;
|
package generic.test;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.Map.Entry;
|
import java.util.List;
|
||||||
|
|
||||||
import utilities.util.reflection.ReflectionUtilities;
|
import utilities.util.reflection.ReflectionUtilities;
|
||||||
|
|
||||||
|
@ -44,18 +44,7 @@ public class TestUtils {
|
||||||
* @return the stack trace string
|
* @return the stack trace string
|
||||||
*/
|
*/
|
||||||
public static String createStackTraceForAllThreads() {
|
public static String createStackTraceForAllThreads() {
|
||||||
Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
|
return ReflectionUtilities.createStackTraceForAllThreads();
|
||||||
Set<Entry<Thread, StackTraceElement[]>> entrySet = allStackTraces.entrySet();
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (Entry<Thread, StackTraceElement[]> entry : entrySet) {
|
|
||||||
builder.append("Thread: " + entry.getKey().getName()).append('\n');
|
|
||||||
StackTraceElement[] value = entry.getValue();
|
|
||||||
for (StackTraceElement stackTraceElement : value) {
|
|
||||||
builder.append('\t').append("at ").append(stackTraceElement).append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,11 +58,11 @@ public class TestUtils {
|
||||||
* @param ownerInstance The object instance from which to get the
|
* @param ownerInstance The object instance from which to get the
|
||||||
* variable instance.
|
* variable instance.
|
||||||
* @param value The value to use when setting the given field
|
* @param value The value to use when setting the given field
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
* @see Field#set(Object, Object))
|
* @see Field#set(Object, Object)
|
||||||
*/
|
*/
|
||||||
public static void setInstanceField(String fieldName, Object ownerInstance, Object value)
|
public static void setInstanceField(String fieldName, Object ownerInstance, Object value)
|
||||||
throws RuntimeException {
|
throws RuntimeException {
|
||||||
|
@ -110,7 +99,7 @@ public class TestUtils {
|
||||||
* @param ownerInstance The object instance from which to get the
|
* @param ownerInstance The object instance from which to get the
|
||||||
* variable instance.
|
* variable instance.
|
||||||
* @return The field instance.
|
* @return The field instance.
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -193,7 +182,7 @@ public class TestUtils {
|
||||||
* to pass
|
* to pass
|
||||||
* @return The return value as returned from executing the method.
|
* @return The return value as returned from executing the method.
|
||||||
* @see Method#invoke(java.lang.Object, java.lang.Object[])
|
* @see Method#invoke(java.lang.Object, java.lang.Object[])
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -259,7 +248,7 @@ public class TestUtils {
|
||||||
* This value can be null or zero length if there are no parameters
|
* This value can be null or zero length if there are no parameters
|
||||||
* to pass
|
* to pass
|
||||||
* @return The return value as returned from executing the method.
|
* @return The return value as returned from executing the method.
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -301,7 +290,7 @@ public class TestUtils {
|
||||||
* @param parameterType The parameter types that the method takes.
|
* @param parameterType The parameter types that the method takes.
|
||||||
* @param arg The parameter value that should be passed to the method.
|
* @param arg The parameter value that should be passed to the method.
|
||||||
* @return The return value as returned from executing the method.
|
* @return The return value as returned from executing the method.
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -350,10 +339,9 @@ public class TestUtils {
|
||||||
* @param methodName The name of the method to execute.
|
* @param methodName The name of the method to execute.
|
||||||
* @param ownerInstance The object instance of which the method will be
|
* @param ownerInstance The object instance of which the method will be
|
||||||
* executed.
|
* executed.
|
||||||
* @param parameterType The parameter types that the method takes.
|
* @param args The parameter value that should be passed to the method.
|
||||||
* @param arg The parameter value that should be passed to the method.
|
|
||||||
* @return The return value as returned from executing the method.
|
* @return The return value as returned from executing the method.
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -385,7 +373,7 @@ public class TestUtils {
|
||||||
* executed.
|
* executed.
|
||||||
* @return The return value as returned from executing the method.
|
* @return The return value as returned from executing the method.
|
||||||
* @see Method#invoke(java.lang.Object, java.lang.Object[])
|
* @see Method#invoke(java.lang.Object, java.lang.Object[])
|
||||||
* @throws A RuntimeException if there is a problem accessing the field
|
* @throws RuntimeException if there is a problem accessing the field
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -409,7 +397,7 @@ public class TestUtils {
|
||||||
* This value can be null or zero length if there are no parameters
|
* This value can be null or zero length if there are no parameters
|
||||||
* to pass
|
* to pass
|
||||||
* @return The new class instance
|
* @return The new class instance
|
||||||
* @throws A RuntimeException if there is a problem accessing the constructor
|
* @throws RuntimeException if there is a problem accessing the constructor
|
||||||
* using reflection. A RuntimeException is used so that calling
|
* using reflection. A RuntimeException is used so that calling
|
||||||
* tests can avoid using a try/catch block, but will still fail
|
* tests can avoid using a try/catch block, but will still fail
|
||||||
* when an error is encountered.
|
* when an error is encountered.
|
||||||
|
@ -492,9 +480,10 @@ public class TestUtils {
|
||||||
* Get the first field object contained within object ownerInstance which has the type classType.
|
* Get the first field object contained within object ownerInstance which has the type classType.
|
||||||
* This method is only really useful if it is known that only a single field of
|
* This method is only really useful if it is known that only a single field of
|
||||||
* classType exists within the ownerInstance.
|
* classType exists within the ownerInstance.
|
||||||
* @param <T>
|
*
|
||||||
* @param classType
|
* @param <T> the type
|
||||||
* @param ownerInstance
|
* @param classType the class type of the desired field
|
||||||
|
* @param ownerInstance the object instance that owns the field
|
||||||
* @return field object of type classType or null
|
* @return field object of type classType or null
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -533,8 +522,9 @@ public class TestUtils {
|
||||||
* Get the first field specification contained within containingClass which has the type classType.
|
* Get the first field specification contained within containingClass which has the type classType.
|
||||||
* This method is only really useful if it is known that only a single field of
|
* This method is only really useful if it is known that only a single field of
|
||||||
* classType exists within the containingClass hierarchy.
|
* classType exists within the containingClass hierarchy.
|
||||||
* @param classType
|
*
|
||||||
* @param containingClass
|
* @param classType the class
|
||||||
|
* @param containingClass the class that contains a field of the given type
|
||||||
* @return field which corresponds to type classType or null
|
* @return field which corresponds to type classType or null
|
||||||
*/
|
*/
|
||||||
public static Field locateFieldByTypeOnClass(Class<?> classType, Class<?> containingClass) {
|
public static Field locateFieldByTypeOnClass(Class<?> classType, Class<?> containingClass) {
|
||||||
|
|
|
@ -21,11 +21,13 @@ import java.awt.*;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
|
||||||
|
@ -213,11 +215,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
// placeholder
|
// placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DockingWindowManager getWindowManager() {
|
|
||||||
return winMgr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDefaultOptionValues() {
|
private void setDefaultOptionValues() {
|
||||||
Options toolOptions = optionsMgr.getOptions("Tool");
|
Options toolOptions = optionsMgr.getOptions("Tool");
|
||||||
boolean windowsOnTop = toolOptions.getBoolean(DOCKING_WINDOWS_ON_TOP, false);
|
boolean windowsOnTop = toolOptions.getBoolean(DOCKING_WINDOWS_ON_TOP, false);
|
||||||
|
@ -318,47 +315,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
popupListeners.remove(listener);
|
popupListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the action to the tool.
|
|
||||||
* @param action the action to be added.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addAction(DockingActionIf action) {
|
|
||||||
actionMgr.addToolAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an action that is associated with the given provider. The action
|
|
||||||
* works only in the context of the provider, and not across the tool
|
|
||||||
* as for a "global" action.
|
|
||||||
* @param provider provider that has a visible component in the tool
|
|
||||||
* @param action local action to associate with the provider
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
|
||||||
actionMgr.addLocalAction(provider, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the given action from the tool
|
|
||||||
* @param action the action to be removed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void removeAction(DockingActionIf action) {
|
|
||||||
actionMgr.removeToolAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a visible component to the tool.
|
|
||||||
* @param provider The component provider that provides the component to be added.
|
|
||||||
* @param show flag to initially show the component.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addComponentProvider(final ComponentProvider provider, final boolean show) {
|
|
||||||
Runnable r = () -> winMgr.addComponent(provider, show);
|
|
||||||
SystemUtilities.runSwingNow(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether a component's header should be shown; the header is the component that
|
* Set whether a component's header should be shown; the header is the component that
|
||||||
* is dragged in order to move the component within the tool, or out of the tool
|
* is dragged in order to move the component within the tool, or out of the tool
|
||||||
|
@ -371,76 +327,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
winMgr.showComponentHeader(provider, b);
|
winMgr.showComponentHeader(provider, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isActive(ComponentProvider provider) {
|
|
||||||
return winMgr.isActiveProvider(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hides or shows the component associated with the given provider.
|
|
||||||
* @param provider the provider of the component to be hidden or shown.
|
|
||||||
* @param visibleState true to show the component, false to hide it.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void showComponentProvider(final ComponentProvider provider,
|
|
||||||
final boolean visibleState) {
|
|
||||||
Runnable r = () -> winMgr.showComponent(provider, visibleState);
|
|
||||||
SystemUtilities.runSwingNow(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void toFront(final ComponentProvider provider) {
|
|
||||||
Runnable r = () -> winMgr.toFront(provider);
|
|
||||||
SystemUtilities.runSwingNow(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeComponentProvider(final ComponentProvider provider) {
|
|
||||||
Runnable r = () -> actionMgr.removeComponent(provider);
|
|
||||||
SystemUtilities.runSwingNow(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateTitle(ComponentProvider provider) {
|
|
||||||
winMgr.updateTitle(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isVisible(ComponentProvider provider) {
|
|
||||||
return winMgr.isVisible(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isVisible() {
|
|
||||||
return winMgr.isVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.Tool#setVisible(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setVisible(boolean visibility) {
|
|
||||||
winMgr.setVisible(visibility);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void toFront() {
|
|
||||||
JFrame frame = winMgr.getRootFrame();
|
|
||||||
if (frame.getExtendedState() == Frame.ICONIFIED) {
|
|
||||||
frame.setExtendedState(Frame.NORMAL);
|
|
||||||
}
|
|
||||||
frame.toFront();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tool's frame
|
|
||||||
* @return the tool's frame
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public JFrame getToolFrame() {
|
|
||||||
return winMgr.getRootFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Install any services that are not provided by plugins */
|
/** Install any services that are not provided by plugins */
|
||||||
private void installServices() {
|
private void installServices() {
|
||||||
serviceMgr.addService(ProjectDataService.class,
|
serviceMgr.addService(ProjectDataService.class,
|
||||||
|
@ -489,31 +375,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
serviceMgr.removeServiceListener(listener);
|
serviceMgr.removeServiceListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the status information.
|
|
||||||
* @param text string to be displayed in the Status display area
|
|
||||||
* @param beep whether to be or not
|
|
||||||
*/
|
|
||||||
public void setStatusInfo(String text, boolean beep) {
|
|
||||||
winMgr.setStatusText(text);
|
|
||||||
if (beep) {
|
|
||||||
Toolkit tk = getToolFrame().getToolkit();
|
|
||||||
tk.beep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStatusInfo(String text) {
|
|
||||||
winMgr.setStatusText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the status information.
|
|
||||||
*/
|
|
||||||
public void clearStatusInfo() {
|
|
||||||
winMgr.setStatusText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the provider that should get the default focus when no component has focus.
|
* Sets the provider that should get the default focus when no component has focus.
|
||||||
* @param provider the provider that should get the default focus when no component has focus.
|
* @param provider the provider that should get the default focus when no component has focus.
|
||||||
|
@ -1037,30 +898,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
winMgr.removeStatusItem(c);
|
winMgr.removeStatusItem(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
|
||||||
Set<DockingActionIf> set = new HashSet<>();
|
|
||||||
set.addAll(actionMgr.getDockingActionsByFullActionName(fullActionName));
|
|
||||||
set.addAll(winMgr.getActions(fullActionName));
|
|
||||||
return new ArrayList<>(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
|
||||||
List<DockingActionIf> actions = actionMgr.getActions(owner);
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DockingActionIf> getAllActions() {
|
|
||||||
return actionMgr.getAllActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
|
||||||
actionMgr.removeProviderAction(provider, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addExitAction() {
|
protected void addExitAction() {
|
||||||
DockingAction exitAction = new DockingAction("Exit Ghidra", "Tool") {
|
DockingAction exitAction = new DockingAction("Exit Ghidra", "Tool") {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1584,18 +1421,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
return pluginMgr.getUndoRedoToolState(domainObject);
|
return pluginMgr.getUndoRedoToolState(domainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the dialog using the active top-level window (often the tool's root frame)
|
|
||||||
* as a parent. Also, remembers any
|
|
||||||
* size and location adjustments made by the user for the next time the dialog is shown.
|
|
||||||
*
|
|
||||||
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void showDialog(DialogComponentProvider dialogComponent) {
|
|
||||||
DockingWindowManager.showDialog(dialogComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the dialog using the tool's currently active window as a parent. Also,
|
* Shows the dialog using the tool's currently active window as a parent. Also,
|
||||||
* remembers any size and location adjustments made by the user for the next
|
* remembers any size and location adjustments made by the user for the next
|
||||||
|
@ -1679,11 +1504,6 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
winMgr.removePreferenceState(name);
|
winMgr.removePreferenceState(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Window getProviderWindow(ComponentProvider componentProvider) {
|
|
||||||
return winMgr.getProviderWindow(componentProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Inner Classes
|
// Inner Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.processors.sleigh;
|
package ghidra.app.plugin.processors.sleigh;
|
||||||
|
|
||||||
import static utilities.util.FileUtilities.existsAndIsCaseDependent;
|
import static utilities.util.FileUtilities.*;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -99,6 +99,11 @@ public class SleighLanguageProvider implements LanguageProvider {
|
||||||
return getNewSleigh(languageId);
|
return getNewSleigh(languageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLanguageLoaded(LanguageID languageId) {
|
||||||
|
return languages.get(languageId) != null;
|
||||||
|
}
|
||||||
|
|
||||||
private Language getNewSleigh(LanguageID languageId) {
|
private Language getNewSleigh(LanguageID languageId) {
|
||||||
SleighLanguageDescription description = descriptions.get(languageId);
|
SleighLanguageDescription description = descriptions.get(languageId);
|
||||||
SleighLanguage lang = languages.get(languageId);
|
SleighLanguage lang = languages.get(languageId);
|
||||||
|
@ -108,31 +113,31 @@ public class SleighLanguageProvider implements LanguageProvider {
|
||||||
languages.put(languageId, lang);
|
languages.put(languageId, lang);
|
||||||
}
|
}
|
||||||
catch (SleighException e) {
|
catch (SleighException e) {
|
||||||
Msg.showError(this, null, "Error", "Can't read language spec " +
|
Msg.showError(this, null, "Error",
|
||||||
description.getSlaFile().getAbsolutePath(), e);
|
"Can't read language spec " + description.getSlaFile().getAbsolutePath(), e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e) {
|
catch (FileNotFoundException e) {
|
||||||
Msg.showError(this, null, "Error", "Can't read language spec " +
|
Msg.showError(this, null, "Error",
|
||||||
description.getSlaFile().getAbsolutePath(), e);
|
"Can't read language spec " + description.getSlaFile().getAbsolutePath(), e);
|
||||||
throw new SleighException(
|
throw new SleighException(
|
||||||
"File not found - language probably did not compile properly", e);
|
"File not found - language probably did not compile properly", e);
|
||||||
}
|
}
|
||||||
catch (UnknownInstructionException e) {
|
catch (UnknownInstructionException e) {
|
||||||
Msg.showError(this, null, "Error", "Can't read language spec " +
|
Msg.showError(this, null, "Error",
|
||||||
description.getSlaFile().getAbsolutePath(), e);
|
"Can't read language spec " + description.getSlaFile().getAbsolutePath(), e);
|
||||||
throw new SleighException(
|
throw new SleighException(
|
||||||
"Unknown instruction - language probably did not compile properly", e);
|
"Unknown instruction - language probably did not compile properly", e);
|
||||||
}
|
}
|
||||||
catch (SAXException e) {
|
catch (SAXException e) {
|
||||||
Msg.showError(this, null, "Error", "Can't read language spec " +
|
Msg.showError(this, null, "Error",
|
||||||
description.getSlaFile().getAbsolutePath(), e);
|
"Can't read language spec " + description.getSlaFile().getAbsolutePath(), e);
|
||||||
throw new SleighException(
|
throw new SleighException(
|
||||||
"SAXException - language probably did not compile properly", e);
|
"SAXException - language probably did not compile properly", e);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
Msg.showError(this, null, "Error", "Can't read language spec " +
|
Msg.showError(this, null, "Error",
|
||||||
description.getSlaFile().getAbsolutePath(), e);
|
"Can't read language spec " + description.getSlaFile().getAbsolutePath(), e);
|
||||||
throw new SleighException(
|
throw new SleighException(
|
||||||
"IOException - language probably did not compile properly", e);
|
"IOException - language probably did not compile properly", e);
|
||||||
}
|
}
|
||||||
|
@ -162,7 +167,8 @@ public class SleighLanguageProvider implements LanguageProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fatalError(SAXParseException exception) throws SAXException {
|
public void fatalError(SAXParseException exception) throws SAXException {
|
||||||
Msg.error(SleighLanguageProvider.this, "Fatal error parsing " + specFile, exception);
|
Msg.error(SleighLanguageProvider.this, "Fatal error parsing " + specFile,
|
||||||
|
exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -256,8 +262,8 @@ public class SleighLanguageProvider implements LanguageProvider {
|
||||||
truncatedSpaceMap = new HashMap<String, Integer>();
|
truncatedSpaceMap = new HashMap<String, Integer>();
|
||||||
}
|
}
|
||||||
if (truncatedSpaceMap.put(spaceName, truncatedSize) != null) {
|
if (truncatedSpaceMap.put(spaceName, truncatedSize) != null) {
|
||||||
throw new SleighException("truncated space '" + spaceName +
|
throw new SleighException(
|
||||||
"' alread specified");
|
"truncated space '" + spaceName + "' alread specified");
|
||||||
}
|
}
|
||||||
parser.end(element);
|
parser.end(element);
|
||||||
}
|
}
|
||||||
|
@ -301,11 +307,10 @@ public class SleighLanguageProvider implements LanguageProvider {
|
||||||
|
|
||||||
// skip the language end tag
|
// skip the language end tag
|
||||||
parser.end(languageEnter);
|
parser.end(languageEnter);
|
||||||
description =
|
description = new SleighLanguageDescription(id, descriptionText,
|
||||||
new SleighLanguageDescription(id, descriptionText,
|
Processor.findOrPossiblyCreateProcessor(processorName), endian, instructionEndian,
|
||||||
Processor.findOrPossiblyCreateProcessor(processorName), endian,
|
size, variant, version, minorVersion, deprecated, truncatedSpaceMap, compilerSpecs,
|
||||||
instructionEndian, size, variant, version, minorVersion, deprecated,
|
externalNameMap);
|
||||||
truncatedSpaceMap, compilerSpecs, externalNameMap);
|
|
||||||
final ResourceFile defsFile = new ResourceFile(parentDirectory, ldefs);
|
final ResourceFile defsFile = new ResourceFile(parentDirectory, ldefs);
|
||||||
FileResolutionResult result = existsAndIsCaseDependent(defsFile);
|
FileResolutionResult result = existsAndIsCaseDependent(defsFile);
|
||||||
if (!result.isOk()) {
|
if (!result.isOk()) {
|
||||||
|
@ -337,8 +342,7 @@ public class SleighLanguageProvider implements LanguageProvider {
|
||||||
|
|
||||||
String slaspecfilename = slabase + ".slaspec";
|
String slaspecfilename = slabase + ".slaspec";
|
||||||
|
|
||||||
ResourceFile slaspecFile =
|
ResourceFile slaspecFile = findFile(parentDirectory, slaspecfilename, ".slaspec");
|
||||||
findFile(parentDirectory, slaspecfilename, ".slaspec");
|
|
||||||
result = existsAndIsCaseDependent(slaspecFile);
|
result = existsAndIsCaseDependent(slaspecFile);
|
||||||
if (!result.isOk()) {
|
if (!result.isOk()) {
|
||||||
throw new SleighException("sla file source " + slaspecFile +
|
throw new SleighException("sla file source " + slaspecFile +
|
||||||
|
|
|
@ -45,4 +45,11 @@ public interface LanguageProvider extends ExtensionPoint {
|
||||||
*/
|
*/
|
||||||
boolean hadLoadFailure();
|
boolean hadLoadFailure();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given language has been successfully loaded
|
||||||
|
*
|
||||||
|
* @param languageId the name of the language to be retrieved
|
||||||
|
* @return true if the given language has been successfully loaded
|
||||||
|
*/
|
||||||
|
boolean isLanguageLoaded(LanguageID languageId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,33 +102,15 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.lang.LanguageService#getLanguage(ghidra.program.model.lang.LanguageID)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Language getLanguage(LanguageID languageID) throws LanguageNotFoundException {
|
public Language getLanguage(LanguageID languageID) throws LanguageNotFoundException {
|
||||||
LanguageInfo info = languageMap.get(languageID);
|
LanguageInfo info = languageMap.get(languageID);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
throw new LanguageNotFoundException(languageID);
|
throw new LanguageNotFoundException(languageID);
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
TaskBuilder.withRunnable(monitor -> {
|
|
||||||
info.getLanguage(); // load and cache
|
|
||||||
})
|
|
||||||
.setTitle("Loading language '" + languageID + "'")
|
|
||||||
.setCanCancel(false)
|
|
||||||
.setHasProgress(false)
|
|
||||||
.launchModal()
|
|
||||||
;
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
return info.getLanguage();
|
return info.getLanguage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.lang.LanguageService#getLanguageDescription(ghidra.program.model.lang.LanguageID)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public LanguageDescription getLanguageDescription(LanguageID languageID)
|
public LanguageDescription getLanguageDescription(LanguageID languageID)
|
||||||
throws LanguageNotFoundException {
|
throws LanguageNotFoundException {
|
||||||
|
@ -136,34 +118,26 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
throw new LanguageNotFoundException(languageID);
|
throw new LanguageNotFoundException(languageID);
|
||||||
}
|
}
|
||||||
return info.ld;
|
return info.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.lang.LanguageService#getLanguageDescriptions(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<LanguageDescription> getLanguageDescriptions(boolean includeDeprecatedLanguages) {
|
public List<LanguageDescription> getLanguageDescriptions(boolean includeDeprecatedLanguages) {
|
||||||
List<LanguageDescription> languageDescriptions = new ArrayList<>();
|
List<LanguageDescription> languageDescriptions = new ArrayList<>();
|
||||||
for (LanguageInfo info : languageInfos) {
|
for (LanguageInfo info : languageInfos) {
|
||||||
if (includeDeprecatedLanguages || !info.ld.isDeprecated()) {
|
if (includeDeprecatedLanguages || !info.description.isDeprecated()) {
|
||||||
languageDescriptions.add(info.ld);
|
languageDescriptions.add(info.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return languageDescriptions;
|
return languageDescriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.lang.LanguageService#getLanguageDescriptions(ghidra.program.model.lang.Processor,
|
|
||||||
* ghidra.program.model.lang.Endian, java.lang.Integer,
|
|
||||||
* java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<LanguageDescription> getLanguageDescriptions(Processor processor, Endian endianess,
|
public List<LanguageDescription> getLanguageDescriptions(Processor processor, Endian endianess,
|
||||||
Integer size, String variant) {
|
Integer size, String variant) {
|
||||||
List<LanguageDescription> languageDescriptions = new ArrayList<>();
|
List<LanguageDescription> languageDescriptions = new ArrayList<>();
|
||||||
for (LanguageInfo info : languageInfos) {
|
for (LanguageInfo info : languageInfos) {
|
||||||
LanguageDescription description = info.ld;
|
LanguageDescription description = info.description;
|
||||||
if (processor != null && processor != description.getProcessor()) {
|
if (processor != null && processor != description.getProcessor()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -206,7 +180,7 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
|
|
||||||
List<LanguageDescription> languageDescriptions = new ArrayList<>();
|
List<LanguageDescription> languageDescriptions = new ArrayList<>();
|
||||||
for (LanguageInfo info : languageInfos) {
|
for (LanguageInfo info : languageInfos) {
|
||||||
LanguageDescription description = info.ld;
|
LanguageDescription description = info.description;
|
||||||
|
|
||||||
if (!languageMatchesExternalProcessor(description, externalProcessorName,
|
if (!languageMatchesExternalProcessor(description, externalProcessorName,
|
||||||
externalTool)) {
|
externalTool)) {
|
||||||
|
@ -300,16 +274,13 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.lang.LanguageService#getLanguageDescriptions(ghidra.program.model.lang.Processor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<LanguageDescription> getLanguageDescriptions(Processor processor) {
|
public List<LanguageDescription> getLanguageDescriptions(Processor processor) {
|
||||||
ArrayList<LanguageDescription> list = new ArrayList<>();
|
ArrayList<LanguageDescription> list = new ArrayList<>();
|
||||||
|
|
||||||
for (LanguageInfo info : languageInfos) {
|
for (LanguageInfo info : languageInfos) {
|
||||||
if (info.ld.getProcessor().equals(processor)) {
|
if (info.description.getProcessor().equals(processor)) {
|
||||||
list.add(info.ld);
|
list.add(info.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
@ -350,16 +321,13 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.lang.LanguageService#getDefaultLanguage(ghidra.program.model.lang.Processor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Language getDefaultLanguage(Processor processor) throws LanguageNotFoundException {
|
public Language getDefaultLanguage(Processor processor) throws LanguageNotFoundException {
|
||||||
if (processor == null) {
|
if (processor == null) {
|
||||||
throw new IllegalArgumentException("processor == null not allowed");
|
throw new IllegalArgumentException("processor == null not allowed");
|
||||||
}
|
}
|
||||||
for (LanguageInfo info : languageInfos) {
|
for (LanguageInfo info : languageInfos) {
|
||||||
if (info.ld.getProcessor().equals(processor)) {
|
if (info.description.getProcessor().equals(processor)) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Language language = info.getLanguage();
|
Language language = info.getLanguage();
|
||||||
log.debug("getDefaultLanguage(" + language.getLanguageID() + ") took " +
|
log.debug("getDefaultLanguage(" + language.getLanguageID() + ") took " +
|
||||||
|
@ -385,7 +353,7 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
languageInfos.add(info);
|
languageInfos.add(info);
|
||||||
LanguageID id = info.ld.getLanguageID();
|
LanguageID id = info.description.getLanguageID();
|
||||||
if (languageMap.containsKey(id)) {
|
if (languageMap.containsKey(id)) {
|
||||||
throw new IllegalStateException("Duplicate language ID encountered: " + id);
|
throw new IllegalStateException("Duplicate language ID encountered: " + id);
|
||||||
}
|
}
|
||||||
|
@ -393,22 +361,42 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LanguageInfo {
|
private class LanguageInfo {
|
||||||
LanguageDescription ld;
|
|
||||||
LanguageProvider lp;
|
private LanguageProvider provider;
|
||||||
|
LanguageDescription description;
|
||||||
|
|
||||||
LanguageInfo(LanguageDescription ld, LanguageProvider lp) {
|
LanguageInfo(LanguageDescription ld, LanguageProvider lp) {
|
||||||
this.ld = ld;
|
this.description = ld;
|
||||||
this.lp = lp;
|
this.provider = lp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Language getLanguage() {
|
// synchronized to prevent multiple clients from trying to load the language at once
|
||||||
return lp.getLanguage(ld.getLanguageID());
|
synchronized Language getLanguage() {
|
||||||
|
|
||||||
|
LanguageID id = description.getLanguageID();
|
||||||
|
if (provider.isLanguageLoaded(id)) {
|
||||||
|
// already loaded; no need to create a task
|
||||||
|
return provider.getLanguage(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
TaskBuilder.withRunnable(monitor -> {
|
||||||
|
provider.getLanguage(id); // load and cache
|
||||||
|
})
|
||||||
|
.setTitle("Loading language '" + id + "'")
|
||||||
|
.setCanCancel(false)
|
||||||
|
.setHasProgress(false)
|
||||||
|
.launchModal()
|
||||||
|
;
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
return provider.getLanguage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return ld.getLanguageID().getIdAsString();
|
return description.getLanguageID().getIdAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -417,18 +405,15 @@ public class DefaultLanguageService implements LanguageService, ChangeListener {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LanguageInfo otherInfo = (LanguageInfo) obj;
|
LanguageInfo otherInfo = (LanguageInfo) obj;
|
||||||
return ld.getLanguageID().equals(otherInfo.ld.getLanguageID());
|
return description.getLanguageID().equals(otherInfo.description.getLanguageID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return ld.getLanguageID().hashCode();
|
return description.getLanguageID().hashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(ChangeEvent e) {
|
public void stateChanged(ChangeEvent e) {
|
||||||
// NOTE: this is only intended to pickup new language providers
|
// NOTE: this is only intended to pickup new language providers
|
||||||
|
|
|
@ -101,6 +101,36 @@ public class Swing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the given runnable on the Swing thread in the future by putting the request on
|
||||||
|
* the back of the event queue.
|
||||||
|
*
|
||||||
|
* @param r the runnable
|
||||||
|
*/
|
||||||
|
public static void runLater(Runnable r) {
|
||||||
|
doRun(r, false, SWING_RUN_ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the given runnable now if the caller is on the Swing thread. Otherwise, the
|
||||||
|
* runnable will be posted later.
|
||||||
|
*
|
||||||
|
* @param r the runnable
|
||||||
|
*/
|
||||||
|
public static void runIfSwingOrRunLater(Runnable r) {
|
||||||
|
if (isInHeadlessMode()) {
|
||||||
|
r.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SwingUtilities.invokeLater(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls the given suppler on the Swing thread, blocking with a
|
* Calls the given suppler on the Swing thread, blocking with a
|
||||||
* {@link SwingUtilities#invokeAndWait(Runnable)} if not on the Swing thread.
|
* {@link SwingUtilities#invokeAndWait(Runnable)} if not on the Swing thread.
|
||||||
|
@ -136,8 +166,29 @@ public class Swing {
|
||||||
runNow(r, SWING_TIMEOUT_SECONDS_VALUE, TimeUnit.SECONDS);
|
runNow(r, SWING_TIMEOUT_SECONDS_VALUE, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
catch (UnableToSwingException e) {
|
catch (UnableToSwingException e) {
|
||||||
throw new RuntimeException("Timed-out waiting to run a Swing task--potential deadlock!",
|
|
||||||
e);
|
//
|
||||||
|
// Special Cases: if we are in production mode, then this is most likely a deadlock.
|
||||||
|
// In that case, log the thread state. In development mode, it is possible for this
|
||||||
|
// to happen while debugging. In that case, log a message, and then post the work
|
||||||
|
// to be done without a timeout.
|
||||||
|
//
|
||||||
|
String warning = "Timed-out waiting to run a Swing task--potential deadlock!";
|
||||||
|
if (SystemUtilities.isInReleaseMode()) {
|
||||||
|
Throwable threadDump = ReflectionUtilities.createJavaFilteredThrowable();
|
||||||
|
Msg.error(Swing.class, warning + "\nThreads State:\n" + threadDump);
|
||||||
|
throw new RuntimeException(warning, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// dev or testing mode
|
||||||
|
//
|
||||||
|
|
||||||
|
// note: using Swing.class for the originator does not work (presumably it conflicts
|
||||||
|
// with another logger sharing its name. So, use the full name here.
|
||||||
|
String originator = Swing.class.getName();
|
||||||
|
Msg.debug(originator, warning + " Ignore this message if debugging");
|
||||||
|
doRun(r, true, SWING_RUN_ERROR_MSG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +223,7 @@ public class Swing {
|
||||||
runLater(() -> {
|
runLater(() -> {
|
||||||
|
|
||||||
if (!waitFor(start)) {
|
if (!waitFor(start)) {
|
||||||
return; // must have timed-out
|
return; // interrupted or timed-out
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -185,46 +236,29 @@ public class Swing {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!waitFor(start, timeout, unit)) {
|
if (!waitFor(start, timeout, unit)) {
|
||||||
throw new UnableToSwingException(
|
// Special case: if the wait() returns false, then it was interrupted. If the
|
||||||
"Timed-out waiting for Swing thread lock in " + timeout + " " + unit);
|
// timeout occurred, an exception would have been thrown. Interrupts are expected,
|
||||||
|
// so just exit.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
waitFor(end);
|
waitFor(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static boolean waitFor(CyclicBarrier barrier, long timeout, TimeUnit unit)
|
||||||
* Calls the given runnable on the Swing thread in the future by putting the request on
|
throws UnableToSwingException {
|
||||||
* the back of the event queue.
|
|
||||||
*
|
|
||||||
* @param r the runnable
|
|
||||||
*/
|
|
||||||
public static void runLater(Runnable r) {
|
|
||||||
doRun(r, false, SWING_RUN_ERROR_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void runIfSwingOrRunLater(Runnable r) {
|
|
||||||
if (isInHeadlessMode()) {
|
|
||||||
r.run();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
r.run();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SwingUtilities.invokeLater(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean waitFor(CyclicBarrier barrier, long timeout, TimeUnit unit) {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
barrier.await(timeout, unit);
|
barrier.await(timeout, unit);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
|
catch (InterruptedException e) {
|
||||||
// our Swing tasks may be interrupted from the framework
|
// our Swing tasks may be interrupted from the framework
|
||||||
}
|
}
|
||||||
|
catch (BrokenBarrierException | TimeoutException e) {
|
||||||
|
throw new UnableToSwingException(
|
||||||
|
"Timed-out waiting for Swing thread lock in " + timeout + " " + unit);
|
||||||
|
}
|
||||||
|
|
||||||
// timed-out or was interrupted
|
// timed-out or was interrupted
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -18,6 +18,7 @@ package utilities.util.reflection;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -158,8 +159,8 @@ public class ReflectionUtilities {
|
||||||
* Get the first field specification contained within containingClass which has the type classType.
|
* Get the first field specification contained within containingClass which has the type classType.
|
||||||
* This method is only really useful if it is known that only a single field of
|
* This method is only really useful if it is known that only a single field of
|
||||||
* classType exists within the containingClass hierarchy.
|
* classType exists within the containingClass hierarchy.
|
||||||
* @param classType
|
* @param classType the class
|
||||||
* @param containingClass
|
* @param containingClass the class that contains a field of the given type
|
||||||
* @return field which corresponds to type classType or null
|
* @return field which corresponds to type classType or null
|
||||||
*/
|
*/
|
||||||
public static Field locateFieldByTypeOnClass(Class<?> classType, Class<?> containingClass) {
|
public static Field locateFieldByTypeOnClass(Class<?> classType, Class<?> containingClass) {
|
||||||
|
@ -255,12 +256,11 @@ public class ReflectionUtilities {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the first occurrence of the given pattern and then stops filtering when it finds
|
* Finds the first occurrence of the given pattern and then stops filtering when it finds
|
||||||
* something that is not that pattern.
|
* something that is not that pattern
|
||||||
*
|
*
|
||||||
* @param trace the trace to update
|
* @param trace the trace to update
|
||||||
* @param patterns the non-regex patterns used to perform a
|
* @param pattern the non-regex patterns used to perform a
|
||||||
* {@link String#contains(CharSequence)} on each {@link StackTraceElement}
|
* {@link String#contains(CharSequence)} on each {@link StackTraceElement} line
|
||||||
* line.
|
|
||||||
* @return the updated trace
|
* @return the updated trace
|
||||||
*/
|
*/
|
||||||
public static StackTraceElement[] movePastStackTracePattern(StackTraceElement[] trace,
|
public static StackTraceElement[] movePastStackTracePattern(StackTraceElement[] trace,
|
||||||
|
@ -355,6 +355,7 @@ public class ReflectionUtilities {
|
||||||
* lines (e.g., AWT, Swing, Security, etc).
|
* lines (e.g., AWT, Swing, Security, etc).
|
||||||
* This can be useful for emitting diagnostic stack traces with reduced noise.
|
* This can be useful for emitting diagnostic stack traces with reduced noise.
|
||||||
*
|
*
|
||||||
|
* @param t the throwable to filter
|
||||||
* @return the throwable
|
* @return the throwable
|
||||||
*/
|
*/
|
||||||
public static Throwable filterJavaThrowable(Throwable t) {
|
public static Throwable filterJavaThrowable(Throwable t) {
|
||||||
|
@ -375,6 +376,26 @@ public class ReflectionUtilities {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string which is a printout of a stack trace for each thread running in the
|
||||||
|
* current JVM
|
||||||
|
* @return the stack trace string
|
||||||
|
*/
|
||||||
|
public static String createStackTraceForAllThreads() {
|
||||||
|
Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
|
||||||
|
Set<Entry<Thread, StackTraceElement[]>> entrySet = allStackTraces.entrySet();
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (Entry<Thread, StackTraceElement[]> entry : entrySet) {
|
||||||
|
builder.append("Thread: " + entry.getKey().getName()).append('\n');
|
||||||
|
StackTraceElement[] value = entry.getValue();
|
||||||
|
for (StackTraceElement stackTraceElement : value) {
|
||||||
|
builder.append('\t').append("at ").append(stackTraceElement).append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an ordered set of interfaces and classes that are shared amongst the items in
|
* Returns an ordered set of interfaces and classes that are shared amongst the items in
|
||||||
* the list.
|
* the list.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue