diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/CreateNamespacesCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/CreateNamespacesCmd.java index 73e973f703..8aa1a8a83e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/CreateNamespacesCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/CreateNamespacesCmd.java @@ -31,7 +31,7 @@ import ghidra.util.exception.InvalidInputException; * * Example strings: * *

diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ThunkReferenceAddressDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ThunkReferenceAddressDialog.java index f636f73dce..30c674c790 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ThunkReferenceAddressDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ThunkReferenceAddressDialog.java @@ -243,14 +243,14 @@ public class ThunkReferenceAddressDialog extends DialogComponentProvider { return null; } - List namespaces = NamespaceUtils.getNamespaces(parentNs, null, program); + List namespaces = NamespaceUtils.getNamespaceByPath(program, null, parentNs); if (namespaces.isEmpty()) { SymbolTable symbolTable = program.getSymbolTable(); for (String libraryName : program.getExternalManager().getExternalLibraryNames()) { Symbol librarySymbol = symbolTable.getLibrarySymbol(libraryName); - namespaces = NamespaceUtils.getNamespaces(parentNs, - (Library) librarySymbol.getObject(), program); + namespaces = NamespaceUtils.getNamespaceByPath(program, + (Library) librarySymbol.getObject(), parentNs); if (!namespaces.isEmpty()) { break; // use first library containing namespace } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToHelper.java index 7a0d13ab4d..eafa0d4e37 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToHelper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToHelper.java @@ -394,7 +394,7 @@ public class GoToHelper { StringBuilder buf = new StringBuilder(); while (!nameStack.isEmpty()) { buf.append(nameStack.pop()); - buf.append(Namespace.NAMESPACE_DELIMITER); + buf.append(Namespace.DELIMITER); } buf.append(externalLoc.getLabel()); return buf.toString(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/match/MatchSymbol.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/match/MatchSymbol.java index 03248faad5..5b909fa8b0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/match/MatchSymbol.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/match/MatchSymbol.java @@ -117,7 +117,7 @@ public class MatchSymbol { SymbolPath namespacePath = aSymbolPath.getParent(); if (!aSymbolIdentifier.isExternalSymbol() && namespacePath != null && !aSymbolPath.equals(bSymbolIdentifier.symbolPath) && - NamespaceUtils.getNamespace(bProgram, namespacePath, null) != null) { + NamespaceUtils.getNonFunctionNamespace(bProgram, namespacePath) != null) { // skip match with namespace mismatch when source namespace exists in destination continue; } 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 f42980ba6c..1d4cbdd4fe 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 @@ -172,24 +172,39 @@ public class AddEditDialog extends DialogComponentProvider { if (parentPath == null) { return rootNamespace; } - String relativeParentPath = parentPath.getPath(); - SymbolPath absoluteParentPath = - new SymbolPath(rootNamespace.getSymbol()).append(parentPath); - Namespace parentNamespace = NamespaceUtils.getNamespace(program, absoluteParentPath, addr); - if (parentNamespace != null) { - return parentNamespace; + // + // 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; } - // run the create namespaces command - CreateNamespacesCmd command = - new CreateNamespacesCmd(relativeParentPath, rootNamespace, SourceType.USER_DEFINED); - - if (tool.execute(command, program)) { - return command.getNamespace(); + // + // 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; + } } - setStatusText(command.getStatusMsg()); + CreateNamespacesCmd cmd = + new CreateNamespacesCmd(parentPath.getPath(), rootNamespace, SourceType.USER_DEFINED); + if (tool.execute(cmd, program)) { + return cmd.getNamespace(); + } + + setStatusText(cmd.getStatusMsg()); return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java index 624c42856c..614b790db3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java @@ -192,7 +192,7 @@ public class NamespacePath implements Comparable { public String asNamespaceString() { StringBuilder sb = new StringBuilder(); doInOrderTraversal( - nsp -> sb.append(sb.length() != 0 ? Namespace.NAMESPACE_DELIMITER : "").append( + nsp -> sb.append(sb.length() != 0 ? Namespace.DELIMITER : "").append( nsp.isRoot() ? "ROOT" : nsp.name)); return sb.toString(); } @@ -207,7 +207,7 @@ public class NamespacePath implements Comparable { doInOrderTraversal(nsp -> { if (!nsp.isRoot()) { - sb.append(sb.length() != 0 ? Namespace.NAMESPACE_DELIMITER : "").append(nsp.name); + sb.append(sb.length() != 0 ? Namespace.DELIMITER : "").append(nsp.name); } }); @@ -219,7 +219,7 @@ public class NamespacePath implements Comparable { public String toString() { StringBuilder sb = new StringBuilder(); doInOrderTraversal( - nsp -> sb.append(sb.length() != 0 ? Namespace.NAMESPACE_DELIMITER : "").append( + nsp -> sb.append(sb.length() != 0 ? Namespace.DELIMITER : "").append( nsp.isRoot() ? "ROOT" : nsp.name).append( "(" + (nsp.getType() != null ? nsp.getType() : "unknown type") + ")")); return sb.toString(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java index aae834ea12..c0a2e8ca89 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java @@ -39,7 +39,7 @@ public abstract class DemangledObject { protected static final String SPACE = " "; protected static final Pattern SPACE_PATTERN = Pattern.compile(SPACE); - protected static final String NAMESPACE_SEPARATOR = Namespace.NAMESPACE_DELIMITER; + protected static final String NAMESPACE_SEPARATOR = Namespace.DELIMITER; protected static final String EMPTY_STRING = ""; protected String originalMangled; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledType.java index 389eb05262..4f627fbd4d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledType.java @@ -193,7 +193,7 @@ public class DemangledType { return ""; } - buffer.append(Namespace.NAMESPACE_DELIMITER); + buffer.append(Namespace.DELIMITER); return buffer.toString(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java index 00143d4758..628bfa2892 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java @@ -75,12 +75,12 @@ class FunctionsXmlMgr { * <!ELEMENT FUNCTION (RETURN_TYPE?, ADDRESS_RANGE*, REGULAR_CMT?, REPEATABLE_CMT?, TYPEINFO_CMT?, STACK_FRAME?, REGISTER_VAR*)> * *

- * @param parser - * @param overwriteConflicts - * @param ignoreStackFrames - * @param monitor - * @throws AddressFormatException - * @throws CancelledException + * @param parser the parser + * @param overwriteConflicts true to overwrite any conflicts + * @param ignoreStackFrames true to ignore stack frames + * @param monitor the task monitor + * @throws AddressFormatException if any address is not parsable + * @throws CancelledException if the operation is cancelled through the monitor */ void read(XmlPullParser parser, boolean overwriteConflicts, boolean ignoreStackFrames, TaskMonitor monitor) throws AddressFormatException, CancelledException { @@ -94,9 +94,7 @@ class FunctionsXmlMgr { dtParser = new DtParser(dataManager); while (parser.peek().isStart()) { - if (monitor.isCancelled()) { - throw new CancelledException(); - } + monitor.checkCanceled(); final XmlElement functionElement = parser.start("FUNCTION"); @@ -155,7 +153,8 @@ class FunctionsXmlMgr { try { Symbol symbol = func.getSymbol(); Namespace namespace = - NamespaceUtils.getNamespace(program, namespacePath, entryPoint); + NamespaceUtils.getFunctionNamespaceAt(program, namespacePath, + entryPoint); if (namespace == null) { namespace = program.getGlobalNamespace(); } @@ -258,13 +257,6 @@ class FunctionsXmlMgr { } } - /** - * Add local vars to a function. - * - * @param function - * @param variables - * @throws InvalidInputException - */ private void addLocalVars(Function function, List variables, boolean overwriteConflicts) throws InvalidInputException { for (Variable v : variables) { @@ -275,8 +267,9 @@ class FunctionsXmlMgr { try { String name = v.getName(); boolean isDefaultVariableName = (name == null) || - SymbolUtilities.getDefaultLocalName(program, v.getStackOffset(), 0).equals( - name); + SymbolUtilities.getDefaultLocalName(program, v.getStackOffset(), 0) + .equals( + name); SourceType sourceType = isDefaultVariableName ? SourceType.DEFAULT : SourceType.USER_DEFINED; @@ -305,13 +298,9 @@ class FunctionsXmlMgr { return dtParser.parseDataType(dtName, cp, size); } - /** + /* * Returns the text embedded in an optional xml element. If the next element in the stream is not - * the "expectedElementName", the xml parser stream is unchanged. - *

- * @param parser - * @param expectedElementName - * @return + * the "expectedElementName", the xml parser stream is unchanged */ private String getElementText(XmlPullParser parser, String expectedElementName) { String result = null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java index 28dd1f4c2a..acee54c937 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java @@ -1065,7 +1065,7 @@ public class ProgramBuilder { ExternalManager extMgr = program.getExternalManager(); Namespace namespace = extMgr.addExternalLibraryName(libraryName, sourceType); - if (externalLabel != null && externalLabel.indexOf(Namespace.NAMESPACE_DELIMITER) > 0) { + if (externalLabel != null && externalLabel.indexOf(Namespace.DELIMITER) > 0) { // External manager API does not yet support creation of namespaces within // library so we handle that here SymbolPath symPath = new SymbolPath(externalLabel); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java index a091bb3d66..1d23a6e51d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java @@ -1293,8 +1293,8 @@ public class CodeUnitFormat { namespaceName = parentNamespace.getName(true); } } - if (namespaceName.length() != 0 && !namespaceName.endsWith(Namespace.NAMESPACE_DELIMITER)) { - namespaceName += Namespace.NAMESPACE_DELIMITER; + if (namespaceName.length() != 0 && !namespaceName.endsWith(Namespace.DELIMITER)) { + namespaceName += Namespace.DELIMITER; } return namespaceName + name; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java index d39862997f..5a097d98db 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java @@ -27,6 +27,7 @@ import org.junit.*; import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.app.cmd.label.AddLabelCmd; +import ghidra.app.cmd.label.CreateNamespacesCmd; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin; import ghidra.app.util.AddEditDialog; @@ -93,6 +94,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { @After public void tearDown() throws Exception { + dialog.close(); env.dispose(); } @@ -107,14 +109,14 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(globalScope, scope); assertTrue(primaryCheckBox.isSelected()); assertTrue(!primaryCheckBox.isEnabled()); - dialogCancel(); + pressCancel(); } @Test public void testLabelChangeOne() { addLabel(addr(0x0100642a)); setText("printf"); - dialogOK(); + pressOk(); Symbol s = getUniqueSymbol(program, "printf", null); assertNotNull(s); @@ -126,14 +128,14 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { public void testDuplicateLabelForAdd() { addLabel(addr(0x0100642a)); setText("printf"); - dialogOK(); + pressOk(); addLabel(addr(0x0100642c)); setText("printf"); assertEquals(" ", dialog.getStatusText()); - dialogOK(); + pressOk(); assertTrue(dialog.getStatusText().length() > 0); - dialogCancel(); + pressCancel(); } @Test @@ -141,7 +143,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { addLabel(addr(0x0100642a)); setText("printf"); setCheckbox(entryCheckBox, true); - dialogOK(); + pressOk(); assertTrue(!dialog.isVisible()); Symbol s = getUniqueSymbol(program, "printf", null); assertNotNull(s); @@ -153,7 +155,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { addLabel(addr(0x0100642a)); setText("printf"); setCheckbox(pinnedCheckBox, true); - dialogOK(); + pressOk(); assertTrue(!dialog.isVisible()); Symbol s = getUniqueSymbol(program, "printf", null); assertNotNull(s); @@ -161,7 +163,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { editLabel(s); setCheckbox(pinnedCheckBox, false); - dialogOK(); + pressOk(); assertTrue(!s.isPinned()); } @@ -169,7 +171,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testEmptyLabel() { addLabel(addr(0x0100642a)); - dialogOK(); + pressOk(); assertTrue(dialog.isVisible()); assertTrue(dialog.getStatusText().length() > 0); @@ -239,7 +241,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { setText("printf"); Namespace scope = st.getNamespace(a); setScope(scope); - dialogOK(); + pressOk(); s = getUniqueSymbol(program, "printf", scope); assertNotNull(s); assertTrue(!s.isGlobal()); @@ -259,7 +261,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { setText("printf"); setCheckbox(primaryCheckBox, true); - dialogOK(); + pressOk(); s = getUniqueSymbol(program, "entry", null); assertTrue(!s.isPrimary()); s = getUniqueSymbol(program, "printf", null); @@ -286,7 +288,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { addLabel(addr(0x100642a)); setText("aaaa"); assertEquals(0, recentLabels.size()); - dialogOK(); + pressOk(); assertEquals(1, recentLabels.size()); assertEquals("aaaa", recentLabels.get(0)); @@ -295,7 +297,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("", getText()); //assertEquals("aaaa", getText()); setText("bbbb"); - dialogOK(); + pressOk(); assertEquals(2, recentLabels.size()); assertEquals("bbbb", recentLabels.get(0)); @@ -308,7 +310,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { for (int i = 0; i < 12; i++) { addLabel(addr(0x100642a)); setText("l" + i); - dialogOK(); + pressOk(); } assertEquals(10, recentLabels.size()); @@ -328,7 +330,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(entryCheckBox.isSelected()); assertTrue(primaryCheckBox.isSelected()); assertTrue(!primaryCheckBox.isEnabled()); - dialogCancel(); + pressCancel(); } @@ -352,7 +354,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { editLabel(s); assertEquals("entry", getText()); setText("bob"); - dialogOK(); + pressOk(); program.flushEvents(); waitForSwing(); assertEquals("bob", function.getName()); @@ -378,7 +380,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { editLabel(fredSymbol); setCheckbox(primaryCheckBox, true); - dialogOK(); + pressOk(); program.flushEvents(); waitForSwing(); assertEquals("fred", function.getName()); @@ -400,7 +402,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { Object selectedItem = namespacesComboBox.getSelectedItem(); assertEquals(ns, ((AddEditDialog.NamespaceWrapper) selectedItem).getNamespace()); - dialogCancel(); + pressCancel(); } @@ -414,7 +416,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(primaryCheckBox.isSelected()); assertTrue(!primaryCheckBox.isEnabled()); setText("aaaa"); - dialogOK(); + pressOk(); s = st.getPrimarySymbol(refAddr); assertEquals("aaaa", s.getName()); } @@ -426,7 +428,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { editLabel(s); setText("fred"); - dialogOK(); + pressOk(); assertEquals("fred", s.getName()); s = st.getPrimarySymbol(a); @@ -438,17 +440,17 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { public void testDuplicateLabelForEdit() { addLabel(addr(0x100642a)); setText("printf"); - dialogOK(); + pressOk(); addLabel(addr(0x100642a)); setText("fred"); - dialogOK(); + pressOk(); Symbol s = getUniqueSymbol(program, "printf", null); editLabel(s); setText("fred"); - dialogOK(); + pressOk(); assertTrue(dialog.isVisible()); assertTrue(dialog.getStatusText().length() > 0); @@ -459,18 +461,18 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { Address a = addr(0x100642a); addLabel(a); setText("aaaa"); - dialogOK(); + pressOk(); addLabel(a); setText("bbbb"); - dialogOK(); + pressOk(); addLabel(a); setText("cccc"); - dialogOK(); + pressOk(); Symbol s = getUniqueSymbol(program, "bbbb", null); editLabel(s); setText("zzzz"); - dialogOK(); + pressOk(); assertNotNull(getUniqueSymbol(program, "aaaa", null)); assertNotNull(getUniqueSymbol(program, "zzzz", null)); assertNotNull(getUniqueSymbol(program, "cccc", null)); @@ -491,7 +493,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(!primaryCheckBox.isSelected()); assertTrue(primaryCheckBox.isEnabled()); setText("foo"); - dialogOK(); + pressOk(); s = st.getPrimarySymbol(a); assertNotNull(s); @@ -509,16 +511,16 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { addLabel(s.getAddress()); setText("aaaa"); - dialogOK(); + pressOk(); s = getUniqueSymbol(program, "aaaa", null); editLabel(s); setText("zzzz"); - dialogOK(); + pressOk(); editLabel(s); setText("bbbb"); - dialogOK(); + pressOk(); assertEquals(3, recentLabels.size()); assertEquals("bbbb", recentLabels.get(0)); @@ -532,13 +534,13 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { addLabel(s.getAddress()); setScope(s.getParentNamespace()); setText("foo"); - dialogOK(); + pressOk(); s = getUniqueSymbol(program, "foo", null); editLabel(s); assertTrue(primaryCheckBox.isEnabled()); assertTrue(!primaryCheckBox.isSelected()); - dialogOK(); + pressOk(); } @Test @@ -579,7 +581,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { Address entryAddress = s.getAddress(); addLabel(entryAddress); setText("label_1"); - dialogOK(); + pressOk(); assertTrue("Encountered a problem adding a label to the Global " + "namespace", !dialog.isVisible()); @@ -588,7 +590,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { s = getUniqueSymbol(program, "label_1", null); editLabel(s); setText("namespace_1::label_1"); - dialogOK(); + pressOk(); // make sure there were no problems assertTrue( @@ -599,18 +601,128 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { s = st.getSymbols("label_1").next(); editLabel(s); setText("Global::label_1"); - dialogOK(); + pressOk(); assertTrue("Encountered a problem changing a symbol's namespace to " + "the Global namespace while editing the symbol", !dialog.isVisible()); } @Test - public void testEntryNamespacePathWithAmbiguousFunctionName() { - Symbol origEntry = getUniqueSymbol(program, "entry", null); - assertNotNull(origEntry); + public void testSetLabelNamespace_InsideFunctionBody_ToFunctionNamespace() { + Symbol entry = getUniqueSymbol(program, "entry", null); + assertNotNull(entry); - Symbol dupEntry = st.getPrimarySymbol(addr(0x1002239)); + Address inBodyAddress = entry.getAddress().add(1); + addLabel(inBodyAddress); + String newName = "label_1"; + setText("entry" + Namespace.DELIMITER + newName); + pressOk(); + assertFalse("Encountered a problem adding a label to the Global namespace", + dialog.isVisible()); + + Symbol label1 = getSymbol(newName); + Namespace parentNamespace = label1.getParentNamespace(); + assertTrue("Namespace is not a function", parentNamespace instanceof Function); + Function fun = (Function) parentNamespace; + assertEquals(entry.getAddress(), fun.getEntryPoint()); + } + + @Test + public void testSetLabelNamespace_InsideFunctionBody_ToExistingNonFunctionNamespace() { + + Symbol entry = getUniqueSymbol(program, "entry", null); + assertNotNull(entry); + + String namespaceName = "NewNamespace"; + createNamespace(namespaceName); + + Address inBodyAddress = entry.getAddress().add(1); + addLabel(inBodyAddress); + String newName = "label_1"; + setText(namespaceName + Namespace.DELIMITER + newName); + pressOk(); + assertFalse("Encountered a problem adding a label to the Global namespace", + dialog.isVisible()); + + Symbol label1 = getSymbol(newName); + Namespace parentNamespace = label1.getParentNamespace(); + assertFalse("Namespace is not a function", parentNamespace instanceof Function); + } + + @Test + public void testSetLabelNamespace_InsideFunctionBody_ToNonExistentNonFunctionNamespace() { + + Symbol entry = getUniqueSymbol(program, "entry", null); + assertNotNull(entry); + + String namespaceName = "NewNamespace"; + Address inBodyAddress = entry.getAddress().add(1); + addLabel(inBodyAddress); + String newName = "label_1"; + setText(namespaceName + Namespace.DELIMITER + newName); + pressOk(); + assertFalse("Encountered a problem adding a label to the Global namespace", + dialog.isVisible()); + + Symbol label1 = getSymbol(newName); + Namespace parentNamespace = label1.getParentNamespace(); + assertFalse("Namespace is not a function", parentNamespace instanceof Function); + } + + @Test + public void testEntryNamespacePathWithAmbiguousFunctionName() { + Symbol entry = getUniqueSymbol(program, "entry", null); + assertNotNull(entry); + + Address otherEntryAddress = addr(0x1002239); + Symbol dupEntry = createOtherEntry(otherEntryAddress); + + Address inBodyAddress = otherEntryAddress.add(1); + addLabel(inBodyAddress); + String newName = "label_1"; + setText("entry" + Namespace.DELIMITER + newName); + pressOk(); + assertFalse("Encountered a problem adding a label to the Global namespace", + dialog.isVisible()); + + Symbol label1 = getSymbol(newName); + Namespace parentNamespace = label1.getParentNamespace(); + assertTrue("Namespace is not a function", parentNamespace instanceof Function); + Function fun = (Function) parentNamespace; + assertEquals(dupEntry.getAddress(), fun.getEntryPoint()); + } + + @Test + public void testSetNamespace_NonExistentNamespace_SameNameAsFunction() throws Exception { + + // + // Test that we can create a new namespace using the dialog when: + // 1) that namespace does not exist + // 2) the namespace matches the existing function name + // 3) the function name is not default + // + + String functionName = "Foo"; + Symbol function = createFunction(functionName); + + editLabel(function); + String nsName = functionName; + setText(nsName + Namespace.DELIMITER + functionName); + pressOk(); + assertFalse("Rename unsuccesful", dialog.isShowing()); + + Symbol newFunction = getSymbol(functionName); + Namespace parentNs = newFunction.getParentNamespace(); + assertFalse(parentNs instanceof Function); + assertEquals(nsName, parentNs.getName()); + } + +//================================================================================================== +// Private Methods +//================================================================================================== + + private Symbol createOtherEntry(Address otherAddress) { + Symbol dupEntry = st.getPrimarySymbol(otherAddress); assertNotNull(dupEntry); int id = program.startTransaction("test"); @@ -618,42 +730,48 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { dupEntry.setName("entry", SourceType.USER_DEFINED); } catch (Exception e) { - fail("Got Exception trying to set the function name to entry at 0x1002239 "); + fail("Got Exception trying to set the function name to entry at " + otherAddress); } finally { program.endTransaction(id, true); } - - Address entryAddress = dupEntry.getAddress(); - addLabel(entryAddress); - setText("entry::label_1"); - dialogOK(); - - assertTrue("Encountered a problem adding a label to the Global " + "namespace", - !dialog.isVisible()); - - SymbolIterator symbolIt = st.getSymbols("label_1"); - Symbol label1 = symbolIt.next(); - assertNotNull(label1); - Namespace parentNamespace = label1.getParentNamespace(); - assertTrue(parentNamespace instanceof Function); - Function fun = (Function) parentNamespace; - assertEquals(dupEntry.getAddress(), fun.getEntryPoint()); + return dupEntry; + } + + private Symbol getSymbol(String functionName) { + + SymbolIterator it = st.getSymbols(functionName); + Symbol newLabel = it.next(); + assertNotNull(newLabel); + assertEquals(functionName, newLabel.getName()); + return newLabel; + } + + private Symbol createFunction(String name) throws Exception { + Symbol entry = getUniqueSymbol(program, "entry", null); + createEntryFunction(); + editLabel(entry); + setText(name); + pressOk(); + + SymbolIterator it = st.getSymbols(name); + Symbol newLabel = it.next(); + assertNotNull(newLabel); + assertEquals(name, newLabel.getName()); + return newLabel; } -//================================================================================================== -// Private Methods -//================================================================================================== private Address addr(long addr) { return program.getAddressFactory().getAddress(Long.toHexString(addr)); } - private void dialogCancel() { + private void pressCancel() { runSwing(() -> invokeInstanceMethod("cancelCallback", dialog)); } - private void dialogOK() { - runSwing(() -> invokeInstanceMethod("okCallback", dialog)); + private void pressOk() { + runSwing(() -> invokeInstanceMethod("okCallback", dialog), false); + waitForSwing(); } private void setText(final String text) { @@ -738,4 +856,8 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(tool.execute(cmd, program)); } } + + private void createNamespace(String name) { + applyCmd(program, new CreateNamespacesCmd(name, SourceType.USER_DEFINED)); + } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin1Test.java index c267d9e113..5f7f26d3bc 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin1Test.java @@ -651,7 +651,7 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest { String newNamespace = "bob"; String prefix = "MY"; String newNameWithoutNamespace = prefix + s.getName(); - String newName = newNamespace + Namespace.NAMESPACE_DELIMITER + newNameWithoutNamespace; + String newName = newNamespace + Namespace.DELIMITER + newNameWithoutNamespace; util.rename(advapi32Node, newName); util.waitForTree(); assertEquals(newNameWithoutNamespace, s.getName()); @@ -681,7 +681,7 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest { GTreeNode nsNode = newNsNode; String newNamespace = "OuterNamespace"; String newName = "MyNamespace"; - String newFullName = newNamespace + Namespace.NAMESPACE_DELIMITER + newName; + String newFullName = newNamespace + Namespace.DELIMITER + newName; setEditorText(path, nsNode, newFullName); namespacesNode = rootNode.getChild("Namespaces"); 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 654342d9ed..6cd1458227 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 @@ -1379,7 +1379,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest { Command command = new CreateNamespacesCmd(namespaceName, SourceType.USER_DEFINED); if (tool.execute(command, program)) { List namespaces = - NamespaceUtils.getNamespaces(namespaceName, null, program); + NamespaceUtils.getNamespaceByPath(program, null, namespaceName); if (namespaces.size() != 1) { Assert.fail("Unable to find the newly created parent namespace."); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/label/CreateNamespacesCmdTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/label/CreateNamespacesCmdTest.java index 8791f88077..c6d1485b0e 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/label/CreateNamespacesCmdTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/label/CreateNamespacesCmdTest.java @@ -308,7 +308,7 @@ public class CreateNamespacesCmdTest extends AbstractGenericTest { for (int i = 0; i < namespaceNames.length; i++) { buffer.append(namespaceNames[i]); if (i + 1 < namespaceNames.length) { - buffer.append(Namespace.NAMESPACE_DELIMITER); + buffer.append(Namespace.DELIMITER); } } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java index 06acd97d3e..2a993b5f4b 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java @@ -107,7 +107,7 @@ public class CreateRtti1BackgroundCmd extends AbstractCreateDataBackgroundCmd 1) { String[] categoryNames = new String[names.length - 1]; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/NamespaceUtils.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/NamespaceUtils.java index 26b1ec61a5..a03b6323d4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/NamespaceUtils.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/NamespaceUtils.java @@ -29,17 +29,14 @@ import ghidra.util.exception.*; * * Example string format: *

* * Assumptions for creating namespaces from a path string: *