From f9f71fe57640285d0601234eeaaeb6f051f3ff08 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:17:58 -0400 Subject: [PATCH] GP-6692 - Added an option to limit the number of symbols displayed at an address --- .../topics/CodeBrowserPlugin/CodeBrowser.htm | 53 ++- .../CodeBrowserPlugin/CodeBrowserOptions.htm | 4 + .../help/topics/LabelMgrPlugin/Labels.htm | 10 +- .../symbol_table_transient.htm | 12 + .../app/plugin/core/label/LabelMgrPlugin.java | 15 +- .../plugin/core/label/OperandLabelDialog.java | 178 ------- .../core/label/SetOperandLabelAction.java | 19 +- .../core/label/SymbolChooserDialog.java | 192 ++++++++ .../core/symboltree/SymbolTreeProvider.java | 4 +- .../actions/CreateSymbolTableAction.java | 75 +-- .../actions/SetSymbolPrimaryAction.java | 86 ++++ .../symtable/AbstractSymbolTableModel.java | 164 +++++-- .../app/plugin/core/symtable/SymbolPanel.java | 14 +- .../core/symtable/SymbolTablePlugin.java | 190 +++++++- .../core/symtable/SymbolTableService.java | 33 ++ .../symtable/TransientSymbolTableModel.java | 12 +- .../viewer/field/LabelCodeUnitFormat.java | 11 +- .../util/viewer/field/LabelFieldFactory.java | 433 ++++++++---------- .../viewer/field/LabelFieldMouseHandler.java | 95 ++++ .../viewer/field/LabelFieldSymbolLoader.java | 223 +++++++++ .../viewer/field/XRefFieldMouseHandler.java | 2 +- .../program/model/listing/CodeUnitFormat.java | 20 +- .../core/label/OperandLabelDialogTest.java | 19 +- .../viewer/field/LabelFieldFactoryTest.java | 3 +- .../fieldpanel/support/FieldLocation.java | 7 + .../table/DynamicColumnTableModel.java | 21 +- .../java/docking/widgets/table/GTable.java | 33 +- .../ghidra/framework/cmd/CompoundCmd.java | 16 +- .../program/model/symbol/SymbolTable.java | 4 +- .../ghidra/program/util/CodeUnitLocation.java | 16 +- .../program/util/MoreLabelFieldLocation.java | 40 ++ .../screenshot/LabelMgrPluginScreenShots.java | 20 +- 32 files changed, 1424 insertions(+), 600 deletions(-) delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/OperandLabelDialog.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/SymbolChooserDialog.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/SetSymbolPrimaryAction.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableService.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldMouseHandler.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldSymbolLoader.java create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/MoreLabelFieldLocation.java diff --git a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowser.htm b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowser.htm index 6e98541b5d..9bbf7281f4 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowser.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowser.htm @@ -112,14 +112,18 @@ certain Navigation behaviors.
+ +++ + + +In the XRef field, sometimes there are too many addresses to display so the field will display "[more]" to indicate that one or more cross-reference addresses are not shown.
+ "green">XREF[n]: or [more]" + text will cause a dialog containing all the Xrefs to appear.
Double-clicking on the "XREF[n]: or [more]" text will cause a - dialog containing all the Xrefs to appear.
This differs from the @@ -178,6 +182,51 @@
+ + ++ + + + diff --git a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm index 4e0cecd1bd..c51a55f9e8 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm @@ -848,6 +848,10 @@ this off, the function name will only appear in the function signature. If it's on, the function name will also appear as a label below the function header. +In the Labels field, sometimes there are too many labels to display so the field will + display "[more]" to indicate that one or more labels are not shown.
+ +++ ++
Double-clicking on the + "[more]" text will cause a dialog containing all the + labels to appear.
Refresh +
+ +++ + ++ This action will refresh the table of labels. This table does not respond to + program changes, such as adding or deleting lables. Thus, if you would like + the table to update to the current state of the program, then you can press + the refresh button. +
+Delete Label +
+ +++ ++ This action will delete all selected labels from the database. This differs + from the + Remove Items action, which will simply remove items from the table. +
+
Maximum Number of Labels to Display - Sets the maximum number of labels to + display. If the max is reached, a '[more]' field will appear. You can double-click that + field to see all labels at that address.
+Display Non-local Namespace - Select this option to prepend the namespace to all labels that are not in the current Function's namespace. Currently, this would only affect a label that is not global, but is in a namespace other than the function that diff --git a/Ghidra/Features/Base/src/main/help/help/topics/LabelMgrPlugin/Labels.htm b/Ghidra/Features/Base/src/main/help/help/topics/LabelMgrPlugin/Labels.htm index afb0bfa9bd..e6dfaa6dd2 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/LabelMgrPlugin/Labels.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/LabelMgrPlugin/Labels.htm @@ -254,20 +254,12 @@ the address using the Set Label dialog.
-![]() |
-
@@ -60,6 +69,9 @@Label
-+The list in the combo box will show all symbols associated with the address shown in the +
The drop-down list will show all symbols associated with the address shown in the dialog title. Choosing a label from the list will cause that symbol to be associated with the operand reference being modified. Typing in a new name will cause a new symbol to be created at the target address before associating it with the operand reference.
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/SymbolTablePlugin/symbol_table_transient.htm b/Ghidra/Features/Base/src/main/help/help/topics/SymbolTablePlugin/symbol_table_transient.htm index bd5a6b7f8f..349be4903f 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/SymbolTablePlugin/symbol_table_transient.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/SymbolTablePlugin/symbol_table_transient.htm @@ -45,6 +45,15 @@Set Primary
+ ++++ Sets the selected symbol to be the primary symbol at the symbol's address. The primary + symbol is the symbol displayed by default for the 'from' side of an xref. +
+
AddLabelAction allows the user to add a label.
- */
class SetOperandLabelAction extends ListingContextAction {
private LabelMgrPlugin plugin;
private static final String[] POPUP_PATH = { "Set Associated Label..." };
private static final KeyStroke KEYBINDING =
- KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_MASK | InputEvent.ALT_MASK);
+ KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK);
- /**
- * Creates a new instance of the action.
- *
- * @param plugin Label Manager Plugin instance
- */
SetOperandLabelAction(LabelMgrPlugin plugin) {
super("Set Operand Label", plugin.getName());
@@ -59,13 +51,8 @@ class SetOperandLabelAction extends ListingContextAction {
plugin.isOnSymbol(context);
}
- /**
- * Method called when the action is invoked.
- * @param ActionEvent details regarding the invocation of this action
- */
@Override
public void actionPerformed(ListingActionContext context) {
plugin.setOperandLabelCallback(context);
}
-
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/SymbolChooserDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/SymbolChooserDialog.java
new file mode 100644
index 0000000000..18b2eb603d
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/SymbolChooserDialog.java
@@ -0,0 +1,192 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.label;
+
+import java.awt.BorderLayout;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.Document;
+
+import docking.DialogComponentProvider;
+import docking.DockingWindowManager;
+import docking.widgets.DefaultDropDownSelectionDataModel;
+import docking.widgets.DropDownSelectionTextField;
+import docking.widgets.DropDownTextFieldDataModel.SearchMode;
+import ghidra.app.cmd.label.AddLabelCmd;
+import ghidra.app.cmd.refs.AssociateSymbolCmd;
+import ghidra.app.context.ListingActionContext;
+import ghidra.framework.cmd.CompoundCmd;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Program;
+import ghidra.program.model.symbol.*;
+import ghidra.program.util.OperandFieldLocation;
+
+public class SymbolChooserDialog extends DialogComponentProvider {
+
+ private List
+ * The preference key is used to save the column state of this configurable model. All models
+ * that share a preference key will share the same visible column state.
+ * The {@link GTableColumnModel} manages this state for the framework. The column model will
+ * ask the table for its preference key, which will ask the model when not key has been set on
+ * the table. In the case that no key is set in the table or the model, a key will be created
+ * based on the classname and default columns.
+ *
+ * @return the preference key; the default value is null
+ */
+ public default String getPreferenceKey() {
+ return null;
+ }
+
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java
index 79d850ce8f..6b8ba7e24b 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java
@@ -15,10 +15,10 @@
*/
package docking.widgets.table;
-import static docking.DockingUtils.CONTROL_KEY_MODIFIER_MASK;
-import static docking.action.MenuData.NO_MNEMONIC;
-import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
-import static javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
+import static docking.DockingUtils.*;
+import static docking.action.MenuData.*;
+import static java.awt.event.InputEvent.*;
+import static javax.swing.ListSelectionModel.*;
import java.awt.*;
import java.awt.event.*;
@@ -636,7 +636,7 @@ public class GTable extends JTable {
}
/**
- * {@return the underlying ConfigurableColumnTableModel if one is in-use}
+ * {@return the underlying ConfigurableColumnTableModel if one is in use}
*/
public ConfigurableColumnTableModel getConfigurableColumnTableModel() {
TableModel model = getUnwrappedTableModel();
@@ -646,6 +646,17 @@ public class GTable extends JTable {
return null;
}
+ /**
+ * {@return the underlying DynamicColumnTableModel if one is in use}
+ */
+ public DynamicColumnTableModel> getDynamicTableModel() {
+ TableModel model = getUnwrappedTableModel();
+ if (model instanceof DynamicColumnTableModel>) {
+ return (DynamicColumnTableModel>) model;
+ }
+ return null;
+ }
+
/**
* Unrolls the current model by checking if the current model is inside of a wrapper table
* model.
@@ -912,7 +923,17 @@ public class GTable extends JTable {
* @see #setPreferenceKey(String)
*/
public String getPreferenceKey() {
- return preferenceKey;
+ if (preferenceKey != null) {
+ // prefer the key that has been set programmatically
+ return preferenceKey;
+ }
+
+ DynamicColumnTableModel> dynamicModel = getDynamicTableModel();
+ if (dynamicModel != null) {
+ return dynamicModel.getPreferenceKey();
+ }
+
+ return null;
}
/**
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/cmd/CompoundCmd.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/cmd/CompoundCmd.java
index 75eab940d9..61dbc61740 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/cmd/CompoundCmd.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/cmd/CompoundCmd.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,9 +15,9 @@
*/
package ghidra.framework.cmd;
-import ghidra.framework.model.DomainObject;
+import java.util.*;
-import java.util.ArrayList;
+import ghidra.framework.model.DomainObject;
/**
* Implementation for multiple commands that are done as a unit.
@@ -28,7 +28,7 @@ import java.util.ArrayList;
* @param
- * NOTE: All external symbols will be omiitted unless the full
+ * NOTE: All external symbols will be omitted unless the full
* {@link AddressSpace#EXTERNAL_SPACE} range is included within the specified address set
* or a null addressSet is specified. All global dynamic label symbols will be omitted.
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/CodeUnitLocation.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/CodeUnitLocation.java
index 3ae9ca4cae..242975d0ce 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/CodeUnitLocation.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/CodeUnitLocation.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.
@@ -36,8 +36,8 @@ public class CodeUnitLocation extends ProgramLocation {
* @param componentPath if this is not null it is the path to a data
* component inside of another data component
* @param row the row within the field.
- * @param col - the display item index on the given row. (Note most fields only have one display item per row)
- * @param charOffset - the character offset within the display item.
+ * @param col the display item index on the given row. (Note most fields only have one display item per row)
+ * @param charOffset the character offset within the display item.
*
*/
public CodeUnitLocation(Program program, Address addr, int[] componentPath, int row, int col,
@@ -53,8 +53,8 @@ public class CodeUnitLocation extends ProgramLocation {
* @param componentPath if this is not null it is the path to a data
* component inside of another data component
* @param row the row within the field.
- * @param col - the display item index on the given row. (Note most fields only have one display item per row)
- * @param charOffset - the character offset within the display item.
+ * @param col the display item index on the given row. (Note most fields only have one display item per row)
+ * @param charOffset the character offset within the display item.
*
*/
protected CodeUnitLocation(Program program, Address addr, Address byteAddr, int[] componentPath,
@@ -70,8 +70,8 @@ public class CodeUnitLocation extends ProgramLocation {
* @param program the program for obtaining the code unit
* @param addr address of the location; should not be null
* @param row the row within the field.
- * @param col - the display item index on the given row. (Note most fields only have one display item per row)
- * @param charOffset - the character offset within the display item.
+ * @param col the display item index on the given row. (Note most fields only have one display item per row)
+ * @param charOffset the character offset within the display item.
*
*/
public CodeUnitLocation(Program program, Address addr, int row, int col, int charOffset) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/MoreLabelFieldLocation.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/MoreLabelFieldLocation.java
new file mode 100644
index 0000000000..11a849456a
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/MoreLabelFieldLocation.java
@@ -0,0 +1,40 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.util;
+
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Program;
+
+/**
+ * Represents the '[more]' text used by the label field factory.
+ */
+public class MoreLabelFieldLocation extends CodeUnitLocation {
+
+ public static final String MORE_LABELS_STRING = "[more]";
+
+ public MoreLabelFieldLocation() {
+ // for serialization
+ }
+
+ public MoreLabelFieldLocation(Program p, Address addr, int row, int charOffset) {
+ super(p, addr, row, 0, charOffset);
+ }
+
+ @Override
+ public String toString() {
+ return MORE_LABELS_STRING;
+ }
+}
diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LabelMgrPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LabelMgrPluginScreenShots.java
index 69f5dc025e..d5fc118b32 100644
--- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LabelMgrPluginScreenShots.java
+++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LabelMgrPluginScreenShots.java
@@ -21,8 +21,8 @@ import javax.swing.*;
import org.junit.Test;
-import docking.widgets.combobox.GhidraComboBox;
-import ghidra.app.plugin.core.label.*;
+import ghidra.app.plugin.core.label.LabelHistoryDialog;
+import ghidra.app.plugin.core.label.LabelHistoryInputDialog;
import ghidra.app.util.*;
import ghidra.program.model.address.*;
import ghidra.program.model.symbol.LabelHistory;
@@ -85,22 +85,6 @@ public class LabelMgrPluginScreenShots extends GhidraScreenShotGenerator {
captureDialog();
}
- @Test
- public void testSetLabel() {
- LabelMgrPlugin plugin = getPlugin(tool, LabelMgrPlugin.class);
- final OperandLabelDialog dialog = new OperandLabelDialog(plugin);
- final GhidraComboBox> combo = (GhidraComboBox>) getInstanceField("myChoice", dialog);
- runSwing(new Runnable() {
- @Override
- public void run() {
- dialog.setTitle("Set Label at 004a671");
- combo.setSelectedItem("LAB_0040a671");
- }
- });
- showDialogWithoutBlocking(tool, dialog);
- captureDialog(350, 116);
- }
-
@Test
public void testShowLabelHistory() {
AddressSpace space = new GenericAddressSpace("Test", 32, AddressSpace.TYPE_RAM, 0);