mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-10 05:49:26 +08:00
Merge remote-tracking branch 'origin/GP-6692-dragonmacher-too-many-symbols--SQUASHED'
This commit is contained in:
@@ -112,14 +112,18 @@
|
||||
certain Navigation behaviors.</P>
|
||||
|
||||
|
||||
|
||||
<H3>Xrefs</H3>
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<A name="Show_Xrefs"></A>
|
||||
<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>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<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
|
||||
dialog containing all the Xrefs to appear.</P>
|
||||
"green"><TT>XREF[n]:</TT></FONT> or <FONT color="green"><TT>[more]</TT></FONT>"
|
||||
text will cause a dialog containing all the Xrefs to appear.</P>
|
||||
<P>
|
||||
This differs from the <A href=
|
||||
"help/topics/LocationReferencesPlugin/Location_References.html#LocationReferencesPlugin">
|
||||
@@ -178,6 +182,51 @@
|
||||
</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>
|
||||
|
||||
|
||||
+4
@@ -848,6 +848,10 @@
|
||||
this off, the function name will only appear in the function signature. If it's on, the
|
||||
function name will also appear as a label below the function header.</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
|
||||
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
|
||||
|
||||
@@ -254,20 +254,12 @@
|
||||
the address using the <I>Set Label</I> dialog.</P>
|
||||
</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>
|
||||
<H3>Label</H3>
|
||||
|
||||
<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
|
||||
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>
|
||||
|
||||
+12
@@ -45,6 +45,15 @@
|
||||
</P>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -60,6 +69,9 @@
|
||||
</LI>
|
||||
<LI>
|
||||
<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>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
@@ -102,10 +102,6 @@ public class LabelMgrPlugin extends Plugin {
|
||||
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
|
||||
* 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) {
|
||||
getOperandLabelDialog().setOperandLabel(context);
|
||||
|
||||
SymbolChooserDialog dialog = new SymbolChooserDialog(this, context);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
Symbol getSymbol(ListingActionContext context) {
|
||||
ProgramLocation location = context.getLocation();
|
||||
if (location instanceof LabelFieldLocation) {
|
||||
LabelFieldLocation lfl = (LabelFieldLocation) location;
|
||||
if (location instanceof LabelFieldLocation lfl) {
|
||||
return lfl.getSymbol();
|
||||
}
|
||||
else if (location instanceof OperandFieldLocation) {
|
||||
VariableOffset variableOffset = ((OperandFieldLocation) location).getVariableOffset();
|
||||
else if (location instanceof OperandFieldLocation ofl) {
|
||||
VariableOffset variableOffset = ofl.getVariableOffset();
|
||||
if (variableOffset != null) {
|
||||
Variable var = variableOffset.getVariable();
|
||||
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");
|
||||
* 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.
|
||||
@@ -26,20 +26,12 @@ import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.program.util.OperandFieldLocation;
|
||||
|
||||
/**
|
||||
* <CODE>AddLabelAction</CODE> allows the user to add a label.
|
||||
*/
|
||||
class SetOperandLabelAction extends ListingContextAction {
|
||||
private LabelMgrPlugin plugin;
|
||||
private static final String[] POPUP_PATH = { "Set Associated Label..." };
|
||||
private static final KeyStroke KEYBINDING =
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_MASK | InputEvent.ALT_MASK);
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK);
|
||||
|
||||
/**
|
||||
* Creates a new instance of the action.
|
||||
*
|
||||
* @param plugin Label Manager Plugin instance
|
||||
*/
|
||||
SetOperandLabelAction(LabelMgrPlugin plugin) {
|
||||
super("Set Operand Label", plugin.getName());
|
||||
|
||||
@@ -59,13 +51,8 @@ class SetOperandLabelAction extends ListingContextAction {
|
||||
plugin.isOnSymbol(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when the action is invoked.
|
||||
* @param ActionEvent details regarding the invocation of this action
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ListingActionContext context) {
|
||||
plugin.setOperandLabelCallback(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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);
|
||||
|
||||
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, setExternalProgramAction);
|
||||
@@ -311,6 +312,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
||||
tool.addLocalAction(this, goToExternalAction);
|
||||
tool.addLocalAction(this, cloneAction);
|
||||
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.MenuData;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.table.GTable;
|
||||
import docking.widgets.table.threaded.GThreadedTablePanel;
|
||||
import ghidra.app.context.ProgramSymbolActionContext;
|
||||
@@ -32,8 +33,8 @@ import ghidra.app.plugin.core.table.TableComponentProvider;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.app.util.SymbolInspector;
|
||||
import ghidra.app.util.query.TableService;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.util.HelpLocation;
|
||||
@@ -43,11 +44,11 @@ import ghidra.util.table.GhidraThreadedTablePanel;
|
||||
|
||||
public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
||||
|
||||
private Plugin plugin;
|
||||
private ServiceProvider services;
|
||||
|
||||
public CreateSymbolTableAction(Plugin plugin) {
|
||||
super("Create Table", plugin.getName(), KeyBindingType.SHARED);
|
||||
this.plugin = plugin;
|
||||
public CreateSymbolTableAction(ServiceProvider services) {
|
||||
super("Create Table", ToolConstants.SHARED_OWNER, KeyBindingType.SHARED);
|
||||
this.services = services;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Create Table" },
|
||||
SymbolTreeContextAction.MIDDLE_MENU_GROUP));
|
||||
@@ -72,25 +73,39 @@ public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
||||
rowObjects.add(new SymbolRowObject(symbol));
|
||||
}
|
||||
|
||||
PluginTool tool = plugin.getTool();
|
||||
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;
|
||||
GoToService goToService = tool.getService(GoToService.class);
|
||||
GoToService goToService = services.getService(GoToService.class);
|
||||
if (goToService != null) {
|
||||
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 =
|
||||
service.showTable("Symbols", "Symbols", model, "Symbols", navigatable);
|
||||
service.showTable(title, "Symbols", model, "Symbols", navigatable);
|
||||
|
||||
provider.setActionContextProvider(mouseEvent -> {
|
||||
|
||||
@@ -101,32 +116,38 @@ public class CreateSymbolTableAction extends ProgramSymbolContextAction {
|
||||
return new ProgramSymbolActionContext(provider, program, selectedSymbols, table);
|
||||
});
|
||||
|
||||
// replace the generic provider help with this action's help
|
||||
provider.setHelpLocation(getHelpLocation());
|
||||
// replace the generic provider help
|
||||
provider.setHelpLocation(new HelpLocation("SymbolTablePlugin", "Temporary_Symbol_Table"));
|
||||
|
||||
addActions(provider, model);
|
||||
addActions(services, provider, model);
|
||||
|
||||
GhidraThreadedTablePanel<SymbolRowObject> tablePanel = provider.getThreadedTablePanel();
|
||||
GhidraTable table = tablePanel.getTable();
|
||||
|
||||
configureSymbolTable(tool, table, model, program);
|
||||
configureSymbolTable(services, table, model, program);
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
private void addActions(TableComponentProvider<SymbolRowObject> provider,
|
||||
TransientSymbolTableModel model) {
|
||||
private static void addActions(ServiceProvider services,
|
||||
TableComponentProvider<SymbolRowObject> provider, TransientSymbolTableModel model) {
|
||||
|
||||
provider.installRemoveItemsAction();
|
||||
|
||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(plugin);
|
||||
provider.getTool().addLocalAction(provider, tableAction);
|
||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(services);
|
||||
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) {
|
||||
|
||||
new TransientSymbolTableDnDAdapter(table, model);
|
||||
|
||||
SymbolInspector symbolInspector = new SymbolInspector(tool, table);
|
||||
SymbolInspector symbolInspector = new SymbolInspector(services, table);
|
||||
SymbolRenderer renderer = model.getSymbolRenderer();
|
||||
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<>();
|
||||
int[] rows = table.getSelectedRows();
|
||||
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.util.template.TemplateSimplifier;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.cmd.CompoundCmd;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
@@ -33,9 +33,11 @@ import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.table.AddressBasedTableModel;
|
||||
import ghidra.util.table.column.*;
|
||||
import ghidra.util.table.field.*;
|
||||
import ghidra.util.task.*;
|
||||
|
||||
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 REFS_COL = 6;
|
||||
|
||||
private PluginTool tool;
|
||||
protected SymbolTable symbolTable;
|
||||
protected ReferenceManager refMgr;
|
||||
protected SymbolRowObject lastSymbol;
|
||||
@@ -59,9 +60,8 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
|
||||
protected SymbolRenderer symbolRenderer = new SymbolRenderer();
|
||||
|
||||
AbstractSymbolTableModel(PluginTool tool) {
|
||||
super("Symbols", tool, null, null);
|
||||
this.tool = tool;
|
||||
AbstractSymbolTableModel(ServiceProvider sp) {
|
||||
super("Symbols", sp, null, null);
|
||||
this.filter = new NewSymbolFilter();
|
||||
}
|
||||
|
||||
@@ -166,9 +166,11 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
return;
|
||||
}
|
||||
|
||||
RenameLabelCmd cmd = new RenameLabelCmd(symbol, newName, SourceType.USER_DEFINED);
|
||||
if (!tool.execute(cmd, getProgram())) {
|
||||
Msg.showError(getClass(), null, "Error Renaming Symbol", cmd.getStatusMsg());
|
||||
RenameTask task = new RenameTask(symbol, newName);
|
||||
TaskLauncher.launch(task);
|
||||
|
||||
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) {
|
||||
if (rowObjects == null || rowObjects.isEmpty()) {
|
||||
protected void delete(List<Symbol> symbols) {
|
||||
if (symbols == null || symbols.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tool.setStatusInfo("");
|
||||
List<Symbol> deleteList = new LinkedList<>();
|
||||
CompoundCmd<Program> cmd = new CompoundCmd<>("Delete symbol(s)");
|
||||
for (Symbol symbol : rowObjects) {
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol.isDynamic()) {
|
||||
continue; // can't delete dynamic symbols...
|
||||
}
|
||||
@@ -262,16 +263,19 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
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) {
|
||||
removeObject(new SymbolRowObject(s));
|
||||
}
|
||||
updateNow();
|
||||
}
|
||||
else {
|
||||
tool.setStatusInfo(cmd.getStatusMsg());
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
public SymbolFilter getFilter() {
|
||||
@@ -328,16 +332,102 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
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
|
||||
//==================================================================================================
|
||||
|
||||
private class NameTableColumn
|
||||
protected class NameTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Symbol> {
|
||||
|
||||
public static final String NAME = "Name";
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Name";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -347,7 +437,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class PinnedTableColumn
|
||||
protected class PinnedTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Boolean> {
|
||||
|
||||
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> {
|
||||
|
||||
@Override
|
||||
@@ -404,12 +494,14 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class SymbolTypeTableColumn
|
||||
protected class SymbolTypeTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||
|
||||
public static final String NAME = "Type";
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Type";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@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) {
|
||||
super(variable.getSymbol().getAddress(), variable.getVariableStorage().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private class DataTypeTableColumn
|
||||
protected class DataTypeTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||
|
||||
@Override
|
||||
@@ -470,7 +562,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class NamespaceTableColumn
|
||||
protected class NamespaceTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||
|
||||
@Override
|
||||
@@ -489,9 +581,11 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class SourceTableColumn
|
||||
protected class SourceTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, SourceType> {
|
||||
|
||||
public static final String NAME = "Source";
|
||||
|
||||
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<>() {
|
||||
@Override
|
||||
protected String getText(Object value) {
|
||||
@@ -509,7 +603,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Source";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -529,14 +623,16 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class ReferenceCountTableColumn
|
||||
protected class ReferenceCountTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
||||
|
||||
public static final String NAME = "Ref Count";
|
||||
|
||||
private ReferenceCountRenderer renderer = new ReferenceCountRenderer();
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Reference Count";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -562,7 +658,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class OffcutReferenceCountTableColumn
|
||||
protected class OffcutReferenceCountTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
||||
|
||||
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> {
|
||||
|
||||
@Override
|
||||
@@ -650,7 +746,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
|
||||
}
|
||||
|
||||
class OriginalNameColumn
|
||||
protected class OriginalNameColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||
|
||||
@Override
|
||||
@@ -688,7 +784,7 @@ public abstract class AbstractSymbolTableModel extends AddressBasedTableModel<Sy
|
||||
}
|
||||
}
|
||||
|
||||
private class SimplifiedNameColumn
|
||||
protected class SimplifiedNameColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
||||
|
||||
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.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.program.util.LabelFieldLocation;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.table.*;
|
||||
|
||||
@@ -126,12 +127,17 @@ class SymbolPanel extends JPanel {
|
||||
Program program = location.getProgram();
|
||||
SymbolTable symbolTable = program.getSymbolTable();
|
||||
Address address = location.getAddress();
|
||||
Symbol primarySymbol = symbolTable.getPrimarySymbol(address);
|
||||
if (primarySymbol == null) {
|
||||
return;
|
||||
|
||||
Symbol symbol = null;
|
||||
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);
|
||||
if (index >= 0) {
|
||||
gTable.selectRow(index);
|
||||
|
||||
+179
-11
@@ -21,16 +21,19 @@ import static ghidra.program.util.ProgramEvent.*;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.OptionDialogBuilder;
|
||||
import docking.widgets.table.DynamicTableColumn;
|
||||
import docking.widgets.table.TableColumnDescriptor;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||
@@ -39,17 +42,20 @@ import ghidra.app.events.ProgramActivatedPluginEvent;
|
||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.core.symboltree.actions.*;
|
||||
import ghidra.app.plugin.core.table.TableComponentProvider;
|
||||
import ghidra.app.services.BlockModelService;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
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.DomainObjectListenerBuilder;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.ProgramChangeRecord;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
@@ -79,12 +85,13 @@ import resources.Icons;
|
||||
"allows symbols to be renamed and deleted. This plugin also " +
|
||||
"shows references to a symbol. Filters can be set " +
|
||||
"to show subsets of the symbols.",
|
||||
servicesProvided = { SymbolTableService.class },
|
||||
servicesRequired = { GoToService.class, BlockModelService.class },
|
||||
eventsProduced = { ProgramLocationPluginEvent.class },
|
||||
eventsConsumed = { ProgramActivatedPluginEvent.class, ProgramLocationPluginEvent.class }
|
||||
)
|
||||
//@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_OUTGOING_EVENT_KEY = "NAVIGATE_ON_OUTGOING_EVENT";
|
||||
@@ -106,6 +113,10 @@ public class SymbolTablePlugin extends Plugin {
|
||||
private BlockModelService blockModelService;
|
||||
private SwingUpdateManager swingMgr;
|
||||
|
||||
// providers shown by the service interface
|
||||
private Map<String, TableComponentProvider<SymbolRowObject>> transientTableProviders =
|
||||
new HashMap<>();
|
||||
|
||||
private DomainObjectListener domainObjectListener = createDomainObjectListener();
|
||||
|
||||
/**
|
||||
@@ -126,6 +137,7 @@ public class SymbolTablePlugin extends Plugin {
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
|
||||
gotoService = tool.getService(GoToService.class);
|
||||
blockModelService = tool.getService(BlockModelService.class);
|
||||
|
||||
@@ -138,11 +150,6 @@ public class SymbolTablePlugin extends Plugin {
|
||||
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
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
@@ -456,10 +463,14 @@ public class SymbolTablePlugin extends Plugin {
|
||||
DockingAction clearPinnedAction = new ClearPinSymbolAction(getName(), pinnedPopupGroup);
|
||||
tool.addAction(clearPinnedAction);
|
||||
|
||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(this);
|
||||
CreateSymbolTableAction tableAction = new CreateSymbolTableAction(getTool());
|
||||
tableAction.getPopupMenuData().setMenuGroup(popupGroup);
|
||||
tool.addLocalAction(symProvider, tableAction);
|
||||
|
||||
SetSymbolPrimaryAction primaryAction = new SetSymbolPrimaryAction();
|
||||
primaryAction.getPopupMenuData().setMenuGroup(popupGroup);
|
||||
tool.addLocalAction(symProvider, primaryAction);
|
||||
|
||||
//@formatter:off
|
||||
String bottomGroup = "ShowReferencesTo" + 1;
|
||||
new ActionBuilder("Delete All References", getName())
|
||||
@@ -641,6 +652,163 @@ public class SymbolTablePlugin extends Plugin {
|
||||
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
|
||||
//==================================================================================================
|
||||
|
||||
+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");
|
||||
* 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.
|
||||
@@ -22,7 +22,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.model.DomainObjectListenerBuilder;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramChangeRecord;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
@@ -36,13 +36,13 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class TransientSymbolTableModel extends AbstractSymbolTableModel {
|
||||
|
||||
private HashSet<SymbolRowObject> rowObjects;
|
||||
protected HashSet<SymbolRowObject> rowObjects;
|
||||
|
||||
private SwingUpdateManager updater = new SwingUpdateManager(this::fireTableDataChanged);
|
||||
|
||||
public TransientSymbolTableModel(PluginTool tool, Program program,
|
||||
public TransientSymbolTableModel(ServiceProvider sp, Program program,
|
||||
HashSet<SymbolRowObject> rowObjects) {
|
||||
super(tool);
|
||||
super(sp);
|
||||
this.rowObjects = rowObjects;
|
||||
setProgram(program);
|
||||
symbolTable = program.getSymbolTable();
|
||||
|
||||
+7
-4
@@ -34,17 +34,20 @@ public class LabelCodeUnitFormat extends BrowserCodeUnitFormat {
|
||||
|
||||
@Override
|
||||
protected String getOffcutLabelStringForInstruction(Address offcutAddress,
|
||||
Instruction instruction, Address markupAddress) {
|
||||
Instruction instruction, Address markupAddress, Symbol symbol) {
|
||||
if (markupAddress != null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
Program program = instruction.getProgram();
|
||||
Symbol offsym = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
||||
|
||||
if (symbol == null) {
|
||||
symbol = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
||||
}
|
||||
Address instructionAddress = instruction.getMinAddress();
|
||||
long diff = offcutAddress.subtract(instructionAddress);
|
||||
boolean decorate = !offsym.isDynamic();
|
||||
boolean decorate = !symbol.isDynamic();
|
||||
boolean simplify = true;
|
||||
return getDefaultOffcutString(offsym, instruction, diff, decorate, simplify);
|
||||
return getDefaultOffcutString(symbol, instruction, diff, decorate, simplify);
|
||||
}
|
||||
|
||||
@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.*;
|
||||
|
||||
/**
|
||||
* A handler to process {@link XRefFieldMouseHandler} clicks
|
||||
* A handler to process XRef field clicks
|
||||
*/
|
||||
public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||
|
||||
|
||||
+13
-7
@@ -1367,7 +1367,7 @@ public class CodeUnitFormat {
|
||||
if (symbolAddress.isMemoryAddress()) {
|
||||
CodeUnit cu = program.getListing().getCodeUnitContaining(symbolAddress);
|
||||
if (isOffcut(symbolAddress, cu)) {
|
||||
return getOffcutLabelString(symbolAddress, cu, markupAddress);
|
||||
return getOffcutLabelString(symbolAddress, cu, markupAddress, symbol);
|
||||
}
|
||||
else if (isStringData(cu)) {
|
||||
return getLabelStringForStringData((Data) cu, symbol);
|
||||
@@ -1408,10 +1408,11 @@ public class CodeUnitFormat {
|
||||
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) {
|
||||
return getOffcutLabelStringForInstruction(offcutAddress, (Instruction) cu,
|
||||
markupAddress);
|
||||
markupAddress, symbol);
|
||||
}
|
||||
return getOffcutDataString(offcutAddress, (Data) cu);
|
||||
}
|
||||
@@ -1460,17 +1461,22 @@ public class CodeUnitFormat {
|
||||
* @param offcutAddress address for which generated label represents
|
||||
* @param instruction instruction containing offcut address
|
||||
* @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
|
||||
*/
|
||||
protected String getOffcutLabelStringForInstruction(Address offcutAddress,
|
||||
Instruction instruction, Address markupAddress) {
|
||||
Instruction instruction, Address markupAddress, Symbol symbol) {
|
||||
Program program = instruction.getProgram();
|
||||
Symbol offsym = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
||||
|
||||
if (symbol == null) {
|
||||
symbol = program.getSymbolTable().getPrimarySymbol(offcutAddress);
|
||||
}
|
||||
|
||||
Address instructionAddress = instruction.getMinAddress();
|
||||
long diff = offcutAddress.subtract(instructionAddress);
|
||||
boolean decorate = false; // we never decorate in the operand field
|
||||
boolean simplify = true; // we always simplify names of instruction labels
|
||||
if (offsym.isDynamic()) {
|
||||
if (symbol.isDynamic()) {
|
||||
Symbol containingSymbol = program.getSymbolTable().getPrimarySymbol(instructionAddress);
|
||||
if (containingSymbol != null) {
|
||||
String displayName = containingSymbol.getName();
|
||||
@@ -1481,7 +1487,7 @@ public class CodeUnitFormat {
|
||||
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,
|
||||
|
||||
+8
-11
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -20,7 +20,6 @@ import static org.junit.Assert.*;
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
@@ -74,10 +73,9 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest
|
||||
performAction(setLabelAction, context, false);
|
||||
waitForSwing();
|
||||
|
||||
OperandLabelDialog dialog = waitForDialogComponent(OperandLabelDialog.class);
|
||||
GhidraComboBox<?> combo = (GhidraComboBox<?>) findComponentByName(dialog, "MYCHOICE");
|
||||
SymbolChooserDialog dialog = waitForDialogComponent(SymbolChooserDialog.class);
|
||||
|
||||
setSelectedItem(combo, "bob");
|
||||
setSelectedItem(dialog, "bob");
|
||||
|
||||
pressButtonByText(dialog, "OK");
|
||||
waitForSwing();
|
||||
@@ -91,10 +89,9 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest
|
||||
performAction(setLabelAction, context, false);
|
||||
waitForSwing();
|
||||
|
||||
dialog = waitForDialogComponent(OperandLabelDialog.class);
|
||||
combo = (GhidraComboBox<?>) findComponentByName(dialog, "MYCHOICE");
|
||||
dialog = waitForDialogComponent(SymbolChooserDialog.class);
|
||||
|
||||
setSelectedItem(combo, "b");
|
||||
setSelectedItem(dialog, "b");
|
||||
pressButtonByText(dialog, "OK");
|
||||
|
||||
program.flushEvents();
|
||||
@@ -108,7 +105,7 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest
|
||||
assertEquals("dword ptr [b]", cb.getCurrentFieldText());
|
||||
}
|
||||
|
||||
private void setSelectedItem(GhidraComboBox<?> combo, String s) {
|
||||
runSwing(() -> combo.setSelectedItem(s));
|
||||
private void setSelectedItem(SymbolChooserDialog dialog, String item) {
|
||||
runSwing(() -> dialog.setSelectedItem(item));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -169,8 +169,9 @@ public class LabelFieldFactoryTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||
|
||||
// 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",
|
||||
tf.getText()); // bad offcut put on instruction
|
||||
actual); // bad offcut put on instruction
|
||||
|
||||
assertEquals(5, tf.getNumRows());
|
||||
}
|
||||
|
||||
+7
@@ -93,6 +93,13 @@ public class FieldLocation implements Comparable<FieldLocation> {
|
||||
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) {
|
||||
this.index = index;
|
||||
this.fieldNum = fieldNum;
|
||||
|
||||
+19
-2
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -38,4 +38,21 @@ public interface DynamicColumnTableModel<ROW_TYPE>
|
||||
* @return the model index
|
||||
*/
|
||||
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;
|
||||
|
||||
import static docking.DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||
import static docking.action.MenuData.NO_MNEMONIC;
|
||||
import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
|
||||
import static javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
|
||||
import static docking.DockingUtils.*;
|
||||
import static docking.action.MenuData.*;
|
||||
import static java.awt.event.InputEvent.*;
|
||||
import static javax.swing.ListSelectionModel.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
@@ -636,7 +636,7 @@ public class GTable extends JTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the underlying ConfigurableColumnTableModel if one is in-use}
|
||||
* {@return the underlying ConfigurableColumnTableModel if one is in use}
|
||||
*/
|
||||
public ConfigurableColumnTableModel getConfigurableColumnTableModel() {
|
||||
TableModel model = getUnwrappedTableModel();
|
||||
@@ -646,6 +646,17 @@ public class GTable extends JTable {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the underlying DynamicColumnTableModel if one is in use}
|
||||
*/
|
||||
public DynamicColumnTableModel<?> getDynamicTableModel() {
|
||||
TableModel model = getUnwrappedTableModel();
|
||||
if (model instanceof DynamicColumnTableModel<?>) {
|
||||
return (DynamicColumnTableModel<?>) model;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unrolls the current model by checking if the current model is inside of a wrapper table
|
||||
* model.
|
||||
@@ -912,7 +923,17 @@ public class GTable extends JTable {
|
||||
* @see #setPreferenceKey(String)
|
||||
*/
|
||||
public String getPreferenceKey() {
|
||||
return preferenceKey;
|
||||
if (preferenceKey != null) {
|
||||
// prefer the key that has been set programmatically
|
||||
return preferenceKey;
|
||||
}
|
||||
|
||||
DynamicColumnTableModel<?> dynamicModel = getDynamicTableModel();
|
||||
if (dynamicModel != null) {
|
||||
return dynamicModel.getPreferenceKey();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package ghidra.framework.cmd;
|
||||
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import java.util.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
|
||||
/**
|
||||
* Implementation for multiple commands that are done as a unit.
|
||||
@@ -28,7 +28,7 @@ import java.util.ArrayList;
|
||||
* @param <T> {@link DomainObject} implementation interface
|
||||
*/
|
||||
public class CompoundCmd<T extends DomainObject> implements Command<T> {
|
||||
private ArrayList<Command<T>> cmds;
|
||||
private List<Command<T>> cmds;
|
||||
private String statusMsg;
|
||||
private String name;
|
||||
|
||||
@@ -81,4 +81,10 @@ public class CompoundCmd<T extends DomainObject> implements Command<T> {
|
||||
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 source the source of this symbol. In general, a source of {@link SourceType#DEFAULT}
|
||||
* 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
|
||||
* non-default source
|
||||
* @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.
|
||||
* <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
|
||||
* 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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -36,8 +36,8 @@ public class CodeUnitLocation extends ProgramLocation {
|
||||
* @param componentPath if this is not null it is the path to a data
|
||||
* component inside of another data component
|
||||
* @param row the row within the field.
|
||||
* @param col - the display item index on the given row. (Note most fields only have one display item per row)
|
||||
* @param charOffset - the character offset within the display item.
|
||||
* @param col the display item index on the given row. (Note most fields only have one display item per row)
|
||||
* @param charOffset the character offset within the display item.
|
||||
*
|
||||
*/
|
||||
public CodeUnitLocation(Program program, Address addr, int[] componentPath, int row, int col,
|
||||
@@ -53,8 +53,8 @@ public class CodeUnitLocation extends ProgramLocation {
|
||||
* @param componentPath if this is not null it is the path to a data
|
||||
* component inside of another data component
|
||||
* @param row the row within the field.
|
||||
* @param col - the display item index on the given row. (Note most fields only have one display item per row)
|
||||
* @param charOffset - the character offset within the display item.
|
||||
* @param col the display item index on the given row. (Note most fields only have one display item per row)
|
||||
* @param charOffset the character offset within the display item.
|
||||
*
|
||||
*/
|
||||
protected CodeUnitLocation(Program program, Address addr, Address byteAddr, int[] componentPath,
|
||||
@@ -70,8 +70,8 @@ public class CodeUnitLocation extends ProgramLocation {
|
||||
* @param program the program for obtaining the code unit
|
||||
* @param addr address of the location; should not be null
|
||||
* @param row the row within the field.
|
||||
* @param col - the display item index on the given row. (Note most fields only have one display item per row)
|
||||
* @param charOffset - the character offset within the display item.
|
||||
* @param col the display item index on the given row. (Note most fields only have one display item per row)
|
||||
* @param charOffset the character offset within the display item.
|
||||
*
|
||||
*/
|
||||
public CodeUnitLocation(Program program, Address addr, int row, int col, int charOffset) {
|
||||
|
||||
+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 docking.widgets.combobox.GhidraComboBox;
|
||||
import ghidra.app.plugin.core.label.*;
|
||||
import ghidra.app.plugin.core.label.LabelHistoryDialog;
|
||||
import ghidra.app.plugin.core.label.LabelHistoryInputDialog;
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.LabelHistory;
|
||||
@@ -85,22 +85,6 @@ public class LabelMgrPluginScreenShots extends GhidraScreenShotGenerator {
|
||||
captureDialog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLabel() {
|
||||
LabelMgrPlugin plugin = getPlugin(tool, LabelMgrPlugin.class);
|
||||
final OperandLabelDialog dialog = new OperandLabelDialog(plugin);
|
||||
final GhidraComboBox<?> combo = (GhidraComboBox<?>) getInstanceField("myChoice", dialog);
|
||||
runSwing(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dialog.setTitle("Set Label at 004a671");
|
||||
combo.setSelectedItem("LAB_0040a671");
|
||||
}
|
||||
});
|
||||
showDialogWithoutBlocking(tool, dialog);
|
||||
captureDialog(350, 116);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowLabelHistory() {
|
||||
AddressSpace space = new GenericAddressSpace("Test", 32, AddressSpace.TYPE_RAM, 0);
|
||||
|
||||
Reference in New Issue
Block a user