Updated GoTo service to handle concurrent usage

This commit is contained in:
dragonmacher 2022-02-15 13:20:35 -05:00
parent 0f3aa2b9de
commit 6ca07aa2c3
21 changed files with 530 additions and 502 deletions

View file

@ -17,12 +17,16 @@ package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.io.IOException;
import org.junit.experimental.categories.Category;
import generic.test.category.NightlyCategory;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.trace.model.Trace;
import ghidra.util.database.UndoableTransaction;
@Category(NightlyCategory.class)
public class DebuggerBreakpointsProviderObjectTest extends DebuggerBreakpointsProviderTest {
protected SchemaContext ctx;

View file

@ -23,11 +23,13 @@ import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.google.common.collect.Range;
import docking.action.DockingActionIf;
import generic.Unique;
import generic.test.category.NightlyCategory;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec;
import ghidra.app.plugin.core.debug.gui.action.NoneAutoReadMemorySpec;
@ -50,6 +52,7 @@ import ghidra.trace.model.TraceLocation;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.util.database.UndoableTransaction;
@Category(NightlyCategory.class)
public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerGUITest {
DebuggerCopyActionsPlugin copyActionsPlugin;
@ -136,8 +139,8 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG
try (UndoableTransaction tid = UndoableTransaction.start(program, "Add blocks", true)) {
program.getMemory()
.createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x8000,
(byte) 0, monitor, false);
.createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x8000, (byte) 0,
monitor, false);
program.getMemory()
.createInitializedBlock(".text2", tb.addr(stSpace, 0x00408000), 0x8000,
(byte) 0, monitor, false);
@ -145,8 +148,8 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG
try (UndoableTransaction tid = tb.startTransaction()) {
DBTraceMemoryManager mm = tb.trace.getMemoryManager();
mm.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
mm.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ,
TraceMemoryFlag.EXECUTE);
mm.putBytes(0, tb.addr(0x00401234), tb.buf(1, 2, 3, 4));
// This region should be excluded, since it cannot be mapped identically into 32-bits
@ -163,9 +166,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG
traceManager.activateTrace(tb.trace);
assertDisabled(copyActionsPlugin.actionCopyIntoCurrentProgram);
select(tb.set(
tb.range(0x00400000, 0x0040ffff),
tb.range(0x7fff00400000L, 0x7fff0040ffffL),
select(tb.set(tb.range(0x00400000, 0x0040ffff), tb.range(0x7fff00400000L, 0x7fff0040ffffL),
tb.range(0xfffff000L, 0x100000fffL)));
performEnabledAction(copyActionsPlugin.actionCopyIntoCurrentProgram);

View file

@ -24,13 +24,16 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import generic.test.category.NightlyCategory;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
import ghidra.app.plugin.core.interpreter.InterpreterComponentProvider;
import ghidra.dbg.model.TestTargetInterpreter.ExecuteCall;
import ghidra.dbg.target.TargetConsole.Channel;
import ghidra.dbg.testutil.DebuggerModelTestUtils;
@Category(NightlyCategory.class)
public class DebuggerInterpreterPluginTest extends AbstractGhidraHeadedDebuggerGUITest
implements DebuggerModelTestUtils {
private DebuggerInterpreterPlugin interpreterPlugin;
@ -124,8 +127,7 @@ public class DebuggerInterpreterPluginTest extends AbstractGhidraHeadedDebuggerG
InterpreterComponentProvider interpreter =
waitForComponentProvider(InterpreterComponentProvider.class);
mb.testModel.session.changeAttributes(List.of(
"Interpreter" //
mb.testModel.session.changeAttributes(List.of("Interpreter" //
), Map.of(), "Invalidate interpreter");
waitForSwing();
@ -142,8 +144,7 @@ public class DebuggerInterpreterPluginTest extends AbstractGhidraHeadedDebuggerG
waitForComponentProvider(InterpreterComponentProvider.class);
conn.setPinned(true);
mb.testModel.session.changeAttributes(List.of(
"Interpreter" //
mb.testModel.session.changeAttributes(List.of("Interpreter" //
), Map.of(), "Invalidate interpreter");
waitForSwing();

View file

@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.gui.listing;
import static ghidra.lifecycle.Unfinished.TODO;
import static ghidra.lifecycle.Unfinished.*;
import static org.junit.Assert.*;
import java.awt.Color;
@ -26,12 +26,14 @@ import java.util.Arrays;
import java.util.Set;
import org.junit.*;
import org.junit.experimental.categories.Category;
import com.google.common.collect.Range;
import docking.menu.ActionState;
import docking.menu.MultiStateDockingAction;
import docking.widgets.EventTrigger;
import generic.test.category.NightlyCategory;
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
@ -65,6 +67,7 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@Category(NightlyCategory.class)
public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
protected DebuggerListingPlugin listingPlugin;
@ -233,8 +236,9 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
createAndOpenTrace();
TraceThread thread1;
TraceThread thread2;
DebuggerListingProvider extraProvider = SwingExecutorService.INSTANCE.submit(
() -> listingPlugin.createListingIfMissing(trackPc, true)).get();
DebuggerListingProvider extraProvider = SwingExecutorService.INSTANCE
.submit(() -> listingPlugin.createListingIfMissing(trackPc, true))
.get();
try (UndoableTransaction tid = tb.startTransaction()) {
DBTraceMemoryManager memory = tb.trace.getMemoryManager();
memory.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
@ -301,8 +305,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
}
@Test
public void testFollowsCurrentTraceOnTraceChangeWithoutRegisterTracking()
throws Exception {
public void testFollowsCurrentTraceOnTraceChangeWithoutRegisterTracking() throws Exception {
listingProvider.setTrackingSpec(trackNone);
try ( //
ToyDBTraceBuilder b1 =
@ -358,8 +361,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
}
@Test
public void testFollowsCurrentThreadOnThreadChangeWithoutRegisterTracking()
throws Exception {
public void testFollowsCurrentThreadOnThreadChangeWithoutRegisterTracking() throws Exception {
listingProvider.setTrackingSpec(trackNone);
try ( //
ToyDBTraceBuilder b1 =
@ -616,8 +618,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
// While we're here, ensure static view didn't track anywhere
assertEquals(cur, codeViewer.getCurrentLocation().getAddress());
assertListingBackgroundAt(Color.WHITE,
codeViewer.getListingPanel(), ss.getAddress(0x00601234), 0);
assertListingBackgroundAt(Color.WHITE, codeViewer.getListingPanel(),
ss.getAddress(0x00601234), 0);
}
@Test
@ -703,8 +705,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
assertListingBackgroundAt(DebuggerResources.DEFAULT_COLOR_BACKGROUND_STALE,
listingProvider.getListingPanel(), tb.addr(0x00401233), 0);
assertListingBackgroundAt(Color.WHITE,
listingProvider.getListingPanel(), tb.addr(0x00401234), 0);
assertListingBackgroundAt(Color.WHITE, listingProvider.getListingPanel(),
tb.addr(0x00401234), 0);
assertListingBackgroundAt(DebuggerResources.DEFAULT_COLOR_BACKGROUND_ERROR,
listingProvider.getListingPanel(), tb.addr(0x00401235), 0);
}
@ -717,8 +719,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
assertEquals(traceManager.getCurrentView(), listingProvider.getProgram());
assertEquals("(nowhere)", listingProvider.locationLabel.getText());
DebuggerListingProvider extraProvider = runSwing(
() -> listingPlugin.createListingIfMissing(trackNone, false));
DebuggerListingProvider extraProvider =
runSwing(() -> listingPlugin.createListingIfMissing(trackNone, false));
waitForSwing();
assertEquals(traceManager.getCurrentView(), extraProvider.getProgram());
assertEquals("(nowhere)", extraProvider.locationLabel.getText());
@ -765,18 +767,18 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
assertTrue(listingProvider.actionGoTo.isEnabled());
performAction(listingProvider.actionGoTo, false);
DebuggerGoToDialog dialog = waitForDialogComponent(DebuggerGoToDialog.class);
DebuggerGoToDialog dialog1 = waitForDialogComponent(DebuggerGoToDialog.class);
dialog.setExpression("r0");
dialog.okCallback();
dialog1.setExpression("r0");
runSwing(() -> dialog1.okCallback());
waitForPass(
() -> assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress()));
performAction(listingProvider.actionGoTo, false);
dialog = waitForDialogComponent(DebuggerGoToDialog.class);
dialog.setExpression("*:4 r0");
dialog.okCallback();
DebuggerGoToDialog dialog2 = waitForDialogComponent(DebuggerGoToDialog.class);
dialog2.setExpression("*:4 r0");
runSwing(() -> dialog2.okCallback());
waitForPass(
() -> assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress()));
@ -844,8 +846,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace();
try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) {
program.getMemory()
.createInitializedBlock(
".text", ss.getAddress(0x00600000), 0x10000, (byte) 0, monitor, false);
.createInitializedBlock(".text", ss.getAddress(0x00600000), 0x10000, (byte) 0,
monitor, false);
}
try (UndoableTransaction tid = tb.startTransaction()) {
DBTraceMemoryManager memory = tb.trace.getMemoryManager();
@ -905,8 +907,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
traceManager.activateThread(thread1);
// NOTE: Action does not exist for main dynamic listing
DebuggerListingProvider extraProvider = runSwing(
() -> listingPlugin.createListingIfMissing(trackNone, true));
DebuggerListingProvider extraProvider =
runSwing(() -> listingPlugin.createListingIfMissing(trackNone, true));
waitForSwing();
assertTrue(extraProvider.actionFollowsCurrentThread.isEnabled());
assertTrue(extraProvider.actionFollowsCurrentThread.isSelected());
@ -1032,8 +1034,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
assertEquals(readVisROOnce, listingProvider.getAutoReadMemorySpec());
assertEquals(readVisROOnce, listingProvider.actionAutoReadMemory.getCurrentUserData());
listingProvider.actionAutoReadMemory
.setCurrentActionStateByUserData(readNone);
listingProvider.actionAutoReadMemory.setCurrentActionStateByUserData(readNone);
waitForSwing();
assertEquals(readNone, listingProvider.getAutoReadMemorySpec());
assertEquals(readNone, listingProvider.actionAutoReadMemory.getCurrentUserData());
@ -1061,8 +1062,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE));
TraceModule bin = tb.trace.getModuleManager()
.addLoadedModule("/bin/bash", "/bin/bash",
tb.range(0x00400000, 0x0041ffff), 0);
.addLoadedModule("/bin/bash", "/bin/bash", tb.range(0x00400000, 0x0041ffff), 0);
bin.addSection("bash[.text]", tb.range(0x00400000, 0x0040ffff));
traceManager.activateTrace(tb.trace);
@ -1092,8 +1092,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE));
tb.trace.getModuleManager()
.addLoadedModule("/bin/bash", "/bin/bash",
tb.range(0x00400000, 0x0041ffff), 0);
.addLoadedModule("/bin/bash", "/bin/bash", tb.range(0x00400000, 0x0041ffff), 0);
traceManager.activateTrace(tb.trace);
}
@ -1128,8 +1127,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceModule modExe;
try (UndoableTransaction tid = tb.startTransaction()) {
modExe = tb.trace.getModuleManager()
.addModule("modExe", "modExe",
tb.range(0x55550000, 0x555501ff), Range.atLeast(0L));
.addModule("modExe", "modExe", tb.range(0x55550000, 0x555501ff),
Range.atLeast(0L));
}
waitForDomainObject(tb.trace);
waitForPass(() -> assertEquals("modExe", listingProvider.locationLabel.getText()));
@ -1157,19 +1156,17 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
thread1 = tb.getOrAddThread("Thread1", 0);
tb.exec(0, 0, thread1, java.util.List.of(
"RIP = 0x00400000;"));
tb.exec(0, 0, thread1, java.util.List.of("RIP = 0x00400000;"));
}
TraceThread thread2;
try (UndoableTransaction tid = tb2.startTransaction()) {
tb2.trace.getTimeManager().createSnapshot("First");
tb2.trace.getMemoryManager()
.createRegion(".text", 0, tb2.range(0x200, 0x3ff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
.createRegion(".text", 0, tb2.range(0x200, 0x3ff), TraceMemoryFlag.READ,
TraceMemoryFlag.EXECUTE);
thread2 = tb2.getOrAddThread("Thread2", 0);
tb2.exec(0, 0, thread2, java.util.List.of(
"PC = 0x100;"));
tb2.exec(0, 0, thread2, java.util.List.of("PC = 0x100;"));
}
traceManager.openTrace(tb.trace);

View file

@ -17,11 +17,15 @@ package ghidra.app.plugin.core.debug.gui.memory;
import java.io.IOException;
import org.junit.experimental.categories.Category;
import generic.test.category.NightlyCategory;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.util.database.UndoableTransaction;
@Category(NightlyCategory.class)
public class DebuggerRegionsProviderObjectTest extends DebuggerRegionsProviderTest {
protected SchemaContext ctx;

View file

@ -21,10 +21,12 @@ import java.util.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.google.common.collect.Range;
import generic.Unique;
import generic.test.category.NightlyCategory;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
import ghidra.app.plugin.core.debug.gui.DebuggerBlockChooserDialog;
import ghidra.app.plugin.core.debug.gui.DebuggerBlockChooserDialog.MemoryBlockRow;
@ -41,6 +43,7 @@ import ghidra.trace.model.memory.*;
import ghidra.trace.model.modules.TraceStaticMapping;
import ghidra.util.database.UndoableTransaction;
@Category(NightlyCategory.class)
public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
DebuggerRegionsProvider provider;
@ -105,8 +108,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager();
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
}
traceManager.openTrace(tb.trace);
@ -134,8 +136,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager();
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
}
waitForSwing();
@ -152,8 +153,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager();
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
}
traceManager.openTrace(tb.trace);
@ -222,8 +222,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager();
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
}
traceManager.openTrace(tb.trace);
@ -338,8 +337,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager();
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
}
traceManager.openTrace(tb.trace);
@ -371,8 +369,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager();
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
}
traceManager.openTrace(tb.trace);

View file

@ -17,12 +17,16 @@ package ghidra.app.plugin.core.debug.gui.modules;
import java.io.IOException;
import org.junit.experimental.categories.Category;
import generic.test.category.NightlyCategory;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.trace.model.Trace;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.trace.model.Trace;
import ghidra.util.database.UndoableTransaction;
@Category(NightlyCategory.class)
public class DebuggerModulesProviderObjectTest extends DebuggerModulesProviderTest {
protected SchemaContext ctx;

View file

@ -23,10 +23,12 @@ import java.util.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.google.common.collect.Range;
import generic.Unique;
import generic.test.category.NightlyCategory;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
@ -41,6 +43,7 @@ import ghidra.trace.model.modules.TraceStaticMappingManager;
import ghidra.util.database.UndoableTransaction;
import ghidra.util.task.TaskMonitor;
@Category(NightlyCategory.class)
public class DebuggerStaticMappingProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
protected DebuggerStaticMappingPlugin mappingsPlugin;
protected DebuggerStaticMappingProvider mappingsProvider;

View file

@ -17,12 +17,16 @@ package ghidra.app.plugin.core.debug.gui.thread;
import java.io.IOException;
import org.junit.experimental.categories.Category;
import generic.test.category.NightlyCategory;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.trace.model.Trace;
import ghidra.util.database.UndoableTransaction;
@Category(NightlyCategory.class)
public class DebuggerThreadsProviderObjectTest extends DebuggerThreadsProviderTest {
protected SchemaContext ctx;

View file

@ -76,15 +76,14 @@ public class OpenFunctionTableAction extends DockingAction {
this.comparisonService = tool.getService(FunctionComparisonService.class);
setDescription("Add functions to comparison");
setPopupMenuData(new MenuData(new String[] { "Add functions" },
ADD_TO_COMPARISON_ICON, ADD_COMPARISON_GROUP));
setPopupMenuData(new MenuData(new String[] { "Add functions" }, ADD_TO_COMPARISON_ICON,
ADD_COMPARISON_GROUP));
ToolBarData newToolBarData =
new ToolBarData(ADD_TO_COMPARISON_ICON, ADD_COMPARISON_GROUP);
ToolBarData newToolBarData = new ToolBarData(ADD_TO_COMPARISON_ICON, ADD_COMPARISON_GROUP);
setToolBarData(newToolBarData);
HelpLocation helpLocation = new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC,
"Add_To_Comparison");
HelpLocation helpLocation =
new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC, "Add_To_Comparison");
setHelpLocation(helpLocation);
KeyBindingData data = new KeyBindingData('A', InputEvent.SHIFT_DOWN_MASK);
@ -98,19 +97,14 @@ public class OpenFunctionTableAction extends DockingAction {
@Override
public void actionPerformed(ActionContext context) {
if (!(context.getComponentProvider() instanceof FunctionComparisonProvider)) {
return;
}
FunctionComparisonProvider provider =
(FunctionComparisonProvider) context.getComponentProvider();
Program currentProgram = programManagerService.getCurrentProgram();
FunctionTableModel model = new FunctionTableModel(tool, currentProgram);
model.reload(programManagerService.getCurrentProgram());
TableSelectionDialog<FunctionRowObject> diag =
new TableSelectionDialog<>("Select Functions: " + currentProgram.getName(),
model, true);
TableSelectionDialog<FunctionRowObject> diag = new TableSelectionDialog<>(
"Select Functions: " + currentProgram.getName(), model, true);
tool.showDialog(diag);
List<FunctionRowObject> rows = diag.getSelectionItems();
if (CollectionUtils.isBlank(rows)) {

View file

@ -40,6 +40,7 @@ import ghidra.program.model.mem.Memory;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.util.HelpLocation;
import ghidra.util.Swing;
import ghidra.util.table.AddressArrayTableModel;
public class GoToHelper {
@ -80,6 +81,10 @@ public class GoToHelper {
}
public boolean goTo(final Navigatable navigatable, ProgramLocation loc, Program program) {
return Swing.runNow(() -> doGoTo(navigatable, loc, program));
}
private boolean doGoTo(final Navigatable navigatable, ProgramLocation loc, Program program) {
if (loc == null || loc.getAddress() == null) {
return false;
}
@ -116,17 +121,6 @@ public class GoToHelper {
return false;
}
// If we want the goto to request focus then we will need to add a new parameter - you don't always
// want to request focus.
// // sometimes this gets call directly after creating a new provider window. Need to
// // request focus in an invokeLater to give WindowManager a chance to create the component
// // hierarchy tree.
// SwingUtilities.invokeLater(new Runnable() {
// public void run() {
// navigatable.requestFocus();
// }
// });
saveLocation(navigatable);
return true;
@ -148,6 +142,7 @@ public class GoToHelper {
if (loc != null) {
return loc;
}
if (gotoAddress.isStackAddress() || gotoAddress.isRegisterAddress()) {
// Convert stack/register address into variable address
Function func = program.getFunctionManager().getFunctionContaining(currentAddress);
@ -347,7 +342,7 @@ public class GoToHelper {
String extProgName = externalLocation.getLibraryName();
if (Library.UNKNOWN.equals(extProgName)) {
tool.setStatusInfo(" External location refers to " + Library.UNKNOWN +
" library. Unable to " + "perform navigation.", true);
" library. Unable to perform navigation.", true);
return null;
}
@ -391,6 +386,7 @@ public class GoToHelper {
if (nameStack == null) {
return null; // name is not valid for external program
}
StringBuilder buf = new StringBuilder();
while (!nameStack.isEmpty()) {
buf.append(nameStack.pop());
@ -439,9 +435,9 @@ public class GoToHelper {
if (result == OptionDialog.CANCEL_OPTION) {
return;
}
final DataTreeDialog dialog = new DataTreeDialog(null,
"Choose External Program (" + extProgName + ")", DataTreeDialog.OPEN);
DataTreeDialog dialog = new DataTreeDialog(null,
"Choose External Program (" + extProgName + ")", DataTreeDialog.OPEN);
dialog.setSearchText(extProgName);
dialog.setHelpLocation(new HelpLocation("ReferencesPlugin", "ChooseExternalProgram"));
tool.showDialog(dialog);

View file

@ -17,7 +17,12 @@ package ghidra.app.plugin.core.progmgr;
import java.net.URL;
import java.rmi.NoSuchObjectException;
import java.util.*;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.jdom.Element;
@ -32,30 +37,36 @@ import ghidra.framework.plugintool.util.TransientToolState;
import ghidra.framework.protocol.ghidra.GhidraURL;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.*;
import ghidra.util.task.TaskLauncher;
class MultiProgramManager implements DomainObjectListener, TransactionListener {
private static int nextProgramInfoInstance = 0;
// arbitrary counter for given ProgramInfo objects and ID to use for sorting
private static final AtomicInteger nextAvailableId = new AtomicInteger();
private ProgramManagerPlugin plugin;
private PluginTool tool;
private ArrayList<ProgramInfo> openProgramList;
private HashMap<Program, ProgramInfo> programMap;
private ProgramInfo currentInfo;
private TransactionMonitor txMonitor;
private MyFolderListener folderListener;
private Runnable programChangedRunnable;
private Runnable programChangedRunnable;
private boolean hasUnsavedPrograms;
// These data structures are accessed from multiple threads. Rather than synchronizing all
// accesses, we have chosen to be weakly consistent. We assume that any out-of-date checks
// for open program state will be self-correcting. For example, if a client checks to see if
// a program is open before opening it, then a repeated call to open the program will not
// result in a second copy of that program being opened. This is safe because program opens
// and closes are all done from the Swing thread.
private List<ProgramInfo> openPrograms = new CopyOnWriteArrayList<>();
private ConcurrentHashMap<Program, ProgramInfo> programMap = new ConcurrentHashMap<>();
MultiProgramManager(ProgramManagerPlugin programManagerPlugin) {
this.plugin = programManagerPlugin;
this.tool = programManagerPlugin.getTool();
openProgramList = new ArrayList<>();
programMap = new HashMap<>();
txMonitor = new TransactionMonitor();
txMonitor.setName("Transaction Open (Program being modified)");
tool.addStatusComponent(txMonitor, true, true);
@ -72,13 +83,13 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
void addProgram(Program p, URL ghidraURL, int state) {
ProgramInfo oldInfo = programMap.get(p);
ProgramInfo oldInfo = getInfo(p);
if (oldInfo == null) {
p.addConsumer(tool);
ProgramInfo info = new ProgramInfo(p, state != ProgramManager.OPEN_HIDDEN);
info.ghidraURL = ghidraURL;
openProgramList.add(info);
Collections.sort(openProgramList);
openPrograms.add(info);
openPrograms.sort(Comparator.naturalOrder());
programMap.put(p, info);
fireOpenEvents(p);
@ -100,16 +111,15 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
void dispose() {
tool.getProject().getProjectData().removeDomainFolderChangeListener(folderListener);
fireActivatedEvent(null);
Iterator<Program> it = programMap.keySet().iterator();
while (it.hasNext()) {
Program p = it.next();
for (Program p : programMap.keySet()) {
p.removeListener(this);
p.removeTransactionListener(this);
fireCloseEvents(p);
p.release(tool);
}
programMap.clear();
openProgramList.clear();
openPrograms.clear();
tool.setSubTitle("");
tool.removeStatusComponent(txMonitor);
tool = null;
@ -117,8 +127,11 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
void removeProgram(Program p) {
ProgramInfo info = programMap.get(p);
if (info != null) {
ProgramInfo info = getInfo(p);
if (info == null) {
return;
}
if (info.owner != null) {
// persist program
info.setVisible(false);
@ -131,24 +144,21 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
p.removeTransactionListener(this);
programMap.remove(p);
p.removeListener(this);
openProgramList.remove(info);
openPrograms.remove(info);
if (info == currentInfo) {
ProgramInfo newCurrent = findNextCurrent();
setCurrentProgram(newCurrent);
}
fireCloseEvents(p);
p.release(tool);
if (openProgramList.isEmpty()) {
if (openPrograms.isEmpty()) {
plugin.getTool().clearLastEvents();
}
}
}
}
private ProgramInfo findNextCurrent() {
Iterator<ProgramInfo> iter = openProgramList.iterator();
while (iter.hasNext()) {
ProgramInfo pi = iter.next();
for (ProgramInfo pi : openPrograms) {
if (pi.visible) {
return pi;
}
@ -158,23 +168,17 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
Program[] getOtherPrograms() {
Program currentProgram = getCurrentProgram();
ArrayList<Program> list = new ArrayList<>();
int size = openProgramList.size();
for (int index = 0; index < size; index++) {
Program program = openProgramList.get(index).program;
if (currentProgram != program) {
list.add(program);
}
}
List<Program> list = openPrograms.stream()
.map(info -> info.program)
.filter(program -> program != currentProgram)
.collect(Collectors.toList());
return list.toArray(new Program[list.size()]);
}
Program[] getAllPrograms() {
Program[] programs = new Program[openProgramList.size()];
for (int i = 0; i < programs.length; i++) {
programs[i] = (openProgramList.get(i)).program;
}
return programs;
List<Program> list =
openPrograms.stream().map(info -> info.program).collect(Collectors.toList());
return list.toArray(Program[]::new);
}
Program getCurrentProgram() {
@ -191,16 +195,18 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
}
ProgramInfo info = programMap.get(p);
if (p == null) {
return;
}
ProgramInfo info = getInfo(p);
if (info != null) {
setCurrentProgram(info);
}
}
Program getProgram(Address addr) {
Iterator<ProgramInfo> it = openProgramList.iterator();
while (it.hasNext()) {
ProgramInfo pi = it.next();
for (ProgramInfo pi : openPrograms) {
if (pi.program.getMemory().contains(addr)) {
return pi.program;
}
@ -257,26 +263,17 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
}
/**
* @param program
*/
private void fireOpenEvents(Program program) {
plugin.firePluginEvent(new ProgramOpenedPluginEvent("", program));
plugin.firePluginEvent(new OpenProgramPluginEvent("", program));
}
/**
* @param program
*/
private void fireCloseEvents(Program program) {
plugin.firePluginEvent(new ProgramClosedPluginEvent("", program));
plugin.firePluginEvent(new CloseProgramPluginEvent("", program, true));
// tool.contextChanged();
}
/**
* @param p
*/
private void fireActivatedEvent(Program newProgram) {
plugin.firePluginEvent(new ProgramActivatedPluginEvent("", newProgram));
}
@ -285,14 +282,12 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
plugin.firePluginEvent(new ProgramVisibilityChangePluginEvent("", program, isVisible));
}
/**
* @see ghidra.framework.model.DomainObjectListener#domainObjectChanged(ghidra.framework.model.DomainObjectChangedEvent)
*/
@Override
public void domainObjectChanged(DomainObjectChangedEvent ev) {
if (!(ev.getSource() instanceof Program)) {
return;
}
Program program = (Program) ev.getSource();
if (ev.containsEvent(DomainObject.DO_DOMAIN_FILE_CHANGED) ||
ev.containsEvent(DomainObject.DO_OBJECT_ERROR)) {
@ -320,7 +315,6 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
"\nby the local filesystem or server.";
}
//abort();
Msg.showError(this, tool.getToolFrame(), "Severe Error Condition", msg);
removeProgram(program);
return;
@ -330,21 +324,147 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
}
/**
* @return
*/
public boolean isEmpty() {
return openProgramList.isEmpty();
return openPrograms.isEmpty();
}
public boolean contains(Program p) {
if (p == null) {
return false;
}
return programMap.containsKey(p);
}
boolean isVisible(Program p) {
ProgramInfo info = getInfo(p);
return info != null ? info.visible : false;
}
void releaseProgram(Program program, Object owner) {
ProgramInfo info = getInfo(program);
if (info != null && info.owner == owner) {
info.owner = null;
if (!info.visible) {
if (program.isChanged()) {
info.setVisible(true);
}
plugin.closeProgram(program, false);
}
else if (program.isTemporary()) {
plugin.closeProgram(program, false);
}
}
}
boolean setPersistentOwner(Program program, Object owner) {
ProgramInfo info = getInfo(program);
if (info != null && info.owner == null) {
info.owner = owner;
return true;
}
return false;
}
boolean isPersistent(Program p) {
ProgramInfo info = getInfo(p);
return (info != null && info.owner != null);
}
private ProgramInfo getInfo(Program p) {
if (p == null) {
return null;
}
return programMap.get(p);
}
Program getOpenProgram(URL ghidraURL) {
if (!GhidraURL.isServerRepositoryURL(ghidraURL)) {
return null;
}
URL normalizedURL = GhidraURL.getNormalizedURL(ghidraURL);
for (ProgramInfo info : programMap.values()) {
URL url = info.ghidraURL;
if (url != null && url.equals(normalizedURL)) {
return info.program;
}
}
return null;
}
Program getOpenProgram(DomainFile domainFile, int version) {
for (Program program : programMap.keySet()) {
DomainFile programDomainFile = program.getDomainFile();
if (filesMatch(domainFile, version, programDomainFile)) {
return program;
}
}
return null;
}
private boolean filesMatch(DomainFile file1, int version, DomainFile file2) {
if (!file1.getPathname().equals(file2.getPathname())) {
return false;
}
if (file1.isCheckedOut() != file2.isCheckedOut()) {
return false;
}
if (!SystemUtilities.isEqual(file1.getProjectLocator(), file2.getProjectLocator())) {
return false;
}
int openVersion = file2.isReadOnly() ? file2.getVersion() : -1;
return version == openVersion;
}
/**
* @param program
* @return
* Returns true if there is at least one program that has unsaved changes.
* @return true if there is at least one program that has unsaved changes.
*/
public boolean contains(Program program) {
return programMap.containsKey(program);
boolean hasUnsavedPrograms() {
return hasUnsavedPrograms;
}
private boolean checkForUnsavedPrograms() {
// first check the current program as that is the one most likely to have changes
Program currentProgram = getCurrentProgram();
if (currentProgram != null && currentProgram.isChanged()) {
return true;
}
// look at all the open programs to see if any have changes
for (ProgramInfo programInfo : openPrograms) {
if (programInfo.program.isChanged()) {
return true;
}
}
return false;
}
@Override
public void transactionEnded(DomainObjectAdapterDB domainObj) {
// don't care
}
@Override
public void transactionStarted(DomainObjectAdapterDB domainObj, Transaction tx) {
// don't care
}
@Override
public void undoRedoOccurred(DomainObjectAdapterDB domainObj) {
// don't care
}
@Override
public void undoStackChanged(DomainObjectAdapterDB domainObj) {
Swing.runLater(programChangedRunnable);
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class MyFolderListener extends DomainFolderListenerAdapter {
@Override
@ -367,8 +487,6 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
OpenProgramTask openTask = new OpenProgramTask(file, -1, this);
openTask.setSilent();
// OpenDomainFileTask openTask = new OpenDomainFileTask(file, -1, tool,
// plugin, true, dataState != null ? ProgramManager.OPEN_CURRENT : ProgramManager.OPEN_VISIBLE);
new TaskLauncher(openTask, tool.getToolFrame());
Program openProgram = openTask.getOpenProgram();
plugin.openProgram(openProgram,
@ -381,56 +499,19 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
}
}
boolean isVisible(Program program) {
ProgramInfo info = programMap.get(program);
return info != null ? info.visible : false;
}
void releaseProgram(Program program, Object owner) {
ProgramInfo info = programMap.get(program);
if (info != null && info.owner == owner) {
info.owner = null;
if (!info.visible) {
if (program.isChanged()) {
info.setVisible(true);
}
plugin.closeProgram(program, false);
}
else if (program.isTemporary()) {
plugin.closeProgram(program, false);
}
}
}
boolean setPersistentOwner(Program program, Object owner) {
ProgramInfo info = programMap.get(program);
if (info != null && info.owner == null) {
info.owner = owner;
return true;
}
return false;
}
public boolean isPersistent(Program program) {
ProgramInfo info = programMap.get(program);
return (info != null && info.owner != null);
}
private class ProgramInfo implements Comparable<ProgramInfo> {
Program program;
URL ghidraURL;
TransientToolState lastState;
private Program program;
private URL ghidraURL;
private TransientToolState lastState;
private int instance;
boolean visible;
Object owner;
private boolean visible;
private Object owner;
ProgramInfo(Program p, boolean visible) {
this.program = p;
this.visible = visible;
synchronized (ProgramInfo.class) {
instance = ++nextProgramInfoInstance;
}
instance = nextAvailableId.incrementAndGet();
}
public void setVisible(boolean state) {
@ -443,98 +524,4 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
return instance - info.instance;
}
}
@Override
public void transactionEnded(DomainObjectAdapterDB domainObj) {
// don't care
}
@Override
public void transactionStarted(DomainObjectAdapterDB domainObj, Transaction tx) {
// don't care
}
@Override
public void undoRedoOccurred(DomainObjectAdapterDB domainObj) {
// don't care
}
@Override
public void undoStackChanged(DomainObjectAdapterDB domainObj) {
SystemUtilities.runSwingLater(programChangedRunnable);
}
public Program getOpenProgram(URL ghidraURL) {
if (!GhidraURL.isServerRepositoryURL(ghidraURL)) {
return null;
}
URL normalizedURL = GhidraURL.getNormalizedURL(ghidraURL);
for (ProgramInfo info : programMap.values()) {
URL url = info.ghidraURL;
if (url != null && url.equals(normalizedURL)) {
return info.program;
}
}
return null;
}
public Program getOpenProgram(DomainFile domainFile, int version) {
for (Program program : programMap.keySet()) {
DomainFile programDomainFile = program.getDomainFile();
if (filesMatch(domainFile, version, programDomainFile)) {
return program;
}
}
return null;
}
private boolean filesMatch(DomainFile file, int version, DomainFile openFile) {
if (!file.getPathname().equals(openFile.getPathname())) {
return false;
}
if (file.isCheckedOut() != openFile.isCheckedOut()) {
return false;
}
if (!SystemUtilities.isEqual(file.getProjectLocator(), openFile.getProjectLocator())) {
return false;
}
int openVersion = openFile.isReadOnly() ? openFile.getVersion() : -1;
return version == openVersion;
}
/**
* Returns true if this ProgramManager is managing the given program
* @param program the program to check
* @return true if this ProgramManager is managing the given programs
*/
public boolean hasProgram(Program program) {
return programMap.containsKey(program);
}
/**
* Returns true if there is at least one program that has unsaved changes.
* @return true if there is at least one program that has unsaved changes.
*/
public boolean hasUnsavedPrograms() {
return hasUnsavedPrograms;
}
private boolean checkForUnsavedPrograms() {
// first check the current program as that is the one most likely to have changes
Program currentProgram = getCurrentProgram();
if (currentProgram != null && currentProgram.isChanged()) {
return true;
}
// look at all the open programs to see if any have changes
for (ProgramInfo programInfo : openProgramList) {
if (programInfo.program.isChanged()) {
return true;
}
}
return false;
}
}

View file

@ -23,7 +23,6 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import docking.action.DockingAction;
import docking.action.builder.ActionBuilder;
@ -138,17 +137,14 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
}
@Override
public Program openProgram(final URL ghidraURL, final int state) {
public Program openProgram(URL ghidraURL, int state) {
if (locked) {
Msg.showError(this, tool.getToolFrame(), "Open Program Failed",
"Program manager is locked and cannot open additional programs");
return null;
}
AtomicReference<Program> ref = new AtomicReference<>();
Runnable r = () -> ref.set(doOpenProgram(ghidraURL, state));
SystemUtilities.runSwingNow(r);
return ref.get();
return Swing.runNow(() -> doOpenProgram(ghidraURL, state));
}
private void messageBadProgramURL(URL ghidraURL) {
@ -341,7 +337,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
public boolean closeOtherPrograms(boolean ignoreChanges) {
Program[] otherPrograms = programMgr.getOtherPrograms();
Runnable r = () -> doCloseAllPrograms(otherPrograms, ignoreChanges);
SystemUtilities.runSwingNow(r);
Swing.runNow(r);
return programMgr.isEmpty();
}
@ -349,7 +345,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
public boolean closeAllPrograms(boolean ignoreChanges) {
Program[] openPrograms = programMgr.getAllPrograms();
Runnable r = () -> doCloseAllPrograms(openPrograms, ignoreChanges);
SystemUtilities.runSwingNow(r);
Swing.runNow(r);
return programMgr.isEmpty();
}
@ -405,7 +401,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
contextChanged();
}
};
SystemUtilities.runSwingNow(r);
Swing.runNow(r);
return !programMgr.contains(program);
}
@ -436,7 +432,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
programMgr.setCurrentProgram(p);
contextChanged();
};
SystemUtilities.runSwingNow(r);
Swing.runNow(r);
}
@Override
@ -476,7 +472,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
}
contextChanged();
};
SystemUtilities.runSwingNow(r);
Swing.runNow(r);
}
@Override
@ -506,8 +502,8 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
int subMenuGroup = 1;
DockingAction openAction = new ActionBuilder("Open File", getName())
.menuPath(ToolConstants.MENU_FILE, "&Open...")
DockingAction openAction =
new ActionBuilder("Open File", getName()).menuPath(ToolConstants.MENU_FILE, "&Open...")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroup++))
.keyBinding("ctrl O")
.enabledWhen(c -> !locked)
@ -522,7 +518,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.enabled(false)
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.enabledWhen(c -> programMgr.hasProgram(c.getProgram()))
.enabledWhen(c -> programMgr.contains(c.getProgram()))
.onAction(c -> closeOtherPrograms(false))
.buildAndInstall(tool);

View file

@ -22,12 +22,20 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.ExternalLocation;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Swing;
import ghidra.util.task.TaskMonitor;
/**
* The GoToService provides a general service for plugins to generate GoTo
* events. The provider of this service will take care of interfacing with
* any history service that may be available.
* <p>
* This class will execute all {@code goTo} calls on the Java Swing thread. This will happen in
* a blocking manner if the client calls from any other thread. This has the potential to lead
* to deadlocks if the client is using custom synchronization. Care must be taken to not be
* holding any lock that will cause the Swing thread to block when using this class from any other
* thread. To work around this issue, clients can always call this service from within a
* {@link Swing#runLater(Runnable)} call, which will prevent any deadlock issues.
*/
@ServiceInfo(defaultProvider = GoToServicePlugin.class, description = "Navigate to a program location")
public interface GoToService {
@ -50,11 +58,11 @@ public interface GoToService {
/**
* Generates a GoTo event and handles any history state that needs to be saved. This
* overloaded version of {@link #goTo(Address)} uses the given program as the program
* within which to perform the GoTo. If the given program does not contain the given
* address, then the GoTo will not be performed and false will be returned. Passing
* <code>null</code> as the <code>program</code> parameter will cause this method to attempt to find
* a program that contains the given ProgramLocation.
* overloaded version of {@link #goTo(Address)} uses the given program as the program within
* which to perform the GoTo. If the given program does not contain the given address, then
* the GoTo will not be performed and false will be returned. Passing <code>null</code> as the
* <code>program</code> parameter will cause this method to attempt to find a program that
* contains the given ProgramLocation.
*
* @param loc location to go to
* @param program the program within which to perform the GoTo
@ -63,20 +71,46 @@ public interface GoToService {
*/
public boolean goTo(ProgramLocation loc, Program program);
/**
* Generates a GoTo event to the given location in the given program.
*
* @param navigatable the destination navigatable
* @param loc the location
* @param program program
* @return true if the go to was successful
*/
public boolean goTo(Navigatable navigatable, ProgramLocation loc, Program program);
/**
* Generates a GoTo event to the given address. The refAddress is used to determine if
* there is a specific symbol reference from that reference.
*
* @param navigatable the destination navigatable
* @param program program
* @param address the destination address
* @param refAddress the from reference address
* @return true if the go to was successful
*/
public boolean goTo(Navigatable navigatable, Program program, Address address,
Address refAddress);
/**
* Generates a GoTo event to the goToAddress or symbol. The currentAddress is used to
* determine if there is a specific symbol reference from the current address.
* @param currentAddress the current address
* Generates a GoTo event to the given address. The fromAddress is used to determine if
* there is a specific symbol reference from the current address.
*
* @param fromAddress the current address
* @param address the address to goto
* @return true if the go to was successful
*/
public boolean goTo(Address fromAddress, Address address);
/**
* Generates a GoTo event to the given address for the specific navigatable.
*
* @param navigatable the destination navigatable
* @param goToAddress the address to goto
* @return true if the go to was successful
*/
public boolean goTo(Address currentAddress, Address goToAddress);
public boolean goTo(Navigatable navigatable, Address goToAddress);
/**
@ -89,11 +123,11 @@ public interface GoToService {
/**
* Generates a GoTo event to the gotoAddress. This overloaded version of
* {@link #goTo(Address)} uses the given program as the program within which to
* perform the GoTo. If the given program does not contain the given address, then the
* GoTo will not be performed and false will be returned. Passing <code>null</code> as the
* <code>program</code> parameter will cause this method to attempt to find
* a program that contains the given ProgramLocation.
* {@link #goTo(Address)} uses the given program as the program within which to perform the
* GoTo. If the given program does not contain the given address, then the GoTo will not be
* performed and false will be returned. Passing <code>null</code> as the <code>program</code>
* parameter will cause this method to attempt to find a program that contains the given
* ProgramLocation.
*
* @param goToAddress the address to goto
* @param program the program within which to perform the GoTo
@ -103,67 +137,82 @@ public interface GoToService {
public boolean goTo(Address goToAddress, Program program);
/**
* Navigate to either the external program location or address linkage location.
* Specific behavior may vary based upon implementation.
* Navigate to either the external program location or address linkage location. Specific
* behavior may vary based upon implementation.
*
* @param externalLoc external location
* @param checkNavigationOption if true the service navigation
* option will be used to determine if navigation to the external program will be
* attempted, or if navigation to the external linkage location within the current
* program will be attempted. If false, the implementations default behavior
* will be performed.
* @return true if either navigation to the external program or to a
* linkage location was completed successfully.
* @param checkNavigationOption if true the service navigation option will be used to determine
* if navigation to the external program will be attempted, or if navigation to the
* external linkage location within the current program will be attempted. If false, the
* implementations default behavior will be performed.
* @return true if either navigation to the external program or to a linkage location was
* completed successfully.
*/
public boolean goToExternalLocation(ExternalLocation externalLoc,
boolean checkNavigationOption);
/**
* Navigate to either the external program location or address linkage location.
* Specific behavior may vary based upon implementation.
* Navigate to either the external program location or address linkage location. Specific
* behavior may vary based upon implementation.
*
* @param navigatable Navigatable
* @param externalLoc external location
* @param checkNavigationOption if true the service navigation
* option will be used to determine if navigation to the external program will be
* attempted, or if navigation to the external linkage location within the current
* program will be attempted. If false, the implementations default behavior
* will be performed.
* @return true if either navigation to the external program or to a
* linkage location was completed successfully.
* @param checkNavigationOption if true the service navigation option will be used to determine
* if navigation to the external program will be attempted, or if navigation to the
* external linkage location within the current program will be attempted. If false, the
* implementations default behavior will be performed.
* @return true if either navigation to the external program or to a linkage location was
* completed successfully.
*/
public boolean goToExternalLocation(Navigatable navigatable, ExternalLocation externalLoc,
boolean checkNavigationOption);
/**
* Parses the input string as either:
* an address/symbol expression (0x1000+5, or LAB1000+5)
* a symbol wildcard expression (LAB*, LAB?100)
* a symbol lookup
* an address lookup
*
* Generates a GoTo event for the given query.
* <p>
* If the query results in more than one location, a list of locations will be displayed.
* If the query results in only one location, then a goto event will be fired(except for a
* wildcard query in which case a list will still be displayed.
*
* <p>
* The listener will be notified after query and will indicate the query status.
*
* @param fromAddr The address used to determine the scope of the query
* @param queryData the query input data
* @param listener the listener that will be notified when the query completes.
* @param listener the listener that will be notified when the query completes
* @param monitor the task monitor
* @return true if the queryInput is found or appears to be a wildcard search.
* @return true if the queryInput is found or appears to be a wildcard search
*/
public boolean goToQuery(Address fromAddr, QueryData queryData, GoToServiceListener listener,
TaskMonitor monitor);
/**
* Generates a GoTo event for the given query.
* <p>
* If the query results in more than one location, a list of locations will be displayed.
* If the query results in only one location, then a goto event will be fired(except for a
* wildcard query in which case a list will still be displayed.
* <p>
* The listener will be notified after query and will indicate the query status.
*
* @param navigatable the destination for the go to event
* @param fromAddr The address used to determine the scope of the query
* @param queryData the query input data
* @param listener the listener that will be notified when the query completes
* @param monitor the task monitor
* @return true if the queryInput is found or appears to be a wildcard search
*/
public boolean goToQuery(Navigatable navigatable, Address fromAddr, QueryData queryData,
GoToServiceListener listener, TaskMonitor monitor);
public GoToOverrideService getOverrideService();
public void setOverrideService(GoToOverrideService override);
/**
* Returns the default navigatable that is the destination for GoTo events.
* @return the navigatable
*/
public Navigatable getDefaultNavigatable();
@Deprecated(forRemoval = true, since = "10.2")
public GoToOverrideService getOverrideService();
@Deprecated(forRemoval = true, since = "10.2")
public void setOverrideService(GoToOverrideService override);
}

View file

@ -29,9 +29,7 @@ import ghidra.program.model.listing.Program;
* Service for managing programs. Multiple programs may be open in a tool, but only one is active at
* any given time.
*/
@ServiceInfo(
defaultProvider = ProgramManagerPlugin.class,
description = "Get the currently open program")
@ServiceInfo(defaultProvider = ProgramManagerPlugin.class, description = "Get the currently open program")
public interface ProgramManager {
/**
@ -194,7 +192,9 @@ public interface ProgramManager {
* @return true if program is open and another object is not already the owner, or the specified
* owner is already the owner.
* @see #releaseProgram(Program, Object)
* @deprecated this method is no longer used by the system
*/
@Deprecated(forRemoval = true, since = "10.2")
public boolean setPersistentOwner(Program program, Object owner);
/**
@ -208,7 +208,9 @@ public interface ProgramManager {
*
* @param program the program
* @param persistentOwner the owner defined by {@link #setPersistentOwner(Program, Object)}
* @deprecated this method is no longer used by the system
*/
@Deprecated(forRemoval = true, since = "10.2")
public void releaseProgram(Program program, Object persistentOwner);
/**

View file

@ -42,7 +42,7 @@ import ghidra.program.model.symbol.*;
import ghidra.program.util.AddressEvaluator;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.Swing;
import ghidra.util.table.AddressArrayTableModel;
import ghidra.util.table.GhidraProgramTableModel;
import ghidra.util.task.TaskMonitor;
@ -187,7 +187,7 @@ public class GoToQuery {
return;
}
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
Swing.runIfSwingOrRunLater(() -> {
model = new AddressArrayTableModel("Goto: ", plugin.getTool(), program, validAddresses,
monitor);
model.addInitialLoadListener(tableModelListener);
@ -203,7 +203,7 @@ public class GoToQuery {
return;
}
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
Swing.runIfSwingOrRunLater(() -> {
model = new GoToQueryResultsTableModel(program, plugin.getTool(), locations, monitor);
model.addInitialLoadListener(tableModelListener);
});
@ -214,7 +214,7 @@ public class GoToQuery {
return false;
}
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
Swing.runIfSwingOrRunLater(() -> {
model = new GoToQueryResultsTableModel(navigatable.getProgram(), queryData,
plugin.getTool(), maxHits, monitor);
model.addInitialLoadListener(tableModelListener);
@ -337,7 +337,7 @@ public class GoToQuery {
return false;
}
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
Swing.runIfSwingOrRunLater(() -> {
Program program = navigatable.getProgram();
model = new GoToQueryResultsTableModel(program, cleanupQuery(program, queryData),
plugin.getTool(), maxHits, monitor);

View file

@ -46,6 +46,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.layout.HorizontalLayout;
public class ListingPanel extends JPanel implements FieldMouseListener, FieldLocationListener,
@ -574,6 +575,9 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
* screen will be scrolled only enough to show the cursor.
*/
public boolean goTo(ProgramLocation loc, boolean centerWhenNotVisible) {
Swing.assertSwingThread("goTo() must be called on the Swing thread");
final FieldLocation floc = getFieldLocation(loc);
if (floc == null) {
return false;
@ -623,9 +627,6 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
if (programAddressSpace != locAddressSpace) {
FieldLocation compatibleLocation =
getFieldLocationForDifferingAddressSpaces(loc, program);
if (compatibleLocation == null) {
return null;
}
return compatibleLocation;
}
@ -1125,7 +1126,6 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
/**
* Returns the currently selected text. The value will only be non-null for selections within a
* single field.
*
* @return the selected text or null
*/
public String getTextSelection() {

View file

@ -37,7 +37,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.test.*;
import ghidra.util.task.TaskMonitorAdapter;
import ghidra.util.task.TaskMonitor;
/**
* Tests for tool state history plugin.
@ -87,7 +87,7 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
@After
public void tearDown() throws Exception {
waitForPostedSwingRunnables();
waitForSwing();
env.dispose();
}
@ -95,8 +95,7 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
public void testPrevious() throws Exception {
// go to sscanf
QueryData queryData = new QueryData("sscanf", false);
goToService.goToQuery(program.getMinAddress(), queryData, null,
TaskMonitorAdapter.DUMMY_MONITOR);
goToService.goToQuery(program.getMinAddress(), queryData, null, TaskMonitor.DUMMY);
assertTrue(plugin.hasPrevious(navigatable));
@ -119,30 +118,29 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(loc, cb.getCurrentLocation());
assertTrue(prevAction.isEnabledForContext(provider.getActionContext(null)));
assertTrue(nextAction.isEnabledForContext(provider.getActionContext(null)));
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(program.getMinAddress(), cb.getCurrentAddress());
assertTrue(!prevAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(prevAction.isEnabledForContext(provider.getActionContext(null)));
assertTrue(nextAction.isEnabledForContext(provider.getActionContext(null)));
}
@Test
public void testNext() throws Exception {
QueryData queryData = new QueryData("sscanf", false);
goToService.goToQuery(program.getMinAddress(), queryData, null,
TaskMonitorAdapter.DUMMY_MONITOR);
goToService.goToQuery(program.getMinAddress(), queryData, null, TaskMonitor.DUMMY);
assertTrue(plugin.hasPrevious(navigatable));
assertNotNull(prevAction);
assertTrue(prevAction.isEnabledForContext(provider.getActionContext(null)));
assertTrue(!nextAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(nextAction.isEnabledForContext(provider.getActionContext(null)));
ProgramLocation loc = cb.getCurrentLocation();
assertTrue(loc instanceof FunctionSignatureFieldLocation);
@ -174,17 +172,17 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(opLoc, cb.getCurrentLocation());
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(xrefLoc, cb.getCurrentLocation());
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(loc, cb.getCurrentLocation());
assertTrue(prevAction.isEnabledForContext(provider.getActionContext(null)));
@ -192,18 +190,18 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(program.getMinAddress(), cb.getCurrentAddress());
assertTrue(!prevAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(prevAction.isEnabledForContext(provider.getActionContext(null)));
performAction(nextAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(loc, cb.getCurrentLocation());
performAction(nextAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(xrefLoc, cb.getCurrentLocation());
assertTrue(prevAction.isEnabledForContext(provider.getActionContext(null)));
@ -211,24 +209,23 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
performAction(prevAction, provider, true);
performAction(prevAction, provider, true);
assertTrue(!prevAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(prevAction.isEnabledForContext(provider.getActionContext(null)));
assertTrue(nextAction.isEnabledForContext(provider.getActionContext(null)));
for (ProgramLocation element : locations) {
performAction(nextAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(element, cb.getCurrentLocation());
}
assertTrue(!nextAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(nextAction.isEnabledForContext(provider.getActionContext(null)));
}
@Test
public void testNavigationInCodeBrowser() throws Exception {
QueryData queryData = new QueryData("sscanf", false);
goToService.goToQuery(program.getMinAddress(), queryData, null,
TaskMonitorAdapter.DUMMY_MONITOR);
goToService.goToQuery(program.getMinAddress(), queryData, null, TaskMonitor.DUMMY);
ProgramLocation loc = cb.getCurrentLocation();
assertTrue(loc instanceof FunctionSignatureFieldLocation);
@ -279,8 +276,7 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
DockingActionIf clearAction = getAction(nextPrevPlugin, "Clear History Buffer");
QueryData queryData = new QueryData("sscanf", false);
goToService.goToQuery(program.getMinAddress(), queryData, null,
TaskMonitorAdapter.DUMMY_MONITOR);
goToService.goToQuery(program.getMinAddress(), queryData, null, TaskMonitor.DUMMY);
ProgramLocation loc = cb.getCurrentLocation();
@ -294,8 +290,8 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
click(cb, 2);
performAction(clearAction, provider, true);
assertTrue(!plugin.hasNext(navigatable));
assertTrue(!plugin.hasPrevious(navigatable));
assertFalse(plugin.hasNext(navigatable));
assertFalse(plugin.hasPrevious(navigatable));
}
@Test
@ -303,14 +299,13 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
ProgramLocation initialLoc = cb.getCurrentLocation();
QueryData queryData = new QueryData("sscanf", false);
goToService.goToQuery(program.getMinAddress(), queryData, null,
TaskMonitorAdapter.DUMMY_MONITOR);
goToService.goToQuery(program.getMinAddress(), queryData, null, TaskMonitor.DUMMY);
assertTrue(plugin.hasPrevious(navigatable));
assertNotNull(prevAction);
assertTrue(prevAction.isEnabledForContext(provider.getActionContext(null)));
assertTrue(!nextAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(nextAction.isEnabledForContext(provider.getActionContext(null)));
ProgramLocation loc = cb.getCurrentLocation();
assertTrue(loc instanceof FunctionSignatureFieldLocation);
@ -347,10 +342,10 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
for (int i = locations.length - 1; i >= 0; i--) {
performAction(prevAction, provider, true);
cb.updateNow();
waitForPostedSwingRunnables();
waitForSwing();
assertEquals(locations[i], cb.getCurrentLocation());
}
assertTrue(!prevAction.isEnabledForContext(provider.getActionContext(null)));
assertFalse(prevAction.isEnabledForContext(provider.getActionContext(null)));
}
@Test
@ -367,16 +362,17 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
++count;
goToService.goTo(currentAddr, symbol.getAddress());
Address addr = currentAddr;
runSwing(() -> goToService.goTo(addr, symbol.getAddress()));
cb.updateNow();
currentAddr = symbol.getAddress();
if (count > NavigationHistoryPlugin.MAX_HISTORY_SIZE) {
for (int i = 0; i < NavigationHistoryPlugin.MAX_HISTORY_SIZE - 1; i++) {
assertTrue(plugin.hasPrevious(navigatable));
plugin.previous(navigatable);
runSwing(() -> plugin.previous(navigatable));
cb.updateNow();
}
assertTrue(!plugin.hasPrevious(navigatable));
assertFalse(plugin.hasPrevious(navigatable));
break;
}
}
@ -396,7 +392,8 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
}
++count;
goToService.goTo(currentAddr, symbol.getAddress());
Address addr = currentAddr;
runSwing(() -> goToService.goTo(addr, symbol.getAddress()));
cb.updateNow();
currentAddr = symbol.getAddress();
if (count > 2 * NavigationHistoryPlugin.MAX_HISTORY_SIZE) {
@ -413,10 +410,10 @@ public class NavigationHistoryPluginTest extends AbstractGhidraHeadedIntegration
for (int i = 0; i < NavigationHistoryPlugin.MAX_HISTORY_SIZE - 1; i++) {
assertTrue(plugin.hasPrevious(navigatable));
plugin.previous(navigatable);
runSwing(() -> plugin.previous(navigatable));
cb.updateNow();
}
assertTrue(!plugin.hasPrevious(navigatable));
assertFalse(plugin.hasPrevious(navigatable));
}
@Test

View file

@ -25,7 +25,6 @@ import javax.swing.tree.TreePath;
import org.junit.*;
import docking.ComponentProvider;
import docking.action.DockingActionIf;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
@ -33,6 +32,7 @@ import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.marker.MarkerManagerPlugin;
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
import ghidra.app.plugin.core.programtree.ProgramTreePlugin;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
import ghidra.app.plugin.core.select.programtree.ProgramTreeSelectionPlugin;
import ghidra.app.services.ProgramManager;
import ghidra.framework.plugintool.PluginTool;
@ -57,7 +57,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
private DockingActionIf selectInstructionAction;
private DockingActionIf selectUndefinedAction;
private ProgramTreePlugin pt;
private ComponentProvider programTreeProvider;
private ViewManagerComponentProvider programTreeProvider;
private DockingActionIf replaceView;
private ToyProgramBuilder builder;
@ -94,10 +94,9 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
}
private void showProgramTree() {
ProgramTreePlugin ptree = env.getPlugin(ProgramTreePlugin.class);
programTreeProvider = (ComponentProvider) getInstanceField("viewProvider", pt);
programTreeProvider = (ViewManagerComponentProvider) getInstanceField("viewProvider", pt);
tool.showComponentProvider(programTreeProvider, true);
waitForComponentProvider(ViewManagerComponentProvider.class);
}
protected void setUpQualifiedSelection(PluginTool tool) throws Exception {
@ -115,7 +114,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
// Select All Instructions.
performAction(selectInstructionAction, provider, true);
ProgramSelection instructionSet = getCurrentSelection();
assertTrue(!instructionSet.isEmpty());
assertFalse(instructionSet.isEmpty());
// Select No Data (because there is a selection of all instructions).
performAction(selectDataAction, provider, true);
@ -124,7 +123,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
// Select All Data.
performAction(selectDataAction, provider, true);
ProgramSelection dataSet = getCurrentSelection();
assertTrue(!dataSet.isEmpty());
assertFalse(dataSet.isEmpty());
// Select No Undefined.
performAction(selectUndefinedAction, provider, true);
@ -133,7 +132,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
// Select All Undefined.
performAction(selectUndefinedAction, provider, true);
ProgramSelection undefinedSet = getCurrentSelection();
assertTrue(!undefinedSet.isEmpty());
assertFalse(undefinedSet.isEmpty());
// Select No Instructions.
performAction(selectInstructionAction, provider, true);
@ -170,7 +169,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
// Select Instructions.
performAction(selectInstructionAction, provider, true);
ProgramSelection instructionSet = getCurrentSelection();
assertTrue(!instructionSet.isEmpty());
assertFalse(instructionSet.isEmpty());
assertTrue(instructionSet.getMinAddress().compareTo(addr("010012d2")) >= 0);
assertTrue(instructionSet.getMaxAddress().compareTo(addr("01001960")) <= 0);
@ -182,7 +181,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
performAction(selectDataAction, provider, true);
waitForSwing();
ProgramSelection dataSet = getCurrentSelection();
assertTrue(!dataSet.isEmpty());
assertFalse(dataSet.isEmpty());
assertTrue(dataSet.getMinAddress().compareTo(addr("010012d2")) >= 0);
assertTrue(dataSet.getMaxAddress().compareTo(addr("01001960")) <= 0);
@ -194,7 +193,7 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
performAction(selectUndefinedAction, provider, true);
waitForSwing();
ProgramSelection undefinedSet = getCurrentSelection();
assertTrue(!undefinedSet.isEmpty());
assertFalse(undefinedSet.isEmpty());
assertTrue(undefinedSet.getMinAddress().compareTo(addr("010012d2")) >= 0);
assertTrue(undefinedSet.getMaxAddress().compareTo(addr("01001960")) <= 0);
@ -219,7 +218,8 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
@Test
public void testSelectWithView() throws Exception {
AddressSet rsrcSet = new AddressSet(addr("0100a000"), addr("0100f3ff"));
JTree tree = findComponent(tool.getToolFrame(), JTree.class);
JTree tree = waitFor(() -> findComponent(tool.getToolFrame(), JTree.class));
// Replace view with .rsrc
selectTreeNodeByText(tree, ".rsrc", true);
@ -254,12 +254,12 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
performAction(selectDataAction, provider, true);
waitForSwing();
ProgramSelection rsrcDataSet = getCurrentSelection();
assertTrue(!rsrcDataSet.isEmpty());
assertFalse(rsrcDataSet.isEmpty());
// Change to program view
selectTreeNodeByText(tree, "Test", true);
performAction(replaceView, provider, true);
ProgramSelection dataSet = getCurrentSelection();
assertTrue(!dataSet.isEmpty());
assertFalse(dataSet.isEmpty());
// Select No Undefined.
performAction(selectUndefinedAction, provider, true);
@ -274,12 +274,12 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
performAction(selectUndefinedAction, provider, true);
waitForSwing();
ProgramSelection rsrcUndefinedSet = getCurrentSelection();
assertTrue(!rsrcUndefinedSet.isEmpty());
assertFalse(rsrcUndefinedSet.isEmpty());
// Change to program view
selectTreeNodeByText(tree, "Test", true);
performAction(replaceView, provider, true);
ProgramSelection undefinedSet = getCurrentSelection();
assertTrue(!undefinedSet.isEmpty());
assertFalse(undefinedSet.isEmpty());
// Select No Instructions.
performAction(selectInstructionAction, provider, true);
@ -396,9 +396,6 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
}, wait);
}
/**
* @param instructionSet
*/
private void checkForInstructions(ProgramSelection instructionSet) {
Listing listing = program.getListing();
AddressIterator iter = instructionSet.getAddresses(true);
@ -409,9 +406,6 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
}
}
/**
* @param dataSet
*/
private void checkForDefinedData(ProgramSelection dataSet) {
Listing listing = program.getListing();
AddressIterator iter = dataSet.getAddresses(true);
@ -422,9 +416,6 @@ public class QualifiedSelectionPluginTest extends AbstractGhidraHeadedIntegratio
}
}
/**
* @param undefinedSet
*/
private void checkForUndefined(ProgramSelection undefinedSet) {
Listing listing = program.getListing();
AddressIterator iter = undefinedSet.getAddresses(true);

View file

@ -169,14 +169,13 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
clickComponentProvider(provider);
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction, false);
performAction(openTableAction, provider, false);
Window selectWindow = waitForWindowByTitleContaining("Select Functions");
assertNotNull(selectWindow);
selectWindow.setVisible(false);
}
@SuppressWarnings("unchecked")
@Test
public void testAddFunctionToExistingCompare() {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo);
@ -189,10 +188,12 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
assertTrue(provider.getModel().getSourceFunctions().contains(foo));
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction, false);
performAction(openTableAction, provider, false);
@SuppressWarnings("unchecked")
TableSelectionDialog<FunctionTableModel> chooser =
waitForDialogComponent(TableSelectionDialog.class);
@SuppressWarnings("unchecked")
GFilterTable<FunctionRowObject> table =
(GFilterTable<FunctionRowObject>) getInstanceField("gFilterTable", chooser);