mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-30 16:47:43 +08:00
GP-6692 - Added an option to limit the number of symbols displayed at an address
This commit is contained in:
@@ -112,14 +112,18 @@
|
|||||||
certain Navigation behaviors.</P>
|
certain Navigation behaviors.</P>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<H3>Xrefs</H3>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
|
||||||
<A name="Show_Xrefs"></A>
|
<A name="Show_Xrefs"></A>
|
||||||
<P>In the XRef field, sometimes there are too many addresses to display so the field will
|
<P>In the XRef field, sometimes there are too many addresses to display so the field will
|
||||||
display "[more]" to indicate that one or more cross-reference addresses are not shown.</P>
|
display "[more]" to indicate that one or more cross-reference addresses are not shown.</P>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P><IMG border="0" src="help/shared/tip.png" alt=""> Double-clicking on the "<FONT color=
|
<P><IMG border="0" src="help/shared/tip.png" alt=""> Double-clicking on the "<FONT color=
|
||||||
"green"><TT>XREF[n]:</TT></FONT> or <FONT><TT>[more]</TT></FONT>" text will cause a
|
"green"><TT>XREF[n]:</TT></FONT> or <FONT color="green"><TT>[more]</TT></FONT>"
|
||||||
dialog containing all the Xrefs to appear.</P>
|
text will cause a dialog containing all the Xrefs to appear.</P>
|
||||||
<P>
|
<P>
|
||||||
This differs from the <A href=
|
This differs from the <A href=
|
||||||
"help/topics/LocationReferencesPlugin/Location_References.html#LocationReferencesPlugin">
|
"help/topics/LocationReferencesPlugin/Location_References.html#LocationReferencesPlugin">
|
||||||
@@ -178,6 +182,51 @@
|
|||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3>Labels</H3>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
|
||||||
|
<A name="Show_Labels"></A>
|
||||||
|
<P>In the Labels field, sometimes there are too many labels to display so the field will
|
||||||
|
display "[more]" to indicate that one or more labels are not shown.</P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><IMG border="0" src="help/shared/tip.png" alt=""> Double-clicking on the
|
||||||
|
"<FONT><TT>[more]</TT></FONT>" text will cause a dialog containing all the
|
||||||
|
labels to appear.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3><A NAME="Refresh_Labels"></A>Refresh
|
||||||
|
<IMG border="0" src="Icons.REFRESH_ICON" alt=""></H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
This action will refresh the table of labels. This table does not respond to
|
||||||
|
program changes, such as adding or deleting lables. Thus, if you would like
|
||||||
|
the table to update to the current state of the program, then you can press
|
||||||
|
the refresh button.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
<H3><A NAME="Delete_Label"></A>Delete Label
|
||||||
|
<IMG border="0" src="Icons.DELETE_ICON" alt=""></H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
This action will delete all selected labels 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>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|||||||
+4
@@ -848,6 +848,10 @@
|
|||||||
this off, the function name will only appear in the function signature. If it's on, the
|
this off, the function name will only appear in the function signature. If it's on, the
|
||||||
function name will also appear as a label below the function header.</P>
|
function name will also appear as a label below the function header.</P>
|
||||||
|
|
||||||
|
<P><B>Maximum Number of Labels to Display -</B> Sets the maximum number of labels to
|
||||||
|
display. If the max is reached, a '[more]' field will appear. You can double-click that
|
||||||
|
field to see all labels at that address.</P>
|
||||||
|
|
||||||
<P><B>Display Non-local Namespace -</B> Select this option to prepend the namespace to all
|
<P><B>Display Non-local Namespace -</B> Select this option to prepend the namespace to all
|
||||||
labels that are not in the current Function's namespace. Currently, this would only
|
labels that are not in the current Function's namespace. Currently, this would only
|
||||||
affect a label that is not global, but is in a namespace other than the function that
|
affect a label that is not global, but is in a namespace other than the function that
|
||||||
|
|||||||
@@ -254,20 +254,12 @@
|
|||||||
the address using the <I>Set Label</I> dialog.</P>
|
the address using the <I>Set Label</I> dialog.</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<TABLE x-use-null-cells="" width="100%">
|
|
||||||
<TBODY>
|
|
||||||
<TR>
|
|
||||||
<TD align="center" width="100%"><IMG src="images/SetLabel.png" border="0"></TD>
|
|
||||||
</TR>
|
|
||||||
</TBODY>
|
|
||||||
</TABLE><BR>
|
|
||||||
<BR>
|
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<H3>Label</H3>
|
<H3>Label</H3>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The list in the combo box will show all symbols associated with the address shown in the
|
<P>The drop-down list will show all symbols associated with the address shown in the
|
||||||
dialog title. Choosing a label from the list will cause that symbol to be associated with
|
dialog title. Choosing a label from the list will cause that symbol to be associated with
|
||||||
the operand reference being modified. Typing in a new name will cause a new symbol to be
|
the operand reference being modified. Typing in a new name will cause a new symbol to be
|
||||||
created at the target address before associating it with the operand reference.</P>
|
created at the target address before associating it with the operand reference.</P>
|
||||||
|
|||||||
+12
@@ -45,6 +45,15 @@
|
|||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3><A NAME="Set_Primary">Set Primary</A></H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
Sets the selected symbol to be the primary symbol at the symbol's address. The primary
|
||||||
|
symbol is the symbol displayed by default for the 'from' side of an xref.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
@@ -60,6 +69,9 @@
|
|||||||
</LI>
|
</LI>
|
||||||
<LI>
|
<LI>
|
||||||
<A href="help/topics/SymbolTreePlugin/SymbolTree.htm">Symbol Tree</A>
|
<A href="help/topics/SymbolTreePlugin/SymbolTree.htm">Symbol Tree</A>
|
||||||
|
</LI>
|
||||||
|
<LI>
|
||||||
|
<A href="help/topics/CodeBrowserPlugin/CodeBrowser.htm#Show_Labels">Show All Labels</A>
|
||||||
</LI>
|
</LI>
|
||||||
</UL>
|
</UL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|||||||
@@ -102,10 +102,6 @@ public class LabelMgrPlugin extends Plugin {
|
|||||||
return new EditFieldNameDialog("", tool);
|
return new EditFieldNameDialog("", tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
OperandLabelDialog getOperandLabelDialog() {
|
|
||||||
return new OperandLabelDialog(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the label or alias that the cursor is over from the current label field. If an
|
* Removes the label or alias that the cursor is over from the current label field. If an
|
||||||
* exception is caught during the removal of the label or alias, a message is written to the
|
* exception is caught during the removal of the label or alias, a message is written to the
|
||||||
@@ -171,17 +167,18 @@ public class LabelMgrPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setOperandLabelCallback(ListingActionContext context) {
|
void setOperandLabelCallback(ListingActionContext context) {
|
||||||
getOperandLabelDialog().setOperandLabel(context);
|
|
||||||
|
SymbolChooserDialog dialog = new SymbolChooserDialog(this, context);
|
||||||
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol getSymbol(ListingActionContext context) {
|
Symbol getSymbol(ListingActionContext context) {
|
||||||
ProgramLocation location = context.getLocation();
|
ProgramLocation location = context.getLocation();
|
||||||
if (location instanceof LabelFieldLocation) {
|
if (location instanceof LabelFieldLocation lfl) {
|
||||||
LabelFieldLocation lfl = (LabelFieldLocation) location;
|
|
||||||
return lfl.getSymbol();
|
return lfl.getSymbol();
|
||||||
}
|
}
|
||||||
else if (location instanceof OperandFieldLocation) {
|
else if (location instanceof OperandFieldLocation ofl) {
|
||||||
VariableOffset variableOffset = ((OperandFieldLocation) location).getVariableOffset();
|
VariableOffset variableOffset = ofl.getVariableOffset();
|
||||||
if (variableOffset != null) {
|
if (variableOffset != null) {
|
||||||
Variable var = variableOffset.getVariable();
|
Variable var = variableOffset.getVariable();
|
||||||
if (var != null) {
|
if (var != null) {
|
||||||
|
|||||||
-178
@@ -1,178 +0,0 @@
|
|||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.app.plugin.core.label;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
import docking.DialogComponentProvider;
|
|
||||||
import docking.widgets.combobox.GhidraComboBox;
|
|
||||||
import docking.widgets.label.GDLabel;
|
|
||||||
import ghidra.app.cmd.label.AddLabelCmd;
|
|
||||||
import ghidra.app.cmd.refs.AssociateSymbolCmd;
|
|
||||||
import ghidra.app.context.ListingActionContext;
|
|
||||||
import ghidra.app.util.HelpTopics;
|
|
||||||
import ghidra.framework.cmd.CompoundCmd;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.model.symbol.*;
|
|
||||||
import ghidra.program.util.OperandFieldLocation;
|
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
import ghidra.util.layout.PairLayout;
|
|
||||||
|
|
||||||
public class OperandLabelDialog extends DialogComponentProvider {
|
|
||||||
|
|
||||||
private JLabel label;
|
|
||||||
private GhidraComboBox<String> myChoice;
|
|
||||||
private LabelMgrPlugin plugin;
|
|
||||||
private ListingActionContext programActionContext;
|
|
||||||
|
|
||||||
public OperandLabelDialog(LabelMgrPlugin plugin) {
|
|
||||||
super("");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setHelpLocation(new HelpLocation(HelpTopics.LABEL, "OperandLabelDialog"));
|
|
||||||
|
|
||||||
addWorkPanel(buildMainPanel());
|
|
||||||
addOKButton();
|
|
||||||
addCancelButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the Main panel for the dialog here.
|
|
||||||
* @return JPanel the completed Main Panel
|
|
||||||
*/
|
|
||||||
protected JPanel buildMainPanel() {
|
|
||||||
JPanel mainPanel = new JPanel(new PairLayout(5, 5));
|
|
||||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
||||||
|
|
||||||
label = new GDLabel("Label: ");
|
|
||||||
myChoice = new GhidraComboBox<>();
|
|
||||||
myChoice.setName("MYCHOICE");
|
|
||||||
myChoice.setEditable(true);
|
|
||||||
|
|
||||||
myChoice.getAccessibleContext().setAccessibleName("My Choice");
|
|
||||||
mainPanel.add(label);
|
|
||||||
mainPanel.add(myChoice);
|
|
||||||
mainPanel.getAccessibleContext().setAccessibleName("Operand Label");
|
|
||||||
return mainPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method gets called when the user clicks on the Ok Button. The base
|
|
||||||
* class calls this method.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void okCallback() {
|
|
||||||
Program program = programActionContext.getProgram();
|
|
||||||
ProgramLocation loc = programActionContext.getLocation();
|
|
||||||
OperandFieldLocation location = (OperandFieldLocation) loc;
|
|
||||||
Symbol sym = getSymbol(programActionContext);
|
|
||||||
String currentLabel = myChoice.getText();
|
|
||||||
if (currentLabel.equals(sym.getName(true))) {
|
|
||||||
close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReferenceManager refMgr = program.getReferenceManager();
|
|
||||||
SymbolTable symTable = program.getSymbolTable();
|
|
||||||
int opIndex = location.getOperandIndex();
|
|
||||||
Address addr = location.getAddress();
|
|
||||||
Address symAddr = sym.getAddress();
|
|
||||||
Reference ref = refMgr.getReference(addr, symAddr, opIndex);
|
|
||||||
|
|
||||||
CompoundCmd<Program> cmd = new CompoundCmd<>("Set Label");
|
|
||||||
Namespace scope = null;
|
|
||||||
|
|
||||||
Symbol newSym = findSymbol(symTable, currentLabel, symAddr);
|
|
||||||
if (newSym == null) {
|
|
||||||
cmd.add(new AddLabelCmd(symAddr, currentLabel, SourceType.USER_DEFINED));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scope = newSym.getParentNamespace();
|
|
||||||
currentLabel = newSym.getName();
|
|
||||||
}
|
|
||||||
cmd.add(new AssociateSymbolCmd(ref, currentLabel, scope));
|
|
||||||
|
|
||||||
if (!plugin.getTool().execute(cmd, program)) {
|
|
||||||
setStatusText(cmd.getStatusMsg());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find and return the first symbol at the address with the given name. Since this is about
|
|
||||||
// the presentation at the call or jump instruction, it doesn't matter which symbol of the
|
|
||||||
// same name you pick.
|
|
||||||
private Symbol findSymbol(SymbolTable symTable, String currentLabel, Address symAddr) {
|
|
||||||
SymbolIterator symbols = symTable.getSymbolsAsIterator(symAddr);
|
|
||||||
for (Symbol symbol : symbols) {
|
|
||||||
if (symbol.getName(true).equals(currentLabel)) {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method gets called when the user clicks on the Cancel Button. The base
|
|
||||||
* class calls this method.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void cancelCallback() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
programActionContext = null;
|
|
||||||
super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOperandLabel(ListingActionContext context) {
|
|
||||||
programActionContext = context;
|
|
||||||
setStatusText("");
|
|
||||||
myChoice.clearModel();
|
|
||||||
|
|
||||||
Symbol s = getSymbol(context);
|
|
||||||
Symbol[] symbols = context.getProgram().getSymbolTable().getSymbols(s.getAddress());
|
|
||||||
for (Symbol symbol : symbols) {
|
|
||||||
myChoice.addToModel(symbol.getName(true));
|
|
||||||
}
|
|
||||||
setTitle("Set Label at " + s.getAddress());
|
|
||||||
myChoice.setSelectedItem(s.getName(true));
|
|
||||||
PluginTool tool = plugin.getTool();
|
|
||||||
tool.showDialog(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Symbol getSymbol(ListingActionContext context) {
|
|
||||||
Program program = context.getProgram();
|
|
||||||
OperandFieldLocation location = (OperandFieldLocation) context.getLocation();
|
|
||||||
|
|
||||||
Address address = location.getAddress();
|
|
||||||
int opIndex = location.getOperandIndex();
|
|
||||||
|
|
||||||
ReferenceManager refMgr = program.getReferenceManager();
|
|
||||||
|
|
||||||
Reference ref = refMgr.getPrimaryReferenceFrom(address, opIndex);
|
|
||||||
if (ref != null) {
|
|
||||||
SymbolTable st = program.getSymbolTable();
|
|
||||||
return st.getSymbol(ref);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-16
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,20 +26,12 @@ import ghidra.app.context.ListingActionContext;
|
|||||||
import ghidra.app.context.ListingContextAction;
|
import ghidra.app.context.ListingContextAction;
|
||||||
import ghidra.program.util.OperandFieldLocation;
|
import ghidra.program.util.OperandFieldLocation;
|
||||||
|
|
||||||
/**
|
|
||||||
* <CODE>AddLabelAction</CODE> allows the user to add a label.
|
|
||||||
*/
|
|
||||||
class SetOperandLabelAction extends ListingContextAction {
|
class SetOperandLabelAction extends ListingContextAction {
|
||||||
private LabelMgrPlugin plugin;
|
private LabelMgrPlugin plugin;
|
||||||
private static final String[] POPUP_PATH = { "Set Associated Label..." };
|
private static final String[] POPUP_PATH = { "Set Associated Label..." };
|
||||||
private static final KeyStroke KEYBINDING =
|
private static final KeyStroke KEYBINDING =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_MASK | InputEvent.ALT_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK);
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of the action.
|
|
||||||
*
|
|
||||||
* @param plugin Label Manager Plugin instance
|
|
||||||
*/
|
|
||||||
SetOperandLabelAction(LabelMgrPlugin plugin) {
|
SetOperandLabelAction(LabelMgrPlugin plugin) {
|
||||||
super("Set Operand Label", plugin.getName());
|
super("Set Operand Label", plugin.getName());
|
||||||
|
|
||||||
@@ -59,13 +51,8 @@ class SetOperandLabelAction extends ListingContextAction {
|
|||||||
plugin.isOnSymbol(context);
|
plugin.isOnSymbol(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method called when the action is invoked.
|
|
||||||
* @param ActionEvent details regarding the invocation of this action
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ListingActionContext context) {
|
public void actionPerformed(ListingActionContext context) {
|
||||||
plugin.setOperandLabelCallback(context);
|
plugin.setOperandLabelCallback(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+192
@@ -0,0 +1,192 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.label;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
import javax.swing.text.Document;
|
||||||
|
|
||||||
|
import docking.DialogComponentProvider;
|
||||||
|
import docking.DockingWindowManager;
|
||||||
|
import docking.widgets.DefaultDropDownSelectionDataModel;
|
||||||
|
import docking.widgets.DropDownSelectionTextField;
|
||||||
|
import docking.widgets.DropDownTextFieldDataModel.SearchMode;
|
||||||
|
import ghidra.app.cmd.label.AddLabelCmd;
|
||||||
|
import ghidra.app.cmd.refs.AssociateSymbolCmd;
|
||||||
|
import ghidra.app.context.ListingActionContext;
|
||||||
|
import ghidra.framework.cmd.CompoundCmd;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
|
import ghidra.program.util.OperandFieldLocation;
|
||||||
|
|
||||||
|
public class SymbolChooserDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
|
private List<String> names;
|
||||||
|
private DropDownSelectionTextField<String> textField;
|
||||||
|
|
||||||
|
private LabelMgrPlugin plugin;
|
||||||
|
private ListingActionContext context;
|
||||||
|
|
||||||
|
public SymbolChooserDialog(LabelMgrPlugin plugin, ListingActionContext context) {
|
||||||
|
super("Choose Label");
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
Symbol symbol = getOperandLabel();
|
||||||
|
Program program = context.getProgram();
|
||||||
|
SymbolTable st = program.getSymbolTable();
|
||||||
|
Address address = symbol.getAddress();
|
||||||
|
Symbol[] symbols = st.getSymbols(address);
|
||||||
|
|
||||||
|
names = Arrays.stream(symbols)
|
||||||
|
.map(s -> s.getName())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
addWorkPanel(buildWorkPanel());
|
||||||
|
|
||||||
|
addOKButton();
|
||||||
|
addCancelButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
DockingWindowManager.showDialog(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JComponent buildWorkPanel() {
|
||||||
|
|
||||||
|
DefaultDropDownSelectionDataModel<String> model =
|
||||||
|
DefaultDropDownSelectionDataModel.getStringModel(names);
|
||||||
|
textField = new DropDownSelectionTextField<>(model);
|
||||||
|
textField.setShowMatchingListOnEmptyText(true);
|
||||||
|
textField.setSearchMode(SearchMode.CONTAINS);
|
||||||
|
|
||||||
|
Document doc = textField.getDocument();
|
||||||
|
doc.addDocumentListener(new DocumentListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
updateOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
updateOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
updateOk();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
|
panel.add(textField, BorderLayout.NORTH);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOk() {
|
||||||
|
setOkEnabled(!textField.getText().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void okCallback() {
|
||||||
|
Program program = context.getProgram();
|
||||||
|
OperandFieldLocation location = (OperandFieldLocation) context.getLocation();
|
||||||
|
Symbol currentSymbol = getOperandLabel();
|
||||||
|
|
||||||
|
String newLabel = textField.getSelectedValue();
|
||||||
|
if (newLabel == null) {
|
||||||
|
setStatusText("Please choose a label");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newLabel.equals(currentSymbol.getName(true))) {
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
|
SymbolTable symTable = program.getSymbolTable();
|
||||||
|
int opIndex = location.getOperandIndex();
|
||||||
|
Address addr = location.getAddress();
|
||||||
|
Address symAddr = currentSymbol.getAddress();
|
||||||
|
Reference ref = refMgr.getReference(addr, symAddr, opIndex);
|
||||||
|
|
||||||
|
CompoundCmd<Program> cmd = new CompoundCmd<>("Set Label");
|
||||||
|
Namespace scope = null;
|
||||||
|
Symbol newSym = findSymbol(symTable, newLabel, symAddr);
|
||||||
|
if (newSym == null) {
|
||||||
|
cmd.add(new AddLabelCmd(symAddr, newLabel, SourceType.USER_DEFINED));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope = newSym.getParentNamespace();
|
||||||
|
newLabel = newSym.getName();
|
||||||
|
}
|
||||||
|
cmd.add(new AssociateSymbolCmd(ref, newLabel, scope));
|
||||||
|
|
||||||
|
if (!plugin.getTool().execute(cmd, program)) {
|
||||||
|
setStatusText(cmd.getStatusMsg());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find and return the first symbol at the address with the given name. Since this is about
|
||||||
|
// the presentation at the call or jump instruction, it doesn't matter which symbol of the
|
||||||
|
// same name you pick.
|
||||||
|
private Symbol findSymbol(SymbolTable symTable, String currentLabel, Address symAddr) {
|
||||||
|
SymbolIterator symbols = symTable.getSymbolsAsIterator(symAddr);
|
||||||
|
for (Symbol symbol : symbols) {
|
||||||
|
if (symbol.getName(true).equals(currentLabel)) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Symbol getOperandLabel() {
|
||||||
|
Program program = context.getProgram();
|
||||||
|
OperandFieldLocation location = (OperandFieldLocation) context.getLocation();
|
||||||
|
|
||||||
|
Address address = location.getAddress();
|
||||||
|
int opIndex = location.getOperandIndex();
|
||||||
|
|
||||||
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
|
|
||||||
|
Reference ref = refMgr.getPrimaryReferenceFrom(address, opIndex);
|
||||||
|
if (ref != null) {
|
||||||
|
SymbolTable st = program.getSymbolTable();
|
||||||
|
return st.getSymbol(ref);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getChoice() {
|
||||||
|
return textField.getSelectedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSelectedItem(String value) {
|
||||||
|
textField.setSelectedValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -291,7 +291,8 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
|||||||
goToExternalAction.setEnabled(false);
|
goToExternalAction.setEnabled(false);
|
||||||
|
|
||||||
CloneSymbolTreeAction cloneAction = new CloneSymbolTreeAction(plugin, this);
|
CloneSymbolTreeAction cloneAction = new CloneSymbolTreeAction(plugin, this);
|
||||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(plugin);
|
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(plugin.getTool());
|
||||||
|
SetSymbolPrimaryAction primaryAction = new SetSymbolPrimaryAction();
|
||||||
|
|
||||||
tool.addLocalAction(this, createImportAction);
|
tool.addLocalAction(this, createImportAction);
|
||||||
tool.addLocalAction(this, setExternalProgramAction);
|
tool.addLocalAction(this, setExternalProgramAction);
|
||||||
@@ -311,6 +312,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
|||||||
tool.addLocalAction(this, goToExternalAction);
|
tool.addLocalAction(this, goToExternalAction);
|
||||||
tool.addLocalAction(this, cloneAction);
|
tool.addLocalAction(this, cloneAction);
|
||||||
tool.addLocalAction(this, tableAction);
|
tool.addLocalAction(this, tableAction);
|
||||||
|
tool.addLocalAction(this, primaryAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|||||||
+48
-27
@@ -22,6 +22,7 @@ import javax.swing.table.TableColumnModel;
|
|||||||
|
|
||||||
import docking.action.KeyBindingType;
|
import docking.action.KeyBindingType;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
import docking.widgets.table.GTable;
|
import docking.widgets.table.GTable;
|
||||||
import docking.widgets.table.threaded.GThreadedTablePanel;
|
import docking.widgets.table.threaded.GThreadedTablePanel;
|
||||||
import ghidra.app.context.ProgramSymbolActionContext;
|
import ghidra.app.context.ProgramSymbolActionContext;
|
||||||
@@ -32,8 +33,8 @@ import ghidra.app.plugin.core.table.TableComponentProvider;
|
|||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.util.SymbolInspector;
|
import ghidra.app.util.SymbolInspector;
|
||||||
import ghidra.app.util.query.TableService;
|
import ghidra.app.util.query.TableService;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
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.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
@@ -43,11 +44,11 @@ import ghidra.util.table.GhidraThreadedTablePanel;
|
|||||||
|
|
||||||
public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
||||||
|
|
||||||
private Plugin plugin;
|
private ServiceProvider services;
|
||||||
|
|
||||||
public CreateSymbolTableAction(Plugin plugin) {
|
public CreateSymbolTableAction(ServiceProvider services) {
|
||||||
super("Create Table", plugin.getName(), KeyBindingType.SHARED);
|
super("Create Table", ToolConstants.SHARED_OWNER, KeyBindingType.SHARED);
|
||||||
this.plugin = plugin;
|
this.services = services;
|
||||||
|
|
||||||
setPopupMenuData(new MenuData(new String[] { "Create Table" },
|
setPopupMenuData(new MenuData(new String[] { "Create Table" },
|
||||||
SymbolTreeContextAction.MIDDLE_MENU_GROUP));
|
SymbolTreeContextAction.MIDDLE_MENU_GROUP));
|
||||||
@@ -72,25 +73,39 @@ public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
|||||||
rowObjects.add(new SymbolRowObject(symbol));
|
rowObjects.add(new SymbolRowObject(symbol));
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginTool tool = plugin.getTool();
|
|
||||||
Program program = context.getProgram();
|
Program program = context.getProgram();
|
||||||
TransientSymbolTableModel model = new TransientSymbolTableModel(tool, program, rowObjects);
|
TransientSymbolTableModel model =
|
||||||
|
new TransientSymbolTableModel(services, program, rowObjects);
|
||||||
|
showTransientTable(services, "Symbols", context.getProgram(), model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to show a table of symbols.
|
||||||
|
* @param services the service provider
|
||||||
|
* @param title the provider's title
|
||||||
|
* @param program the program
|
||||||
|
* @param model the model
|
||||||
|
* @return the new provider
|
||||||
|
*/
|
||||||
|
public static TableComponentProvider<SymbolRowObject> showTransientTable(
|
||||||
|
ServiceProvider services, String title, Program program,
|
||||||
|
TransientSymbolTableModel model) {
|
||||||
|
|
||||||
|
TableService service = services.getService(TableService.class);
|
||||||
|
if (service == null) {
|
||||||
|
Msg.showError(CreateSymbolTableAction.class, null, "Table Service Not Installed",
|
||||||
|
"You must have a Table Service installed to create a Symbol Table");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Navigatable navigatable = null;
|
Navigatable navigatable = null;
|
||||||
GoToService goToService = tool.getService(GoToService.class);
|
GoToService goToService = services.getService(GoToService.class);
|
||||||
if (goToService != null) {
|
if (goToService != null) {
|
||||||
navigatable = goToService.getDefaultNavigatable();
|
navigatable = goToService.getDefaultNavigatable();
|
||||||
}
|
}
|
||||||
|
|
||||||
TableService service = tool.getService(TableService.class);
|
|
||||||
if (service == null) {
|
|
||||||
Msg.showError(this, null, "Table Service Not Installed",
|
|
||||||
"You must have a Table Service installed to create a Symbol Table");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TableComponentProvider<SymbolRowObject> provider =
|
TableComponentProvider<SymbolRowObject> provider =
|
||||||
service.showTable("Symbols", "Symbols", model, "Symbols", navigatable);
|
service.showTable(title, "Symbols", model, "Symbols", navigatable);
|
||||||
|
|
||||||
provider.setActionContextProvider(mouseEvent -> {
|
provider.setActionContextProvider(mouseEvent -> {
|
||||||
|
|
||||||
@@ -101,32 +116,38 @@ public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
|||||||
return new ProgramSymbolActionContext(provider, program, selectedSymbols, table);
|
return new ProgramSymbolActionContext(provider, program, selectedSymbols, table);
|
||||||
});
|
});
|
||||||
|
|
||||||
// replace the generic provider help with this action's help
|
// replace the generic provider help
|
||||||
provider.setHelpLocation(getHelpLocation());
|
provider.setHelpLocation(new HelpLocation("SymbolTablePlugin", "Temporary_Symbol_Table"));
|
||||||
|
|
||||||
addActions(provider, model);
|
addActions(services, provider, model);
|
||||||
|
|
||||||
GhidraThreadedTablePanel<SymbolRowObject> tablePanel = provider.getThreadedTablePanel();
|
GhidraThreadedTablePanel<SymbolRowObject> tablePanel = provider.getThreadedTablePanel();
|
||||||
GhidraTable table = tablePanel.getTable();
|
GhidraTable table = tablePanel.getTable();
|
||||||
|
|
||||||
configureSymbolTable(tool, table, model, program);
|
configureSymbolTable(services, table, model, program);
|
||||||
|
|
||||||
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addActions(TableComponentProvider<SymbolRowObject> provider,
|
private static void addActions(ServiceProvider services,
|
||||||
TransientSymbolTableModel model) {
|
TableComponentProvider<SymbolRowObject> provider, TransientSymbolTableModel model) {
|
||||||
|
|
||||||
provider.installRemoveItemsAction();
|
provider.installRemoveItemsAction();
|
||||||
|
|
||||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(plugin);
|
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(services);
|
||||||
provider.getTool().addLocalAction(provider, tableAction);
|
PluginTool tool = provider.getTool();
|
||||||
|
tool.addLocalAction(provider, tableAction);
|
||||||
|
|
||||||
|
SetSymbolPrimaryAction primaryAction = new SetSymbolPrimaryAction();
|
||||||
|
tool.addLocalAction(provider, primaryAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureSymbolTable(PluginTool tool, GhidraTable table,
|
private static void configureSymbolTable(ServiceProvider services, GhidraTable table,
|
||||||
TransientSymbolTableModel model, Program program) {
|
TransientSymbolTableModel model, Program program) {
|
||||||
|
|
||||||
new TransientSymbolTableDnDAdapter(table, model);
|
new TransientSymbolTableDnDAdapter(table, model);
|
||||||
|
|
||||||
SymbolInspector symbolInspector = new SymbolInspector(tool, table);
|
SymbolInspector symbolInspector = new SymbolInspector(services, table);
|
||||||
SymbolRenderer renderer = model.getSymbolRenderer();
|
SymbolRenderer renderer = model.getSymbolRenderer();
|
||||||
renderer.setSymbolInspector(symbolInspector);
|
renderer.setSymbolInspector(symbolInspector);
|
||||||
|
|
||||||
@@ -141,7 +162,7 @@ public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Symbol> getSelectedSymbols(GTable table, TransientSymbolTableModel model) {
|
private static List<Symbol> getSelectedSymbols(GTable table, TransientSymbolTableModel model) {
|
||||||
List<Symbol> list = new ArrayList<>();
|
List<Symbol> list = new ArrayList<>();
|
||||||
int[] rows = table.getSelectedRows();
|
int[] rows = table.getSelectedRows();
|
||||||
for (int row : rows) {
|
for (int row : rows) {
|
||||||
|
|||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.symboltree.actions;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.action.DockingAction;
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
|
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
||||||
|
import ghidra.app.context.ProgramSymbolActionContext;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.Namespace;
|
||||||
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.task.TaskLauncher;
|
||||||
|
|
||||||
|
public class SetSymbolPrimaryAction extends DockingAction {
|
||||||
|
|
||||||
|
private static final String NAME = "Set Label Primary";
|
||||||
|
|
||||||
|
public SetSymbolPrimaryAction() {
|
||||||
|
super(NAME, ToolConstants.SHARED_OWNER);
|
||||||
|
|
||||||
|
// Note: the group '2' is that of the PinSymbolAction. That group seems like a nice place.
|
||||||
|
setPopupMenuData(new MenuData(new String[] { "Set Primary" }, "2"));
|
||||||
|
setHelpLocation(new HelpLocation("SymbolTablePlugin", "Set_Primary"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(ActionContext context) {
|
||||||
|
|
||||||
|
if (!(context instanceof ProgramSymbolActionContext psac)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = psac.getSymbolCount();
|
||||||
|
if (n != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol s = psac.getFirstSymbol();
|
||||||
|
return !s.isPrimary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
|
||||||
|
ProgramSymbolActionContext psac = (ProgramSymbolActionContext) context;
|
||||||
|
Symbol s = psac.getFirstSymbol();
|
||||||
|
Namespace ns = s.getParentNamespace();
|
||||||
|
String name = s.getName();
|
||||||
|
Address addr = s.getAddress();
|
||||||
|
SetLabelPrimaryCmd cmd = new SetLabelPrimaryCmd(addr, name, ns);
|
||||||
|
TaskLauncher.launchModal(NAME, () -> {
|
||||||
|
|
||||||
|
Program p = psac.getProgram();
|
||||||
|
p.withTransaction(NAME, () -> {
|
||||||
|
cmd.applyTo(p);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
String errorMessage = cmd.getStatusMsg();
|
||||||
|
if (!StringUtils.isBlank(errorMessage)) {
|
||||||
|
Msg.showError(getClass(), null, "Unable to Set Label Primary", errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+130
-34
@@ -23,8 +23,8 @@ import ghidra.app.cmd.label.DeleteLabelCmd;
|
|||||||
import ghidra.app.cmd.label.RenameLabelCmd;
|
import ghidra.app.cmd.label.RenameLabelCmd;
|
||||||
import ghidra.app.util.template.TemplateSimplifier;
|
import ghidra.app.util.template.TemplateSimplifier;
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
|
import ghidra.framework.cmd.Command;
|
||||||
import ghidra.framework.cmd.CompoundCmd;
|
import ghidra.framework.cmd.CompoundCmd;
|
||||||
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.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
@@ -33,9 +33,11 @@ import ghidra.program.model.symbol.*;
|
|||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.table.AddressBasedTableModel;
|
import ghidra.util.table.AddressBasedTableModel;
|
||||||
import ghidra.util.table.column.*;
|
import ghidra.util.table.column.*;
|
||||||
import ghidra.util.table.field.*;
|
import ghidra.util.table.field.*;
|
||||||
|
import ghidra.util.task.*;
|
||||||
|
|
||||||
public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
|
|
||||||
@@ -51,7 +53,6 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
public static final int SOURCE_COL = 5;
|
public static final int SOURCE_COL = 5;
|
||||||
public static final int REFS_COL = 6;
|
public static final int REFS_COL = 6;
|
||||||
|
|
||||||
private PluginTool tool;
|
|
||||||
protected SymbolTable symbolTable;
|
protected SymbolTable symbolTable;
|
||||||
protected ReferenceManager refMgr;
|
protected ReferenceManager refMgr;
|
||||||
protected SymbolRowObject lastSymbol;
|
protected SymbolRowObject lastSymbol;
|
||||||
@@ -59,9 +60,8 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
|
|
||||||
protected SymbolRenderer symbolRenderer = new SymbolRenderer();
|
protected SymbolRenderer symbolRenderer = new SymbolRenderer();
|
||||||
|
|
||||||
AbstractSymbolTableModel(PluginTool tool) {
|
AbstractSymbolTableModel(ServiceProvider sp) {
|
||||||
super("Symbols", tool, null, null);
|
super("Symbols", sp, null, null);
|
||||||
this.tool = tool;
|
|
||||||
this.filter = new NewSymbolFilter();
|
this.filter = new NewSymbolFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,9 +166,11 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenameLabelCmd cmd = new RenameLabelCmd(symbol, newName, SourceType.USER_DEFINED);
|
RenameTask task = new RenameTask(symbol, newName);
|
||||||
if (!tool.execute(cmd, getProgram())) {
|
TaskLauncher.launch(task);
|
||||||
Msg.showError(getClass(), null, "Error Renaming Symbol", cmd.getStatusMsg());
|
|
||||||
|
if (!task.success()) {
|
||||||
|
Msg.showError(getClass(), null, "Error Renaming Symbol", task.status());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,15 +231,14 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete(List<Symbol> rowObjects) {
|
protected void delete(List<Symbol> symbols) {
|
||||||
if (rowObjects == null || rowObjects.isEmpty()) {
|
if (symbols == null || symbols.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tool.setStatusInfo("");
|
|
||||||
List<Symbol> deleteList = new LinkedList<>();
|
List<Symbol> deleteList = new LinkedList<>();
|
||||||
CompoundCmd<Program> cmd = new CompoundCmd<>("Delete symbol(s)");
|
CompoundCmd<Program> cmd = new CompoundCmd<>("Delete symbol(s)");
|
||||||
for (Symbol symbol : rowObjects) {
|
for (Symbol symbol : symbols) {
|
||||||
if (symbol.isDynamic()) {
|
if (symbol.isDynamic()) {
|
||||||
continue; // can't delete dynamic symbols...
|
continue; // can't delete dynamic symbols...
|
||||||
}
|
}
|
||||||
@@ -262,16 +263,19 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tool.execute(cmd, getProgram())) {
|
DeleteTask task = new DeleteTask(cmd);
|
||||||
|
TaskLauncher.launch(task);
|
||||||
|
|
||||||
|
if (!task.success()) {
|
||||||
|
reload();
|
||||||
|
Msg.showError(getClass(), null, "Error Deleting Symbol(s)", task.status());
|
||||||
|
}
|
||||||
|
else {
|
||||||
for (Symbol s : deleteList) {
|
for (Symbol s : deleteList) {
|
||||||
removeObject(new SymbolRowObject(s));
|
removeObject(new SymbolRowObject(s));
|
||||||
}
|
}
|
||||||
updateNow();
|
updateNow();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
tool.setStatusInfo(cmd.getStatusMsg());
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SymbolFilter getFilter() {
|
public SymbolFilter getFilter() {
|
||||||
@@ -328,16 +332,102 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
return symbolRenderer;
|
return symbolRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Task Classes
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
private class DeleteTask extends Task {
|
||||||
|
|
||||||
|
private CompoundCmd<Program> compoundCmd;
|
||||||
|
|
||||||
|
private boolean success;
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
DeleteTask(CompoundCmd<Program> compoundCmd) {
|
||||||
|
super("Delete Symbols");
|
||||||
|
this.compoundCmd = compoundCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
program.withTransaction(getName(), () -> {
|
||||||
|
doRun(monitor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRun(TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
monitor.initialize(compoundCmd.size());
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
List<Command<Program>> commands = compoundCmd.getCommands();
|
||||||
|
for (Command<Program> cmd : commands) {
|
||||||
|
|
||||||
|
monitor.increment();
|
||||||
|
|
||||||
|
if (!cmd.applyTo(program)) {
|
||||||
|
success = false;
|
||||||
|
status = cmd.getStatusMsg();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
String status() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameTask extends Task {
|
||||||
|
|
||||||
|
private Symbol symbol;
|
||||||
|
private String newName;
|
||||||
|
|
||||||
|
private boolean success;
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
public RenameTask(Symbol symbol, String newName) {
|
||||||
|
super("Rename Symbol");
|
||||||
|
this.symbol = symbol;
|
||||||
|
this.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
program.withTransaction(getName(), () -> {
|
||||||
|
RenameLabelCmd cmd = new RenameLabelCmd(symbol, newName, SourceType.USER_DEFINED);
|
||||||
|
success = cmd.applyTo(program);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
String status() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Table Column Classes
|
// Table Column Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private class NameTableColumn
|
protected class NameTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Symbol> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Symbol> {
|
||||||
|
|
||||||
|
public static final String NAME = "Name";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
return "Name";
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -347,7 +437,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PinnedTableColumn
|
protected class PinnedTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Boolean> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Boolean> {
|
||||||
|
|
||||||
private PinnedRenderer renderer = new PinnedRenderer();
|
private PinnedRenderer renderer = new PinnedRenderer();
|
||||||
@@ -378,7 +468,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LocationTableColumn
|
protected class LocationTableColumn
|
||||||
extends AbstractProgramLocationTableColumn<SymbolRowObject, AddressBasedLocation> {
|
extends AbstractProgramLocationTableColumn<SymbolRowObject, AddressBasedLocation> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -404,12 +494,14 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SymbolTypeTableColumn
|
protected class SymbolTypeTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||||
|
|
||||||
|
public static final String NAME = "Type";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
return "Type";
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -426,14 +518,14 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VariableSymbolLocation extends AddressBasedLocation {
|
protected class VariableSymbolLocation extends AddressBasedLocation {
|
||||||
|
|
||||||
VariableSymbolLocation(Variable variable) {
|
VariableSymbolLocation(Variable variable) {
|
||||||
super(variable.getSymbol().getAddress(), variable.getVariableStorage().toString());
|
super(variable.getSymbol().getAddress(), variable.getVariableStorage().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DataTypeTableColumn
|
protected class DataTypeTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -470,7 +562,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NamespaceTableColumn
|
protected class NamespaceTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -489,9 +581,11 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SourceTableColumn
|
protected class SourceTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, SourceType> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, SourceType> {
|
||||||
|
|
||||||
|
public static final String NAME = "Source";
|
||||||
|
|
||||||
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<>() {
|
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<>() {
|
||||||
@Override
|
@Override
|
||||||
protected String getText(Object value) {
|
protected String getText(Object value) {
|
||||||
@@ -509,7 +603,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
return "Source";
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -529,14 +623,16 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReferenceCountTableColumn
|
protected class ReferenceCountTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
||||||
|
|
||||||
|
public static final String NAME = "Ref Count";
|
||||||
|
|
||||||
private ReferenceCountRenderer renderer = new ReferenceCountRenderer();
|
private ReferenceCountRenderer renderer = new ReferenceCountRenderer();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
return "Reference Count";
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -562,7 +658,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OffcutReferenceCountTableColumn
|
protected class OffcutReferenceCountTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
||||||
|
|
||||||
private OffcutReferenceCountRenderer renderer = new OffcutReferenceCountRenderer();
|
private OffcutReferenceCountRenderer renderer = new OffcutReferenceCountRenderer();
|
||||||
@@ -613,7 +709,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UserTableColumn
|
protected class UserTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -650,7 +746,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class OriginalNameColumn
|
protected class OriginalNameColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -688,7 +784,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SimplifiedNameColumn
|
protected class SimplifiedNameColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||||
|
|
||||||
private TemplateSimplifier simplifier = new TemplateSimplifier();
|
private TemplateSimplifier simplifier = new TemplateSimplifier();
|
||||||
|
|||||||
+10
-4
@@ -36,6 +36,7 @@ import ghidra.program.model.address.Address;
|
|||||||
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.model.symbol.SymbolTable;
|
import ghidra.program.model.symbol.SymbolTable;
|
||||||
|
import ghidra.program.util.LabelFieldLocation;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.table.*;
|
import ghidra.util.table.*;
|
||||||
|
|
||||||
@@ -126,12 +127,17 @@ class SymbolPanel extends JPanel {
|
|||||||
Program program = location.getProgram();
|
Program program = location.getProgram();
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
Address address = location.getAddress();
|
Address address = location.getAddress();
|
||||||
Symbol primarySymbol = symbolTable.getPrimarySymbol(address);
|
|
||||||
if (primarySymbol == null) {
|
Symbol symbol = null;
|
||||||
return;
|
if (location instanceof LabelFieldLocation lfl) {
|
||||||
|
symbol = lfl.getSymbol();
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolRowObject rowObject = new SymbolRowObject(primarySymbol);
|
if (symbol == null) {
|
||||||
|
symbol = symbolTable.getPrimarySymbol(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolRowObject rowObject = new SymbolRowObject(symbol);
|
||||||
int index = symbolModel.getRowIndex(rowObject);
|
int index = symbolModel.getRowIndex(rowObject);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
gTable.selectRow(index);
|
gTable.selectRow(index);
|
||||||
|
|||||||
+179
-11
@@ -21,16 +21,19 @@ import static ghidra.program.util.ProgramEvent.*;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
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 docking.action.builder.ActionBuilder;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.OptionDialogBuilder;
|
import docking.widgets.OptionDialogBuilder;
|
||||||
|
import docking.widgets.table.DynamicTableColumn;
|
||||||
|
import docking.widgets.table.TableColumnDescriptor;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
@@ -39,17 +42,20 @@ import ghidra.app.events.ProgramActivatedPluginEvent;
|
|||||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.core.symboltree.actions.*;
|
import ghidra.app.plugin.core.symboltree.actions.*;
|
||||||
|
import ghidra.app.plugin.core.table.TableComponentProvider;
|
||||||
import ghidra.app.services.BlockModelService;
|
import ghidra.app.services.BlockModelService;
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.app.util.SymbolInspector;
|
import ghidra.app.util.SymbolInspector;
|
||||||
|
import ghidra.app.util.viewer.field.LabelFieldSymbolLoader;
|
||||||
|
import ghidra.app.util.viewer.field.LabelFieldSymbolLoader.Symbols;
|
||||||
import ghidra.framework.model.DomainObjectListener;
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
import ghidra.framework.model.DomainObjectListenerBuilder;
|
import ghidra.framework.model.DomainObjectListenerBuilder;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Data;
|
import ghidra.program.model.listing.*;
|
||||||
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.program.util.ProgramLocation;
|
||||||
@@ -79,12 +85,13 @@ import resources.Icons;
|
|||||||
"allows symbols to be renamed and deleted. This plugin also " +
|
"allows symbols to be renamed and deleted. This plugin also " +
|
||||||
"shows references to a symbol. Filters can be set " +
|
"shows references to a symbol. Filters can be set " +
|
||||||
"to show subsets of the symbols.",
|
"to show subsets of the symbols.",
|
||||||
|
servicesProvided = { SymbolTableService.class },
|
||||||
servicesRequired = { GoToService.class, BlockModelService.class },
|
servicesRequired = { GoToService.class, BlockModelService.class },
|
||||||
eventsProduced = { ProgramLocationPluginEvent.class },
|
eventsProduced = { ProgramLocationPluginEvent.class },
|
||||||
eventsConsumed = { ProgramActivatedPluginEvent.class, ProgramLocationPluginEvent.class }
|
eventsConsumed = { ProgramActivatedPluginEvent.class, ProgramLocationPluginEvent.class }
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class SymbolTablePlugin extends Plugin {
|
public class SymbolTablePlugin extends Plugin implements SymbolTableService {
|
||||||
|
|
||||||
private static final String NAVIGATE_ON_INCOMING_EVENT_KEY = "NAVIGATE_ON_INCOMING_EVENT";
|
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";
|
private static final String NAVIGATE_ON_OUTGOING_EVENT_KEY = "NAVIGATE_ON_OUTGOING_EVENT";
|
||||||
@@ -106,6 +113,10 @@ public class SymbolTablePlugin extends Plugin {
|
|||||||
private BlockModelService blockModelService;
|
private BlockModelService blockModelService;
|
||||||
private SwingUpdateManager swingMgr;
|
private SwingUpdateManager swingMgr;
|
||||||
|
|
||||||
|
// providers shown by the service interface
|
||||||
|
private Map<String, TableComponentProvider<SymbolRowObject>> transientTableProviders =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
private DomainObjectListener domainObjectListener = createDomainObjectListener();
|
private DomainObjectListener domainObjectListener = createDomainObjectListener();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,6 +137,7 @@ public class SymbolTablePlugin extends Plugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
|
|
||||||
gotoService = tool.getService(GoToService.class);
|
gotoService = tool.getService(GoToService.class);
|
||||||
blockModelService = tool.getService(BlockModelService.class);
|
blockModelService = tool.getService(BlockModelService.class);
|
||||||
|
|
||||||
@@ -138,11 +150,6 @@ public class SymbolTablePlugin extends Plugin {
|
|||||||
inspector = new SymbolInspector(getTool(), symProvider.getComponent());
|
inspector = new SymbolInspector(getTool(), symProvider.getComponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells a plugin that it is no longer needed.
|
|
||||||
* The plugin should remove itself from anything that
|
|
||||||
* it is registered to and release any resources.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@@ -456,10 +463,14 @@ public class SymbolTablePlugin extends Plugin {
|
|||||||
DockingAction clearPinnedAction = new ClearPinSymbolAction(getName(), pinnedPopupGroup);
|
DockingAction clearPinnedAction = new ClearPinSymbolAction(getName(), pinnedPopupGroup);
|
||||||
tool.addAction(clearPinnedAction);
|
tool.addAction(clearPinnedAction);
|
||||||
|
|
||||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(this);
|
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(getTool());
|
||||||
tableAction.getPopupMenuData().setMenuGroup(popupGroup);
|
tableAction.getPopupMenuData().setMenuGroup(popupGroup);
|
||||||
tool.addLocalAction(symProvider, tableAction);
|
tool.addLocalAction(symProvider, tableAction);
|
||||||
|
|
||||||
|
SetSymbolPrimaryAction primaryAction = new SetSymbolPrimaryAction();
|
||||||
|
primaryAction.getPopupMenuData().setMenuGroup(popupGroup);
|
||||||
|
tool.addLocalAction(symProvider, primaryAction);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
String bottomGroup = "ShowReferencesTo" + 1;
|
String bottomGroup = "ShowReferencesTo" + 1;
|
||||||
new ActionBuilder("Delete All References", getName())
|
new ActionBuilder("Delete All References", getName())
|
||||||
@@ -641,6 +652,163 @@ public class SymbolTablePlugin extends Plugin {
|
|||||||
action.setSelected(true);
|
action.setSelected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// Service Methods
|
||||||
|
//=================================================================================================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableComponentProvider<SymbolRowObject> showSymbols(CodeUnit codeUnit) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(codeUnit);
|
||||||
|
|
||||||
|
Program program = codeUnit.getProgram();
|
||||||
|
Address addr = codeUnit.getMinAddress();
|
||||||
|
String title = "Labels at " + addr;
|
||||||
|
|
||||||
|
TableComponentProvider<SymbolRowObject> provider = transientTableProviders.get(title);
|
||||||
|
if (provider != null) {
|
||||||
|
|
||||||
|
if (provider.isShowing()) {
|
||||||
|
LabelFieldSymbolModel model = (LabelFieldSymbolModel) provider.getModel();
|
||||||
|
reload(codeUnit, model);
|
||||||
|
provider.toFront();
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
transientTableProviders.remove(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelFieldSymbolLoader loader =
|
||||||
|
new LabelFieldSymbolLoader(codeUnit, Integer.MAX_VALUE, true);
|
||||||
|
Symbols symbols = loader.getSymbols();
|
||||||
|
|
||||||
|
List<Symbol> list = symbols.getAllSymbols();
|
||||||
|
|
||||||
|
HashSet<SymbolRowObject> rowObjects = list.stream()
|
||||||
|
.map(s -> new SymbolRowObject(s))
|
||||||
|
.collect(Collectors.toCollection(HashSet::new));
|
||||||
|
|
||||||
|
LabelFieldSymbolModel model =
|
||||||
|
new LabelFieldSymbolModel(tool, program, rowObjects);
|
||||||
|
provider = CreateSymbolTableAction.showTransientTable(tool, title, program, model);
|
||||||
|
if (provider == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
provider.setClosedCallback(() -> {
|
||||||
|
transientTableProviders.remove(title);
|
||||||
|
});
|
||||||
|
|
||||||
|
addActions(provider, model, codeUnit);
|
||||||
|
|
||||||
|
transientTableProviders.put(title, provider);
|
||||||
|
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addActions(TableComponentProvider<SymbolRowObject> provider,
|
||||||
|
LabelFieldSymbolModel model, CodeUnit cu) {
|
||||||
|
|
||||||
|
new ActionBuilder("Refresh", ToolConstants.SHARED_OWNER)
|
||||||
|
.toolBarGroup("_", "1") // first
|
||||||
|
.toolBarIcon(Icons.REFRESH_ICON)
|
||||||
|
.helpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, "Refresh_Labels"))
|
||||||
|
.onAction(c -> {
|
||||||
|
reload(cu, model);
|
||||||
|
})
|
||||||
|
.buildAndInstallLocal(provider);
|
||||||
|
|
||||||
|
new ActionBuilder("Delete", ToolConstants.SHARED_OWNER)
|
||||||
|
.toolBarGroup("_", "2") // first
|
||||||
|
.toolBarIcon(Icons.DELETE_ICON)
|
||||||
|
.helpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, "Delete_Label"))
|
||||||
|
.enabledWhen(c -> {
|
||||||
|
GhidraTable table = provider.getTable();
|
||||||
|
return table.getSelectedRowCount() > 0;
|
||||||
|
})
|
||||||
|
.onAction(c -> {
|
||||||
|
deleteSymbols(provider, model);
|
||||||
|
})
|
||||||
|
.buildAndInstallLocal(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteSymbols(TableComponentProvider<SymbolRowObject> provider,
|
||||||
|
LabelFieldSymbolModel model) {
|
||||||
|
|
||||||
|
List<Symbol> symbols = new ArrayList<>();
|
||||||
|
|
||||||
|
GhidraTable table = provider.getTable();
|
||||||
|
int[] rows = table.getSelectedRows();
|
||||||
|
for (int row : rows) {
|
||||||
|
SymbolRowObject ro = model.getRowObject(row);
|
||||||
|
Symbol symbol = ro.getSymbol();
|
||||||
|
if (symbol.isDeleted()) {
|
||||||
|
// this symbol was deleted outside of the table and the table did not update
|
||||||
|
model.removeObject(ro);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols.add(symbol);
|
||||||
|
}
|
||||||
|
model.delete(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reload(CodeUnit cu, LabelFieldSymbolModel model) {
|
||||||
|
LabelFieldSymbolLoader loader =
|
||||||
|
new LabelFieldSymbolLoader(cu, Integer.MAX_VALUE, true);
|
||||||
|
Symbols symbols = loader.getSymbols();
|
||||||
|
|
||||||
|
List<Symbol> list = symbols.getAllSymbols();
|
||||||
|
|
||||||
|
HashSet<SymbolRowObject> rowObjects = list.stream()
|
||||||
|
.map(s -> new SymbolRowObject(s))
|
||||||
|
.collect(Collectors.toCollection(HashSet::new));
|
||||||
|
|
||||||
|
model.setData(rowObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LabelFieldSymbolModel extends TransientSymbolTableModel {
|
||||||
|
|
||||||
|
public LabelFieldSymbolModel(ServiceProvider sp, Program program,
|
||||||
|
HashSet<SymbolRowObject> rowObjects) {
|
||||||
|
super(sp, program, rowObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(HashSet<SymbolRowObject> rowObjects) {
|
||||||
|
this.rowObjects = rowObjects;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void delete(List<Symbol> symbols) {
|
||||||
|
super.delete(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TableColumnDescriptor<SymbolRowObject> createTableColumnDescriptor() {
|
||||||
|
|
||||||
|
TableColumnDescriptor<SymbolRowObject> descriptor = super.createTableColumnDescriptor();
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Set<String> visibleNames = new HashSet<>(Set.of(
|
||||||
|
NameTableColumn.NAME,
|
||||||
|
SymbolTypeTableColumn.NAME,
|
||||||
|
SourceTableColumn.NAME,
|
||||||
|
ReferenceCountTableColumn.NAME));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
List<DynamicTableColumn<SymbolRowObject, ?, ?>> allColumns = descriptor.getAllColumns();
|
||||||
|
|
||||||
|
for (DynamicTableColumn<SymbolRowObject, ?, ?> column : allColumns) {
|
||||||
|
String columnName = column.getColumnName();
|
||||||
|
boolean visible = visibleNames.contains(columnName);
|
||||||
|
descriptor.setVisible(columnName, visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Table Update Jobs
|
// Table Update Jobs
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/* ###
|
||||||
|
* 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 ghidra.app.plugin.core.table.TableComponentProvider;
|
||||||
|
import ghidra.app.plugin.processors.sleigh.symbol.Symbol;
|
||||||
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for showing {@link Symbol}s in a table.
|
||||||
|
*/
|
||||||
|
public interface SymbolTableService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows all symbols and offcut symbols contained in the given code unit.
|
||||||
|
* @param codeUnit the code unit
|
||||||
|
* @return the table provider that is shown
|
||||||
|
*/
|
||||||
|
public TableComponentProvider<SymbolRowObject> showSymbols(CodeUnit codeUnit);
|
||||||
|
}
|
||||||
+6
-6
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -22,7 +22,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.model.DomainObjectListenerBuilder;
|
import ghidra.framework.model.DomainObjectListenerBuilder;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramChangeRecord;
|
import ghidra.program.util.ProgramChangeRecord;
|
||||||
import ghidra.util.datastruct.Accumulator;
|
import ghidra.util.datastruct.Accumulator;
|
||||||
@@ -36,13 +36,13 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
*/
|
*/
|
||||||
public class TransientSymbolTableModel extends AbstractSymbolTableModel {
|
public class TransientSymbolTableModel extends AbstractSymbolTableModel {
|
||||||
|
|
||||||
private HashSet<SymbolRowObject> rowObjects;
|
protected HashSet<SymbolRowObject> rowObjects;
|
||||||
|
|
||||||
private SwingUpdateManager updater = new SwingUpdateManager(this::fireTableDataChanged);
|
private SwingUpdateManager updater = new SwingUpdateManager(this::fireTableDataChanged);
|
||||||
|
|
||||||
public TransientSymbolTableModel(PluginTool tool, Program program,
|
public TransientSymbolTableModel(ServiceProvider sp, Program program,
|
||||||
HashSet<SymbolRowObject> rowObjects) {
|
HashSet<SymbolRowObject> rowObjects) {
|
||||||
super(tool);
|
super(sp);
|
||||||
this.rowObjects = rowObjects;
|
this.rowObjects = rowObjects;
|
||||||
setProgram(program);
|
setProgram(program);
|
||||||
symbolTable = program.getSymbolTable();
|
symbolTable = program.getSymbolTable();
|
||||||
|
|||||||
+7
-4
@@ -34,17 +34,20 @@ public class LabelCodeUnitFormat extends BrowserCodeUnitFormat {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getOffcutLabelStringForInstruction(Address offcutAddress,
|
protected String getOffcutLabelStringForInstruction(Address offcutAddress,
|
||||||
Instruction instruction, Address markupAddress) {
|
Instruction instruction, Address markupAddress, Symbol symbol) {
|
||||||
if (markupAddress != null) {
|
if (markupAddress != null) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
Program program = instruction.getProgram();
|
Program program = instruction.getProgram();
|
||||||
Symbol offsym = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
|
||||||
|
if (symbol == null) {
|
||||||
|
symbol = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
||||||
|
}
|
||||||
Address instructionAddress = instruction.getMinAddress();
|
Address instructionAddress = instruction.getMinAddress();
|
||||||
long diff = offcutAddress.subtract(instructionAddress);
|
long diff = offcutAddress.subtract(instructionAddress);
|
||||||
boolean decorate = !offsym.isDynamic();
|
boolean decorate = !symbol.isDynamic();
|
||||||
boolean simplify = true;
|
boolean simplify = true;
|
||||||
return getDefaultOffcutString(offsym, instruction, diff, decorate, simplify);
|
return getDefaultOffcutString(symbol, instruction, diff, decorate, simplify);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+195
-238
File diff suppressed because it is too large
Load Diff
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.util.viewer.field;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
import docking.widgets.fieldpanel.field.FieldElement;
|
||||||
|
import ghidra.app.nav.Navigatable;
|
||||||
|
import ghidra.app.plugin.core.symtable.SymbolTableService;
|
||||||
|
import ghidra.app.services.GoToService;
|
||||||
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.util.*;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler to process Label field clicks
|
||||||
|
*/
|
||||||
|
public class LabelFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||||
|
|
||||||
|
private final static Class<?>[] SUPPORTED_CLASSES =
|
||||||
|
new Class<?>[] { LabelFieldLocation.class, MoreLabelFieldLocation.class };
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fieldElementClicked(Object clickedObject, Navigatable sourceNavigatable,
|
||||||
|
ProgramLocation location, MouseEvent mouseEvent, ServiceProvider serviceProvider) {
|
||||||
|
|
||||||
|
if (mouseEvent.getClickCount() != 2 || mouseEvent.getButton() != MouseEvent.BUTTON1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GoToService goToService = serviceProvider.getService(GoToService.class);
|
||||||
|
if (goToService == null) {
|
||||||
|
Msg.error(this, GoToService.class.getSimpleName() + " not installed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTableService service = serviceProvider.getService(SymbolTableService.class);
|
||||||
|
if (service == null) {
|
||||||
|
Msg.error(this, SymbolTableService.class.getSimpleName() + " not installed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String clickedText = getText(clickedObject);
|
||||||
|
if (MoreLabelFieldLocation.MORE_LABELS_STRING.equals(clickedText)) {
|
||||||
|
showLabelsDialog(service, location);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location instanceof LabelFieldLocation) {
|
||||||
|
// Allow double-clicking of any label to show the label dialog. This allows the user to
|
||||||
|
// use the dialog even when the [more] is not showing.
|
||||||
|
showLabelsDialog(service, location);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showLabelsDialog(SymbolTableService service, ProgramLocation location) {
|
||||||
|
|
||||||
|
Address addr = location.getAddress();
|
||||||
|
Program program = location.getProgram();
|
||||||
|
Listing listing = program.getListing();
|
||||||
|
CodeUnit cu = listing.getCodeUnitAt(addr);
|
||||||
|
service.showSymbols(cu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getText(Object clickedObject) {
|
||||||
|
if (clickedObject instanceof FieldElement) {
|
||||||
|
FieldElement fieldElement = (FieldElement) clickedObject;
|
||||||
|
return fieldElement.getText();
|
||||||
|
}
|
||||||
|
return clickedObject.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?>[] getSupportedProgramLocations() {
|
||||||
|
return SUPPORTED_CLASSES;
|
||||||
|
}
|
||||||
|
}
|
||||||
+223
@@ -0,0 +1,223 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.util.viewer.field;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import generic.json.Json;
|
||||||
|
import ghidra.program.database.symbol.FunctionSymbol;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressIterator;
|
||||||
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple class to load all symbols for a given code unit
|
||||||
|
*/
|
||||||
|
public class LabelFieldSymbolLoader {
|
||||||
|
|
||||||
|
private boolean displayFunctionLabel;
|
||||||
|
private Symbols symbols;
|
||||||
|
|
||||||
|
private boolean hasMore;
|
||||||
|
|
||||||
|
public LabelFieldSymbolLoader(CodeUnit cu, int max, boolean displayFunctionLabel) {
|
||||||
|
|
||||||
|
this.displayFunctionLabel = displayFunctionLabel;
|
||||||
|
|
||||||
|
symbols = new Symbols();
|
||||||
|
gatherRealSymbols(cu, max);
|
||||||
|
gatherOffcutSymbols(cu, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Symbols getSymbols() {
|
||||||
|
return symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMore() {
|
||||||
|
return hasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void gatherRealSymbols(CodeUnit cu, int max) {
|
||||||
|
|
||||||
|
Address addr = cu.getMinAddress();
|
||||||
|
Program program = cu.getProgram();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Place the primary symbol to the front so that it is always rendered, even if we hit the
|
||||||
|
// symbol limit. Also, remove the function symbol if the user doesn't want to see it.
|
||||||
|
//
|
||||||
|
SymbolTable st = program.getSymbolTable();
|
||||||
|
SymbolIterator it = st.getSymbolsAsIterator(addr);
|
||||||
|
Symbol primary = st.getPrimarySymbol(addr);
|
||||||
|
if (primary == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Symbol s = it.next();
|
||||||
|
if (s.isPrimary()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((max - 1) == symbols.size()) { // -1 to save space for primary
|
||||||
|
hasMore = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s instanceof FunctionSymbol && !displayFunctionLabel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols.add(primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void gatherOffcutSymbols(CodeUnit cu, int max) {
|
||||||
|
|
||||||
|
if (max == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address startAddr = cu.getMinAddress();
|
||||||
|
if (!startAddr.isMemoryAddress()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program program = cu.getProgram();
|
||||||
|
if (cu.getLength() == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address nextAddr = startAddr.next();
|
||||||
|
if (nextAddr == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
Address endAddress = cu.getMaxAddress();
|
||||||
|
ReferenceManager referenceManager = program.getReferenceManager();
|
||||||
|
AddressIterator it = referenceManager.getReferenceDestinationIterator(nextAddr, true);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
|
||||||
|
Address addr = it.next();
|
||||||
|
if (addr.compareTo(endAddress) > 0 ||
|
||||||
|
// Note: check for wrapping - temporary work-around
|
||||||
|
addr.compareTo(cu.getMinAddress()) <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max == symbols.size()) {
|
||||||
|
hasMore = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol s = symbolTable.getPrimarySymbol(addr);
|
||||||
|
symbols.addOffcut(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolIterator symIter = symbolTable.getSymbolIterator(nextAddr, true);
|
||||||
|
while (symIter.hasNext()) {
|
||||||
|
|
||||||
|
Symbol s = symIter.next();
|
||||||
|
Address addr = s.getAddress();
|
||||||
|
if (addr.compareTo(endAddress) > 0 ||
|
||||||
|
// Note: check for wrapping - temporary work-around
|
||||||
|
addr.compareTo(cu.getMinAddress()) <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max == symbols.size()) {
|
||||||
|
hasMore = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove to handle the case where this symbol was added in the above loop
|
||||||
|
symbols.removeOffct(s);
|
||||||
|
symbols.addOffcut(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple class to hold all real and offcut symbols for a given code unit. The client will
|
||||||
|
* limit the number of symbols added to this class. The real symbols are loaded first, with any
|
||||||
|
* remaining space filled with existing offcut symbols.
|
||||||
|
*/
|
||||||
|
public class Symbols {
|
||||||
|
|
||||||
|
private List<Symbol> realSymbols = new ArrayList<>();
|
||||||
|
private List<Symbol> offcutSymbols = new ArrayList<>();
|
||||||
|
|
||||||
|
void addOffcut(Symbol s) {
|
||||||
|
offcutSymbols.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeOffct(Symbol s) {
|
||||||
|
offcutSymbols.remove(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(Symbol s) {
|
||||||
|
realSymbols.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(int index, Symbol s) {
|
||||||
|
realSymbols.add(index, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(Symbol s) {
|
||||||
|
realSymbols.remove(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int size() {
|
||||||
|
return offcutSymbols.size() + realSymbols.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol get(int index) {
|
||||||
|
|
||||||
|
if (index < offcutSymbols.size()) {
|
||||||
|
return offcutSymbols.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int updatedIndex = index - offcutSymbols.size();
|
||||||
|
return realSymbols.get(updatedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Symbol> getAllSymbols() {
|
||||||
|
List<Symbol> list = new ArrayList<>();
|
||||||
|
|
||||||
|
list.addAll(realSymbols);
|
||||||
|
list.addAll(offcutSymbols);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Symbol> getOffcuts() {
|
||||||
|
return Collections.unmodifiableList(offcutSymbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverseSymbols() {
|
||||||
|
realSymbols = realSymbols.reversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Json.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -30,7 +30,7 @@ import ghidra.program.model.symbol.Reference;
|
|||||||
import ghidra.program.util.*;
|
import ghidra.program.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handler to process {@link XRefFieldMouseHandler} clicks
|
* A handler to process XRef field clicks
|
||||||
*/
|
*/
|
||||||
public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||||
|
|
||||||
|
|||||||
+13
-7
@@ -1367,7 +1367,7 @@ public class CodeUnitFormat {
|
|||||||
if (symbolAddress.isMemoryAddress()) {
|
if (symbolAddress.isMemoryAddress()) {
|
||||||
CodeUnit cu = program.getListing().getCodeUnitContaining(symbolAddress);
|
CodeUnit cu = program.getListing().getCodeUnitContaining(symbolAddress);
|
||||||
if (isOffcut(symbolAddress, cu)) {
|
if (isOffcut(symbolAddress, cu)) {
|
||||||
return getOffcutLabelString(symbolAddress, cu, markupAddress);
|
return getOffcutLabelString(symbolAddress, cu, markupAddress, symbol);
|
||||||
}
|
}
|
||||||
else if (isStringData(cu)) {
|
else if (isStringData(cu)) {
|
||||||
return getLabelStringForStringData((Data) cu, symbol);
|
return getLabelStringForStringData((Data) cu, symbol);
|
||||||
@@ -1408,10 +1408,11 @@ public class CodeUnitFormat {
|
|||||||
return prefix + UNDERSCORE + SymbolUtilities.getAddressString(symbol.getAddress());
|
return prefix + UNDERSCORE + SymbolUtilities.getAddressString(symbol.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOffcutLabelString(Address offcutAddress, CodeUnit cu, Address markupAddress) {
|
public String getOffcutLabelString(Address offcutAddress, CodeUnit cu, Address markupAddress,
|
||||||
|
Symbol symbol) {
|
||||||
if (cu instanceof Instruction) {
|
if (cu instanceof Instruction) {
|
||||||
return getOffcutLabelStringForInstruction(offcutAddress, (Instruction) cu,
|
return getOffcutLabelStringForInstruction(offcutAddress, (Instruction) cu,
|
||||||
markupAddress);
|
markupAddress, symbol);
|
||||||
}
|
}
|
||||||
return getOffcutDataString(offcutAddress, (Data) cu);
|
return getOffcutDataString(offcutAddress, (Data) cu);
|
||||||
}
|
}
|
||||||
@@ -1460,17 +1461,22 @@ public class CodeUnitFormat {
|
|||||||
* @param offcutAddress address for which generated label represents
|
* @param offcutAddress address for which generated label represents
|
||||||
* @param instruction instruction containing offcut address
|
* @param instruction instruction containing offcut address
|
||||||
* @param markupAddress address where a label will be referenced from (may be null)
|
* @param markupAddress address where a label will be referenced from (may be null)
|
||||||
|
* @param symbol an optional symbol that is used to generate the symbol name
|
||||||
* @return generated offcut label
|
* @return generated offcut label
|
||||||
*/
|
*/
|
||||||
protected String getOffcutLabelStringForInstruction(Address offcutAddress,
|
protected String getOffcutLabelStringForInstruction(Address offcutAddress,
|
||||||
Instruction instruction, Address markupAddress) {
|
Instruction instruction, Address markupAddress, Symbol symbol) {
|
||||||
Program program = instruction.getProgram();
|
Program program = instruction.getProgram();
|
||||||
Symbol offsym = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
|
||||||
|
if (symbol == null) {
|
||||||
|
symbol = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
||||||
|
}
|
||||||
|
|
||||||
Address instructionAddress = instruction.getMinAddress();
|
Address instructionAddress = instruction.getMinAddress();
|
||||||
long diff = offcutAddress.subtract(instructionAddress);
|
long diff = offcutAddress.subtract(instructionAddress);
|
||||||
boolean decorate = false; // we never decorate in the operand field
|
boolean decorate = false; // we never decorate in the operand field
|
||||||
boolean simplify = true; // we always simplify names of instruction labels
|
boolean simplify = true; // we always simplify names of instruction labels
|
||||||
if (offsym.isDynamic()) {
|
if (symbol.isDynamic()) {
|
||||||
Symbol containingSymbol = program.getSymbolTable().getPrimarySymbol(instructionAddress);
|
Symbol containingSymbol = program.getSymbolTable().getPrimarySymbol(instructionAddress);
|
||||||
if (containingSymbol != null) {
|
if (containingSymbol != null) {
|
||||||
String displayName = containingSymbol.getName();
|
String displayName = containingSymbol.getName();
|
||||||
@@ -1481,7 +1487,7 @@ public class CodeUnitFormat {
|
|||||||
return simplifyTemplate(displayName) + PLUS + SymbolUtilities.getDiffString(diff);
|
return simplifyTemplate(displayName) + PLUS + SymbolUtilities.getDiffString(diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getDefaultOffcutString(offsym, instruction, diff, decorate, simplify);
|
return getDefaultOffcutString(symbol, instruction, diff, decorate, simplify);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String addOffcutInformation(String prefix, String addressString, int diff,
|
protected String addOffcutInformation(String prefix, String addressString, int diff,
|
||||||
|
|||||||
+8
-11
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -20,7 +20,6 @@ import static org.junit.Assert.*;
|
|||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.widgets.combobox.GhidraComboBox;
|
|
||||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
@@ -74,10 +73,9 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest
|
|||||||
performAction(setLabelAction, context, false);
|
performAction(setLabelAction, context, false);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
OperandLabelDialog dialog = waitForDialogComponent(OperandLabelDialog.class);
|
SymbolChooserDialog dialog = waitForDialogComponent(SymbolChooserDialog.class);
|
||||||
GhidraComboBox<?> combo = (GhidraComboBox<?>) findComponentByName(dialog, "MYCHOICE");
|
|
||||||
|
|
||||||
setSelectedItem(combo, "bob");
|
setSelectedItem(dialog, "bob");
|
||||||
|
|
||||||
pressButtonByText(dialog, "OK");
|
pressButtonByText(dialog, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
@@ -91,10 +89,9 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest
|
|||||||
performAction(setLabelAction, context, false);
|
performAction(setLabelAction, context, false);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
dialog = waitForDialogComponent(OperandLabelDialog.class);
|
dialog = waitForDialogComponent(SymbolChooserDialog.class);
|
||||||
combo = (GhidraComboBox<?>) findComponentByName(dialog, "MYCHOICE");
|
|
||||||
|
|
||||||
setSelectedItem(combo, "b");
|
setSelectedItem(dialog, "b");
|
||||||
pressButtonByText(dialog, "OK");
|
pressButtonByText(dialog, "OK");
|
||||||
|
|
||||||
program.flushEvents();
|
program.flushEvents();
|
||||||
@@ -108,7 +105,7 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest
|
|||||||
assertEquals("dword ptr [b]", cb.getCurrentFieldText());
|
assertEquals("dword ptr [b]", cb.getCurrentFieldText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSelectedItem(GhidraComboBox<?> combo, String s) {
|
private void setSelectedItem(SymbolChooserDialog dialog, String item) {
|
||||||
runSwing(() -> combo.setSelectedItem(s));
|
runSwing(() -> dialog.setSelectedItem(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -169,8 +169,9 @@ public class LabelFieldFactoryTest extends AbstractGhidraHeadedIntegrationTest {
|
|||||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||||
|
|
||||||
// 4 offcut labels and one dynamic label
|
// 4 offcut labels and one dynamic label
|
||||||
|
String actual = tf.getText();
|
||||||
assertEquals("LAB_01002000+1 LAB_01002000+2 LAB_01002000+3 LAB_01002000+4 LAB_01002000",
|
assertEquals("LAB_01002000+1 LAB_01002000+2 LAB_01002000+3 LAB_01002000+4 LAB_01002000",
|
||||||
tf.getText()); // bad offcut put on instruction
|
actual); // bad offcut put on instruction
|
||||||
|
|
||||||
assertEquals(5, tf.getNumRows());
|
assertEquals(5, tf.getNumRows());
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -93,6 +93,13 @@ public class FieldLocation implements Comparable<FieldLocation> {
|
|||||||
this(BigInteger.valueOf(index), fieldNum, row, col);
|
this(BigInteger.valueOf(index), fieldNum, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new FieldLocation with the given index,fieldNum,row, and col.
|
||||||
|
* @param index the index of the layout containing the location
|
||||||
|
* @param fieldNum the index of the field in the layout containing the location
|
||||||
|
* @param row the text row in the field containing the location.
|
||||||
|
* @param col the character position in the row containing the location.
|
||||||
|
*/
|
||||||
public FieldLocation(BigInteger index, int fieldNum, int row, int col) {
|
public FieldLocation(BigInteger index, int fieldNum, int row, int col) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.fieldNum = fieldNum;
|
this.fieldNum = fieldNum;
|
||||||
|
|||||||
+19
-2
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -38,4 +38,21 @@ public interface DynamicColumnTableModel<ROW_TYPE>
|
|||||||
* @return the model index
|
* @return the model index
|
||||||
*/
|
*/
|
||||||
public int getColumnIndex(DynamicTableColumn<ROW_TYPE, ?, ?> column);
|
public int getColumnIndex(DynamicTableColumn<ROW_TYPE, ?, ?> column);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows table models to create their own preference key.
|
||||||
|
* <p>
|
||||||
|
* The preference key is used to save the column state of this configurable model. All models
|
||||||
|
* that share a preference key will share the same visible column state.
|
||||||
|
* The {@link GTableColumnModel} manages this state for the framework. The column model will
|
||||||
|
* ask the table for its preference key, which will ask the model when not key has been set on
|
||||||
|
* the table. In the case that no key is set in the table or the model, a key will be created
|
||||||
|
* based on the classname and default columns.
|
||||||
|
*
|
||||||
|
* @return the preference key; the default value is null
|
||||||
|
*/
|
||||||
|
public default String getPreferenceKey() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package docking.widgets.table;
|
package docking.widgets.table;
|
||||||
|
|
||||||
import static docking.DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
import static docking.DockingUtils.*;
|
||||||
import static docking.action.MenuData.NO_MNEMONIC;
|
import static docking.action.MenuData.*;
|
||||||
import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
|
import static java.awt.event.InputEvent.*;
|
||||||
import static javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
|
import static javax.swing.ListSelectionModel.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
@@ -636,7 +636,7 @@ public class GTable extends JTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return the underlying ConfigurableColumnTableModel if one is in-use}
|
* {@return the underlying ConfigurableColumnTableModel if one is in use}
|
||||||
*/
|
*/
|
||||||
public ConfigurableColumnTableModel getConfigurableColumnTableModel() {
|
public ConfigurableColumnTableModel getConfigurableColumnTableModel() {
|
||||||
TableModel model = getUnwrappedTableModel();
|
TableModel model = getUnwrappedTableModel();
|
||||||
@@ -646,6 +646,17 @@ public class GTable extends JTable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the underlying DynamicColumnTableModel if one is in use}
|
||||||
|
*/
|
||||||
|
public DynamicColumnTableModel<?> getDynamicTableModel() {
|
||||||
|
TableModel model = getUnwrappedTableModel();
|
||||||
|
if (model instanceof DynamicColumnTableModel<?>) {
|
||||||
|
return (DynamicColumnTableModel<?>) model;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unrolls the current model by checking if the current model is inside of a wrapper table
|
* Unrolls the current model by checking if the current model is inside of a wrapper table
|
||||||
* model.
|
* model.
|
||||||
@@ -912,7 +923,17 @@ public class GTable extends JTable {
|
|||||||
* @see #setPreferenceKey(String)
|
* @see #setPreferenceKey(String)
|
||||||
*/
|
*/
|
||||||
public String getPreferenceKey() {
|
public String getPreferenceKey() {
|
||||||
return preferenceKey;
|
if (preferenceKey != null) {
|
||||||
|
// prefer the key that has been set programmatically
|
||||||
|
return preferenceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicColumnTableModel<?> dynamicModel = getDynamicTableModel();
|
||||||
|
if (dynamicModel != null) {
|
||||||
|
return dynamicModel.getPreferenceKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -15,9 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.framework.cmd;
|
package ghidra.framework.cmd;
|
||||||
|
|
||||||
import ghidra.framework.model.DomainObject;
|
import java.util.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import ghidra.framework.model.DomainObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation for multiple commands that are done as a unit.
|
* Implementation for multiple commands that are done as a unit.
|
||||||
@@ -28,7 +28,7 @@ import java.util.ArrayList;
|
|||||||
* @param <T> {@link DomainObject} implementation interface
|
* @param <T> {@link DomainObject} implementation interface
|
||||||
*/
|
*/
|
||||||
public class CompoundCmd<T extends DomainObject> implements Command<T> {
|
public class CompoundCmd<T extends DomainObject> implements Command<T> {
|
||||||
private ArrayList<Command<T>> cmds;
|
private List<Command<T>> cmds;
|
||||||
private String statusMsg;
|
private String statusMsg;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@@ -81,4 +81,10 @@ public class CompoundCmd<T extends DomainObject> implements Command<T> {
|
|||||||
return cmds.size();
|
return cmds.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the commands in this compound command}
|
||||||
|
*/
|
||||||
|
public List<Command<T>> getCommands() {
|
||||||
|
return Collections.unmodifiableList(cmds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -65,7 +65,7 @@ public interface SymbolTable {
|
|||||||
* @param name the name of the symbol
|
* @param name the name of the symbol
|
||||||
* @param source the source of this symbol. In general, a source of {@link SourceType#DEFAULT}
|
* @param source the source of this symbol. In general, a source of {@link SourceType#DEFAULT}
|
||||||
* should never be specified using this method.
|
* should never be specified using this method.
|
||||||
* @return new labe or function symbol
|
* @return new label or function symbol
|
||||||
* @throws InvalidInputException if name contains white space, is zero length, or is null for
|
* @throws InvalidInputException if name contains white space, is zero length, or is null for
|
||||||
* non-default source
|
* non-default source
|
||||||
* @throws IllegalArgumentException if {@link SourceType#DEFAULT} is improperly specified, or
|
* @throws IllegalArgumentException if {@link SourceType#DEFAULT} is improperly specified, or
|
||||||
@@ -463,7 +463,7 @@ public interface SymbolTable {
|
|||||||
/**
|
/**
|
||||||
* Get all the symbols of the given type within the given address set.
|
* Get all the symbols of the given type within the given address set.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>NOTE:</b> All external symbols will be omiitted unless the full
|
* <b>NOTE:</b> All external symbols will be omitted unless the full
|
||||||
* {@link AddressSpace#EXTERNAL_SPACE} range is included within the specified address set
|
* {@link AddressSpace#EXTERNAL_SPACE} range is included within the specified address set
|
||||||
* or a null addressSet is specified. All global dynamic label symbols will be omitted.
|
* or a null addressSet is specified. All global dynamic label symbols will be omitted.
|
||||||
*
|
*
|
||||||
|
|||||||
+8
-8
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -36,8 +36,8 @@ public class CodeUnitLocation extends ProgramLocation {
|
|||||||
* @param componentPath if this is not null it is the path to a data
|
* @param componentPath if this is not null it is the path to a data
|
||||||
* component inside of another data component
|
* component inside of another data component
|
||||||
* @param row the row within the field.
|
* @param row the row within the field.
|
||||||
* @param col - the display item index on the given row. (Note most fields only have one display item per row)
|
* @param col the display item index on the given row. (Note most fields only have one display item per row)
|
||||||
* @param charOffset - the character offset within the display item.
|
* @param charOffset the character offset within the display item.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public CodeUnitLocation(Program program, Address addr, int[] componentPath, int row, int col,
|
public CodeUnitLocation(Program program, Address addr, int[] componentPath, int row, int col,
|
||||||
@@ -53,8 +53,8 @@ public class CodeUnitLocation extends ProgramLocation {
|
|||||||
* @param componentPath if this is not null it is the path to a data
|
* @param componentPath if this is not null it is the path to a data
|
||||||
* component inside of another data component
|
* component inside of another data component
|
||||||
* @param row the row within the field.
|
* @param row the row within the field.
|
||||||
* @param col - the display item index on the given row. (Note most fields only have one display item per row)
|
* @param col the display item index on the given row. (Note most fields only have one display item per row)
|
||||||
* @param charOffset - the character offset within the display item.
|
* @param charOffset the character offset within the display item.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected CodeUnitLocation(Program program, Address addr, Address byteAddr, int[] componentPath,
|
protected CodeUnitLocation(Program program, Address addr, Address byteAddr, int[] componentPath,
|
||||||
@@ -70,8 +70,8 @@ public class CodeUnitLocation extends ProgramLocation {
|
|||||||
* @param program the program for obtaining the code unit
|
* @param program the program for obtaining the code unit
|
||||||
* @param addr address of the location; should not be null
|
* @param addr address of the location; should not be null
|
||||||
* @param row the row within the field.
|
* @param row the row within the field.
|
||||||
* @param col - the display item index on the given row. (Note most fields only have one display item per row)
|
* @param col the display item index on the given row. (Note most fields only have one display item per row)
|
||||||
* @param charOffset - the character offset within the display item.
|
* @param charOffset the character offset within the display item.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public CodeUnitLocation(Program program, Address addr, int row, int col, int charOffset) {
|
public CodeUnitLocation(Program program, Address addr, int row, int col, int charOffset) {
|
||||||
|
|||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.program.util;
|
||||||
|
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the '[more]' text used by the label field factory.
|
||||||
|
*/
|
||||||
|
public class MoreLabelFieldLocation extends CodeUnitLocation {
|
||||||
|
|
||||||
|
public static final String MORE_LABELS_STRING = "[more]";
|
||||||
|
|
||||||
|
public MoreLabelFieldLocation() {
|
||||||
|
// for serialization
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoreLabelFieldLocation(Program p, Address addr, int row, int charOffset) {
|
||||||
|
super(p, addr, row, 0, charOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MORE_LABELS_STRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-18
@@ -21,8 +21,8 @@ import javax.swing.*;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import docking.widgets.combobox.GhidraComboBox;
|
import ghidra.app.plugin.core.label.LabelHistoryDialog;
|
||||||
import ghidra.app.plugin.core.label.*;
|
import ghidra.app.plugin.core.label.LabelHistoryInputDialog;
|
||||||
import ghidra.app.util.*;
|
import ghidra.app.util.*;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.symbol.LabelHistory;
|
import ghidra.program.model.symbol.LabelHistory;
|
||||||
@@ -85,22 +85,6 @@ public class LabelMgrPluginScreenShots extends GhidraScreenShotGenerator {
|
|||||||
captureDialog();
|
captureDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetLabel() {
|
|
||||||
LabelMgrPlugin plugin = getPlugin(tool, LabelMgrPlugin.class);
|
|
||||||
final OperandLabelDialog dialog = new OperandLabelDialog(plugin);
|
|
||||||
final GhidraComboBox<?> combo = (GhidraComboBox<?>) getInstanceField("myChoice", dialog);
|
|
||||||
runSwing(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
dialog.setTitle("Set Label at 004a671");
|
|
||||||
combo.setSelectedItem("LAB_0040a671");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
showDialogWithoutBlocking(tool, dialog);
|
|
||||||
captureDialog(350, 116);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowLabelHistory() {
|
public void testShowLabelHistory() {
|
||||||
AddressSpace space = new GenericAddressSpace("Test", 32, AddressSpace.TYPE_RAM, 0);
|
AddressSpace space = new GenericAddressSpace("Test", 32, AddressSpace.TYPE_RAM, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user