mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-2140 - Xrefs - Added an action to delete xrefs from the xrefs table
This commit is contained in:
parent
e804e1a01d
commit
1fc7356080
35 changed files with 1032 additions and 278 deletions
|
@ -133,6 +133,19 @@
|
||||||
and a preview of the instruction at that address. Clicking on any row in the table will cause
|
and a preview of the instruction at that address. Clicking on any row in the table will cause
|
||||||
the browser to navigate to that address</P>
|
the browser to navigate to that address</P>
|
||||||
|
|
||||||
|
<H3><A NAME="Refresh"></A>Refresh
|
||||||
|
<IMG border="0" src="Icons.REFRESH_ICON" alt=""></H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
This action will refresh the table of references. This button will appear disabled
|
||||||
|
when the data is not stale. However, if Ghidra detects that the data <I>may</I> be
|
||||||
|
stale, then the button will become color filled, as it is here. You may push the
|
||||||
|
button for a refresh in either state.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
<H3><A NAME="Show_Thunk_Xrefs"></A>Show Thunk Xrefs
|
<H3><A NAME="Show_Thunk_Xrefs"></A>Show Thunk Xrefs
|
||||||
<IMG border="0" src="images/ThunkFunction.gif" alt=""></H3>
|
<IMG border="0" src="images/ThunkFunction.gif" alt=""></H3>
|
||||||
|
|
||||||
|
@ -148,6 +161,17 @@
|
||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3><A NAME="Delete_Reference"></A>Delete Reference
|
||||||
|
<IMG border="0" src="Icons.DELETE_ICON" alt=""></H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
This action will delete all selected references from the database. This differs
|
||||||
|
from the <A HREF="help/topics/Search/Query_Results_Dialog.htm#Remove_Items">Remove Items
|
||||||
|
</A> action, which will simply remove items from the table.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H2><A NAME="Keyboard_Controls">Keyboard Controls</H2>
|
<H2><A NAME="Keyboard_Controls">Keyboard Controls</H2>
|
||||||
|
|
|
@ -126,12 +126,6 @@
|
||||||
table. You may also access this feature by right-clicking an item in the table and
|
table. You may also access this feature by right-clicking an item in the table and
|
||||||
selecting <B>Make Selection</B>.</P>
|
selecting <B>Make Selection</B>.</P>
|
||||||
|
|
||||||
<P align="left"><A name="Highlight"></A>The <IMG alt="" src="images/tag_yellow.png">
|
|
||||||
button toggles the highlighting of the matching references. In this case, the
|
|
||||||
term highlight refers to the background color of the item in the Listing and not
|
|
||||||
a <A HREF="help/topics/SetHighlightPlugin/Highlighting.htm">Program Selection
|
|
||||||
Highlight</A>.
|
|
||||||
</P>
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>
|
<P>
|
||||||
<IMG alt="" src="help/shared/tip.png">
|
<IMG alt="" src="help/shared/tip.png">
|
||||||
|
@ -145,6 +139,26 @@
|
||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P align="left"><A name="Highlight"></A>The <IMG alt="" src="images/tag_yellow.png">
|
||||||
|
button toggles the highlighting of the matching references. In this case, the
|
||||||
|
term highlight refers to the background color of the item in the Listing and not
|
||||||
|
a <A HREF="help/topics/SetHighlightPlugin/Highlighting.htm">Program Selection
|
||||||
|
Highlight</A>.
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<P align="left"><A name="Delete_Reference"></A>The <IMG alt="" src="Icons.DELETE_ICON">
|
||||||
|
button deletes the selected reference(s). This will delete the reference from the database.
|
||||||
|
</P>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
<IMG alt="" src="help/shared/note.yellow.png">Not all table rows can be deleted. This is
|
||||||
|
because the table shows not just items that have a database reference, but also items
|
||||||
|
that are dynamic references, as well as general uses of an item, such as a data access
|
||||||
|
generated by the Decompiler. The delete action will only allow you to delete references
|
||||||
|
that are in the database.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Search Results</H3>
|
<H3>Search Results</H3>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 17 KiB |
|
@ -164,10 +164,22 @@
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H4><B>Provided by:</B> <I>Symbol Table</I> plugin</H4>
|
|
||||||
|
|
||||||
<P><BR>
|
<H2><A name="Delete_Reference"></A>Delete Reference<IMG src="Icons.DELETE_ICON"></H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>This action will delete all selected references from the database.
|
||||||
</P>
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P>
|
||||||
<BR>
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<P class="providedbyplugin">Provided by: <I>Symbol Table Plugin</I></P>
|
||||||
|
<P class="relatedtopic">Related Topics</P>
|
||||||
|
<UL>
|
||||||
|
<LI><A href="help/topics/SymbolTablePlugin/symbol_table.htm">Symbol Table</A></LI>
|
||||||
|
</UL>
|
||||||
|
|
||||||
</BODY>
|
</BODY>
|
||||||
</HTML>
|
</HTML>
|
||||||
|
|
|
@ -164,6 +164,41 @@
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
<H2><A name="Make_Selection"></A>Making a Selection <IMG src="Icons.MAKE_SELECTION_ICON"></H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>You can make a selection that corresponds to the symbol addresses that are selected in the
|
||||||
|
<I>Symbol Table</I>.</P>
|
||||||
|
|
||||||
|
<P>To make a selection:</P>
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Select the symbols in the Symbol Table (hold the <Ctrl> key down to add to the
|
||||||
|
selection) to be added to the selection.</LI>
|
||||||
|
|
||||||
|
<LI>
|
||||||
|
Right-mouse-click and select "Make Selection" from the popup menu.
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI>Or, click the <IMG src="Icons.MAKE_SELECTION_ICON"> button in the <I>Symbol
|
||||||
|
Table</I> toolbar.</LI>
|
||||||
|
</UL>
|
||||||
|
</LI>
|
||||||
|
</OL>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
<H2><A name="Navigate_on_Incoming_Location_Changes"></A>
|
||||||
|
Making a Selection <IMG src="Icons.MAKE_SELECTION_ICON"></H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>When selected, the Symbol Table will select the row in the table that corresponds to the
|
||||||
|
symbol selected in the <A href="help/topics/CodeBrowserPlugin/CodeBrowser.htm">Listing</A>.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
<H2>Renaming a Symbol</H2>
|
<H2>Renaming a Symbol</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
|
@ -199,29 +234,6 @@
|
||||||
for more discussion on the use of the edit dialog).
|
for more discussion on the use of the edit dialog).
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H2><A name="Make_Selection"></A>Making a Selection <IMG src="Icons.MAKE_SELECTION_ICON"></H2>
|
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
|
||||||
<P>You can make a selection that corresponds to the symbol addresses that are selected in the
|
|
||||||
<I>Symbol Table</I>.</P>
|
|
||||||
|
|
||||||
<P>To make a selection:</P>
|
|
||||||
|
|
||||||
<OL>
|
|
||||||
<LI>Select the symbols in the Symbol Table (hold the <Ctrl> key down to add to the
|
|
||||||
selection) to be added to the selection.</LI>
|
|
||||||
|
|
||||||
<LI>
|
|
||||||
Right-mouse-click and select "Make Selection" from the popup menu.
|
|
||||||
|
|
||||||
<UL>
|
|
||||||
<LI>Or, click the <IMG src="Icons.MAKE_SELECTION_ICON"> button in the <I>Symbol
|
|
||||||
Table</I> toolbar.</LI>
|
|
||||||
</UL>
|
|
||||||
</LI>
|
|
||||||
</OL>
|
|
||||||
</BLOCKQUOTE>
|
|
||||||
|
|
||||||
<H2><A name="Pinning a Symbol"></A>Pinning a Symbol</H2>
|
<H2><A name="Pinning a Symbol"></A>Pinning a Symbol</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
|
@ -250,18 +262,16 @@
|
||||||
</LI>
|
</LI>
|
||||||
</OL>
|
</OL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
<H2><A name="Set_Filter"></A>Filtering <IMG src="images/view-filter.png"></H2>
|
<H2><A name="Set_Filter"></A>Filtering</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The list of displayed symbols is determined by the current symbol table settings. These
|
<P>The list of displayed symbols is determined by the current symbol table settings. These
|
||||||
settings can be adjusted by clicking the <I>Filter</I> <IMG src="images/view-filter.png">
|
settings can be adjusted by clicking the <I>Filter</I> <IMG src="Icons.CONFIGURE_FILTER_ICON">
|
||||||
button in the toolbar of the <I>Symbol Table</I> window or from the right-mouse popup menu..
|
button in the toolbar of the <I>Symbol Table</I> window or from the right-mouse popup menu..
|
||||||
The displayed symbols will correspond to the selected checkboxes in the <I>Symbol Table
|
The displayed symbols will correspond to the selected checkboxes in the <I>Symbol Table
|
||||||
Filter</I> dialog.</P>
|
Filter</I> dialog.</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<P align="center"><IMG src="images/view-filter.png"></P>
|
|
||||||
|
|
||||||
<P align="center"><I>Symbol Table Filter</I> Dialog</P>
|
<P align="center"><I>Symbol Table Filter</I> Dialog</P>
|
||||||
|
|
||||||
<P align="center"><IMG src="images/Filter.png"></P>
|
<P align="center"><IMG src="images/Filter.png"></P>
|
||||||
|
@ -606,7 +616,6 @@
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<P class="providedbyplugin">Provided by: <I>Symbol Table Plugin</I></P>
|
<P class="providedbyplugin">Provided by: <I>Symbol Table Plugin</I></P>
|
||||||
|
|
||||||
<P class="relatedtopic">Related Topics</P>
|
<P class="relatedtopic">Related Topics</P>
|
||||||
|
|
||||||
<UL>
|
<UL>
|
||||||
|
|
|
@ -454,7 +454,9 @@ public class CallTreeProvider extends ComponentProviderAdapter {
|
||||||
// navigate incoming nodes on selection
|
// navigate incoming nodes on selection
|
||||||
//
|
//
|
||||||
navigateIncomingAction =
|
navigateIncomingAction =
|
||||||
new ToggleDockingAction("Navigation Incoming Location Changes", plugin.getName()) {
|
new ToggleDockingAction("Navigation Incoming Location Changes", plugin.getName(),
|
||||||
|
KeyBindingType.SHARED) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
// handled later as we receive events
|
// handled later as we receive events
|
||||||
|
|
|
@ -336,9 +336,11 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
||||||
action.getToolBarData().setToolBarGroup("B"); // the other actions are in group 'A'
|
action.getToolBarData().setToolBarGroup("B"); // the other actions are in group 'A'
|
||||||
tool.addLocalAction(this, action);
|
tool.addLocalAction(this, action);
|
||||||
|
|
||||||
toggleNavigateAction = new ToggleActionBuilder("Memory Map Navigation", plugin.getName())
|
toggleNavigateAction =
|
||||||
|
new ToggleActionBuilder("Navigate on Incoming Location Changes", plugin.getName())
|
||||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
||||||
.selected(false)
|
.selected(false)
|
||||||
|
.sharedKeyBinding()
|
||||||
.helpLocation(new HelpLocation("MemoryMapPlugin", "Navigation"))
|
.helpLocation(new HelpLocation("MemoryMapPlugin", "Navigation"))
|
||||||
.description(HTMLUtilities.toHTML("Toggle <b>on</b> means to select the block" +
|
.description(HTMLUtilities.toHTML("Toggle <b>on</b> means to select the block" +
|
||||||
" that contains the current location"))
|
" that contains the current location"))
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static ghidra.app.plugin.core.navigation.locationreferences.LocationRefer
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.symbol.DynamicReference;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
|
||||||
|
@ -36,6 +37,11 @@ public class LocationReference implements Comparable<LocationReference> {
|
||||||
private final LocationReferenceContext context;
|
private final LocationReferenceContext context;
|
||||||
private final ProgramLocation location;
|
private final ProgramLocation location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional reference object. Some clients do not have actual references.
|
||||||
|
*/
|
||||||
|
private Reference reference;
|
||||||
|
|
||||||
private int hashCode = -1;
|
private int hashCode = -1;
|
||||||
|
|
||||||
private static String getRefType(Reference r) {
|
private static String getRefType(Reference r) {
|
||||||
|
@ -57,6 +63,7 @@ public class LocationReference implements Comparable<LocationReference> {
|
||||||
LocationReference(Reference reference, boolean isOffcutReference) {
|
LocationReference(Reference reference, boolean isOffcutReference) {
|
||||||
this(reference.getFromAddress(), null, getRefType(reference), EMPTY_CONTEXT,
|
this(reference.getFromAddress(), null, getRefType(reference), EMPTY_CONTEXT,
|
||||||
isOffcutReference);
|
isOffcutReference);
|
||||||
|
this.reference = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationReference(Address locationOfUseAddress, String refType, boolean isOffcutReference) {
|
LocationReference(Address locationOfUseAddress, String refType, boolean isOffcutReference) {
|
||||||
|
@ -133,6 +140,28 @@ public class LocationReference implements Comparable<LocationReference> {
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reference that this class is using. This may be null if there is no database
|
||||||
|
* reference associated with this object.
|
||||||
|
* @return the reference; may be null
|
||||||
|
*/
|
||||||
|
public Reference getReference() {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this class has a {@link Reference} and that reference is not dynamic (i.e.,
|
||||||
|
* the reference exists in the database).
|
||||||
|
*
|
||||||
|
* @return true if this class has a removable reference
|
||||||
|
*/
|
||||||
|
public boolean isDeletable() {
|
||||||
|
if (reference == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !(reference instanceof DynamicReference);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
if (hashCode != -1) {
|
if (hashCode != -1) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.navigation.locationreferences;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
|
@ -88,6 +88,26 @@ public class LocationReferencesPanel extends JPanel {
|
||||||
tableModel.fullReload();
|
tableModel.fullReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isBusy() {
|
||||||
|
return tableModel.isBusy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(List<LocationReference> refs) {
|
||||||
|
for (LocationReference lr : refs) {
|
||||||
|
tableModel.removeObject(lr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LocationReference> getSelectedReferences() {
|
||||||
|
List<LocationReference> list = new ArrayList<>();
|
||||||
|
int[] rows = table.getSelectedRows();
|
||||||
|
for (int row : rows) {
|
||||||
|
LocationReference lr = tableModel.getRowObject(row);
|
||||||
|
list.add(lr);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
void addTableModelListener(TableModelListener listener) {
|
void addTableModelListener(TableModelListener listener) {
|
||||||
tableModel.addTableModelListener(listener);
|
tableModel.addTableModelListener(listener);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.app.plugin.core.navigation.locationreferences;
|
package ghidra.app.plugin.core.navigation.locationreferences;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
|
@ -133,7 +134,7 @@ public class LocationReferencesPlugin extends Plugin
|
||||||
return; // not sure if this can happen
|
return; // not sure if this can happen
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Reference> refs = XReferenceUtils.getAllXrefs(location);
|
Supplier<Collection<Reference>> refs = () -> XReferenceUtils.getAllXrefs(location);
|
||||||
XReferenceUtils.showXrefs(lac.getNavigatable(), tool, service, location, refs);
|
XReferenceUtils.showXrefs(lac.getNavigatable(), tool, service, location, refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,18 +18,21 @@ package ghidra.app.plugin.core.navigation.locationreferences;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.DefaultActionContext;
|
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.action.builder.ActionBuilder;
|
||||||
import docking.widgets.table.GTable;
|
import docking.widgets.table.GTable;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
import ghidra.app.nav.Navigatable;
|
import ghidra.app.nav.Navigatable;
|
||||||
import ghidra.app.nav.NavigatableRemovalListener;
|
import ghidra.app.nav.NavigatableRemovalListener;
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
|
import ghidra.framework.cmd.CompoundCmd;
|
||||||
import ghidra.framework.model.DomainObjectChangedEvent;
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
import ghidra.framework.model.DomainObjectListener;
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
|
@ -37,6 +40,7 @@ import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
|
@ -97,8 +101,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
program.addListener(this);
|
program.addListener(this);
|
||||||
|
|
||||||
setTitle(TITLE_PREFIX_REFERENCES);
|
setTitle(TITLE_PREFIX_REFERENCES);
|
||||||
setHelpLocation(
|
setHelpLocation(new HelpLocation(getOwner(), "LocationReferencesPlugin"));
|
||||||
new HelpLocation(locationReferencesPlugin.getName(), "LocationReferencesPlugin"));
|
|
||||||
setWindowMenuGroup("References");
|
setWindowMenuGroup("References");
|
||||||
setTransient();
|
setTransient();
|
||||||
createView();
|
createView();
|
||||||
|
@ -235,7 +238,8 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
|
||||||
homeAction = new DockingAction("Home", locationReferencesPlugin.getName()) {
|
String toolbarGroup = "A";
|
||||||
|
homeAction = new DockingAction("Home", getOwner()) {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
goTo(currentLocationDescriptor.getHomeLocation(),
|
goTo(currentLocationDescriptor.getHomeLocation(),
|
||||||
|
@ -243,7 +247,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
homeAction.setToolBarData(new ToolBarData(HOME_ICON));
|
homeAction.setToolBarData(new ToolBarData(HOME_ICON, toolbarGroup));
|
||||||
updateHomeActionState();
|
updateHomeActionState();
|
||||||
|
|
||||||
selectionAction =
|
selectionAction =
|
||||||
|
@ -256,17 +260,17 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
highlightAction.setToolBarData(new ToolBarData(HIGHLIGHT_ICON));
|
highlightAction.setToolBarData(new ToolBarData(HIGHLIGHT_ICON, toolbarGroup));
|
||||||
highlightAction.setSelected(true);
|
highlightAction.setSelected(true);
|
||||||
highlightAction.setDescription("Highlight matches in tool");
|
highlightAction.setDescription("Highlight matches in tool");
|
||||||
|
|
||||||
refreshAction = new DockingAction("Refresh", locationReferencesPlugin.getName()) {
|
refreshAction = new DockingAction("Refresh", getOwner()) {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
updateManager.updateNow();
|
updateManager.updateNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
refreshAction.setToolBarData(new ToolBarData(REFRESH_NOT_NEEDED_ICON));
|
refreshAction.setToolBarData(new ToolBarData(REFRESH_NOT_NEEDED_ICON, toolbarGroup));
|
||||||
refreshAction.setDescription(
|
refreshAction.setDescription(
|
||||||
"<html>Push at any time to refresh the current table of references.<br>" +
|
"<html>Push at any time to refresh the current table of references.<br>" +
|
||||||
"This button is highlighted when the data <i>may</i> be stale.<br>");
|
"This button is highlighted when the data <i>may</i> be stale.<br>");
|
||||||
|
@ -274,6 +278,31 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
SelectionNavigationAction selectionNavigationAction =
|
SelectionNavigationAction selectionNavigationAction =
|
||||||
new SelectionNavigationAction(locationReferencesPlugin, referencesPanel.getTable());
|
new SelectionNavigationAction(locationReferencesPlugin, referencesPanel.getTable());
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
String actionName = "Delete Reference";
|
||||||
|
DockingAction deleteRefAction = new ActionBuilder(actionName, getOwner())
|
||||||
|
.sharedKeyBinding()
|
||||||
|
.toolBarIcon(Icons.DELETE_ICON)
|
||||||
|
.toolBarGroup(toolbarGroup)
|
||||||
|
.enabledWhen(c -> {
|
||||||
|
if (!(c instanceof LocationReferencesProviderContext lrContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (referencesPanel.isBusy()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<LocationReference> refs = lrContext.getDeletableReferences();
|
||||||
|
return !refs.isEmpty();
|
||||||
|
})
|
||||||
|
.onAction(c -> {
|
||||||
|
LocationReferencesProviderContext lrContext = (LocationReferencesProviderContext) c;
|
||||||
|
List<LocationReference> refs = lrContext.getDeletableReferences();
|
||||||
|
deleteRows(refs);
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
GhidraTable table = referencesPanel.getTable();
|
GhidraTable table = referencesPanel.getTable();
|
||||||
DockingAction removeItemsAction = new DeleteAction(tool, table);
|
DockingAction removeItemsAction = new DeleteAction(tool, table);
|
||||||
removeItemsAction.setEnabled(false); // off by default; updated when the user clicks the table
|
removeItemsAction.setEnabled(false); // off by default; updated when the user clicks the table
|
||||||
|
@ -281,12 +310,27 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
tool.addLocalAction(this, refreshAction);
|
tool.addLocalAction(this, refreshAction);
|
||||||
tool.addLocalAction(this, selectionAction);
|
tool.addLocalAction(this, selectionAction);
|
||||||
tool.addLocalAction(this, highlightAction);
|
tool.addLocalAction(this, highlightAction);
|
||||||
|
tool.addLocalAction(this, deleteRefAction);
|
||||||
tool.addLocalAction(this, removeItemsAction);
|
tool.addLocalAction(this, removeItemsAction);
|
||||||
tool.addLocalAction(this, selectionNavigationAction);
|
tool.addLocalAction(this, selectionNavigationAction);
|
||||||
|
|
||||||
setHelpLocation();
|
setHelpLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deleteRows(List<LocationReference> refs) {
|
||||||
|
|
||||||
|
CompoundCmd<Program> compoundCmd = new CompoundCmd<>("Delete References");
|
||||||
|
for (LocationReference lr : refs) {
|
||||||
|
Reference ref = lr.getReference();
|
||||||
|
RemoveReferenceCmd cmd = new RemoveReferenceCmd(ref);
|
||||||
|
compoundCmd.add(cmd);
|
||||||
|
}
|
||||||
|
tool.execute(compoundCmd, program);
|
||||||
|
|
||||||
|
// also remove the object from the table, since they have been deleted
|
||||||
|
referencesPanel.remove(refs);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateHomeActionState() {
|
private void updateHomeActionState() {
|
||||||
// we have no home location sometimes, like when launched from the service interface when
|
// we have no home location sometimes, like when launched from the service interface when
|
||||||
// looking for references to datatypes
|
// looking for references to datatypes
|
||||||
|
@ -300,13 +344,10 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setHelpLocation() {
|
private void setHelpLocation() {
|
||||||
homeAction.setHelpLocation(new HelpLocation(locationReferencesPlugin.getName(), "Home"));
|
homeAction.setHelpLocation(new HelpLocation(getOwner(), "Home"));
|
||||||
refreshAction.setHelpLocation(
|
refreshAction.setHelpLocation(new HelpLocation(getOwner(), "Refresh"));
|
||||||
new HelpLocation(locationReferencesPlugin.getName(), "Refresh"));
|
selectionAction.setHelpLocation(new HelpLocation(getOwner(), "Select"));
|
||||||
selectionAction.setHelpLocation(
|
highlightAction.setHelpLocation(new HelpLocation(getOwner(), "Highlight"));
|
||||||
new HelpLocation(locationReferencesPlugin.getName(), "Select"));
|
|
||||||
highlightAction.setHelpLocation(
|
|
||||||
new HelpLocation(locationReferencesPlugin.getName(), "Highlight"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void goTo(ProgramLocation loc, Program theProgram) {
|
private void goTo(ProgramLocation loc, Program theProgram) {
|
||||||
|
@ -318,7 +359,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
final JTable table = referencesPanel.getTable();
|
final JTable table = referencesPanel.getTable();
|
||||||
table.getSelectionModel().addListSelectionListener(e -> {
|
table.getSelectionModel().addListSelectionListener(e -> {
|
||||||
if (!e.getValueIsAdjusting()) {
|
if (!e.getValueIsAdjusting()) {
|
||||||
selectionAction.setEnabled(table.getSelectedRowCount() > 0);
|
contextChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -361,6 +402,15 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
Program getProgram() {
|
Program getProgram() {
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GTable getTable() {
|
||||||
|
return referencesPanel.getTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationReferencesPanel getPanel() {
|
||||||
|
return referencesPanel;
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Interface methods
|
// Interface methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -403,7 +453,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionContext getActionContext(MouseEvent event) {
|
public ActionContext getActionContext(MouseEvent event) {
|
||||||
return new DefaultActionContext(this, referencesPanel.getTable());
|
return new LocationReferencesProviderContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -413,7 +463,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
private class DeleteAction extends DeleteTableRowAction {
|
private class DeleteAction extends DeleteTableRowAction {
|
||||||
|
|
||||||
DeleteAction(PluginTool tool, GTable table) {
|
DeleteAction(PluginTool tool, GTable table) {
|
||||||
super(table, locationReferencesPlugin.getName());
|
super(table, LocationReferencesProvider.this.getOwner());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* ###
|
||||||
|
* 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.navigation.locationreferences;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.DefaultActionContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ActionContext} for the {@link LocationReferencesProvider}.
|
||||||
|
*/
|
||||||
|
public class LocationReferencesProviderContext extends DefaultActionContext {
|
||||||
|
|
||||||
|
private LocationReferencesProvider locationProvider;
|
||||||
|
private List<LocationReference> selectedReferences;
|
||||||
|
|
||||||
|
public LocationReferencesProviderContext(LocationReferencesProvider provider) {
|
||||||
|
super(provider, provider.getTable());
|
||||||
|
this.locationProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LocationReference> getSelectedReferences() {
|
||||||
|
if (selectedReferences == null) {
|
||||||
|
LocationReferencesPanel panel = locationProvider.getPanel();
|
||||||
|
selectedReferences = panel.getSelectedReferences();
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LocationReference> getDeletableReferences() {
|
||||||
|
List<LocationReference> results = new ArrayList<>();
|
||||||
|
List<LocationReference> refs = getSelectedReferences();
|
||||||
|
for (LocationReference lr : refs) {
|
||||||
|
if (lr.isDeletable()) {
|
||||||
|
results.add(lr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1395,7 +1395,7 @@ public final class ReferenceUtils {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address[] thunkAddrs = func.getFunctionThunkAddresses();
|
Address[] thunkAddrs = func.getFunctionThunkAddresses(false);
|
||||||
if (thunkAddrs == null) {
|
if (thunkAddrs == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
package ghidra.app.plugin.core.symtable;
|
package ghidra.app.plugin.core.symtable;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
@ -23,10 +25,13 @@ import javax.swing.JComponent;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.WindowPosition;
|
import docking.WindowPosition;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
import ghidra.app.context.ProgramActionContext;
|
import ghidra.app.context.ProgramActionContext;
|
||||||
import ghidra.app.util.SymbolInspector;
|
import ghidra.app.util.SymbolInspector;
|
||||||
|
import ghidra.framework.cmd.CompoundCmd;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.Swing;
|
import ghidra.util.Swing;
|
||||||
|
@ -72,7 +77,21 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new ProgramActionContext(this, program);
|
|
||||||
|
List<Reference> selectedReferences = getSelectedReferences();
|
||||||
|
return new ReferenceTableContext(this, selectedReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Reference> getSelectedReferences() {
|
||||||
|
|
||||||
|
List<Reference> list = new ArrayList<>();
|
||||||
|
GhidraTable table = getTable();
|
||||||
|
int[] rows = table.getSelectedRows();
|
||||||
|
for (int row : rows) {
|
||||||
|
Reference ref = referenceKeyModel.getRowObject(row);
|
||||||
|
list.add(ref);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCurrentSymbol(Symbol symbol) {
|
void setCurrentSymbol(Symbol symbol) {
|
||||||
|
@ -104,6 +123,10 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Program getProgram() {
|
||||||
|
return referenceKeyModel.getProgram();
|
||||||
|
}
|
||||||
|
|
||||||
void reload() {
|
void reload() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
referenceKeyModel.reload();
|
referenceKeyModel.reload();
|
||||||
|
@ -126,6 +149,17 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
return referencePanel.getTable();
|
return referencePanel.getTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deleteRows(List<Reference> refs) {
|
||||||
|
|
||||||
|
CompoundCmd<Program> compoundCmd = new CompoundCmd<>("Delete References");
|
||||||
|
for (Reference ref : refs) {
|
||||||
|
RemoveReferenceCmd cmd = new RemoveReferenceCmd(ref);
|
||||||
|
compoundCmd.add(cmd);
|
||||||
|
referenceKeyModel.removeObject(ref);
|
||||||
|
}
|
||||||
|
tool.execute(compoundCmd, getProgram());
|
||||||
|
}
|
||||||
|
|
||||||
private String generateSubTitle() {
|
private String generateSubTitle() {
|
||||||
return "(" + referenceKeyModel.getDescription() + ")";
|
return "(" + referenceKeyModel.getDescription() + ")";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* ###
|
||||||
|
* 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.symtable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.app.context.ProgramActionContext;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
|
|
||||||
|
public class ReferenceTableContext extends ProgramActionContext {
|
||||||
|
|
||||||
|
private List<Reference> references;
|
||||||
|
|
||||||
|
ReferenceTableContext(ReferenceProvider provider, List<Reference> references) {
|
||||||
|
super(provider, provider.getProgram(), provider.getTable());
|
||||||
|
this.references = references;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Reference> getSelectedReferences() {
|
||||||
|
return references;
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,7 +32,11 @@ import docking.widgets.table.RowFilterTransformer;
|
||||||
import ghidra.app.plugin.core.symtable.AbstractSymbolTableModel.OriginalNameColumn;
|
import ghidra.app.plugin.core.symtable.AbstractSymbolTableModel.OriginalNameColumn;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
import ghidra.program.model.symbol.SymbolTable;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.table.*;
|
import ghidra.util.table.*;
|
||||||
|
|
||||||
class SymbolPanel extends JPanel {
|
class SymbolPanel extends JPanel {
|
||||||
|
@ -41,9 +45,9 @@ class SymbolPanel extends JPanel {
|
||||||
|
|
||||||
private static final String FILTER_SETTINGS_ELEMENT_NAME = "FILTER_SETTINGS";
|
private static final String FILTER_SETTINGS_ELEMENT_NAME = "FILTER_SETTINGS";
|
||||||
|
|
||||||
private SymbolProvider symProvider;
|
private SymbolProvider symbolProvider;
|
||||||
private SymbolTableModel tableModel;
|
private SymbolTableModel symbolModel;
|
||||||
private GhidraTable symTable;
|
private GhidraTable gTable;
|
||||||
private TableModelListener listener;
|
private TableModelListener listener;
|
||||||
private FilterDialog filterDialog;
|
private FilterDialog filterDialog;
|
||||||
private GhidraThreadedTablePanel<SymbolRowObject> threadedTablePanel;
|
private GhidraThreadedTablePanel<SymbolRowObject> threadedTablePanel;
|
||||||
|
@ -51,34 +55,31 @@ class SymbolPanel extends JPanel {
|
||||||
|
|
||||||
SymbolPanel(SymbolProvider provider, SymbolTableModel model, SymbolRenderer renderer,
|
SymbolPanel(SymbolProvider provider, SymbolTableModel model, SymbolRenderer renderer,
|
||||||
PluginTool tool) {
|
PluginTool tool) {
|
||||||
|
|
||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
|
|
||||||
this.symProvider = provider;
|
this.symbolProvider = provider;
|
||||||
this.tableModel = model;
|
this.symbolModel = model;
|
||||||
|
this.threadedTablePanel = new GhidraThreadedTablePanel<>(model);
|
||||||
|
this.listener = e -> symbolProvider.updateTitle();
|
||||||
|
|
||||||
threadedTablePanel = new GhidraThreadedTablePanel<>(model);
|
gTable = threadedTablePanel.getTable();
|
||||||
|
gTable.setAutoLookupColumn(AbstractSymbolTableModel.LABEL_COL);
|
||||||
this.listener = e -> symProvider.updateTitle();
|
gTable.setRowSelectionAllowed(true);
|
||||||
|
gTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||||
symTable = threadedTablePanel.getTable();
|
gTable.getModel().addTableModelListener(listener);
|
||||||
symTable.setAutoLookupColumn(AbstractSymbolTableModel.LABEL_COL);
|
gTable.getSelectionModel().addListSelectionListener(e -> {
|
||||||
symTable.setRowSelectionAllowed(true);
|
|
||||||
symTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
||||||
symTable.getModel().addTableModelListener(listener);
|
|
||||||
symTable.getSelectionModel().addListSelectionListener(e -> {
|
|
||||||
if (!e.getValueIsAdjusting()) {
|
if (!e.getValueIsAdjusting()) {
|
||||||
handleTableSelection();
|
handleTableSelection();
|
||||||
tool.contextChanged(symProvider);
|
tool.contextChanged(symbolProvider);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
symTable.setAccessibleNamePrefix("Symbol");
|
gTable.setAccessibleNamePrefix("Symbol");
|
||||||
|
|
||||||
symTable.installNavigation(tool);
|
gTable.installNavigation(tool);
|
||||||
|
|
||||||
for (int i = 0; i < symTable.getColumnCount(); i++) {
|
for (int i = 0; i < gTable.getColumnCount(); i++) {
|
||||||
TableColumn column = symTable.getColumnModel().getColumn(i);
|
TableColumn column = gTable.getColumnModel().getColumn(i);
|
||||||
column.setCellRenderer(renderer);
|
column.setCellRenderer(renderer);
|
||||||
if (column.getModelIndex() == AbstractSymbolTableModel.LABEL_COL) {
|
if (column.getModelIndex() == AbstractSymbolTableModel.LABEL_COL) {
|
||||||
column.setCellEditor(new SymbolEditor());
|
column.setCellEditor(new SymbolEditor());
|
||||||
|
@ -91,11 +92,11 @@ class SymbolPanel extends JPanel {
|
||||||
filterDialog = new FilterDialog(tool);
|
filterDialog = new FilterDialog(tool);
|
||||||
|
|
||||||
// enable dragging symbols out of the symbol table
|
// enable dragging symbols out of the symbol table
|
||||||
new SymbolTableDragProvider(symTable, model);
|
new SymbolTableDragProvider(gTable, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JPanel createFilterFieldPanel() {
|
private JPanel createFilterFieldPanel() {
|
||||||
tableFilterPanel = new GhidraTableFilterPanel<>(symTable, tableModel);
|
tableFilterPanel = new GhidraTableFilterPanel<>(gTable, symbolModel);
|
||||||
tableFilterPanel.setToolTipText("Filters the contents of the table on symbol " +
|
tableFilterPanel.setToolTipText("Filters the contents of the table on symbol " +
|
||||||
"names that start with the given pattern");
|
"names that start with the given pattern");
|
||||||
|
|
||||||
|
@ -120,17 +121,35 @@ class SymbolPanel extends JPanel {
|
||||||
return tableFilterPanel;
|
return tableFilterPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RowFilterTransformer<SymbolRowObject> updateRowDataTransformer(boolean nameOnly) {
|
void locationChanged(ProgramLocation location) {
|
||||||
TableColumnModel columnModel = symTable.getColumnModel();
|
|
||||||
if (nameOnly) {
|
Program program = location.getProgram();
|
||||||
return new NameOnlyRowTransformer(tableModel, columnModel);
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
Address address = location.getAddress();
|
||||||
|
Symbol primarySymbol = symbolTable.getPrimarySymbol(address);
|
||||||
|
if (primarySymbol == null) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return new DefaultRowFilterTransformer<>(tableModel, columnModel);
|
|
||||||
|
SymbolRowObject rowObject = new SymbolRowObject(primarySymbol);
|
||||||
|
int index = symbolModel.getRowIndex(rowObject);
|
||||||
|
if (index >= 0) {
|
||||||
|
gTable.selectRow(index);
|
||||||
|
gTable.scrollToSelectedRow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RowFilterTransformer<SymbolRowObject> updateRowDataTransformer(boolean nameOnly) {
|
||||||
|
TableColumnModel columnModel = gTable.getColumnModel();
|
||||||
|
if (nameOnly) {
|
||||||
|
return new NameOnlyRowTransformer(symbolModel, columnModel);
|
||||||
|
}
|
||||||
|
return new DefaultRowFilterTransformer<>(symbolModel, columnModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
symTable.getModel().removeTableModelListener(listener);
|
gTable.getModel().removeTableModelListener(listener);
|
||||||
symTable.dispose();
|
gTable.dispose();
|
||||||
threadedTablePanel.dispose();
|
threadedTablePanel.dispose();
|
||||||
tableFilterPanel.dispose();
|
tableFilterPanel.dispose();
|
||||||
filterDialog.dispose();
|
filterDialog.dispose();
|
||||||
|
@ -140,24 +159,24 @@ class SymbolPanel extends JPanel {
|
||||||
if (filterDialog == null) {
|
if (filterDialog == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (symTable.isEditing()) {
|
if (gTable.isEditing()) {
|
||||||
symTable.editingCanceled(null);
|
gTable.editingCanceled(null);
|
||||||
}
|
}
|
||||||
symProvider.setCurrentSymbol(null);
|
symbolProvider.setCurrentSymbol(null);
|
||||||
symTable.clearSelection();
|
gTable.clearSelection();
|
||||||
|
|
||||||
filterDialog.adjustFilter(symProvider, tableModel);
|
filterDialog.adjustFilter(symbolProvider, symbolModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolFilter getFilter() {
|
SymbolFilter getFilter() {
|
||||||
return tableModel.getFilter();
|
return symbolModel.getFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void readConfigState(SaveState saveState) {
|
void readConfigState(SaveState saveState) {
|
||||||
Element filterElement = saveState.getXmlElement(FILTER_SETTINGS_ELEMENT_NAME);
|
Element filterElement = saveState.getXmlElement(FILTER_SETTINGS_ELEMENT_NAME);
|
||||||
if (filterElement != null) {
|
if (filterElement != null) {
|
||||||
filterDialog.restoreFilter(filterElement);
|
filterDialog.restoreFilter(filterElement);
|
||||||
tableModel.setFilter(filterDialog.getFilter());
|
symbolModel.setFilter(filterDialog.getFilter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,26 +186,26 @@ class SymbolPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTableSelection() {
|
private void handleTableSelection() {
|
||||||
int selectedRowCount = symTable.getSelectedRowCount();
|
int selectedRowCount = gTable.getSelectedRowCount();
|
||||||
|
|
||||||
if (selectedRowCount == 1) {
|
if (selectedRowCount == 1) {
|
||||||
int selectedRow = symTable.getSelectedRow();
|
int selectedRow = gTable.getSelectedRow();
|
||||||
Symbol symbol = symProvider.getSymbolForRow(selectedRow);
|
Symbol symbol = symbolProvider.getSymbolForRow(selectedRow);
|
||||||
symProvider.setCurrentSymbol(symbol); // null allowed
|
symbolProvider.setCurrentSymbol(symbol); // null allowed
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
symProvider.setCurrentSymbol(null);
|
symbolProvider.setCurrentSymbol(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getActualSymbolCount() {
|
int getActualSymbolCount() {
|
||||||
return symTable.getRowCount();
|
return gTable.getRowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Symbol> getSelectedSymbols() {
|
List<Symbol> getSelectedSymbols() {
|
||||||
List<Symbol> list = new ArrayList<>();
|
List<Symbol> list = new ArrayList<>();
|
||||||
int[] rows = symTable.getSelectedRows();
|
int[] rows = gTable.getSelectedRows();
|
||||||
for (SymbolRowObject rowObject : tableModel.getRowObjects(rows)) {
|
for (SymbolRowObject rowObject : symbolModel.getRowObjects(rows)) {
|
||||||
Symbol s = rowObject.getSymbol();
|
Symbol s = rowObject.getSymbol();
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
list.add(s);
|
list.add(s);
|
||||||
|
@ -196,7 +215,7 @@ class SymbolPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
GhidraTable getTable() {
|
GhidraTable getTable() {
|
||||||
return symTable;
|
return gTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
|
@ -33,6 +33,7 @@ import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
|
|
||||||
|
@ -45,6 +46,8 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
private SymbolTableModel symbolKeyModel;
|
private SymbolTableModel symbolKeyModel;
|
||||||
private SymbolPanel symbolPanel;
|
private SymbolPanel symbolPanel;
|
||||||
|
|
||||||
|
private boolean followIncomingLocationChanges;
|
||||||
|
|
||||||
SymbolProvider(SymbolTablePlugin plugin) {
|
SymbolProvider(SymbolTablePlugin plugin) {
|
||||||
super(plugin.getTool(), "Symbol Table", plugin.getName(), ProgramActionContext.class);
|
super(plugin.getTool(), "Symbol Table", plugin.getName(), ProgramActionContext.class);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
@ -63,6 +66,19 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
addToTool();
|
addToTool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setFollowIncomingLocationChanges(boolean b) {
|
||||||
|
followIncomingLocationChanges = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void locationChanged(ProgramLocation location) {
|
||||||
|
if (!isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (followIncomingLocationChanges) {
|
||||||
|
symbolPanel.locationChanged(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updateTitle() {
|
void updateTitle() {
|
||||||
setSubTitle(generateSubTitle());
|
setSubTitle(generateSubTitle());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.symtable;
|
package ghidra.app.plugin.core.symtable;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import docking.widgets.table.DiscoverableTableUtils;
|
import docking.widgets.table.DiscoverableTableUtils;
|
||||||
import docking.widgets.table.TableColumnDescriptor;
|
import docking.widgets.table.TableColumnDescriptor;
|
||||||
import ghidra.app.services.BlockModelService;
|
import ghidra.app.services.BlockModelService;
|
||||||
|
@ -53,11 +51,10 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
static final int INSTR_REFS_FROM = 1;
|
static final int INSTR_REFS_FROM = 1;
|
||||||
static final int DATA_REFS_FROM = 2;
|
static final int DATA_REFS_FROM = 2;
|
||||||
|
|
||||||
private Symbol currentSymbol;
|
private volatile Symbol currentSymbol;
|
||||||
private ReferenceManager refManager;
|
private ReferenceManager refManager;
|
||||||
private int showRefMode = REFS_TO;
|
private int showRefMode = REFS_TO;
|
||||||
private BlockModelService blockModelService;
|
private BlockModelService blockModelService;
|
||||||
private boolean isDisposed;
|
|
||||||
|
|
||||||
SymbolReferenceModel(BlockModelService bms, PluginTool tool) {
|
SymbolReferenceModel(BlockModelService bms, PluginTool tool) {
|
||||||
super("Symbol References", tool, null, null);
|
super("Symbol References", tool, null, null);
|
||||||
|
@ -98,12 +95,6 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
isDisposed = true;
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProgram(Program prog) {
|
public void setProgram(Program prog) {
|
||||||
if (isDisposed) {
|
if (isDisposed) {
|
||||||
|
@ -145,9 +136,7 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRefs(Symbol symbol) {
|
private void checkRefs(Symbol symbol) {
|
||||||
Iterator<Reference> iter = filteredData.iterator();
|
for (Reference ref : filteredData) {
|
||||||
while (iter.hasNext()) {
|
|
||||||
Reference ref = iter.next();
|
|
||||||
if (ref.getFromAddress().equals(symbol.getAddress())) {
|
if (ref.getFromAddress().equals(symbol.getAddress())) {
|
||||||
reload();
|
reload();
|
||||||
return;
|
return;
|
||||||
|
@ -173,6 +162,7 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
@Override
|
@Override
|
||||||
protected void doLoad(Accumulator<Reference> accumulator, TaskMonitor monitor)
|
protected void doLoad(Accumulator<Reference> accumulator, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
if (currentSymbol == null || getProgram() == null) {
|
if (currentSymbol == null || getProgram() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,13 @@ import static ghidra.program.util.ProgramEvent.*;
|
||||||
|
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.action.builder.ActionBuilder;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.ProgramActivatedPluginEvent;
|
import ghidra.app.events.ProgramActivatedPluginEvent;
|
||||||
|
@ -44,6 +46,7 @@ import ghidra.program.model.listing.Data;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramChangeRecord;
|
import ghidra.program.util.ProgramChangeRecord;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
import ghidra.util.table.SelectionNavigationAction;
|
import ghidra.util.table.SelectionNavigationAction;
|
||||||
import ghidra.util.table.actions.MakeProgramSelectionAction;
|
import ghidra.util.table.actions.MakeProgramSelectionAction;
|
||||||
|
@ -70,11 +73,14 @@ import resources.Icons;
|
||||||
"to show subsets of the symbols.",
|
"to show subsets of the symbols.",
|
||||||
servicesRequired = { GoToService.class, BlockModelService.class },
|
servicesRequired = { GoToService.class, BlockModelService.class },
|
||||||
eventsProduced = { ProgramLocationPluginEvent.class },
|
eventsProduced = { ProgramLocationPluginEvent.class },
|
||||||
eventsConsumed = { ProgramActivatedPluginEvent.class }
|
eventsConsumed = { ProgramActivatedPluginEvent.class, ProgramLocationPluginEvent.class }
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class SymbolTablePlugin extends Plugin {
|
public class SymbolTablePlugin extends Plugin {
|
||||||
|
|
||||||
|
private static final String NAVIGATE_ON_INCOMING_EVENT_KEY = "NAVIGATE_ON_INCOMING_EVENT";
|
||||||
|
private static final String NAVIGATE_ON_OUTGOING_EVENT_KEY = "NAVIGATE_ON_OUTGOING_EVENT";
|
||||||
|
|
||||||
final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
|
final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
|
||||||
final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
|
final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
|
||||||
|
|
||||||
|
@ -85,6 +91,8 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
private ToggleDockingAction referencesToAction;
|
private ToggleDockingAction referencesToAction;
|
||||||
private ToggleDockingAction instructionsFromAction;
|
private ToggleDockingAction instructionsFromAction;
|
||||||
private ToggleDockingAction dataFromAction;
|
private ToggleDockingAction dataFromAction;
|
||||||
|
private ToggleDockingAction followIncomingAction;
|
||||||
|
private SelectionNavigationAction selectionNavigationAction;
|
||||||
|
|
||||||
private SymbolProvider symProvider;
|
private SymbolProvider symProvider;
|
||||||
private ReferenceProvider refProvider;
|
private ReferenceProvider refProvider;
|
||||||
|
@ -164,11 +172,21 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
@Override
|
@Override
|
||||||
public void readConfigState(SaveState saveState) {
|
public void readConfigState(SaveState saveState) {
|
||||||
symProvider.readConfigState(saveState);
|
symProvider.readConfigState(saveState);
|
||||||
|
|
||||||
|
boolean navigateIncoming = saveState.getBoolean(NAVIGATE_ON_INCOMING_EVENT_KEY, false);
|
||||||
|
boolean navigateOutgoing = saveState.getBoolean(NAVIGATE_ON_OUTGOING_EVENT_KEY, false);
|
||||||
|
followIncomingAction.setSelected(navigateIncoming);
|
||||||
|
selectionNavigationAction.setSelected(navigateOutgoing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeConfigState(SaveState saveState) {
|
public void writeConfigState(SaveState saveState) {
|
||||||
symProvider.writeConfigState(saveState);
|
symProvider.writeConfigState(saveState);
|
||||||
|
|
||||||
|
boolean navigateIncoming = followIncomingAction.isSelected();
|
||||||
|
boolean navigateOutgoing = selectionNavigationAction.isSelected();
|
||||||
|
saveState.putBoolean(NAVIGATE_ON_INCOMING_EVENT_KEY, navigateIncoming);
|
||||||
|
saveState.putBoolean(NAVIGATE_ON_OUTGOING_EVENT_KEY, navigateOutgoing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -194,6 +212,10 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
|
|
||||||
tool.contextChanged(symProvider);
|
tool.contextChanged(symProvider);
|
||||||
}
|
}
|
||||||
|
else if (event instanceof ProgramLocationPluginEvent ple) {
|
||||||
|
ProgramLocation location = ple.getLocation();
|
||||||
|
symProvider.locationChanged(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isBusy() {
|
boolean isBusy() {
|
||||||
|
@ -391,8 +413,22 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
setFilterAction.setDescription("Configure Symbol Filter");
|
setFilterAction.setDescription("Configure Symbol Filter");
|
||||||
tool.addLocalAction(symProvider, setFilterAction);
|
tool.addLocalAction(symProvider, setFilterAction);
|
||||||
|
|
||||||
|
String navGroup = "2";
|
||||||
|
followIncomingAction =
|
||||||
|
new ToggleDockingAction("Navigate on Incoming Location Changes", getName(),
|
||||||
|
KeyBindingType.SHARED) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
symProvider.setFollowIncomingLocationChanges(isSelected());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
followIncomingAction
|
||||||
|
.setToolBarData(new ToolBarData(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON, navGroup));
|
||||||
|
tool.addLocalAction(symProvider, followIncomingAction);
|
||||||
|
|
||||||
// override the SelectionNavigationAction to handle both tables that this plugin uses
|
// override the SelectionNavigationAction to handle both tables that this plugin uses
|
||||||
DockingAction selectionNavigationAction =
|
selectionNavigationAction =
|
||||||
new SelectionNavigationAction(this, symProvider.getTable()) {
|
new SelectionNavigationAction(this, symProvider.getTable()) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -401,6 +437,7 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
refProvider.getTable().setNavigateOnSelectionEnabled(listen);
|
refProvider.getTable().setNavigateOnSelectionEnabled(listen);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
selectionNavigationAction.getToolBarData().setToolBarGroup(navGroup);
|
||||||
tool.addLocalAction(symProvider, selectionNavigationAction);
|
tool.addLocalAction(symProvider, selectionNavigationAction);
|
||||||
|
|
||||||
String pinnedPopupGroup = "2"; // second group
|
String pinnedPopupGroup = "2"; // second group
|
||||||
|
@ -416,6 +453,7 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createRefActions() {
|
private void createRefActions() {
|
||||||
|
String toolbarGroup = "1";
|
||||||
referencesToAction = new ToggleDockingAction("References To", getName()) {
|
referencesToAction = new ToggleDockingAction("References To", getName()) {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
|
@ -435,7 +473,7 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
referencesToAction.setDescription("References To");
|
referencesToAction.setDescription("References To");
|
||||||
referencesToAction.setSelected(true);
|
referencesToAction.setSelected(true);
|
||||||
referencesToAction.setToolBarData(
|
referencesToAction.setToolBarData(
|
||||||
new ToolBarData(new GIcon("icon.plugin.symboltable.references.to"), null));
|
new ToolBarData(new GIcon("icon.plugin.symboltable.references.to"), toolbarGroup));
|
||||||
|
|
||||||
tool.addLocalAction(refProvider, referencesToAction);
|
tool.addLocalAction(refProvider, referencesToAction);
|
||||||
|
|
||||||
|
@ -458,7 +496,7 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
instructionsFromAction.setDescription("Instructions From");
|
instructionsFromAction.setDescription("Instructions From");
|
||||||
instructionsFromAction.setSelected(false);
|
instructionsFromAction.setSelected(false);
|
||||||
instructionsFromAction.setToolBarData(
|
instructionsFromAction.setToolBarData(
|
||||||
new ToolBarData(new GIcon("icon.plugin.symboltable.instructions.from"), null));
|
new ToolBarData(new GIcon("icon.plugin.symboltable.instructions.from"), toolbarGroup));
|
||||||
|
|
||||||
tool.addLocalAction(refProvider, instructionsFromAction);
|
tool.addLocalAction(refProvider, instructionsFromAction);
|
||||||
|
|
||||||
|
@ -481,9 +519,36 @@ public class SymbolTablePlugin extends Plugin {
|
||||||
dataFromAction.setDescription("Data From");
|
dataFromAction.setDescription("Data From");
|
||||||
dataFromAction.setSelected(false);
|
dataFromAction.setSelected(false);
|
||||||
dataFromAction.setToolBarData(
|
dataFromAction.setToolBarData(
|
||||||
new ToolBarData(new GIcon("icon.plugin.symboltable.data.from"), null));
|
new ToolBarData(new GIcon("icon.plugin.symboltable.data.from"), toolbarGroup));
|
||||||
|
|
||||||
tool.addLocalAction(refProvider, dataFromAction);
|
tool.addLocalAction(refProvider, dataFromAction);
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
toolbarGroup = "2";
|
||||||
|
String actionName = "Delete Reference";
|
||||||
|
new ActionBuilder(actionName, getName())
|
||||||
|
.sharedKeyBinding()
|
||||||
|
.toolBarIcon(Icons.DELETE_ICON)
|
||||||
|
.toolBarGroup(toolbarGroup)
|
||||||
|
.enabledWhen(c -> {
|
||||||
|
if (!(c instanceof ReferenceTableContext context)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refProvider.isBusy()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Reference> refs = context.getSelectedReferences();
|
||||||
|
return !refs.isEmpty();
|
||||||
|
})
|
||||||
|
.onAction(c -> {
|
||||||
|
ReferenceTableContext context = (ReferenceTableContext) c;
|
||||||
|
List<Reference> refs = context.getSelectedReferences();
|
||||||
|
refProvider.deleteRows(refs);
|
||||||
|
})
|
||||||
|
.buildAndInstallLocal(refProvider);
|
||||||
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
// a HACK to make the given action the selected action
|
// a HACK to make the given action the selected action
|
||||||
|
|
|
@ -36,6 +36,7 @@ import ghidra.app.nav.Navigatable;
|
||||||
import ghidra.app.nav.NavigatableRemovalListener;
|
import ghidra.app.nav.NavigatableRemovalListener;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
import ghidra.framework.plugintool.Plugin;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
@ -64,6 +65,9 @@ public class TableComponentProvider<T> extends ComponentProviderAdapter
|
||||||
private List<ComponentProviderActivationListener> activationListenerList = new ArrayList<>();
|
private List<ComponentProviderActivationListener> activationListenerList = new ArrayList<>();
|
||||||
private Callback closedCallback = Dummy.callback();
|
private Callback closedCallback = Dummy.callback();
|
||||||
|
|
||||||
|
// optional client listener
|
||||||
|
private DomainObjectListener programListener;
|
||||||
|
|
||||||
private Navigatable navigatable;
|
private Navigatable navigatable;
|
||||||
private SelectionNavigationAction selectionNavigationAction;
|
private SelectionNavigationAction selectionNavigationAction;
|
||||||
private DockingAction selectAction;
|
private DockingAction selectAction;
|
||||||
|
@ -422,6 +426,15 @@ public class TableComponentProvider<T> extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentHidden() {
|
||||||
|
// Note: this method will get called when this provider is closed. Also, the provider will
|
||||||
|
// be closed if its program is closed.
|
||||||
|
if (programListener != null) {
|
||||||
|
program.removeListener(programListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWindowSubMenuName() {
|
public String getWindowSubMenuName() {
|
||||||
return windowSubMenu;
|
return windowSubMenu;
|
||||||
|
@ -456,4 +469,22 @@ public class TableComponentProvider<T> extends ComponentProviderAdapter
|
||||||
public void setClosedCallback(Callback c) {
|
public void setClosedCallback(Callback c) {
|
||||||
this.closedCallback = Dummy.ifNull(c);
|
this.closedCallback = Dummy.ifNull(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a program listener on this provider. This class will add the listener to the program
|
||||||
|
* and maintain a reference to the listener for the life of this provider. This prevents the
|
||||||
|
* listener from getting garbage collected until this provider is disposed.
|
||||||
|
*
|
||||||
|
* @param programListener the listener
|
||||||
|
*/
|
||||||
|
public void setProgramListener(DomainObjectListener programListener) {
|
||||||
|
if (this.programListener != null) {
|
||||||
|
program.removeListener(programListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.programListener = programListener;
|
||||||
|
if (programListener != null) {
|
||||||
|
program.addListener(programListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.util;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
|
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
|
@ -36,8 +37,8 @@ public class FunctionXrefsTableModel extends ReferencesFromTableModel {
|
||||||
private Function function;
|
private Function function;
|
||||||
private boolean showAllThunkXrefs;
|
private boolean showAllThunkXrefs;
|
||||||
|
|
||||||
public FunctionXrefsTableModel(Function function, Collection<Reference> directRefs, ServiceProvider sp,
|
public FunctionXrefsTableModel(Function function, Supplier<Collection<Reference>> directRefs,
|
||||||
Program program) {
|
ServiceProvider sp, Program program) {
|
||||||
super(directRefs, sp, program);
|
super(directRefs, sp, program);
|
||||||
this.function = function;
|
this.function = function;
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,28 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util;
|
package ghidra.app.util;
|
||||||
|
|
||||||
import java.util.*;
|
import static ghidra.framework.model.DomainObjectEvent.*;
|
||||||
|
import static ghidra.program.util.ProgramEvent.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.action.*;
|
||||||
import docking.action.builder.ToggleActionBuilder;
|
import docking.action.builder.ToggleActionBuilder;
|
||||||
|
import docking.widgets.OptionDialog;
|
||||||
|
import docking.widgets.OptionDialogBuilder;
|
||||||
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
import ghidra.app.nav.Navigatable;
|
import ghidra.app.nav.Navigatable;
|
||||||
import ghidra.app.plugin.core.table.TableComponentProvider;
|
import ghidra.app.plugin.core.table.TableComponentProvider;
|
||||||
import ghidra.app.util.query.TableService;
|
import ghidra.app.util.query.TableService;
|
||||||
|
import ghidra.framework.cmd.CompoundCmd;
|
||||||
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
|
import ghidra.framework.model.DomainObjectListenerBuilder;
|
||||||
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.DataUtilities;
|
import ghidra.program.model.data.DataUtilities;
|
||||||
|
@ -30,16 +46,18 @@ import ghidra.program.util.*;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.table.ReferencesFromTableModel;
|
import ghidra.util.table.ReferencesFromTableModel;
|
||||||
import ghidra.util.table.field.ReferenceEndpoint;
|
import ghidra.util.table.field.ReferenceEndpoint;
|
||||||
|
import resources.Icons;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class XReferenceUtils {
|
public class XReferenceUtils {
|
||||||
|
|
||||||
private static final String X_REFS_TO = "XRefs to ";
|
private static final String X_REFS_TO = "XRefs to ";
|
||||||
|
|
||||||
// Methods in this class treat -1 as a key to return all references and
|
// Methods in this class treat -1 as a key to return all references and not cap the result set.
|
||||||
// not cap the result set.
|
|
||||||
private final static int ALL_REFS = -1;
|
private final static int ALL_REFS = -1;
|
||||||
|
|
||||||
|
private static OptionDialog promptToDeleteXrefsDialog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array containing the first <b><code>max</code></b>
|
* Returns an array containing the first <b><code>max</code></b>
|
||||||
* direct xref references to the specified code unit.
|
* direct xref references to the specified code unit.
|
||||||
|
@ -69,13 +87,15 @@ public class XReferenceUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for thunk reference
|
// Check for thunk reference
|
||||||
Function func = program.getFunctionManager().getFunctionAt(minAddress);
|
Function function = program.getFunctionManager().getFunctionAt(minAddress);
|
||||||
if (func != null) {
|
if (function == null) {
|
||||||
Address[] thunkAddrs = func.getFunctionThunkAddresses();
|
return xrefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address[] thunkAddrs = function.getFunctionThunkAddresses(false);
|
||||||
if (thunkAddrs != null) {
|
if (thunkAddrs != null) {
|
||||||
for (Address thunkAddr : thunkAddrs) {
|
for (Address thunkAddr : thunkAddrs) {
|
||||||
xrefs.add(new ThunkReference(thunkAddr, func.getEntryPoint()));
|
xrefs.add(new ThunkReference(thunkAddr, function.getEntryPoint()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return xrefs;
|
return xrefs;
|
||||||
|
@ -203,10 +223,29 @@ public class XReferenceUtils {
|
||||||
* @param service the service needed to show the table
|
* @param service the service needed to show the table
|
||||||
* @param location the location for which to find references
|
* @param location the location for which to find references
|
||||||
* @param xrefs the xrefs to show
|
* @param xrefs the xrefs to show
|
||||||
|
* @deprecated use {@link #showXrefs(Navigatable, ServiceProvider, TableService,
|
||||||
|
* ProgramLocation, Supplier)}. That method takes a supplier that can regenerate the current
|
||||||
|
* xrefs for the table.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "11.5", forRemoval = true)
|
||||||
public static void showXrefs(Navigatable navigatable, ServiceProvider serviceProvider,
|
public static void showXrefs(Navigatable navigatable, ServiceProvider serviceProvider,
|
||||||
TableService service, ProgramLocation location, Collection<Reference> xrefs) {
|
TableService service, ProgramLocation location, Collection<Reference> xrefs) {
|
||||||
|
|
||||||
|
showXrefs(navigatable, serviceProvider, service, location, () -> xrefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows all xrefs to the given location in a new table.
|
||||||
|
*
|
||||||
|
* @param navigatable the navigatable used for navigation from the table
|
||||||
|
* @param serviceProvider the service provider needed to wire navigation
|
||||||
|
* @param service the service needed to show the table
|
||||||
|
* @param location the location for which to find references
|
||||||
|
* @param xrefs a supplier of the xrefs to show
|
||||||
|
*/
|
||||||
|
public static void showXrefs(Navigatable navigatable, ServiceProvider serviceProvider,
|
||||||
|
TableService service, ProgramLocation location, Supplier<Collection<Reference>> xrefs) {
|
||||||
|
|
||||||
Address address = location.getAddress();
|
Address address = location.getAddress();
|
||||||
Program program = location.getProgram();
|
Program program = location.getProgram();
|
||||||
FunctionManager fm = program.getFunctionManager();
|
FunctionManager fm = program.getFunctionManager();
|
||||||
|
@ -223,9 +262,26 @@ public class XReferenceUtils {
|
||||||
String title = generateXRefTitle(location);
|
String title = generateXRefTitle(location);
|
||||||
TableComponentProvider<ReferenceEndpoint> provider =
|
TableComponentProvider<ReferenceEndpoint> provider =
|
||||||
service.showTable(title, "Xrefs", model, "Xrefs", navigatable);
|
service.showTable(title, "Xrefs", model, "Xrefs", navigatable);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add Actions
|
||||||
|
//
|
||||||
provider.installRemoveItemsAction();
|
provider.installRemoveItemsAction();
|
||||||
|
|
||||||
|
installRefreshAction(provider, model);
|
||||||
|
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
|
installShowThunksAction(provider, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteXrefsAction deleteAction = new DeleteXrefsAction(provider, model, program);
|
||||||
|
provider.addLocalAction(deleteAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void installShowThunksAction(
|
||||||
|
TableComponentProvider<ReferenceEndpoint> provider,
|
||||||
|
ReferencesFromTableModel model) {
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
String actionName = "Show Thunk Xrefs";
|
String actionName = "Show Thunk Xrefs";
|
||||||
new ToggleActionBuilder(actionName, provider.getActionOwner())
|
new ToggleActionBuilder(actionName, provider.getActionOwner())
|
||||||
|
@ -238,10 +294,112 @@ public class XReferenceUtils {
|
||||||
})
|
})
|
||||||
.buildAndInstallLocal(provider);
|
.buildAndInstallLocal(provider);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void installRefreshAction(TableComponentProvider<ReferenceEndpoint> provider,
|
||||||
|
ReferencesFromTableModel model) {
|
||||||
|
|
||||||
|
Icon REFRESH_NOT_NEEDED_ICON = ResourceManager.getDisabledIcon(Icons.REFRESH_ICON, 60);
|
||||||
|
DockingAction refreshAction = new DockingAction("Refresh", provider.getActionOwner()) {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
getToolBarData().setIcon(REFRESH_NOT_NEEDED_ICON);
|
||||||
|
model.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
HelpLocation hl = new HelpLocation(HelpTopics.CODE_BROWSER, refreshAction.getName());
|
||||||
|
refreshAction.setHelpLocation(hl);
|
||||||
|
refreshAction.setToolBarData(new ToolBarData(REFRESH_NOT_NEEDED_ICON, "A"));
|
||||||
|
refreshAction.setDescription(
|
||||||
|
"<html>Push at any time to refresh the current table of references.<br>" +
|
||||||
|
"This button is highlighted when the data <i>may</i> be stale.<br>");
|
||||||
|
|
||||||
|
// Add a listener to
|
||||||
|
DomainObjectListener listener = new DomainObjectListenerBuilder(model)
|
||||||
|
.any(RESTORED, REFERENCE_ADDED, REFERENCE_REMOVED)
|
||||||
|
.call(() -> {
|
||||||
|
// signal that the data in the table does not match the program
|
||||||
|
refreshAction.getToolBarData().setIcon(Icons.REFRESH_ICON);
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
provider.setProgramListener(listener);
|
||||||
|
provider.addLocalAction(refreshAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this action lives in this class so that the action can hold a reference to a domain
|
||||||
|
// object listener. The action will hold a reference so that as long as the the provider is
|
||||||
|
// around, the action will also be around to hold a reference to the listener.
|
||||||
|
private static class DeleteXrefsAction extends DockingAction {
|
||||||
|
|
||||||
|
private TableComponentProvider<ReferenceEndpoint> provider;
|
||||||
|
private Program program;
|
||||||
|
private ReferencesFromTableModel tableModel;
|
||||||
|
|
||||||
|
public DeleteXrefsAction(TableComponentProvider<ReferenceEndpoint> provider,
|
||||||
|
ReferencesFromTableModel tableModel, Program program) {
|
||||||
|
super("Delete Reference", provider.getActionOwner(), KeyBindingType.SHARED);
|
||||||
|
this.provider = provider;
|
||||||
|
this.tableModel = tableModel;
|
||||||
|
this.program = program;
|
||||||
|
|
||||||
|
setToolBarData(new ToolBarData(Icons.DELETE_ICON, "A"));
|
||||||
|
setHelpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(ActionContext c) {
|
||||||
|
Object object = c.getContextObject();
|
||||||
|
if (!(object instanceof JTable table)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tableModel.isBusy()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return table.getSelectedRowCount() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext c) {
|
||||||
|
Object object = c.getContextObject();
|
||||||
|
JTable table = (JTable) object;
|
||||||
|
int[] rows = table.getSelectedRows();
|
||||||
|
PluginTool tool = provider.getTool();
|
||||||
|
deleteXrefs(tool, program, tableModel, rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteXrefs(PluginTool tool, Program program,
|
||||||
|
ReferencesFromTableModel tableModel, int[] rows) {
|
||||||
|
|
||||||
|
if (promptToDeleteXrefsDialog == null) {
|
||||||
|
promptToDeleteXrefsDialog =
|
||||||
|
new OptionDialogBuilder("Delete Xrefs?",
|
||||||
|
"Do you wish to permanently delete the selected xrefs?")
|
||||||
|
.addOption("Delete")
|
||||||
|
.addCancel()
|
||||||
|
.addDontShowAgainOption()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
int choice = promptToDeleteXrefsDialog.show();
|
||||||
|
if (choice != OptionDialog.YES_OPTION) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ReferenceEndpoint> deletedRowObjects = new ArrayList<>();
|
||||||
|
CompoundCmd<Program> compoundCmd = new CompoundCmd<>("Delete References");
|
||||||
|
for (int row : rows) {
|
||||||
|
ReferenceEndpoint endpoint = tableModel.getRowObject(row);
|
||||||
|
deletedRowObjects.add(endpoint);
|
||||||
|
Reference ref = endpoint.getReference();
|
||||||
|
RemoveReferenceCmd cmd = new RemoveReferenceCmd(ref);
|
||||||
|
compoundCmd.add(cmd);
|
||||||
|
}
|
||||||
|
tool.execute(compoundCmd, program);
|
||||||
|
|
||||||
|
// also remove the object from the table, since they have been deleted
|
||||||
|
deletedRowObjects.forEach(ro -> tableModel.removeObject(ro));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateXRefTitle(ProgramLocation location) {
|
private static String generateXRefTitle(ProgramLocation location) {
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.viewer.field;
|
package ghidra.app.util.viewer.field;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import ghidra.app.nav.Navigatable;
|
import ghidra.app.nav.Navigatable;
|
||||||
import ghidra.app.util.XReferenceUtils;
|
import ghidra.app.util.XReferenceUtils;
|
||||||
|
@ -39,7 +39,7 @@ public class VariableXRefFieldMouseHandler extends XRefFieldMouseHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Address getFromReferenceAddress(ProgramLocation programLocation) {
|
protected Address getFromReferenceAddress(ProgramLocation programLocation) {
|
||||||
return ((VariableXRefFieldLocation) programLocation).getRefAddress();
|
return programLocation.getRefAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,7 +63,7 @@ public class VariableXRefFieldMouseHandler extends XRefFieldMouseHandler {
|
||||||
VariableLocation variableLocation = (VariableLocation) location;
|
VariableLocation variableLocation = (VariableLocation) location;
|
||||||
Variable variable = variableLocation.getVariable();
|
Variable variable = variableLocation.getVariable();
|
||||||
|
|
||||||
Set<Reference> refs = getVariableRefs(variable);
|
Supplier<Collection<Reference>> refs = () -> getVariableRefs(variable);
|
||||||
XReferenceUtils.showXrefs(navigatable, serviceProvider, service, location, refs);
|
XReferenceUtils.showXrefs(navigatable, serviceProvider, service, location, refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
package ghidra.app.util.viewer.field;
|
package ghidra.app.util.viewer.field;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.Set;
|
import java.util.Collection;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.field.*;
|
import docking.widgets.fieldpanel.field.*;
|
||||||
import ghidra.app.nav.Navigatable;
|
import ghidra.app.nav.Navigatable;
|
||||||
|
@ -98,7 +99,7 @@ public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Address getFromReferenceAddress(ProgramLocation programLocation) {
|
protected Address getFromReferenceAddress(ProgramLocation programLocation) {
|
||||||
return ((XRefFieldLocation) programLocation).getRefAddress();
|
return programLocation.getRefAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showXRefDialog(Navigatable navigatable, ProgramLocation location,
|
protected void showXRefDialog(Navigatable navigatable, ProgramLocation location,
|
||||||
|
@ -108,7 +109,7 @@ public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Reference> refs = XReferenceUtils.getAllXrefs(location);
|
Supplier<Collection<Reference>> refs = () -> XReferenceUtils.getAllXrefs(location);
|
||||||
XReferenceUtils.showXrefs(navigatable, serviceProvider, service, location, refs);
|
XReferenceUtils.showXrefs(navigatable, serviceProvider, service, location, refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ import resources.Icons;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSelectionNavigationAction extends ToggleDockingAction {
|
public abstract class AbstractSelectionNavigationAction extends ToggleDockingAction {
|
||||||
|
|
||||||
private static final Icon ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON;
|
private static final Icon ICON = Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON;
|
||||||
private static final String SELECTED_STATE = "SELECTION_NAVIGATION_SELECTED_STATE";
|
private static final String SELECTED_STATE = "SELECTION_NAVIGATION_SELECTED_STATE";
|
||||||
|
|
||||||
private SelectionListener selectionListener;
|
private SelectionListener selectionListener;
|
||||||
|
@ -60,7 +60,6 @@ public abstract class AbstractSelectionNavigationAction extends ToggleDockingAct
|
||||||
setDescription(HTMLUtilities.toHTML("Toggle <b>on</b> means to navigate to the location\n" +
|
setDescription(HTMLUtilities.toHTML("Toggle <b>on</b> means to navigate to the location\n" +
|
||||||
"in the program that corresponds to the selected row,\n as the selection changes."));
|
"in the program that corresponds to the selected row,\n as the selection changes."));
|
||||||
setHelpLocation(new HelpLocation("Search", "Selection_Navigation"));
|
setHelpLocation(new HelpLocation("Search", "Selection_Navigation"));
|
||||||
setEnabled(true);
|
|
||||||
setSelected(true); // toggle button; enabled by default
|
setSelected(true); // toggle button; enabled by default
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.util.table;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
|
@ -45,16 +44,21 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public class ReferencesFromTableModel extends AddressBasedTableModel<ReferenceEndpoint> {
|
public class ReferencesFromTableModel extends AddressBasedTableModel<ReferenceEndpoint> {
|
||||||
|
|
||||||
private List<IncomingReferenceEndpoint> refs;
|
private Supplier<Collection<Reference>> refsSupplier;
|
||||||
|
|
||||||
public ReferencesFromTableModel(Collection<Reference> refs, ServiceProvider sp,
|
public ReferencesFromTableModel(Collection<Reference> refs, ServiceProvider sp,
|
||||||
Program program) {
|
Program program) {
|
||||||
super("References", sp, program, null);
|
super("References", sp, program, null);
|
||||||
|
|
||||||
this.refs = refs.stream().map(r -> {
|
this.refsSupplier = () -> refs;
|
||||||
boolean offcut = ReferenceUtils.isOffcut(program, r.getToAddress());
|
|
||||||
return new IncomingReferenceEndpoint(r, offcut);
|
addTableColumn(new ReferenceTypeTableColumn());
|
||||||
}).collect(Collectors.toList());
|
}
|
||||||
|
|
||||||
|
public ReferencesFromTableModel(Supplier<Collection<Reference>> refsSupplier,
|
||||||
|
ServiceProvider sp, Program program) {
|
||||||
|
super("References", sp, program, null);
|
||||||
|
this.refsSupplier = refsSupplier;
|
||||||
|
|
||||||
addTableColumn(new ReferenceTypeTableColumn());
|
addTableColumn(new ReferenceTypeTableColumn());
|
||||||
}
|
}
|
||||||
|
@ -62,7 +66,13 @@ public class ReferencesFromTableModel extends AddressBasedTableModel<ReferenceEn
|
||||||
@Override
|
@Override
|
||||||
protected void doLoad(Accumulator<ReferenceEndpoint> accumulator, TaskMonitor monitor)
|
protected void doLoad(Accumulator<ReferenceEndpoint> accumulator, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
refs.forEach(r -> accumulator.add(r));
|
|
||||||
|
Collection<Reference> xrefs = refsSupplier.get();
|
||||||
|
for (Reference xref : xrefs) {
|
||||||
|
boolean offcut = ReferenceUtils.isOffcut(program, xref.getToAddress());
|
||||||
|
IncomingReferenceEndpoint endpoint = new IncomingReferenceEndpoint(xref, offcut);
|
||||||
|
accumulator.add(endpoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class DeleteTableRowAction extends DockingAction {
|
||||||
|
|
||||||
protected void removeSelectedItems() {
|
protected void removeSelectedItems() {
|
||||||
TableModel model = table.getModel();
|
TableModel model = table.getModel();
|
||||||
if (!(model instanceof RowObjectTableModel)) {
|
if (!(model instanceof ThreadedTableModel)) {
|
||||||
throw new AssertException("This action cannot delete rows for the given table model." +
|
throw new AssertException("This action cannot delete rows for the given table model." +
|
||||||
"You can override this method to peform the delete action yourself.");
|
"You can override this method to peform the delete action yourself.");
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ public class DeleteTableRowAction extends DockingAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkForBusy(TableModel model) {
|
protected boolean checkForBusy(TableModel model) {
|
||||||
|
|
||||||
if (!(model instanceof ThreadedTableModel)) {
|
if (!(model instanceof ThreadedTableModel)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.app.plugin.core.navigation.locationreferences;
|
package ghidra.app.plugin.core.navigation.locationreferences;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
|
@ -16,12 +16,17 @@
|
||||||
package ghidra.app.plugin.core.navigation.locationreferences;
|
package ghidra.app.plugin.core.navigation.locationreferences;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.widgets.table.GTable;
|
||||||
import ghidra.app.cmd.function.SetReturnDataTypeCmd;
|
import ghidra.app.cmd.function.SetReturnDataTypeCmd;
|
||||||
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
import ghidra.app.plugin.core.clear.ClearCmd;
|
import ghidra.app.plugin.core.clear.ClearCmd;
|
||||||
|
@ -142,8 +147,8 @@ public class LocationReferencesPlugin3Test extends AbstractLocationReferencesTes
|
||||||
|
|
||||||
// 0100415a - sscanf
|
// 0100415a - sscanf
|
||||||
Address address = addr(0x0100415a);
|
Address address = addr(0x0100415a);
|
||||||
int parameterColumn = 7;
|
int returnTypeColumn = 7;
|
||||||
goTo(address, "Function Signature", parameterColumn);
|
goTo(address, "Function Signature", returnTypeColumn);
|
||||||
|
|
||||||
search();
|
search();
|
||||||
|
|
||||||
|
@ -172,6 +177,33 @@ public class LocationReferencesPlugin3Test extends AbstractLocationReferencesTes
|
||||||
verifyReferenceAddresses(address, referenceAddresses);
|
verifyReferenceAddresses(address, referenceAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteReferencesFromTable() {
|
||||||
|
|
||||||
|
// 01002cf5 - ghidra
|
||||||
|
Address address = addr(0x01002cf5);
|
||||||
|
int functionNameColumn = 15;
|
||||||
|
goTo(address, "Function Signature", functionNameColumn);
|
||||||
|
|
||||||
|
search();
|
||||||
|
|
||||||
|
List<Address> referenceAddresses = getResultAddresses();
|
||||||
|
int referenceCount = referenceAddresses.size();
|
||||||
|
|
||||||
|
DockingActionIf deleteAction =
|
||||||
|
getAction(tool, locationReferencesPlugin.getName(), "Delete Reference");
|
||||||
|
LocationReferencesProvider provider = getResultsProvider();
|
||||||
|
assertFalse(isEnabled(deleteAction, provider));
|
||||||
|
|
||||||
|
selectRows(0);
|
||||||
|
assertTrue(isEnabled(deleteAction, provider));
|
||||||
|
performAction(deleteAction, provider, true);
|
||||||
|
|
||||||
|
referenceAddresses = getResultAddresses();
|
||||||
|
int updatedReferenceCount = referenceAddresses.size();
|
||||||
|
assertEquals(referenceCount - 1, updatedReferenceCount);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLabelLocationDescriptor() throws Exception {
|
public void testLabelLocationDescriptor() throws Exception {
|
||||||
|
|
||||||
|
@ -369,6 +401,19 @@ public class LocationReferencesPlugin3Test extends AbstractLocationReferencesTes
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
private void selectRows(int... rows) {
|
||||||
|
|
||||||
|
LocationReferencesProvider provider = getResultsProvider();
|
||||||
|
runSwing(() -> {
|
||||||
|
GTable gTable = provider.getTable();
|
||||||
|
ListSelectionModel selectionModel = gTable.getSelectionModel();
|
||||||
|
for (int row : rows) {
|
||||||
|
selectionModel.addSelectionInterval(row, row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waitForSwing();
|
||||||
|
}
|
||||||
|
|
||||||
private void createString_CallStructure(String addressString) throws Exception {
|
private void createString_CallStructure(String addressString) throws Exception {
|
||||||
// String
|
// String
|
||||||
// "call_structure_A: %s\n",00
|
// "call_structure_A: %s\n",00
|
||||||
|
|
|
@ -122,8 +122,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
int row = findRow("ghidra");
|
int row = findRow("ghidra");
|
||||||
|
|
||||||
TableModel model = symbolTable.getModel();
|
TableModel model = symbolTable.getModel();
|
||||||
doubleClick(symbolTable, row, SymbolTableModel.LOCATION_COL);
|
doubleClick(symbolTable, row, AbstractSymbolTableModel.LOCATION_COL);
|
||||||
ProgramLocation pl = getProgramLocation(row, SymbolTableModel.LOCATION_COL, model);
|
ProgramLocation pl = getProgramLocation(row, AbstractSymbolTableModel.LOCATION_COL, model);
|
||||||
assertEquals(pl.getAddress(), cbPlugin.getCurrentAddress());
|
assertEquals(pl.getAddress(), cbPlugin.getCurrentAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testSortingLabelColumn() throws Exception {
|
public void testSortingLabelColumn() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LABEL_COL);
|
sortAscending(AbstractSymbolTableModel.LABEL_COL);
|
||||||
|
|
||||||
TableModel model = symbolTable.getModel();
|
TableModel model = symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -141,7 +141,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue("row " + i + " not sorted correctly", (compare < 0 || compare == 0));
|
assertTrue("row " + i + " not sorted correctly", (compare < 0 || compare == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
sortDescending(SymbolTableModel.LABEL_COL);
|
sortDescending(AbstractSymbolTableModel.LABEL_COL);
|
||||||
|
|
||||||
model = symbolTable.getModel();
|
model = symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -193,7 +193,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testSortingAddressColumn() throws Exception {
|
public void testSortingAddressColumn() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LOCATION_COL);
|
sortAscending(AbstractSymbolTableModel.LOCATION_COL);
|
||||||
|
|
||||||
SymbolTableModel model = (SymbolTableModel) symbolTable.getModel();
|
SymbolTableModel model = (SymbolTableModel) symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -202,7 +202,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(loc1.compareTo(loc2) <= 0);
|
assertTrue(loc1.compareTo(loc2) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sortDescending(SymbolTableModel.LOCATION_COL);
|
sortDescending(AbstractSymbolTableModel.LOCATION_COL);
|
||||||
|
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
AddressBasedLocation loc1 = getLocation(i);
|
AddressBasedLocation loc1 = getLocation(i);
|
||||||
|
@ -215,7 +215,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testSortingReferenceColumn() throws Exception {
|
public void testSortingReferenceColumn() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.REFS_COL);
|
sortAscending(AbstractSymbolTableModel.REFS_COL);
|
||||||
|
|
||||||
TableModel model = symbolTable.getModel();
|
TableModel model = symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -224,7 +224,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(refs1.compareTo(refs2) <= 0);
|
assertTrue(refs1.compareTo(refs2) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sortDescending(SymbolTableModel.REFS_COL);
|
sortDescending(AbstractSymbolTableModel.REFS_COL);
|
||||||
|
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
Integer refs1 = getRefCount(i);
|
Integer refs1 = getRefCount(i);
|
||||||
|
@ -325,12 +325,10 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testEditing() throws Exception {
|
public void testEditing() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
waitForNotBusy();
|
|
||||||
|
|
||||||
String symbolName = "ghidra";
|
String symbolName = "ghidra";
|
||||||
int row = findRow(symbolName);
|
int row = findRow(symbolName);
|
||||||
|
|
||||||
doubleClick(symbolTable, row, SymbolTableModel.LABEL_COL);
|
doubleClick(symbolTable, row, AbstractSymbolTableModel.LABEL_COL);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
assertTrue(symbolTable.isEditing());
|
assertTrue(symbolTable.isEditing());
|
||||||
|
|
||||||
|
@ -361,7 +359,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
String symbolName = "ghidra";
|
String symbolName = "ghidra";
|
||||||
int row = findRow(symbolName);
|
int row = findRow(symbolName);
|
||||||
|
|
||||||
doubleClick(symbolTable, row, SymbolTableModel.LABEL_COL);
|
doubleClick(symbolTable, row, AbstractSymbolTableModel.LABEL_COL);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
assertTrue(symbolTable.isEditing());
|
assertTrue(symbolTable.isEditing());
|
||||||
|
|
||||||
|
@ -782,6 +780,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Address from = sample.getNewAddress(0x01004aea);
|
Address from = sample.getNewAddress(0x01004aea);
|
||||||
Address to = sample.getNewAddress(0x50);
|
Address to = sample.getNewAddress(0x50);
|
||||||
Reference ref = getReference(from, to);
|
Reference ref = getReference(from, to);
|
||||||
|
assertNotNull(ref);
|
||||||
|
|
||||||
tx(program, () -> {
|
tx(program, () -> {
|
||||||
ReferenceManager manager = program.getReferenceManager();
|
ReferenceManager manager = program.getReferenceManager();
|
||||||
|
@ -847,7 +846,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
/************** LABEL **********************/
|
/************** LABEL **********************/
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LABEL_COL);
|
sortAscending(AbstractSymbolTableModel.LABEL_COL);
|
||||||
|
|
||||||
TableModel model = symbolTable.getModel();
|
TableModel model = symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -860,7 +859,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
/************** ADDRESS **********************/
|
/************** ADDRESS **********************/
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LOCATION_COL);
|
sortAscending(AbstractSymbolTableModel.LOCATION_COL);
|
||||||
|
|
||||||
model = symbolTable.getModel();
|
model = symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -874,7 +873,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
/************** REFERENCES **********************/
|
/************** REFERENCES **********************/
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.REFS_COL);
|
sortAscending(AbstractSymbolTableModel.REFS_COL);
|
||||||
|
|
||||||
model = symbolTable.getModel();
|
model = symbolTable.getModel();
|
||||||
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
for (int i = 0; i < model.getRowCount() - 1; ++i) {
|
||||||
|
@ -893,7 +892,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
showReferencesTable();
|
showReferencesTable();
|
||||||
|
|
||||||
singleClick(symbolTable, findRow("ghidra", "Global"), SymbolTableModel.LABEL_COL);
|
singleClick(symbolTable, findRow("ghidra", "Global"), AbstractSymbolTableModel.LABEL_COL);
|
||||||
|
|
||||||
/*****************************/
|
/*****************************/
|
||||||
|
|
||||||
|
@ -1003,7 +1002,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
deleteText(textField);
|
deleteText(textField);
|
||||||
|
|
||||||
// sort on a different column to trigger the other kind of filtering
|
// sort on a different column to trigger the other kind of filtering
|
||||||
sortAscending(SymbolTableModel.REFS_COL);
|
sortAscending(AbstractSymbolTableModel.REFS_COL);
|
||||||
|
|
||||||
text = "_";
|
text = "_";
|
||||||
myTypeText(textField, text);
|
myTypeText(textField, text);
|
||||||
|
@ -1074,7 +1073,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
deleteText(textField);
|
deleteText(textField);
|
||||||
|
|
||||||
// sort on a different column to trigger the other kind of filtering
|
// sort on a different column to trigger the other kind of filtering
|
||||||
sortAscending(SymbolTableModel.LOCATION_COL);
|
sortAscending(AbstractSymbolTableModel.LOCATION_COL);
|
||||||
|
|
||||||
text = "_";
|
text = "_";
|
||||||
myTypeText(textField, text);
|
myTypeText(textField, text);
|
||||||
|
@ -1140,7 +1139,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReferenceRemvoed_ReferenceToDynamicSymbol() throws Exception {
|
public void testReferenceRemoved_ReferenceToDynamicSymbol() throws Exception {
|
||||||
|
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
|
@ -1153,10 +1152,63 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertFalse(row > -1);
|
assertFalse(row > -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteReference() throws Exception {
|
||||||
|
|
||||||
|
openProgram("sample");
|
||||||
|
|
||||||
|
showReferencesTable();
|
||||||
|
ReferenceProvider referencesProvider = waitForComponentProvider(ReferenceProvider.class);
|
||||||
|
|
||||||
|
// pick symbol with refs
|
||||||
|
selectRow("ghidra");
|
||||||
|
|
||||||
|
int refCount = referenceTable.getModel().getRowCount();
|
||||||
|
assertReference("01004101", "00000052", true);
|
||||||
|
|
||||||
|
DockingActionIf deleteRefsAction =
|
||||||
|
getAction(tool, plugin.getName(), "Delete Reference");
|
||||||
|
assertFalse(isEnabled(deleteRefsAction, referencesProvider));
|
||||||
|
|
||||||
|
selectRef(referenceTable, "01004101", "00000052");
|
||||||
|
assertTrue(isEnabled(deleteRefsAction, referencesProvider));
|
||||||
|
|
||||||
|
performAction(deleteRefsAction, referencesProvider, true);
|
||||||
|
assertEquals(refCount - 1, referenceTable.getModel().getRowCount());
|
||||||
|
assertReference("01004101", "00000052", false);
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Helper methods
|
// Helper methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void selectRef(GTable table, String from, String to) throws Exception {
|
||||||
|
|
||||||
|
Reference ref = getReference(addr(from), addr(to));
|
||||||
|
int viewRow = runSwing(() -> {
|
||||||
|
RowObjectTableModel<Reference> model =
|
||||||
|
(RowObjectTableModel<Reference>) table.getModel();
|
||||||
|
return model.getRowIndex(ref);
|
||||||
|
});
|
||||||
|
|
||||||
|
selectRows(table, viewRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertReference(String fromString, String toString, boolean exists) {
|
||||||
|
|
||||||
|
Address from = addr(fromString);
|
||||||
|
Address to = addr(toString);
|
||||||
|
Reference ref = getReference(from, to);
|
||||||
|
if (exists) {
|
||||||
|
assertNotNull(ref);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertNull(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private Reference getReference(Address from, Address to) {
|
private Reference getReference(Address from, Address to) {
|
||||||
|
|
||||||
ReferenceManager rm = program.getReferenceManager();
|
ReferenceManager rm = program.getReferenceManager();
|
||||||
|
@ -1167,7 +1219,6 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fail("Did not find expected mem reference between " + from + " and " + to);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1234,6 +1285,11 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void selectRow(String symbolName) {
|
||||||
|
int row = findRow(symbolName);
|
||||||
|
selectRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
private void selectRow(int row) {
|
private void selectRow(int row) {
|
||||||
selectRows(row, row);
|
selectRows(row, row);
|
||||||
|
|
||||||
|
@ -1243,18 +1299,22 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectRows(int... rows) {
|
private void selectRows(int... rows) {
|
||||||
|
selectRows(symbolTable, rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectRows(JTable table, int... rows) {
|
||||||
assertNotNull(rows);
|
assertNotNull(rows);
|
||||||
assertTrue("Must have at least one row to select", rows.length > 0);
|
assertTrue("Must have at least one row to select", rows.length > 0);
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
|
|
||||||
symbolTable.clearSelection();
|
table.clearSelection();
|
||||||
|
|
||||||
for (int row : rows) {
|
for (int row : rows) {
|
||||||
symbolTable.addRowSelectionInterval(row, row);
|
table.addRowSelectionInterval(row, row);
|
||||||
}
|
}
|
||||||
int end = rows[rows.length - 1];
|
int end = rows[rows.length - 1];
|
||||||
Rectangle rect = symbolTable.getCellRect(end, 0, true);
|
Rectangle rect = table.getCellRect(end, 0, true);
|
||||||
symbolTable.scrollRectToVisible(rect);
|
table.scrollRectToVisible(rect);
|
||||||
});
|
});
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
@ -1326,14 +1386,15 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private Integer getRefCount(int row) {
|
private Integer getRefCount(int row) {
|
||||||
Integer count =
|
Integer count =
|
||||||
runSwing(() -> (Integer) symbolModel.getValueAt(row, SymbolTableModel.REFS_COL));
|
runSwing(
|
||||||
|
() -> (Integer) symbolModel.getValueAt(row, AbstractSymbolTableModel.REFS_COL));
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressBasedLocation getLocation(int row) {
|
private AddressBasedLocation getLocation(int row) {
|
||||||
AddressBasedLocation location =
|
AddressBasedLocation location =
|
||||||
runSwing(() -> (AddressBasedLocation) symbolModel.getValueAt(row,
|
runSwing(() -> (AddressBasedLocation) symbolModel.getValueAt(row,
|
||||||
SymbolTableModel.LOCATION_COL));
|
AbstractSymbolTableModel.LOCATION_COL));
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1650,16 +1711,17 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
waitForNotBusy();
|
waitForNotBusy();
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LABEL_COL);
|
sortAscending(AbstractSymbolTableModel.LABEL_COL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showReferencesTable() {
|
private void showReferencesTable() throws Exception {
|
||||||
|
|
||||||
performAction(viewRefAction, true);
|
performAction(viewRefAction, true);
|
||||||
ReferenceProvider referencesProvider = waitForComponentProvider(ReferenceProvider.class);
|
ReferenceProvider referencesProvider = waitForComponentProvider(ReferenceProvider.class);
|
||||||
referenceTable =
|
referenceTable =
|
||||||
(GTable) findComponentByName(referencesProvider.getComponent(), "Reference Table");
|
(GTable) findComponentByName(referencesProvider.getComponent(), "Reference Table");
|
||||||
assertNotNull(referenceTable);
|
assertNotNull(referenceTable);
|
||||||
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -17,6 +17,9 @@ package ghidra.app.util.viewer.field;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
@ -43,6 +46,7 @@ import ghidra.program.util.XRefHeaderFieldLocation;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.table.GhidraProgramTableModel;
|
import ghidra.util.table.GhidraProgramTableModel;
|
||||||
|
import ghidra.util.table.GhidraTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that references are displayed correctly when selecting the XRef field in
|
* Tests that references are displayed correctly when selecting the XRef field in
|
||||||
|
@ -162,6 +166,27 @@ public class XrefViewerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(3, model.getRowCount());
|
assertEquals(3, model.getRowCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteReferencesFromTable() {
|
||||||
|
|
||||||
|
doubleClickXRef("1001005", "XREF[1]: ");
|
||||||
|
ComponentProvider comp = waitForComponentProvider(TableComponentProvider.class);
|
||||||
|
TableComponentProvider<?> table = (TableComponentProvider<?>) comp;
|
||||||
|
assertEquals(1, table.getModel().getRowCount());
|
||||||
|
assertReference("01001009", "01001005", true);
|
||||||
|
|
||||||
|
DockingActionIf deleteAction = getAction(tool, "TableServicePlugin", "Delete Reference");
|
||||||
|
assertFalse(runSwing(() -> deleteAction.isEnabled()));
|
||||||
|
|
||||||
|
selectRow(table, 0);
|
||||||
|
assertTrue(runSwing(() -> deleteAction.isEnabled()));
|
||||||
|
|
||||||
|
performAction(deleteAction, table, true);
|
||||||
|
|
||||||
|
assertEquals(0, table.getModel().getRowCount());
|
||||||
|
assertReference("01001009", "01001005", false);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testViewReferencesShowThunkXrefs_FromThunk() {
|
public void testViewReferencesShowThunkXrefs_FromThunk() {
|
||||||
|
|
||||||
|
@ -218,6 +243,42 @@ public class XrefViewerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
private void assertReference(String fromString, String toString, boolean exists) {
|
||||||
|
|
||||||
|
Address from = addr(fromString);
|
||||||
|
Address to = addr(toString);
|
||||||
|
List<Reference> refs = getReferences(to);
|
||||||
|
if (exists) {
|
||||||
|
assertEquals(1, refs.size());
|
||||||
|
Reference ref = refs.get(0);
|
||||||
|
Address refFrom = ref.getFromAddress();
|
||||||
|
Address refTo = ref.getToAddress();
|
||||||
|
assertEquals(from, refFrom);
|
||||||
|
assertEquals(to, refTo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertEquals(0, refs.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Reference> getReferences(Address to) {
|
||||||
|
List<Reference> refs = new ArrayList<>();
|
||||||
|
ReferenceManager rm = program.getReferenceManager();
|
||||||
|
ReferenceIterator it = rm.getReferencesTo(to);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
refs.add(it.next());
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectRow(TableComponentProvider<?> provider, int row) {
|
||||||
|
runSwing(() -> {
|
||||||
|
GhidraTable gTable = provider.getTable();
|
||||||
|
gTable.selectRow(row);
|
||||||
|
});
|
||||||
|
waitForSwing();
|
||||||
|
}
|
||||||
|
|
||||||
private void createThunkFunction(String thunkAddressString, String thunkedAddressString) {
|
private void createThunkFunction(String thunkAddressString, String thunkedAddressString) {
|
||||||
|
|
||||||
Address thunkAddress = addr(thunkAddressString);
|
Address thunkAddress = addr(thunkAddressString);
|
||||||
|
|
|
@ -86,7 +86,10 @@ public class TaintSliceTreeProvider extends ComponentProviderAdapter
|
||||||
private GTree inTree;
|
private GTree inTree;
|
||||||
private GTree outTree;
|
private GTree outTree;
|
||||||
private boolean isPrimary;
|
private boolean isPrimary;
|
||||||
private enum Condition {IN, OUT, EITHER}
|
|
||||||
|
private enum Condition {
|
||||||
|
IN, OUT, EITHER
|
||||||
|
}
|
||||||
|
|
||||||
private SwingUpdateManager reloadUpdateManager = new SwingUpdateManager(500, () -> doUpdate());
|
private SwingUpdateManager reloadUpdateManager = new SwingUpdateManager(500, () -> doUpdate());
|
||||||
|
|
||||||
|
@ -286,12 +289,13 @@ public class TaintSliceTreeProvider extends ComponentProviderAdapter
|
||||||
//
|
//
|
||||||
// navigate incoming nodes on selection
|
// navigate incoming nodes on selection
|
||||||
//
|
//
|
||||||
navigationIncomingAction = new ToggleActionBuilder("Navigate Incoming Location Changes", ownerName)
|
navigationIncomingAction = new ToggleActionBuilder("Navigate on Incoming Location Changes", ownerName)
|
||||||
.description(HTMLUtilities.toHTML("Incoming Navigation" +
|
.description(HTMLUtilities.toHTML("Incoming Navigation" +
|
||||||
"<br><br>Toggle <b>On</b> - change the displayed " +
|
"<br><br>Toggle <b>On</b> - change the displayed " +
|
||||||
"function on Listing navigation events" +
|
"function on Listing navigation events" +
|
||||||
"<br>Toggled <b>Off</b> - don't change the displayed function on Listing navigation events"))
|
"<br>Toggled <b>Off</b> - don't change the displayed function on Listing navigation events"))
|
||||||
.helpLocation(new HelpLocation(ownerName, "Call_Tree_Action_Incoming_Navigation"))
|
.helpLocation(new HelpLocation(ownerName, "Call_Tree_Action_Incoming_Navigation"))
|
||||||
|
.sharedKeyBinding()
|
||||||
.toolBarGroup(navigationOptionsToolbarGroup, "2")
|
.toolBarGroup(navigationOptionsToolbarGroup, "2")
|
||||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
||||||
.selected(isPrimary)
|
.selected(isPrimary)
|
||||||
|
@ -305,7 +309,6 @@ public class TaintSliceTreeProvider extends ComponentProviderAdapter
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isValidSelection(ActionContext context) {
|
private boolean isValidSelection(ActionContext context) {
|
||||||
Object contextObject = context.getContextObject();
|
Object contextObject = context.getContextObject();
|
||||||
GTree gTree = (GTree) contextObject;
|
GTree gTree = (GTree) contextObject;
|
||||||
|
@ -390,7 +393,6 @@ public class TaintSliceTreeProvider extends ComponentProviderAdapter
|
||||||
return isValidContextMult(context, Condition.OUT);
|
return isValidContextMult(context, Condition.OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void expandToDepth(ActionContext context) {
|
private void expandToDepth(ActionContext context) {
|
||||||
Object contextObject = context.getContextObject();
|
Object contextObject = context.getContextObject();
|
||||||
GTree gTree = (GTree) contextObject;
|
GTree gTree = (GTree) contextObject;
|
||||||
|
|
|
@ -112,9 +112,12 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
|
||||||
.build();
|
.build();
|
||||||
addAction(eventAction);
|
addAction(eventAction);
|
||||||
|
|
||||||
toggleFollowFocusAction = new ToggleActionBuilder("Follow Focus", ACTION_OWNER)
|
toggleFollowFocusAction =
|
||||||
|
new ToggleActionBuilder("Navigate on Incoming Location Changes", ACTION_OWNER)
|
||||||
|
.sharedKeyBinding()
|
||||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
||||||
.description("On causes component table to constant repopulate as focus changes")
|
.description(
|
||||||
|
"On causes component table to constant repopulate as focus changes")
|
||||||
.onAction(c -> toggleFollowFocus())
|
.onAction(c -> toggleFollowFocus())
|
||||||
.selected(true)
|
.selected(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -36,17 +36,17 @@ public interface Reference extends Comparable<Reference> {
|
||||||
public static final int OTHER = -2;
|
public static final int OTHER = -2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the address of the codeunit that is making the reference.
|
* {@return Get the address of the code unit that is making the reference.}
|
||||||
*/
|
*/
|
||||||
public Address getFromAddress();
|
public Address getFromAddress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the "to" address for this reference.
|
* {@return Get the "to" address for this reference.}
|
||||||
*/
|
*/
|
||||||
public Address getToAddress();
|
public Address getToAddress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether this reference is marked as primary.
|
* {@return Return whether this reference is marked as primary.}
|
||||||
*/
|
*/
|
||||||
public boolean isPrimary();
|
public boolean isPrimary();
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public interface Reference extends Comparable<Reference> {
|
||||||
public long getSymbolID();
|
public long getSymbolID();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of reference being made.
|
* {@return Get the type of reference being made.}
|
||||||
*/
|
*/
|
||||||
public RefType getReferenceType();
|
public RefType getReferenceType();
|
||||||
|
|
||||||
|
@ -71,50 +71,50 @@ public interface Reference extends Comparable<Reference> {
|
||||||
public int getOperandIndex();
|
public int getOperandIndex();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if this reference is on the Mnemonic and not on an operand
|
* {@return Return true if this reference is on the Mnemonic and not on an operand.}
|
||||||
*/
|
*/
|
||||||
public boolean isMnemonicReference();
|
public boolean isMnemonicReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if this reference is on an operand and not on the Mnemonic.
|
* {@return Return true if this reference is on an operand and not on the Mnemonic.}
|
||||||
*/
|
*/
|
||||||
public boolean isOperandReference();
|
public boolean isOperandReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference is an instance of StackReference and
|
* {@return Returns true if this reference is an instance of StackReference and
|
||||||
* refers to a stack location.
|
* refers to a stack location.}
|
||||||
*/
|
*/
|
||||||
public boolean isStackReference();
|
public boolean isStackReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference is an instance of ExternalReference.
|
* {@return Returns true if this reference is an instance of ExternalReference.}
|
||||||
*/
|
*/
|
||||||
public boolean isExternalReference();
|
public boolean isExternalReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference is an instance of EntryReference.
|
* {@return Returns true if this reference is an instance of EntryReference.}
|
||||||
*/
|
*/
|
||||||
public boolean isEntryPointReference();
|
public boolean isEntryPointReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference to an address in the programs memory
|
* {@return Returns true if this reference to an address in the programs memory
|
||||||
* space. This includes offset and shifted references.
|
* space. This includes offset and shifted references.}
|
||||||
*/
|
*/
|
||||||
public boolean isMemoryReference();
|
public boolean isMemoryReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference to an address in the programs register
|
* {@return Returns true if this reference to an address in the programs register
|
||||||
* space.
|
* space.}
|
||||||
*/
|
*/
|
||||||
public boolean isRegisterReference();
|
public boolean isRegisterReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference is an instance of OffsetReference.
|
* {@return Returns true if this reference is an instance of OffsetReference.}
|
||||||
*/
|
*/
|
||||||
public boolean isOffsetReference();
|
public boolean isOffsetReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this reference is an instance of ShiftedReference.
|
* {@return Returns true if this reference is an instance of ShiftedReference.}
|
||||||
*/
|
*/
|
||||||
public boolean isShiftedReference();
|
public boolean isShiftedReference();
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ public interface ReferenceManager {
|
||||||
* @param source the source of this reference
|
* @param source the source of this reference
|
||||||
* @param type reference type - how the location is being referenced
|
* @param type reference type - how the location is being referenced
|
||||||
* @return external reference
|
* @return external reference
|
||||||
* @throws InvalidInputException
|
* @throws InvalidInputException if the input is invalid
|
||||||
*/
|
*/
|
||||||
public Reference addExternalReference(Address fromAddr, int opIndex, ExternalLocation location,
|
public Reference addExternalReference(Address fromAddr, int opIndex, ExternalLocation location,
|
||||||
SourceType source, RefType type) throws InvalidInputException;
|
SourceType source, RefType type) throws InvalidInputException;
|
||||||
|
@ -385,11 +385,13 @@ public interface ReferenceManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of references for "to" addresses.
|
* Return the number of references for "to" addresses.
|
||||||
|
* @return the number of references for "to" addresses.
|
||||||
*/
|
*/
|
||||||
public int getReferenceDestinationCount();
|
public int getReferenceDestinationCount();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of references for "from" addresses.
|
* Return the number of references for "from" addresses.
|
||||||
|
* @return the number of references for "from" addresses.
|
||||||
*/
|
*/
|
||||||
public int getReferenceSourceCount();
|
public int getReferenceSourceCount();
|
||||||
|
|
||||||
|
@ -401,7 +403,7 @@ public interface ReferenceManager {
|
||||||
public boolean hasReferencesTo(Address toAddr);
|
public boolean hasReferencesTo(Address toAddr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uodate the reference type on a memory reference.
|
* Update the reference type on a memory reference.
|
||||||
* @param ref reference to be updated
|
* @param ref reference to be updated
|
||||||
* @param refType new reference type
|
* @param refType new reference type
|
||||||
* @return updated reference
|
* @return updated reference
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue