nsParts = namespacePath.getParts();
+ return nsParts.isEmpty()
+ ? organizationalCategoryPath
+ : new CategoryPath(organizationalCategoryPath, nsParts);
}
/**
@@ -123,6 +199,12 @@ public class DWARFNameInfo {
return !isRoot() ? new DataTypePath(getParentCP(), getName()) : null;
}
+ /**
+ * Returns the Ghidra {@link Namespace} that represents this entry's parent.
+ *
+ * @param program the Ghidra program that contains the namespace
+ * @return {@link Namespace} representing this entry's parent
+ */
public Namespace getParentNamespace(Program program) {
return getParent().asNamespace(program);
}
@@ -143,10 +225,20 @@ public class DWARFNameInfo {
return organizationalCategoryPath.toString() + " || " + namespacePath.toString();
}
+ /**
+ * Returns true if the original name of this entry was blank.
+ *
+ * @return boolean true if there was no original name
+ */
public boolean isAnon() {
return originalName == null;
}
+ /**
+ * Returns the original name (unmodified by Ghidra-isms) of this entry.
+ *
+ * @return original name
+ */
public String getOriginalName() {
return originalName;
}
@@ -156,12 +248,21 @@ public class DWARFNameInfo {
* than its {@link #getOriginalName() original} form.
*
*
- * @return
+ * @return boolean true if the original name doesn't match the ghidra-ized name
*/
public boolean isNameModified() {
return originalName == null || !originalName.equals(namespacePath.getName());
}
+ /**
+ * Creates a {@link DWARFNameInfo} instance, which has a name that is contained with
+ * this instance's namespace, using the specified name and symbol type.
+ *
+ * @param childOriginalName the unmodified name
+ * @param childName the ghidra-ized name of the type/symbol/namespace/etc
+ * @param childType the type of the object being named
+ * @return new DWARFNameInfo instance
+ */
public DWARFNameInfo createChild(String childOriginalName, String childName,
SymbolType childType) {
return new DWARFNameInfo(this, childOriginalName, childName, childType);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java
index 878e5b5746..35686c66a6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java
@@ -170,21 +170,13 @@ public class DWARFParser {
if (origRoot.equals(cp)) {
return newRoot;
}
-
- String origRootPath = origRoot.getPath();
- if (!CategoryPath.ROOT.equals(origRoot)) {
- origRootPath += "/";
+ List origRootParts = origRoot.asList();
+ List cpParts = cp.asList();
+ if (cpParts.size() < origRootParts.size() ||
+ !origRootParts.equals(cpParts.subList(0, origRootParts.size()))) {
+ return null;
}
- String newRootPath = newRoot.getPath();
- if (!CategoryPath.ROOT.equals(newRoot)) {
- newRootPath += "/";
- }
- String cpPath = cp.getPath();
- if (cpPath.startsWith(origRootPath)) {
- String newPath = newRootPath + cpPath.substring(origRootPath.length());
- return new CategoryPath(newPath);
- }
- return null;
+ return new CategoryPath(newRoot, cpParts.subList(origRootParts.size(), cpParts.size()));
}
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java
index 97f68fc3d1..ab27c53490 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java
@@ -15,10 +15,9 @@
*/
package ghidra.app.util.bin.format.dwarf4.next;
-import java.util.*;
-
import java.io.Closeable;
import java.io.IOException;
+import java.util.*;
import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
@@ -396,14 +395,6 @@ public class DWARFProgram implements Closeable {
String origName = isAnon ? null : name;
String workingName = ensureSafeNameLength(name);
- switch (diea.getTag()) {
- // fixup DWARF entries that are related to Ghidra symbols
- case DWARFTag.DW_TAG_subroutine_type:
- case DWARFTag.DW_TAG_subprogram:
- case DWARFTag.DW_TAG_inlined_subroutine:
- workingName = SymbolUtilities.replaceInvalidChars(workingName, false);
- break;
- }
DWARFNameInfo result =
parentDNI.createChild(origName, workingName, DWARFUtil.getSymbolTypeFromDIE(diea));
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 614b790db3..1b4a6e9679 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
@@ -15,10 +15,10 @@
*/
package ghidra.app.util.bin.format.dwarf4.next;
+import java.util.*;
import java.util.function.Consumer;
import ghidra.app.util.NamespaceUtils;
-import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
@@ -55,16 +55,8 @@ public class NamespacePath implements Comparable {
* @return new {@link NamespacePath}
*/
public static NamespacePath create(NamespacePath parent, String name, SymbolType type) {
- return new NamespacePath(parent == null ? ROOT : parent, preMangleName(name), type);
- }
-
- private static final String FWDSLASH_MANGLE = "-fwdslash-";
- private static final String COLON_MANGLE = "-";
-
- private static String preMangleName(String name) {
- return name == null ? null
- : name.replaceAll(":", COLON_MANGLE).replaceAll(" ", "").replaceAll("/",
- FWDSLASH_MANGLE);
+ return new NamespacePath(Objects.requireNonNullElse(parent, ROOT),
+ SymbolUtilities.replaceInvalidChars(name, true), type);
}
private final NamespacePath parent;
@@ -174,17 +166,6 @@ public class NamespacePath implements Comparable {
}
}
- /**
- * Converts this namespace path into a {@link CategoryPath} style string.
- * @return string path "/namespace1/namespace2"
- */
- public String asCategoryPathString() {
- StringBuilder sb = new StringBuilder();
- doInOrderTraversal(
- nsp -> sb.append(sb.length() != 1 ? "/" : "").append(nsp.isRoot() ? "" : nsp.name));
- return sb.toString();
- }
-
/**
* Converts this namespace path into a {@link Namespace} style string.
* @return string path "ROOT::namespace1::namespace2"
@@ -215,6 +196,21 @@ public class NamespacePath implements Comparable {
return sb.toString();
}
+ /**
+ * Returns the individual parts of the path as elements in a list.
+ *
+ * @return list of strings containing individual parts of the path
+ */
+ public List getParts() {
+ List partList = new ArrayList<>();
+ doInOrderTraversal(nsp -> {
+ if (!nsp.isRoot()) {
+ partList.add(nsp.name);
+ }
+ });
+ return partList;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java
index e82e702db5..677ed4450a 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java
@@ -894,6 +894,71 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase {
return results;
}
+ @Test
+ public void testStructNamespaceReservedChar_Colon()
+ throws CancelledException, IOException, DWARFException {
+ DebugInfoEntry intDIE = addInt(cu);
+ DebugInfoEntry floatDIE = addFloat(cu);
+
+ //-----------------------
+ DebugInfoEntry struct1DIE = newStruct("mystruct::with::colons", 100).create(cu);
+ DebugInfoEntry nestedStructDIE =
+ newStruct("nested_struct", 10).setParent(struct1DIE).create(cu);
+ newMember(nestedStructDIE, "blah1", intDIE, 0).create(cu);
+ newMember(struct1DIE, "f1", intDIE, 0).create(cu);
+ newMember(struct1DIE, "f2", floatDIE, 10).create(cu);
+ newMember(struct1DIE, "f3", nestedStructDIE, 20).create(cu);
+ //----------------------
+
+ importAllDataTypes();
+
+ Structure structdt = (Structure) dataMgr.getDataType(rootCP, "mystruct::with::colons");
+ assertEquals(3, structdt.getNumDefinedComponents());
+ Structure nestedStructDt = (Structure) structdt.getDefinedComponents()[2].getDataType();
+ assertEquals("mystruct::with::colons", nestedStructDt.getCategoryPath().getName());
+ }
+
+ @Test
+ public void testStructNamespaceReservedChar_FwdSlash()
+ throws CancelledException, IOException, DWARFException {
+ DebugInfoEntry intDIE = addInt(cu);
+ DebugInfoEntry floatDIE = addFloat(cu);
+
+ //-----------------------
+ DebugInfoEntry struct1DIE = newStruct("mystruct::operator/()", 100).create(cu);
+ DebugInfoEntry nestedStructDIE =
+ newStruct("nested_struct", 10).setParent(struct1DIE).create(cu);
+ newMember(nestedStructDIE, "blah1", intDIE, 0).create(cu);
+ newMember(struct1DIE, "f1", intDIE, 0).create(cu);
+ newMember(struct1DIE, "f2", floatDIE, 10).create(cu);
+ newMember(struct1DIE, "f3", nestedStructDIE, 20).create(cu);
+ //----------------------
+
+ importAllDataTypes();
+
+ Structure structdt = (Structure) dataMgr.getDataType(rootCP, "mystruct::operator/()");
+ assertEquals(3, structdt.getNumDefinedComponents());
+ Structure nestedStructDt = (Structure) structdt.getDefinedComponents()[2].getDataType();
+ assertEquals("mystruct::operator/()", nestedStructDt.getCategoryPath().getName());
+ }
+
+ @Test
+ public void testStructNamespaceReservedChar_Spaces()
+ throws CancelledException, IOException, DWARFException {
+ DebugInfoEntry intDIE = addInt(cu);
+ DebugInfoEntry floatDIE = addFloat(cu);
+
+ //-----------------------
+ DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu);
+ newMember(struct1DIE, "f1", intDIE, 0).create(cu);
+ newMember(struct1DIE, "f2", floatDIE, 10).create(cu);
+ //----------------------
+
+ importAllDataTypes();
+
+ Structure structdt = (Structure) dataMgr.getDataType(rootCP, "mystruct");
+ assertEquals(2, structdt.getNumDefinedComponents());
+ }
//----------------------------------------------------------------------------------------------------
@Test
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java
index 57f70dd740..8802a76594 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java
@@ -18,15 +18,17 @@ package ghidra.app.util.bin.format.dwarf4.next;
import static org.junit.Assert.*;
import java.io.IOException;
+import java.util.List;
import org.junit.Test;
+import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFSourceLanguage;
import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOpCodes;
-import ghidra.program.model.data.DataType;
-import ghidra.program.model.listing.Function;
-import ghidra.program.model.listing.Parameter;
+import ghidra.program.model.data.*;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.Namespace;
import ghidra.util.exception.CancelledException;
public class DWARFFunctionImporterTest extends DWARFTestBase {
@@ -113,4 +115,46 @@ public class DWARFFunctionImporterTest extends DWARFTestBase {
assertNotNull(returnType);
assertEquals("int", returnType.getName());
}
+
+ @Test
+ public void testNamespace_with_reserved_chars()
+ throws CancelledException, IOException, DWARFException {
+ // simulate what happens when a C++ operator/ or a templated classname
+ // that contains a namespaced template argument (templateclass)
+ // is encountered and a Ghidra namespace is created
+
+ DebugInfoEntry intDIE = addInt(cu);
+ DebugInfoEntry floatDIE = addFloat(cu);
+ DebugInfoEntry struct1DIE = newStruct("mystruct::operator/()", 100).create(cu);
+ DebugInfoEntry nestedStructPtrDIE = addFwdPtr(cu, 1);
+ DebugInfoEntry nestedStructDIE =
+ newStruct("nested_struct", 10).setParent(struct1DIE).create(cu);
+ newMember(nestedStructDIE, "blah1", intDIE, 0).create(cu);
+ DebugInfoEntry fooDIE =
+ newSubprogram("foo", intDIE, 0x410, 10).setParent(nestedStructDIE).create(cu);
+ newFormalParam(fooDIE, "this", nestedStructPtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c)
+ .create(cu);
+
+ newMember(struct1DIE, "f1", intDIE, 0).create(cu);
+ newMember(struct1DIE, "f2", floatDIE, 10).create(cu);
+ newMember(struct1DIE, "f3", nestedStructDIE, 20).create(cu);
+
+ importFunctions();
+
+ Function fooFunc = program.getListing().getFunctionAt(addr(0x410));
+ List nsParts = NamespaceUtils.getNameSpaceParts(fooFunc.getParentNamespace());
+
+ assertEquals("foo", fooFunc.getName());
+ assertEquals("nested_struct",
+ ((Pointer) fooFunc.getParameter(0).getDataType()).getDataType().getName());
+ assertEquals("__thiscall", fooFunc.getCallingConventionName());
+ assertEquals("nested_struct", nsParts.get(nsParts.size() - 1).getName());
+ assertEquals("mystruct::operator/()", nsParts.get(nsParts.size() - 2).getName());
+
+ // Test that VariableUtilities can find the structure for the this* pointer
+ Structure nestedStructDT1 = (Structure) dataMgr
+ .getDataType(new CategoryPath(rootCP, "mystruct::operator/()"), "nested_struct");
+ Structure nestedStructDT2 = VariableUtilities.findExistingClassStruct(fooFunc);
+ assertTrue(nestedStructDT1 == nestedStructDT2);
+ }
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java
index 3a8d95da3a..fe0623e93e 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java
@@ -15,15 +15,16 @@
*/
package ghidra.app.util.bin.format.dwarf4.next;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
import java.io.IOException;
-import org.junit.Assert;
import org.junit.Test;
import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.program.model.data.*;
+import ghidra.program.model.listing.GhidraClass;
+import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SymbolType;
import ghidra.util.exception.CancelledException;
@@ -35,8 +36,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testSimple() {
DWARFNameInfo dni = root.createChild("simplename", "simplename", SymbolType.CLASS);
- Assert.assertEquals(new CategoryPath("/TEST_DNI/simplename"), dni.asCategoryPath());
- Assert.assertEquals(
+ assertEquals(new CategoryPath("/TEST_DNI/simplename"), dni.asCategoryPath());
+ assertEquals(
NamespacePath.create(NamespacePath.ROOT, "simplename", SymbolType.CLASS),
dni.getNamespacePath());
}
@@ -44,12 +45,69 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testSlash() {
DWARFNameInfo dni = root.createChild("blah/", "blah/", SymbolType.CLASS);
- Assert.assertEquals(new CategoryPath("/TEST_DNI/blah-fwdslash-"), dni.asCategoryPath());
- Assert.assertEquals(
- NamespacePath.create(NamespacePath.ROOT, "blah-fwdslash-", SymbolType.CLASS),
+ assertEquals(new CategoryPath(CategoryPath.ROOT, "TEST_DNI", "blah/"),
+ dni.asCategoryPath());
+
+ Namespace testNamespace = dni.asNamespace(program);
+ assertEquals("blah/", testNamespace.getName(true));
+ assertEquals(
+ NamespacePath.create(NamespacePath.ROOT, "blah/", SymbolType.CLASS),
dni.getNamespacePath());
}
+ @Test
+ public void testColon() {
+ DWARFNameInfo dni = root.createChild("blah::blah", "blah::blah", SymbolType.CLASS);
+ DWARFNameInfo dni2 = dni.createChild("sub::sub", "sub::sub", SymbolType.CLASS);
+ assertEquals(new CategoryPath("/TEST_DNI/blah::blah/sub::sub"),
+ dni2.asCategoryPath());
+
+ Namespace testNamespace = dni2.asNamespace(program);
+ assertEquals("sub::sub", testNamespace.getName());
+ assertEquals("blah::blah", testNamespace.getParentNamespace().getName());
+ assertTrue(testNamespace instanceof GhidraClass);
+ assertTrue(testNamespace.getParentNamespace() instanceof GhidraClass);
+ }
+
+ @Test
+ public void testNamespaceTypes() {
+ DWARFNameInfo dni_ns1 = root.createChild("ns1", "ns1", SymbolType.NAMESPACE);
+ DWARFNameInfo dni_ns1class1 = dni_ns1.createChild("class1", "class1", SymbolType.CLASS);
+ assertEquals(new CategoryPath("/TEST_DNI/ns1/class1"), dni_ns1class1.asCategoryPath());
+
+ Namespace class1_ns = dni_ns1class1.asNamespace(program);
+ assertEquals("ns1::class1", class1_ns.getName(true));
+ assertTrue(class1_ns instanceof GhidraClass);
+ assertFalse(class1_ns.getParentNamespace() instanceof GhidraClass);
+ }
+
+ @Test
+ public void testNamespaceConvertToClass() {
+ // tests that a plain namespace can be 'upgraded' to a class namespace
+ DWARFNameInfo dni_ns1 = root.createChild("ns1", "ns1", SymbolType.NAMESPACE);
+
+ Namespace ns1 = dni_ns1.asNamespace(program);
+ assertFalse(ns1 instanceof GhidraClass);
+
+ DWARFNameInfo dni_ns1a = root.createChild("ns1", "ns1", SymbolType.CLASS);
+ Namespace ns1a = dni_ns1a.asNamespace(program);
+ assertTrue(ns1a instanceof GhidraClass);
+ }
+
+ @Test
+ public void testClassConvertToNamespace() {
+ // tests that a class namespace isn't 'downgraded' to a plain namespace
+ DWARFNameInfo dni_class1 = root.createChild("class1", "class1", SymbolType.CLASS);
+
+ Namespace class1 = dni_class1.asNamespace(program);
+ assertTrue(class1 instanceof GhidraClass);
+
+ DWARFNameInfo dni_class1a = root.createChild("class1", "class1", SymbolType.NAMESPACE);
+ Namespace class1a = dni_class1a.asNamespace(program);
+ // symbol should NOT have been converted to a plain namespace.
+ assertTrue(class1a instanceof GhidraClass);
+ }
+
@Test
public void testNestedStructNames() throws CancelledException, IOException, DWARFException {
DebugInfoEntry structDIE = newStruct("struct", 100).create(cu);
@@ -60,8 +118,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
DataType structDT = dwarfDTM.getDataType(structDIE.getOffset(), null);
DataType substructDT = dwarfDTM.getDataType(substructDIE.getOffset(), null);
- Assert.assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
- Assert.assertEquals(rootCP.getPath() + "/struct/substruct", substructDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct/substruct", substructDT.getPathName());
}
@Test
@@ -75,8 +133,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
DataType structDT = dwarfDTM.getDataType(structDIE.getOffset(), null);
DataType substructDT = dwarfDTM.getDataType(substructDIE.getOffset(), null);
- Assert.assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
- Assert.assertEquals(rootCP.getPath() + "/struct/anon_struct_0", substructDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct/anon_struct_0", substructDT.getPathName());
}
@Test
@@ -91,8 +149,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
DataType structDT = dwarfDTM.getDataType(structDIE.getOffset(), null);
DataType substructDT = dwarfDTM.getDataType(substructDIE.getOffset(), null);
- Assert.assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
- Assert.assertEquals(rootCP.getPath() + "/struct/anon_struct_for_f1",
+ assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct/anon_struct_for_f1",
substructDT.getPathName());
}
@@ -109,8 +167,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
DataType structDT = dwarfDTM.getDataType(structDIE.getOffset(), null);
DataType substructDT = dwarfDTM.getDataType(substructDIE.getOffset(), null);
- Assert.assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
- Assert.assertEquals(rootCP.getPath() + "/struct/anon_struct_for_f1_f2",
+ assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct/anon_struct_for_f1_f2",
substructDT.getPathName());
}
@@ -125,12 +183,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
importAllDataTypes();
Structure structDT = (Structure) dwarfDTM.getDataType(structDIE.getOffset(), null);
- DataTypeComponent f1 = structDT.getComponentAt(0);
- DataTypeComponent f2 = structDT.getComponentAt(20);
- System.out.println(f1.getDataType());
- System.out.println(f2.getDataType());
- Assert.assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
}
@Test
@@ -143,12 +197,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
importAllDataTypes();
Structure structDT = (Structure) dwarfDTM.getDataType(structDIE.getOffset(), null);
- DataTypeComponent f1 = structDT.getComponentAt(0);
- DataTypeComponent f2 = structDT.getComponentAt(20);
- System.out.println(f1.getDataType());
- System.out.println(f2.getDataType());
- Assert.assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
+ assertEquals(rootCP.getPath() + "/struct", structDT.getPathName());
}
@Test
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java
index ca4cc16ef6..dd21bfabb3 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java
@@ -30,9 +30,6 @@ public class NamespacePathTest {
Assert.assertEquals("ROOT::sub1", nsp.asNamespaceString());
Assert.assertEquals("ROOT::sub1::sub1_1", nsp1_1.asNamespaceString());
- Assert.assertEquals("/sub1", nsp.asCategoryPathString());
- Assert.assertEquals("/sub1/sub1_1", nsp1_1.asCategoryPathString());
-
}
@Test
@@ -41,8 +38,12 @@ public class NamespacePathTest {
NamespacePath nsSpaceA = NamespacePath.create(null, "ns A", SymbolType.NAMESPACE);
NamespacePath nsColonA = NamespacePath.create(null, "ns:A", SymbolType.NAMESPACE);
- Assert.assertEquals("ROOT::ns-fwdslash-A", nsSlashA.asNamespaceString());
+ Assert.assertEquals("ROOT::ns/A", nsSlashA.asNamespaceString());
Assert.assertEquals("ROOT::nsA", nsSpaceA.asNamespaceString());
- Assert.assertEquals("ROOT::ns-A", nsColonA.asNamespaceString());
+ Assert.assertEquals("ROOT::ns:A", nsColonA.asNamespaceString());
+
+ Assert.assertEquals("ns/A", nsSlashA.getName());
+ Assert.assertEquals("nsA", nsSpaceA.getName());
+ Assert.assertEquals("ns:A", nsColonA.getName());
}
}
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 94e7613e0e..5256050e38 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
@@ -537,4 +537,22 @@ public class NamespaceUtils {
SymbolTable symbolTable = namespaceSymbol.getProgram().getSymbolTable();
return symbolTable.convertNamespaceToClass(namespace);
}
+
+ /**
+ * Returns a list of namespaces, where each element is a component of the original specified
+ * namespace, excluding the global root namespace.
+ *
+ * Namespace "ns1::ns2::ns3" returns [ "ns1", "ns1::ns2", "ns1::ns2::ns3" ]
+ *
+ * @param namespace namespace to process
+ * @return list of namespaces
+ */
+ public static List getNameSpaceParts(Namespace namespace) {
+ List result = new ArrayList<>();
+ while (!namespace.isGlobal()) {
+ result.add(0, namespace);
+ namespace = namespace.getParentNamespace();
+ }
+ return result;
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java
index 3d72ba76c7..b9546e2895 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.util.*;
import java.util.regex.Pattern;
+import ghidra.app.util.NamespaceUtils;
import ghidra.docking.settings.Settings;
import ghidra.program.model.address.GlobalNamespace;
import ghidra.program.model.data.*;
@@ -341,23 +342,15 @@ public class DataTypeUtilities {
*/
public static CategoryPath getDataTypeCategoryPath(CategoryPath baseCategory,
Namespace namespace) {
- Namespace ns = namespace;
- String path = "";
- while (!ns.isGlobal() && !(ns instanceof Library)) {
- if (path.length() != 0) {
- path = "/" + path;
+ List categoryPathParts = new ArrayList<>();
+ for (Namespace ns : NamespaceUtils.getNameSpaceParts(namespace)) {
+ if (!(ns instanceof Library)) {
+ categoryPathParts.add(ns.getName());
}
- path = ns.getName() + path;
- ns = ns.getParentNamespace();
}
- if (path.length() == 0) {
- return baseCategory;
- }
- String categoryPath = CategoryPath.DELIMITER_CHAR + path;
- if (!baseCategory.equals(CategoryPath.ROOT)) {
- categoryPath = baseCategory.getPath() + categoryPath;
- }
- return new CategoryPath(categoryPath);
+ return categoryPathParts.isEmpty()
+ ? baseCategory
+ : new CategoryPath(baseCategory, categoryPathParts);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java
index dbbf836370..21305c61d6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java
@@ -364,7 +364,7 @@ public class SymbolUtilities {
return null;
}
int len = str.length();
- StringBuffer buf = new StringBuffer(len);
+ StringBuilder buf = new StringBuilder(len);
for (int i = 0; i < len; ++i) {
char c = str.charAt(i);
if (isInvalidChar(c)) {