diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/ShowInstructionInfo.htm b/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/ShowInstructionInfo.htm index df002a6ff5..715c12a5c4 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/ShowInstructionInfo.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/ShowInstructionInfo.htm @@ -115,7 +115,7 @@ (Mnemonic, Number of Operands, Address, Flow Type, Delay Slot Depth, Prototype Hash, Input Objects, Result Objects, Constructor line numbers, Instruction Bytes, etc.).

-

The Operand columns (Op1, Op2, etc.) display information about a particular +

The Operand columns (Op0, Op1, etc.) display information about a particular operand.  Each operand has a number of rows.  At the end of the row is a descriptive name for the information displayed on that row.

@@ -197,13 +197,13 @@

 

-

The Dynamic Update checkbox indicates whether the window should update when you - change the location in the Code Browser.  By default, the checkbox is selected. As you - change your location - in the Code Browser, the window will be updated to show the info for the new - location.  If you turn off the checkbox, the window does not update; the next time you - choose Instruction Info, a new tab is displayed in the Instruction Info - window.

+

The Dynamic Update toggle indicates whether the + window should update when you change the location in the Code Browser.  By default, the + toggle is selected. As you change your + location in the Code + Browser, the window will be updated to show the info for the new location.  If you turn + off the toggle, the window does not update; the next time you choose Instruction + Info, a new tab is displayed in the Instruction Info window.

 

diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/images/ShowInstructionInfo.png b/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/images/ShowInstructionInfo.png index cff081a85d..bf2aabfba9 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/images/ShowInstructionInfo.png and b/Ghidra/Features/Base/src/main/help/help/topics/ShowInstructionInfoPlugin/images/ShowInstructionInfo.png differ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java index 58c1761f2f..7aa3d2cec1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,12 +15,14 @@ */ package ghidra.app.plugin.core.processors; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Dimension; import javax.swing.*; import javax.swing.table.DefaultTableModel; -import docking.widgets.checkbox.GCheckBox; +import docking.action.ToggleDockingAction; +import docking.action.builder.ToggleActionBuilder; import generic.theme.Gui; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger.SleighDebugMode; @@ -33,6 +35,7 @@ import ghidra.program.model.listing.*; import ghidra.program.util.InstructionUtils; import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTable; +import resources.Icons; /** * Component provider to show the instruction info. @@ -48,7 +51,7 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain private JTextArea instructionText; private JTable opTable; - private JCheckBox dynamicUpdateCB; + private ToggleDockingAction dynamicUpdateAction; private OperandModel operandModel; private Address myAddr; @@ -57,10 +60,11 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain super(plugin.getTool(), "Instruction Info", plugin.getName()); this.plugin = plugin; - buildMainPanel(isDynamic); + buildMainPanel(); setTransient(); setWindowMenuGroup("Instruction Info"); addToTool(); + createActions(isDynamic); } @Override @@ -73,13 +77,23 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain return new HelpLocation(plugin.getName(), "Show_Instruction_Info_Window"); } + private void createActions(boolean isDynamic) { + dynamicUpdateAction = new ToggleActionBuilder("Dynamic Update", plugin.getName()) + .toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON) + .description("Update this panel with navigation") + .onAction(ctx -> dynamicStateChanged()) + .selected(isDynamic) + .buildAndInstallLocal(this); + dynamicStateChanged(); + } + boolean dynamicUpdateSelected() { - return dynamicUpdateCB.isSelected(); + return dynamicUpdateAction.isSelected(); } /** - * Set the status text on this dialog. - */ + * Set the status text on this dialog. + */ void setStatusText(String msg) { tool.setStatusInfo(msg); } @@ -101,7 +115,7 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain * * @return JPanel the completed Main Panel */ - protected JPanel buildMainPanel(boolean isDynamic) { + protected JPanel buildMainPanel() { mainPanel = new JPanel(new BorderLayout()); @@ -120,11 +134,6 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain pane.setResizeWeight(.25); mainPanel.add(pane, BorderLayout.CENTER); - dynamicUpdateCB = new GCheckBox("Dynamic Update", isDynamic); - dynamicUpdateCB.setAlignmentX(Component.CENTER_ALIGNMENT); - dynamicUpdateCB.addItemListener(e -> dynamicStateChanged()); - - mainPanel.add(dynamicUpdateCB, BorderLayout.SOUTH); mainPanel.validate(); return mainPanel; @@ -194,8 +203,9 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain setAddress(myAddr); } - public void setNonDynamic() { - dynamicUpdateCB.setSelected(false); + public void setDynamic(boolean dynamic) { + dynamicUpdateAction.setSelected(dynamic); + dynamicStateChanged(); } public Program getProgram() { @@ -225,6 +235,7 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain /** * Returns the number of columns in this data table. + * * @return the number of columns in the model */ @Override @@ -234,10 +245,10 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain /** * Returns the column name. - * @return a name for this column using the string value of the - * appropriate member in columnIdentfiers. If columnIdentfiers - * is null or does not have and entry for this index return the default - * name provided by the superclass. + * + * @return a name for this column using the string value of the appropriate member in + * columnIdentfiers. If columnIdentfiers is null or does not have and + * entry for this index return the default name provided by the superclass. */ @Override public String getColumnName(int column) { @@ -249,6 +260,7 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain /** * Returns the number of rows in this data table. + * * @return the number of rows in the model */ @Override @@ -257,14 +269,12 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain } /** - * Returns an attribute value for the cell at row - * and column. + * Returns an attribute value for the cell at row and column. * - * @param row the row whose value is to be looked up - * @param column the column whose value is to be looked up - * @return the value Object at the specified cell - * @exception ArrayIndexOutOfBoundsException if an invalid row or - * column was given. + * @param row the row whose value is to be looked up + * @param column the column whose value is to be looked up + * @return the value Object at the specified cell + * @exception ArrayIndexOutOfBoundsException if an invalid row or column was given. */ @Override public Object getValueAt(int row, int column) { @@ -272,56 +282,39 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain return null; } if (column == 0) { - switch (row) { - case 0: - return "Operand"; - case 1: - return "Labeled"; - case 2: - return "Type"; - case 3: - return "Scalar"; - case 4: - return "Address"; - case 5: - return "Register"; - case 6: - return "Op-Objects"; - case 7: - return "Operand Mask"; - case 8: - return "Masked Value"; - } + return switch (row) { + case 0 -> "Operand"; + case 1 -> "Labeled"; + case 2 -> "Type"; + case 3 -> "Scalar"; + case 4 -> "Address"; + case 5 -> "Register"; + case 6 -> "Op-Objects"; + case 7 -> "Operand Mask"; + case 8 -> "Masked Value"; + default -> ""; + }; } int opIndex = column - 1; if (opIndex >= instruction.getNumOperands()) { return ""; } - switch (row) { - case 0: - return instruction.getDefaultOperandRepresentation(opIndex); - case 1: - return CodeUnitFormat.DEFAULT.getOperandRepresentationList(instruction, - opIndex); - case 2: - return OperandType.toString(instruction.getOperandType(opIndex)); - case 3: - return instruction.getScalar(opIndex); - case 4: + return switch (row) { + case 0 -> instruction.getDefaultOperandRepresentation(opIndex); + case 1 -> CodeUnitFormat.DEFAULT.getOperandRepresentationList(instruction, opIndex); + case 2 -> OperandType.toString(instruction.getOperandType(opIndex)); + case 3 -> instruction.getScalar(opIndex); + case 4 -> { Address addr = instruction.getAddress(opIndex); - return addr != null ? addr.toString(true) : ""; - case 5: - return instruction.getRegister(opIndex); - case 6: - return getString( - InstructionUtils.getFormatedOperandObjects(instruction, opIndex)); - case 7: - return debug != null ? debug.getFormattedInstructionMask(opIndex) : null; - case 8: - return debug != null ? debug.getFormattedMaskedValue(opIndex) : null; - } - - return ""; + yield addr != null ? addr.toString(true) : ""; + } + case 5 -> instruction.getRegister(opIndex); + case 6 -> getString( + InstructionUtils.getFormatedOperandObjects(instruction, opIndex)); + case 7 -> debug != null ? debug.getFormattedInstructionMask(opIndex) : null; + case 8 -> debug != null ? debug.getFormattedMaskedValue(opIndex) : null; + default -> ""; + }; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPlugin.java index 353fe1b2a2..9bcf2649c0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPlugin.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -344,8 +344,8 @@ public class ShowInstructionInfoPlugin extends ProgramPlugin { } /** - * Subclass should override this method if it is interested in - * program location events. + * Subclass should override this method if it is interested in program location events. + * * @param loc location could be null */ @Override @@ -463,7 +463,7 @@ public class ShowInstructionInfoPlugin extends ProgramPlugin { } else if (provider != connectedProvider && isDynamic) { if (connectedProvider != null) { - connectedProvider.setNonDynamic(); + connectedProvider.setDynamic(false); } disconnectedProviders.remove(provider); connectedProvider = provider; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPluginTest.java index 4e046c79f7..559e29f2d7 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/processors/ShowInstructionInfoPluginTest.java @@ -22,7 +22,8 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.*; +import javax.swing.JTable; +import javax.swing.JTextArea; import org.junit.*; @@ -150,6 +151,7 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati DockingActionIf infoAction = getAction(plugin, "Show Instruction Info"); // show the window performAction(infoAction, cb.getProvider(), true); + InstructionInfoProvider provider = waitForComponentProvider(InstructionInfoProvider.class); // make sure we are at an invalid Instruction ListingActionContext context = getCurrentContext(); @@ -176,14 +178,8 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati componentProviderTablesHaveData()); // verify dynamic update has changed the window's contents - ComponentProvider componentProvider = getCurrentComponentProviderFromPlugin(); - JComponent comp = componentProvider.getComponent(); - - final JCheckBox dynamicCheckBox = findComponent(comp, JCheckBox.class); // make sure dynamic update is enabled - if (!dynamicCheckBox.isSelected()) { - runSwing(() -> dynamicCheckBox.doClick()); - } + runSwing(() -> provider.setDynamic(true)); // change to another valid Instruction currentInstruction = changeLocationToAddress("01000006"); @@ -200,7 +196,7 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati verifyAddressWithTableModels(currentInstruction.getMinAddress(), true, true); // turn off dynamic update - runSwing(() -> dynamicCheckBox.doClick()); + runSwing(() -> provider.setDynamic(false)); // change to another valid Instruction currentInstruction = changeLocationToAddress("01000009"); @@ -223,7 +219,7 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati // place // turn dynamic update back on - runSwing(() -> dynamicCheckBox.doClick()); + runSwing(() -> provider.setDynamic(true)); // move to a valid location that has yet to be disassembled currentInstruction = changeLocationToAddress("01000ffe"); @@ -269,13 +265,9 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati DockingActionIf infoAction = getAction(plugin, "Show Instruction Info"); // show the window performAction(infoAction, cb.getProvider(), true); + InstructionInfoProvider provider = waitForComponentProvider(InstructionInfoProvider.class); - ComponentProvider componentProvider = getCurrentComponentProviderFromPlugin(); - JComponent comp = componentProvider.getComponent(); - - final JCheckBox dynamicCheckBox = findComponent(comp, JCheckBox.class); - // turn off the checkbox - runSwing(() -> dynamicCheckBox.setSelected(false)); + runSwing(() -> provider.setDynamic(false)); changeLocationToAddress("01000006"); performAction(infoAction, cb.getProvider(), true); @@ -352,7 +344,7 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati private void callGetUrl(ListingActionContext context, Language language) { runSwing(() -> { - + try { plugin.getValidUrl(context, language); } @@ -363,12 +355,10 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati } /** - * Moves the program location to the given address and returns the - * instruction at that location. + * Moves the program location to the given address and returns the instruction at that location. * * @param addressString The address location to move to. - * @return The instruction at the new location or null if there is no - * instruction. + * @return The instruction at the new location or null if there is no instruction. */ private Instruction changeLocationToAddress(String addressString) throws Exception { CodeBrowserPlugin cbp = env.getPlugin(CodeBrowserPlugin.class); @@ -395,18 +385,15 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati } /** - * Tests the addresses of the table models of the "Instruction Info" dialog. - * The method will fail the current test if the result is not as - * expected by the caller of this method. For example, if - * {@code expectedSame} is true, then the method expects the values to - * be the same when compared with the given address and will fail if - * they are not. If {@code expectedSame} is false, then the method will - * fail if the test values are the same. + * Tests the addresses of the table models of the "Instruction Info" dialog. The method will + * fail the current test if the result is not as expected by the caller of this method. For + * example, if {@code expectedSame} is true, then the method expects the values to be the same + * when compared with the given address and will fail if they are not. If {@code expectedSame} + * is false, then the method will fail if the test values are the same. * - * @param instructionAddress The address to compare against the address - * stored in the table model of the dialog. - * @param expectedSame True means a match is expected; false means a - * match is not expected. + * @param instructionAddress The address to compare against the address stored in the table + * model of the dialog. + * @param expectedSame True means a match is expected; false means a match is not expected. */ private void verifyAddressWithTableModels(Address instructionAddress, boolean fromConnected, boolean expectedSame) { @@ -447,8 +434,7 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati } /** - * A simple method to test that the tables of the "Instruction Info" - * dialog contain data. + * A simple method to test that the tables of the "Instruction Info" dialog contain data. * * @return True if either of the tables have data. */ @@ -459,9 +445,9 @@ public class ShowInstructionInfoPluginTest extends AbstractGhidraHeadedIntegrati } /** - * Gets data from the two tables of the "Instruction Info" dialog. + * Gets data from the two tables of the "Instruction Info" dialog. * - * @return data from the two tables of the "Instruction Info" dialog. + * @return data from the two tables of the "Instruction Info" dialog. */ private Object[] getComponentProviderTableData(boolean fromConnected) { ComponentProvider provider = fromConnected ? getCurrentComponentProviderFromPlugin() diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ShowInstructionInfoPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ShowInstructionInfoPluginScreenShots.java index ed26a0326e..db468bf58a 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ShowInstructionInfoPluginScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ShowInstructionInfoPluginScreenShots.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -112,7 +112,9 @@ public class ShowInstructionInfoPluginScreenShots extends GhidraScreenShotGenera performAction("Show Instruction Info", plugin.getName(), true); - captureProviderWindow("Instruction Info", 1200, 500); + ComponentProvider provider = + tool.getWindowManager().getComponentProvider("Instruction Info"); + captureIsolatedProvider(provider, 1200, 510); // finished("ShowInstructionInfoPlugin", "ShowInstructionInfo.png"); }