diff --git a/Ghidra/Features/Base/ghidra_scripts/AutoRenameLabelsScript.java b/Ghidra/Features/Base/ghidra_scripts/AutoRenameLabelsScript.java index ab9863e61b..9af7b67f5b 100644 --- a/Ghidra/Features/Base/ghidra_scripts/AutoRenameLabelsScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/AutoRenameLabelsScript.java @@ -32,30 +32,25 @@ public class AutoRenameLabelsScript extends GhidraScript { return; } - String base = askString("Auto Rename Labels", "Enter label base name:"); - if (base == null) { - println("No base value entered."); + String baseName = askString("Auto Rename Labels", "Enter label name prefix:"); + if (baseName == null) { return; } int num = 1; - AddressSetView view = currentSelection; - if ((view == null) || (view.isEmpty())) + if ((view == null) || (view.isEmpty())) { return; + } - // Obtain the symbol table and listing from program SymbolTable symbolTable = currentProgram.getSymbolTable(); - - // Get the addresses in the set. AddressIterator it = view.getAddresses(true); - CompoundCmd cmd = new CompoundCmd("Auto Rename Labels"); while (it.hasNext()) { Address address = it.next(); Symbol primary = symbolTable.getPrimarySymbol(address); if (primary != null && primary.getSource() == SourceType.DEFAULT) { - cmd.add(new RenameLabelCmd(address, null, base + num++, SourceType.USER_DEFINED)); + cmd.add(new RenameLabelCmd(primary, baseName + num++, SourceType.USER_DEFINED)); } } if (cmd.size() > 0) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/RenameLabelCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/RenameLabelCmd.java index 211a3e982d..c1d572571d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/RenameLabelCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/RenameLabelCmd.java @@ -15,6 +15,12 @@ */ package ghidra.app.cmd.label; +import java.util.Objects; + +import org.apache.commons.lang3.StringUtils; + +import ghidra.app.util.NamespaceUtils; +import ghidra.app.util.SymbolPath; import ghidra.framework.cmd.Command; import ghidra.framework.model.DomainObject; import ghidra.program.model.address.Address; @@ -25,92 +31,119 @@ import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; /** - * Command for renaming labels. Handles converting back and forth between - * default and named labels as well. + * Command for renaming labels. Handles converting back and forth between default and named labels + * as well. */ public class RenameLabelCmd implements Command { private Address addr; private String oldName; private String newName; + private Symbol existingSymbol; private Namespace currentNamespace; private Namespace newNamespace; private SourceType source; - private String errorMsg = ""; + private String errorMessage = ""; /** - * Constructs a new command for renaming a label within a specified namespace. - * @param addr Address of label to be renamed. - * @param oldName the current name of the label to be renamed. - * @param newName the new name for the label. (null for default) - * @param currentNamespace the symbol's current name space. (The namespace to associate this label with) + * Constructs a new command for renaming global labels. + * + * @param addr Address of label to be renamed + * @param oldName the name of the label to be renamed; may be null if the existing label is a + * dynamic label + * @param newName the new name for the label * @param source the source of this symbol */ - public RenameLabelCmd(Address addr, String oldName, String newName, Namespace currentNamespace, + public RenameLabelCmd(Address addr, String oldName, String newName, SourceType source) { + this(addr, oldName, newName, null, null, source); + } + + /** + * Constructor renaming an existing symbol, but not changing its namespace + * + * @param symbol the existing symbol; may not be null + * @param newName the new symbol name + * @param source the desired symbol source + */ + public RenameLabelCmd(Symbol symbol, String newName, SourceType source) { + this(symbol, newName, symbol.getParentNamespace(), source); + } + + /** + * Constructor renaming an existing symbol and changing its namespace. If you do not need + * to change the namespace, then call {@link #RenameLabelCmd(Symbol, String, SourceType)}. + * + * @param symbol the existing symbol; may not be null + * @param newName the new symbol name + * @param newNamespace the new symbol namespace + * @param source the desired symbol source + */ + public RenameLabelCmd(Symbol symbol, String newName, Namespace newNamespace, SourceType source) { - this.addr = addr; - this.oldName = oldName; + + this.existingSymbol = Objects.requireNonNull(symbol); + this.addr = symbol.getAddress(); + this.oldName = symbol.getName(); this.newName = newName; - this.currentNamespace = currentNamespace; - this.newNamespace = currentNamespace; + this.currentNamespace = symbol.getParentNamespace(); + this.newNamespace = newNamespace; this.source = source; } /** * Constructs a new command for renaming a label within currentNamespace and changing the * namespace to newNamespace. - * @param addr Address of label to be renamed. - * @param oldName the current name of the label to be renamed. + * + * @param addr Address of label to be renamed + * @param oldName the current name of the label to be renamed * @param newName the new name for the label. (null for default) - * @param currentNamespace the symbol's current parent name space (null indicates global namespace) - * @param newNamespace final namespace (null indicates global namespace) + * @param currentNamespace the symbol's current parent name space; null for global namespace + * @param newNamespace the desired namespace; null for global namespace * @param source the source of this symbol */ - public RenameLabelCmd(Address addr, String oldName, String newName, Namespace currentNamespace, + private RenameLabelCmd(Address addr, String oldName, String newName, Namespace currentNamespace, Namespace newNamespace, SourceType source) { - this(addr, oldName, newName, currentNamespace, source); + this.addr = addr; + this.oldName = oldName; + this.newName = newName; + this.currentNamespace = currentNamespace; this.newNamespace = newNamespace; + this.source = source; } - /** - * Constructs a new command for renaming global labels. - * @param addr Address of label to be renamed. - * @param oldName the name of the label to be renamed; may be null - * of the existing label is a dynamic label - * @param newName the new name for the label - * @param source the source of this symbol - */ - public RenameLabelCmd(Address addr, String oldName, String newName, SourceType source) { - this(addr, oldName, newName, null, source); + @Override + public String getName() { + return "Rename Label"; + } + + @Override + public String getStatusMsg() { + return errorMessage; } - /** - * - * @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject) - */ @Override public boolean applyTo(DomainObject obj) { + Program program = (Program) obj; if (currentNamespace == null) { currentNamespace = program.getGlobalNamespace(); } - if (newNamespace == null) { newNamespace = program.getGlobalNamespace(); } - SymbolTable st = ((Program) obj).getSymbolTable(); - Symbol s = null; - if (oldName == null) { - s = st.getPrimarySymbol(addr); - } - else { - s = st.getSymbol(oldName, addr, currentNamespace); + if (!parseNameAndNamespace(program, newNamespace, newName)) { + return false; // errorMessage already set } + Symbol s = getSymbol(program); if (s == null) { - errorMsg = "Symbol not found: " + oldName; + return false; // errorMessage already set + } + + if (StringUtils.isBlank(newName) && s.getSource() != SourceType.DEFAULT) { + errorMessage = "Cannot set non-default symbol name to \"\""; return false; } @@ -120,45 +153,121 @@ public class RenameLabelCmd implements Command { } else { s.setName(newName, source); - - if (newName.length() == 0 && s.getSource() != SourceType.DEFAULT) { - errorMsg = "Rename failed - cannot set non-default symbol name to \"\""; - return false; - } - if (!newName.equals(s.getName())) { - errorMsg = "Rename failed"; + errorMessage = "Rename failed"; return false; } } return true; } catch (DuplicateNameException e) { - errorMsg = "Symbol already exists: " + newName; + errorMessage = "Symbol already exists: " + newName; } catch (InvalidInputException e) { - errorMsg = "Invalid entry: " + e.getMessage(); + errorMessage = "Invalid entry: " + e.getMessage(); } catch (CircularDependencyException e) { - errorMsg = e.getMessage(); + errorMessage = e.getMessage(); } return false; } - /** - * @see ghidra.framework.cmd.Command#getName() - */ - @Override - public String getName() { - return "Rename Label"; + private boolean parseNameAndNamespace(Program program, Namespace rootNamespace, String name) { + + SymbolPath symbolPath = getSymbolPath(name); + if (symbolPath == null) { + return false; // invalid symbol name + } + + // see if the user specified a namespace path + Namespace parent = getOrCreateNamespaces(program, symbolPath, rootNamespace); + if (parent == null) { + return false; // create namespace failed + } + + // update the new namespace and symbol name to reflect the parse results + newNamespace = parent; + newName = symbolPath.getName(); + return true; } - /** - * @see ghidra.framework.cmd.Command#getStatusMsg() - */ - @Override - public String getStatusMsg() { - return errorMsg; + private Symbol getSymbol(Program program) { + + if (existingSymbol != null) { + return existingSymbol; + } + + SymbolTable st = program.getSymbolTable(); + Symbol s = null; + if (oldName != null) { + s = st.getSymbol(oldName, addr, currentNamespace); + } + else { + s = st.getPrimarySymbol(addr); + if (s != null && !s.isDynamic()) { + // noted by the constructor, a null name can only be used to rename dynamic symbols + errorMessage = "Must specify name of symbol to be renamed"; + return null; + } + } + + if (s == null) { + errorMessage = "Symbol not found: " + oldName; + return null; + } + return s; } + // note: the root namespace will be used as the parent for any namespaces found in 'symbolPath' + private Namespace getOrCreateNamespaces(Program program, SymbolPath symbolPath, + Namespace rootNamespace) { + SymbolPath parentPath = symbolPath.getParent(); + if (parentPath == null) { + return rootNamespace; + } + + // + // Prefer a non-function namespace. This allows us to put a function inside of a namespace + // sharing the same name. + // + SymbolPath fullPath = new SymbolPath(rootNamespace.getSymbol()).append(parentPath); + Namespace nonFunctionNs = NamespaceUtils.getNonFunctionNamespace(program, fullPath); + if (nonFunctionNs != null) { + return nonFunctionNs; + } + + // + // At this point we can either reuse an existing function namespace or we have to create + // a new non-function namespaces, depending upon the names being used. Only use an + // existing function as a namespace if none of namespace path entries match the function + // name. + // + String name = symbolPath.getName(); + if (!parentPath.containsPathEntry(name)) { + Namespace functionNamespace = + NamespaceUtils.getFunctionNamespaceContaining(program, parentPath, addr); + if (functionNamespace != null) { + return functionNamespace; + } + } + + CreateNamespacesCmd cmd = + new CreateNamespacesCmd(parentPath.getPath(), rootNamespace, SourceType.USER_DEFINED); + if (cmd.applyTo(program)) { + return cmd.getNamespace(); + } + + errorMessage = cmd.getStatusMsg(); + return null; + } + + private SymbolPath getSymbolPath(String symbolName) { + + if (StringUtils.isBlank(symbolName)) { + errorMessage = "Name cannot be blank"; + return null; + } + + return new SymbolPath(symbolName); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java index dae9bddd46..45a1d2a1b7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java @@ -443,11 +443,7 @@ public class CodeBrowserClipboardProvider extends ByteCopier SymbolTable symbolTable = currentProgram.getSymbolTable(); Symbol symbol = symbolTable.getSymbol(reference); if ((symbol instanceof CodeSymbol) || (symbol instanceof FunctionSymbol)) { - String oldName = symbol.getName(); - Namespace namespace = symbol.getParentNamespace(); - Address symbolAddress = symbol.getAddress(); - RenameLabelCmd cmd = new RenameLabelCmd(symbolAddress, oldName, labelName, namespace, - SourceType.USER_DEFINED); + RenameLabelCmd cmd = new RenameLabelCmd(symbol, labelName, SourceType.USER_DEFINED); return tool.execute(cmd, currentProgram); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java index 3774b141f3..aaaf5990b6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java @@ -23,7 +23,6 @@ import ghidra.app.cmd.function.DeleteFunctionCmd; import ghidra.app.cmd.label.DeleteLabelCmd; import ghidra.app.cmd.label.RenameLabelCmd; 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; @@ -207,17 +206,19 @@ class SymbolTableModel extends AddressBasedTableModel { return; } - if (columnIndex == LABEL_COL) { - String newName = aValue.toString(); - if (!symbol.getName().equals(newName)) { - Command renameCmd = new RenameLabelCmd(symbol.getAddress(), symbol.getName(), - newName, symbol.getParentNamespace(), SourceType.USER_DEFINED); + if (columnIndex != LABEL_COL) { + return; + } - if (!tool.execute(renameCmd, getProgram())) { - Msg.showError(getClass(), provider.getComponent(), "Error Renaming Symbol", - renameCmd.getStatusMsg()); - } - } + String newName = aValue.toString(); + if (symbol.getName().equals(newName)) { + return; + } + + RenameLabelCmd renameCmd = new RenameLabelCmd(symbol, newName, SourceType.USER_DEFINED); + if (!tool.execute(renameCmd, getProgram())) { + Msg.showError(getClass(), provider.getComponent(), "Error Renaming Symbol", + renameCmd.getStatusMsg()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java index b581b688fd..632f88416a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java @@ -168,12 +168,16 @@ public class AddEditDialog extends DialogComponentProvider { cmd.add(new AddLabelCmd(addr, symbolName, parent, SourceType.USER_DEFINED)); } else { - cmd.add(new RenameLabelCmd(addr, symbol.getName(), symbolName, - symbol.getParentNamespace(), parent, SourceType.USER_DEFINED)); + cmd.add(new RenameLabelCmd(symbol, labelText, namespace, SourceType.USER_DEFINED)); isCurrentlyEntryPoint = symbol.isExternalEntryPoint(); isCurrentlyPinned = symbol.isPinned(); } + if (!tool.execute(cmd, program)) { + setStatusText(cmd.getStatusMsg()); + return; + } + if (primaryCheckBox.isEnabled() && primaryCheckBox.isSelected()) { cmd.add(new SetLabelPrimaryCmd(addr, symbolName, parent)); } @@ -185,14 +189,12 @@ public class AddEditDialog extends DialogComponentProvider { cmd.add(new PinSymbolCmd(addr, symbolName, !isCurrentlyPinned)); } - if (cmd.size() > 0) { - - if (!tool.execute(cmd, program)) { - setStatusText(cmd.getStatusMsg()); - return; - } - updateRecentLabels(symbolName); + if (!tool.execute(cmd, program)) { + setStatusText(cmd.getStatusMsg()); + return; } + updateRecentLabels(symbolName); + program = null; close(); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/ClearTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/ClearTest.java index 34164585b4..4e492dfc75 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/ClearTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/ClearTest.java @@ -430,8 +430,7 @@ public class ClearTest extends AbstractGhidraHeadedIntegrationTest { Symbol[] symbols = program.getSymbolTable().getSymbols(addr("0x10022bf")); Symbol s = symbols[0]; - RenameLabelCmd cmd = new RenameLabelCmd(s.getAddress(), s.getName(), "Fred", - s.getParentNamespace(), SourceType.USER_DEFINED); + RenameLabelCmd cmd = new RenameLabelCmd(s, "Fred", SourceType.USER_DEFINED); applyCmd(program, cmd); makeSelection(tool, program, addr("0x10022bf"), addr("0x10022c4")); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/LabelActionTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/LabelActionTest.java index 3c0f8cd153..67994aef4c 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/LabelActionTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/LabelActionTest.java @@ -136,25 +136,25 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest @Test public void testNotepadLocations() { ActionContext context = new ActionContext(); - assertEquals(false, addLabel.isEnabledForContext(context)); + assertFalse(addLabel.isEnabledForContext(context)); - assertEquals(false, editLabel.isEnabledForContext(context)); + assertFalse(editLabel.isEnabledForContext(context)); - assertEquals(false, removeLabel.isEnabledForContext(context)); + assertFalse(removeLabel.isEnabledForContext(context)); - assertEquals(false, setLabel.isEnabledForContext(context)); + assertFalse(setLabel.isEnabledForContext(context)); env.open(program); cb.updateNow(); context = cb.getProvider().getActionContext(null); - assertEquals(true, addLabel.isEnabledForContext(context)); + assertTrue(addLabel.isEnabledForContext(context)); - assertEquals(false, editLabel.isEnabledForContext(context)); + assertFalse(editLabel.isEnabledForContext(context)); - assertEquals(false, removeLabel.isEnabledForContext(context)); + assertFalse(removeLabel.isEnabledForContext(context)); - assertEquals(false, setLabel.isEnabledForContext(context)); + assertFalse(setLabel.isEnabledForContext(context)); SampleLocationGenerator locGen = new SampleLocationGenerator(program); locGen.toggleOpenComposites(cb); @@ -162,9 +162,6 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest } - /** - * @see ghidra.app.LocationCallback#locationGenerated(ghidra.program.singleuser.util.ProgramLocation) - */ @Override public void locationGenerated(ProgramLocation loc) { @@ -184,11 +181,11 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest if (loc instanceof LabelFieldLocation) { Symbol s = labelMgrPlugin.getSymbol((ListingActionContext) context); - assertEquals(caseName, false, addLabel.isEnabledForContext(context)); - assertEquals(caseName, true, editLabel.isEnabledForContext(context)); - assertEquals(caseName, false, editExternalLocation.isEnabledForContext(context)); + assertFalse(caseName, addLabel.isEnabledForContext(context)); + assertTrue(caseName, editLabel.isEnabledForContext(context)); + assertFalse(caseName, editExternalLocation.isEnabledForContext(context)); assertEquals(caseName, !s.isDynamic(), removeLabel.isEnabledForContext(context)); - assertEquals(caseName, false, setLabel.isEnabledForContext(context)); + assertFalse(caseName, setLabel.isEnabledForContext(context)); assertEquals(EditLabelAction.EDIT_LABEL, editLabel.getPopupMenuData().getMenuItemName()); @@ -249,8 +246,8 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest assertEquals(caseName, !hasComponentPath, addLabel.isEnabledForContext(context)); assertEquals(caseName, component != null, editLabel.isEnabledForContext(context)); - assertEquals(caseName, false, removeLabel.isEnabledForContext(context)); - assertEquals(caseName, false, setLabel.isEnabledForContext(context)); + assertFalse(caseName, removeLabel.isEnabledForContext(context)); + assertFalse(caseName, setLabel.isEnabledForContext(context)); if (component != null) { assertEquals(EditLabelAction.EDIT_FIELDNAME, @@ -258,16 +255,16 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest } } else if (!(loc instanceof FunctionLocation)) { - assertEquals(caseName, true, addLabel.isEnabledForContext(context)); - assertEquals(caseName, false, editLabel.isEnabledForContext(context)); - assertEquals(caseName, false, removeLabel.isEnabledForContext(context)); - assertEquals(caseName, false, setLabel.isEnabledForContext(context)); + assertTrue(caseName, addLabel.isEnabledForContext(context)); + assertFalse(caseName, editLabel.isEnabledForContext(context)); + assertFalse(caseName, removeLabel.isEnabledForContext(context)); + assertFalse(caseName, setLabel.isEnabledForContext(context)); } else { - assertEquals(caseName, false, addLabel.isEnabledForContext(context)); - assertEquals(caseName, false, editLabel.isEnabledForContext(context)); - assertEquals(caseName, false, removeLabel.isEnabledForContext(context)); - assertEquals(caseName, false, setLabel.isEnabledForContext(context)); + assertFalse(caseName, addLabel.isEnabledForContext(context)); + assertFalse(caseName, editLabel.isEnabledForContext(context)); + assertFalse(caseName, removeLabel.isEnabledForContext(context)); + assertFalse(caseName, setLabel.isEnabledForContext(context)); } } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AutoRenameLabelsScriptTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AutoRenameLabelsScriptTest.java index e216cae385..918c606f33 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AutoRenameLabelsScriptTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AutoRenameLabelsScriptTest.java @@ -25,7 +25,6 @@ import javax.swing.JTextField; import org.junit.*; import ghidra.app.cmd.function.CreateFunctionCmd; -import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.services.ProgramManager; import ghidra.framework.Application; @@ -33,7 +32,6 @@ 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.ProgramSelection; import ghidra.test.*; /** @@ -58,8 +56,9 @@ public class AutoRenameLabelsScriptTest extends AbstractGhidraHeadedIntegrationT env.showTool(); script = - Application.getModuleFile("Base", "ghidra_scripts/AutoRenameLabelsScript.java").getFile( - true); + Application.getModuleFile("Base", "ghidra_scripts/AutoRenameLabelsScript.java") + .getFile( + true); env.showTool(); } @@ -88,12 +87,8 @@ public class AutoRenameLabelsScriptTest extends AbstractGhidraHeadedIntegrationT return builder.getProgram(); } - /* - * @see TestCase#tearDown() - */ @After public void tearDown() throws Exception { - env.release(program); env.dispose(); } @@ -102,29 +97,23 @@ public class AutoRenameLabelsScriptTest extends AbstractGhidraHeadedIntegrationT SymbolTable symbolTable = program.getSymbolTable(); Symbol s1 = symbolTable.getPrimarySymbol(addr(0x01003a94)); assertNotNull(s1); - assertTrue(s1.getSource() == SourceType.DEFAULT); + assertEquals(s1.getSource(), SourceType.DEFAULT); Symbol s2 = symbolTable.getPrimarySymbol(addr(0x01003a97)); assertNotNull(s2); - assertTrue(s2.getSource() == SourceType.DEFAULT); + assertEquals(s2.getSource(), SourceType.DEFAULT); - ProgramSelection sel = new ProgramSelection(addr(0x01003a94), addr(0x01003a9b)); - tool.firePluginEvent(new ProgramSelectionPluginEvent("test", sel, program)); - waitForPostedSwingRunnables(); + makeSelection(tool, program, addr(0x01003a94), addr(0x01003a9b)); ScriptTaskListener scriptID = env.runScript(script); - JDialog dialog = waitForJDialog(tool.getToolFrame(), "Auto Rename Labels", 2000); - final JTextField tf = findComponent(dialog, JTextField.class); + JDialog dialog = waitForJDialog("Auto Rename Labels"); + JTextField tf = findComponent(dialog, JTextField.class); runSwing(() -> tf.setText("My_Label")); pressButtonByText(dialog, "OK"); waitForScriptCompletion(scriptID, 100000); - program.flushEvents(); - waitForPostedSwingRunnables(); - - s1 = symbolTable.getPrimarySymbol(addr(0x01003a94)); - s2 = symbolTable.getPrimarySymbol(addr(0x01003a97)); + waitForProgram(program); assertEquals("My_Label1", s1.getName()); assertEquals("My_Label2", s2.getName()); @@ -134,39 +123,34 @@ public class AutoRenameLabelsScriptTest extends AbstractGhidraHeadedIntegrationT public void testNoRenameOnUserDefined() throws Exception { SymbolTable symbolTable = program.getSymbolTable(); Symbol s1 = symbolTable.getPrimarySymbol(addr(0x010046cc)); - assertTrue(s1.getSource() == SourceType.DEFAULT); + assertEquals(s1.getSource(), SourceType.DEFAULT); // create a function at 10046d0 so we don't have a default label CreateFunctionCmd cmd = new CreateFunctionCmd("My_Function1", addr(0x010046d0), null, SourceType.ANALYSIS); - tool.execute(cmd, program); - program.flushEvents(); - waitForPostedSwingRunnables(); + applyCmd(program, cmd); Symbol s2 = symbolTable.getPrimarySymbol(addr(0x010046d0)); assertNotNull(s2); - assertTrue(s2.getSource() != SourceType.DEFAULT); + assertNotEquals(s2.getSource(), SourceType.DEFAULT); String s2Name = s2.getName(); - ProgramSelection sel = new ProgramSelection(addr(0x010046cc), addr(0x010046d0)); - tool.firePluginEvent(new ProgramSelectionPluginEvent("test", sel, program)); - waitForPostedSwingRunnables(); + makeSelection(tool, program, addr(0x010046cc), addr(0x010046d0)); ScriptTaskListener scriptID = env.runScript(script); - JDialog dialog = waitForJDialog(tool.getToolFrame(), "Auto Rename Labels", 2000); - final JTextField tf = findComponent(dialog, JTextField.class); + JDialog dialog = waitForJDialog("Auto Rename Labels"); + JTextField tf = findComponent(dialog, JTextField.class); runSwing(() -> tf.setText("My_Label")); pressButtonByText(dialog, "OK"); waitForScriptCompletion(scriptID, 100000); - program.flushEvents(); - waitForPostedSwingRunnables(); - s1 = symbolTable.getPrimarySymbol(addr(0x010046cc)); + waitForProgram(program); + assertEquals("My_Label1", s1.getName()); + // only dynamic label should get renamed - s2 = symbolTable.getPrimarySymbol(addr(0x010046d0)); - assertTrue(!s2.getName().equals("My_Label2")); + assertFalse(s2.getName().equals("My_Label2")); assertEquals(s2Name, s2.getName()); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreeNavigationTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreeNavigationTest.java index 5121f14ea8..9abc09db87 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreeNavigationTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreeNavigationTest.java @@ -450,21 +450,16 @@ public class SymbolTreeNavigationTest extends AbstractProgramBasedTest { } private void rename(Symbol symbol, String newName) { - - String oldName = symbol.getName(); - RenameLabelCmd cmd = - new RenameLabelCmd(symbol.getAddress(), oldName, newName, SourceType.USER_DEFINED); + RenameLabelCmd cmd = new RenameLabelCmd(symbol, newName, SourceType.USER_DEFINED); applyCmd(cmd); util.waitForTree(); } private Symbol createGlobalLabel(Address addr) { - return createGlobalLabel(addr, "GlobalLabel"); } private Symbol createGlobalLabel(Address addr, String labelName) { - AddLabelCmd cmd = new AddLabelCmd(addr, labelName, SourceType.USER_DEFINED); applyCmd(cmd); Symbol symbol = cmd.getSymbol(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java index 9e8c6f472f..5cd4cb6489 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java @@ -28,6 +28,7 @@ import java.util.function.BiConsumer; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.table.TableModel; +import javax.swing.text.JTextComponent; import org.jdom.Element; import org.junit.*; @@ -346,12 +347,47 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest { waitForNotBusy(); - assertTrue(!symbolTable.isEditing()); + assertFalse(symbolTable.isEditing()); Symbol s = getSymbol(row); assertEquals("ghidra.Is.Cool", s.getName()); } + @Test + public void testEditName_AddNamespace() throws Exception { + openProgram("sample"); + + waitForNotBusy(); + + String symbolName = "ghidra"; + int row = findRow(symbolName); + + doubleClick(symbolTable, row, SymbolTableModel.LABEL_COL); + waitForSwing(); + assertTrue(symbolTable.isEditing()); + + Component editor = symbolTable.getEditorComponent(); + assertNotNull(editor); + JTextField textField = (JTextField) editor; + String currentText = getText(textField); + assertEquals(symbolName, currentText); + + String newNamespaceName = "NS1"; + JTextComponent textComponent = (JTextComponent) editor; + runSwing(() -> textComponent.selectAll()); + myTypeText(editor, newNamespaceName + Namespace.DELIMITER + symbolName); + runSwing(() -> symbolTable.editingStopped(new ChangeEvent(symbolTable))); + + waitForNotBusy(); + + assertFalse(symbolTable.isEditing()); + + Symbol s = getSymbol(row); + assertEquals(symbolName, s.getName()); + Namespace namespace = s.getParentNamespace(); + assertEquals(newNamespaceName, namespace.getName()); + } + @Test public void testQuickLookup() throws Exception { openProgram("sample"); @@ -400,7 +436,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest { openProgram("sample"); int rowCount = symbolTable.getRowCount(); - assertTrue(!deleteAction.isEnabled()); + assertFalse(deleteAction.isEnabled()); int row = findRow("ghidra"); Rectangle rect = symbolTable.getCellRect(row, 0, true); @@ -488,7 +524,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest { public void testMakeSelection() throws Exception { openProgram("sample"); - assertTrue(!makeSelectionAction.isEnabled()); + assertFalse(makeSelectionAction.isEnabled()); int row1 = findRow("ghidra"); int row2 = findRow("KERNEL32.dll_GetProcAddress"); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java index 24a9f9c321..f696c755d7 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java @@ -508,8 +508,10 @@ public class FillOutStructureCmd extends BackgroundCommand { if (isThisParam) { Namespace rootNamespace = currentProgram.getGlobalNamespace(); Namespace newNamespace = createUniqueClassName(rootNamespace); - RenameLabelCmd command = new RenameLabelCmd(f.getEntryPoint(), f.getName(), f.getName(), - rootNamespace, newNamespace, SourceType.USER_DEFINED); + String name = f.getName(); + Symbol symbol = f.getSymbol(); + RenameLabelCmd command = + new RenameLabelCmd(symbol, name, newNamespace, SourceType.USER_DEFINED); if (!command.applyTo(currentProgram)) { return null; } @@ -545,12 +547,10 @@ public class FillOutStructureCmd extends BackgroundCommand { symbolTable.createClass(rootNamespace, newClassName, SourceType.USER_DEFINED); } catch (DuplicateNameException e) { - // Shouldn't happen - e.printStackTrace(); + Msg.error(this, "Error creating class '" + newClassName + "'", e); } catch (InvalidInputException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Msg.error(this, "Error creating class '" + newClassName + "'", e); } return newClass; }