From be3ea04c4bf6f66888800aaf5388b4cf6c4228ca Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:18:11 -0500 Subject: [PATCH] GP-6365 - Updated the Find References action so that it appears in tables that have addresses --- ...AbstractFindReferencesToAddressAction.java | 60 ++++++++++++++----- .../app/context/FunctionSupplierContext.java | 6 +- .../context/ProgramLocationActionContext.java | 15 +++-- .../ProgramLocationSupplierContext.java | 32 ++++++++++ .../context/ProgramSymbolActionContext.java | 17 +++++- .../plugin/core/bookmark/BookmarkPlugin.java | 2 +- .../core/bookmark/BookmarkProvider.java | 30 ++++++++-- .../FunctionWindowProvider.java | 28 ++++++--- .../FindReferencesToAddressAction.java | 15 ++--- .../core/strings/DefinedStringsContext.java | 13 +++- .../FindReferencesToAddressAction.java | 14 ++--- 11 files changed, 173 insertions(+), 59 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationSupplierContext.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/actions/AbstractFindReferencesToAddressAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/actions/AbstractFindReferencesToAddressAction.java index 57c50b4ee8..f3760bbc8d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/actions/AbstractFindReferencesToAddressAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/actions/AbstractFindReferencesToAddressAction.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,10 +15,14 @@ */ package ghidra.app.actions; +import docking.ActionContext; +import docking.action.DockingAction; import docking.action.KeyBindingType; import ghidra.app.context.NavigatableActionContext; -import ghidra.app.context.NavigatableContextAction; +import ghidra.app.context.ProgramLocationSupplierContext; +import ghidra.app.nav.Navigatable; import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService; +import ghidra.app.services.GoToService; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; @@ -33,7 +37,7 @@ import ghidra.util.Msg; * context for more information, potentially searching for more than just direct references to * the code unit at the current address. */ -public abstract class AbstractFindReferencesToAddressAction extends NavigatableContextAction { +public abstract class AbstractFindReferencesToAddressAction extends DockingAction { public static final String NAME = "Show References To Address"; private static final String HELP_TOPIC = "LocationReferencesPlugin"; @@ -44,12 +48,34 @@ public abstract class AbstractFindReferencesToAddressAction extends NavigatableC super(NAME, owner, KeyBindingType.SHARED); this.tool = tool; - setDescription("Shows references to the current Instruction or Data"); + setDescription("Shows references to the current address"); setHelpLocation(new HelpLocation(HELP_TOPIC, "Show_Refs_To_Code_Unit")); + + setContextClass(ProgramLocationSupplierContext.class, true); } @Override - public void actionPerformed(NavigatableActionContext context) { + public void actionPerformed(ActionContext context) { + ProgramLocationSupplierContext plc = (ProgramLocationSupplierContext) context; + Navigatable navigatable = null; + if (plc instanceof NavigatableActionContext nac) { + navigatable = nac.getNavigatable(); + } + else { + GoToService goToService = tool.getService(GoToService.class); + if (goToService == null) { + Msg.showError(this, null, "Missing Plugin", + "The " + GoToService.class.getSimpleName() + " is not installed.\n" + + "Please add the plugin implementing this service."); + return; + } + navigatable = goToService.getDefaultNavigatable(); + } + + showReferences(plc, navigatable); + } + + private void showReferences(ProgramLocationSupplierContext context, Navigatable navigatable) { LocationReferencesService service = tool.getService(LocationReferencesService.class); if (service == null) { @@ -59,8 +85,8 @@ public abstract class AbstractFindReferencesToAddressAction extends NavigatableC return; } - Program program = context.getProgram(); - ProgramLocation location = getLocation(context); + ProgramLocation location = context.getLocation(); + Program program = location.getProgram(); Address address = location.getAddress(); Listing listing = program.getListing(); CodeUnit cu = listing.getCodeUnitContaining(address); @@ -74,14 +100,19 @@ public abstract class AbstractFindReferencesToAddressAction extends NavigatableC AddressFieldLocation addressLocation = new AddressFieldLocation(program, address, path, address.toString(), 0); - service.showReferencesToLocation(addressLocation, context.getNavigatable()); + service.showReferencesToLocation(addressLocation, navigatable); } @Override - protected boolean isEnabledForContext(NavigatableActionContext context) { + public boolean isEnabledForContext(ActionContext context) { + ProgramLocationSupplierContext plc = (ProgramLocationSupplierContext) context; + if (plc instanceof NavigatableActionContext nac) { + if (!isMyNavigatable(nac)) { + return false; + } + } - Program program = context.getProgram(); - ProgramLocation location = getLocation(context); + ProgramLocation location = plc.getLocation(); if (location == null) { return false; } @@ -91,6 +122,7 @@ public abstract class AbstractFindReferencesToAddressAction extends NavigatableC return false; } + Program program = location.getProgram(); Listing listing = program.getListing(); CodeUnit cu = listing.getCodeUnitContaining(address); if (cu == null) { @@ -100,7 +132,5 @@ public abstract class AbstractFindReferencesToAddressAction extends NavigatableC return true; } - protected ProgramLocation getLocation(NavigatableActionContext context) { - return context.getLocation(); - } + protected abstract boolean isMyNavigatable(NavigatableActionContext context); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/context/FunctionSupplierContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/context/FunctionSupplierContext.java index 5e1c138a20..5863be7f55 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/context/FunctionSupplierContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/context/FunctionSupplierContext.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. @@ -23,7 +23,7 @@ import ghidra.program.model.listing.Function; /** * A "mix-in" interface that specific implementers of {@link ActionContext} may also implement if * they can supply functions in their action context. Actions that want to work on functions - * can look for this interface, which can used in a variety of contexts. + * can look for this interface, which can be used in a variety of contexts. */ public interface FunctionSupplierContext extends ActionContext { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java index dce04ed743..f0e5bb4a42 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java @@ -15,6 +15,7 @@ */ package ghidra.app.context; +import java.awt.Component; import java.util.HashSet; import java.util.Set; @@ -24,7 +25,7 @@ import ghidra.program.model.listing.*; import ghidra.program.util.*; public class ProgramLocationActionContext extends ProgramActionContext - implements FunctionSupplierContext { + implements FunctionSupplierContext, ProgramLocationSupplierContext { private final ProgramLocation location; private final ProgramSelection selection; @@ -41,9 +42,15 @@ public class ProgramLocationActionContext extends ProgramActionContext this.highlight = highlight; } - /** - * @return Returns the program location. - */ + public ProgramLocationActionContext(ComponentProvider provider, Program program, + Component sourceComponent, ProgramLocation location) { + super(provider, program, sourceComponent); + this.location = location; + this.selection = null; + this.highlight = null; + } + + @Override public ProgramLocation getLocation() { return location; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationSupplierContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationSupplierContext.java new file mode 100644 index 0000000000..2dc0441080 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationSupplierContext.java @@ -0,0 +1,32 @@ +/* ### + * 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.context; + +import docking.ActionContext; +import ghidra.program.util.ProgramLocation; + +/** + * A "mix-in" interface that specific implementers of {@link ActionContext} may also implement if + * they can supply a program location in their action context. Actions that want to work on + * locations can look for this interface, which can be used in a variety of contexts. + */ +public interface ProgramLocationSupplierContext extends ActionContext { + + /** + * {@return the program location} + */ + public ProgramLocation getLocation(); +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramSymbolActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramSymbolActionContext.java index 4c7a776b2a..9c82b16f88 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramSymbolActionContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramSymbolActionContext.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. @@ -21,8 +21,10 @@ import java.util.*; import docking.ComponentProvider; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; +import ghidra.program.util.ProgramLocation; -public class ProgramSymbolActionContext extends ProgramActionContext { +public class ProgramSymbolActionContext extends ProgramActionContext + implements ProgramLocationSupplierContext { private List symbols = new ArrayList(); @@ -46,4 +48,13 @@ public class ProgramSymbolActionContext extends ProgramActionContext { public Iterable getSymbols() { return symbols; } + + @Override + public ProgramLocation getLocation() { + if (symbols.isEmpty()) { + return null; + } + Symbol s = symbols.get(0); + return s.getProgramLocation(); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java index 8484023cfa..4ff5125375 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java @@ -182,7 +182,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider DockingAction selectionAction = new DockingAction("Select Bookmark Locations", getName()) { @Override public void actionPerformed(ActionContext context) { - select(provider.getBookmarkLocations()); + select(provider.getBookmarkSelection()); } }; icon = new GIcon("icon.plugin.bookmark.select"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java index 67782a3fa6..1762179bf0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.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. @@ -30,13 +30,16 @@ import docking.action.KeyBindingData; import docking.widgets.combobox.GhidraComboBox; import docking.widgets.table.GTable; import ghidra.app.context.ProgramActionContext; +import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.services.GoToService; import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.model.DomainObject; import ghidra.framework.options.SaveState; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; +import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; import ghidra.util.table.*; @@ -106,7 +109,26 @@ public class BookmarkProvider extends ComponentProviderAdapter { if (program == null) { return null; } - return new ProgramActionContext(this, program, bookmarkTable); + + ProgramLocation location = getBookmarkLocation(); + return new ProgramLocationActionContext(this, program, bookmarkTable, location); + } + + private ProgramLocation getBookmarkLocation() { + int row = bookmarkTable.getSelectedRow(); + if (row < 0) { + return null; + } + + BookmarkRowObject rowObject = model.getRowObject(row); + if (rowObject == null) { + return null; // this can happen when closing + } + + BookmarkManager manager = program.getBookmarkManager(); + Bookmark bookmark = manager.getBookmark(rowObject.getKey()); + Address address = bookmark.getAddress(); + return new ProgramLocation(program, address); } void setGoToService(GoToService goToService) { @@ -339,7 +361,7 @@ public class BookmarkProvider extends ComponentProviderAdapter { } } - ProgramSelection getBookmarkLocations() { + ProgramSelection getBookmarkSelection() { return bookmarkTable.getProgramSelection(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java index 85f8a35f51..d81c440e4d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.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. @@ -29,10 +29,13 @@ import docking.action.DockingAction; import docking.action.builder.ActionBuilder; import generic.theme.GIcon; import ghidra.app.context.FunctionSupplierContext; +import ghidra.app.context.ProgramLocationSupplierContext; import ghidra.app.services.FunctionComparisonService; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.util.ProgramLocation; import ghidra.util.HelpLocation; import ghidra.util.table.*; import ghidra.util.table.actions.MakeProgramSelectionAction; @@ -258,24 +261,18 @@ public class FunctionWindowProvider extends ComponentProviderAdapter { return functionModel; } - /** - * @see docking.ComponentProvider#getWindowSubMenuName() - */ @Override public String getWindowSubMenuName() { return null; } - /** - * @see docking.ComponentProvider#isTransient() - */ @Override public boolean isTransient() { return false; } private class FunctionWindowActionContext extends DefaultActionContext - implements FunctionSupplierContext { + implements FunctionSupplierContext, ProgramLocationSupplierContext { FunctionWindowActionContext() { super(FunctionWindowProvider.this, functionTable); @@ -300,5 +297,18 @@ public class FunctionWindowProvider extends ComponentProviderAdapter { } return functions; } + + @Override + public ProgramLocation getLocation() { + int row = functionTable.getSelectedRow(); + if (row < 0) { + return null; + } + + FunctionRowObject rowObject = functionModel.getRowObject(row); + Function f = rowObject.getFunction(); + Symbol s = f.getSymbol(); + return s.getProgramLocation(); + } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/FindReferencesToAddressAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/FindReferencesToAddressAction.java index 11001dfb5c..cd01e611a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/FindReferencesToAddressAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/FindReferencesToAddressAction.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,12 +36,9 @@ public class FindReferencesToAddressAction extends AbstractFindReferencesToAddre } @Override - public boolean isEnabledForContext(NavigatableActionContext context) { - if (!(context instanceof ListingActionContext)) { - // Restrict this action to the Listing. We have guilty knowledge that there are - // other sibling classes to this one for other contexts. - return false; - } - return super.isEnabledForContext(context); + protected boolean isMyNavigatable(NavigatableActionContext context) { + // Restrict this action to the Listing. We have guilty knowledge that there are + // other sibling classes to this one for other contexts. + return context instanceof ListingActionContext; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/DefinedStringsContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/DefinedStringsContext.java index ca9b6d2094..9da26ec364 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/DefinedStringsContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/DefinedStringsContext.java @@ -21,6 +21,7 @@ import java.util.function.Predicate; import docking.DefaultActionContext; import ghidra.app.context.DataLocationListContext; +import ghidra.app.context.ProgramLocationSupplierContext; import ghidra.program.model.data.DataUtilities; import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Program; @@ -28,7 +29,8 @@ import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.table.GhidraTable; -public class DefinedStringsContext extends DefaultActionContext implements DataLocationListContext { +public class DefinedStringsContext extends DefaultActionContext implements DataLocationListContext, + ProgramLocationSupplierContext { private final DefinedStringsProvider viewStringsProvider; private final GhidraTable table; @@ -52,6 +54,15 @@ public class DefinedStringsContext extends DefaultActionContext implements DataL return viewStringsProvider.getProgram(); } + @Override + public ProgramLocation getLocation() { + int row = table.getSelectedRow(); + if (row < 0) { + return null; + } + return tableModel.getRowObject(row); + } + @Override public List getDataLocationList() { return getDataLocationList(null); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindReferencesToAddressAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindReferencesToAddressAction.java index 9c54ad4569..0610039a74 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindReferencesToAddressAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindReferencesToAddressAction.java @@ -24,7 +24,6 @@ import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesSe import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; -import ghidra.program.util.ProgramLocation; import ghidra.util.HelpLocation; /** @@ -40,21 +39,16 @@ public class FindReferencesToAddressAction extends AbstractFindReferencesToAddre } @Override - protected ProgramLocation getLocation(NavigatableActionContext context) { - if (!(context instanceof DecompilerActionContext)) { - return null; - } - return context.getLocation(); + protected boolean isMyNavigatable(NavigatableActionContext context) { + return context instanceof DecompilerActionContext; } @Override public boolean isEnabledForContext(ActionContext context) { - if (!(context instanceof DecompilerActionContext)) { + if (!(context instanceof DecompilerActionContext dac)) { return false; } - - DecompilerActionContext decompilerContext = (DecompilerActionContext) context; - updateMenuName(decompilerContext.getAddress()); + updateMenuName(dac.getAddress()); return super.isEnabledForContext(context); }