GP-1122 (PR #2043) remove ':', '/' mangling and change ' ' mangling

Change DWARF mangling logic to allow ':', '/' and convert ' ' to '_'.
Fixup some spots that were using fragile CategoryPath / Namespace string
parsing.
This commit is contained in:
dev747368 2021-07-12 16:44:19 -04:00
parent d2a0235fdd
commit 8a407a1169
13 changed files with 354 additions and 100 deletions

View file

@ -81,7 +81,7 @@ public class CreateEnumFromSelectionAction extends DockingAction {
for (DataTypeManager dataTypeManager : dataTypeManagers) {
if (dataTypeManager instanceof ProgramDataTypeManager) {
myDataTypeManager = dataTypeManager;
category = myDataTypeManager.getCategory(new CategoryPath("/"));
category = myDataTypeManager.getCategory(CategoryPath.ROOT);
if (category == null) {
Msg.error(this, "Could not find program data type manager");
return;

View file

@ -689,7 +689,7 @@ public class DWARFFunctionImporter {
DWARFNameInfo dni = prog.getName(diea);
String name = SymbolUtilities.replaceInvalidChars(dni.getName(), false);
String name = dni.getName();
Number lowPC = null;
boolean disjoint = false;

View file

@ -16,8 +16,8 @@
package ghidra.app.util.bin.format.dwarf4.next;
import java.util.List;
import java.util.Objects;
import ghidra.formats.gfilesystem.FSUtilities;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
@ -35,15 +35,38 @@ public class DWARFNameInfo {
private final NamespacePath namespacePath;
private final String originalName;
/**
* Create a root name entry that will serve as the parent for all children.
*
* @param rootCategory {@link CategoryPath} in the data type manager that will contain
* any sub-categories that represent namespaces
* @return a new {@link DWARFNameInfo} instance
*/
public static DWARFNameInfo createRoot(CategoryPath rootCategory) {
return new DWARFNameInfo(null, rootCategory, NamespacePath.ROOT, null);
}
/**
* Create a {@link DWARFNameInfo} instance using the specified {@link DataType}'s name.
*
* @param dataType {@link DataType}
* @return new {@link DWARFNameInfo} using the same name / CategoryPath as the data type
*/
public static DWARFNameInfo fromDataType(DataType dataType) {
return new DWARFNameInfo(null, dataType.getCategoryPath(),
NamespacePath.create(null, dataType.getName(), null), dataType.getName());
}
/**
* Create a child {@link DWARFNameInfo} instance of the specified parent.
* <p>
* Example:<br>
* <pre>fromList(parent, List.of("name1", "name2")) &rarr; parent_name/name1/name2</pre>
*
* @param parent {@link DWARFNameInfo} parent
* @param names list of names
* @return new {@link DWARFNameInfo} instance that is a child of the parent
*/
public static DWARFNameInfo fromList(DWARFNameInfo parent, List<String> names) {
for (String s : names) {
DWARFNameInfo tmp = new DWARFNameInfo(parent, s, s, SymbolType.NAMESPACE);
@ -56,8 +79,8 @@ public class DWARFNameInfo {
NamespacePath namespacePath, String originalName) {
this.parent = parent;
this.organizationalCategoryPath =
(organizationalCategoryPath != null) ? organizationalCategoryPath : CategoryPath.ROOT;
this.namespacePath = (namespacePath != null) ? namespacePath : NamespacePath.ROOT;
Objects.requireNonNullElse(organizationalCategoryPath, CategoryPath.ROOT);
this.namespacePath = Objects.requireNonNullElse(namespacePath, NamespacePath.ROOT);
this.originalName = originalName;
}
@ -68,38 +91,89 @@ public class DWARFNameInfo {
this.originalName = originalName;
}
/**
* Returns the parent name
*
* @return parent
*/
public DWARFNameInfo getParent() {
return parent;
}
/**
* Returns true if this instance has no parent and is considered the root.
*
* @return boolean true if root name, false if not root
*/
public boolean isRoot() {
return parent == null;
}
/**
* Returns the organizational category path.
*
* @return organizational category path for dwarf names
*/
public CategoryPath getOrganizationalCategoryPath() {
return organizationalCategoryPath;
}
/**
* Returns the NamespacePath of this instance.
*
* @return {@link NamespacePath} of this instance
*/
public NamespacePath getNamespacePath() {
return namespacePath;
}
/**
* Returns the parent's CategoryPath.
*
* @return parent name's CategoryPath
*/
public CategoryPath getParentCP() {
return getParent().asCategoryPath();
}
/**
* Returns the name of this entry.
*
* @return string name of this entry, safe to use to name a Ghidra object (datatype, namespace,
* etc)
*/
public String getName() {
return namespacePath.getName();
}
/**
* Creates a new DWARFNameInfo instance, using this instance as the template, replacing
* the name with a new name.
*
* @param newName name for the new instance
* @param newOriginalName originalName for the new instance
* @return new instance with new name
*/
public DWARFNameInfo replaceName(String newName, String newOriginalName) {
return new DWARFNameInfo(getParent(), newOriginalName, newName, getType());
}
/**
* Creates a new DWARFNameInfo instance, using this instance as the template, replacing
* the SymbolType with a new value.
*
* @param newType new SymbolType value
* @return new instance with the specified SymbolType
*/
public DWARFNameInfo replaceType(SymbolType newType) {
return new DWARFNameInfo(parent, originalName, getName(), newType);
}
/**
* Returns the SymbolType of this name.
*
* @return {@link SymbolType} of this entry
*/
public SymbolType getType() {
return namespacePath.getType();
}
@ -110,8 +184,10 @@ public class DWARFNameInfo {
* @return {@link CategoryPath}: "/organizational_cat_path/namespace1/namespace2/obj_name"
*/
public CategoryPath asCategoryPath() {
return new CategoryPath(FSUtilities.appendPath(organizationalCategoryPath.getPath(),
namespacePath.isRoot() ? null : namespacePath.asCategoryPathString()));
List<String> 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.
* <p>
*
* @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);

View file

@ -170,22 +170,14 @@ public class DWARFParser {
if (origRoot.equals(cp)) {
return newRoot;
}
String origRootPath = origRoot.getPath();
if (!CategoryPath.ROOT.equals(origRoot)) {
origRootPath += "/";
}
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);
}
List<String> origRootParts = origRoot.asList();
List<String> cpParts = cp.asList();
if (cpParts.size() < origRootParts.size() ||
!origRootParts.equals(cpParts.subList(0, origRootParts.size()))) {
return null;
}
return new CategoryPath(newRoot, cpParts.subList(origRootParts.size(), cpParts.size()));
}
/**
* Imports DWARF information according to the {@link DWARFImportOptions} set.

View file

@ -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));

View file

@ -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,13 +55,8 @@ public class NamespacePath implements Comparable<NamespacePath> {
* @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 String preMangleName(String name) {
return name == null ? null : name.replaceAll(" ", "").replaceAll("/", FWDSLASH_MANGLE);
return new NamespacePath(Objects.requireNonNullElse(parent, ROOT),
SymbolUtilities.replaceInvalidChars(name, true), type);
}
private final NamespacePath parent;
@ -171,17 +166,6 @@ public class NamespacePath implements Comparable<NamespacePath> {
}
}
/**
* 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"
@ -212,6 +196,21 @@ public class NamespacePath implements Comparable<NamespacePath> {
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<String> getParts() {
List<String> partList = new ArrayList<>();
doInOrderTraversal(nsp -> {
if (!nsp.isRoot()) {
partList.add(nsp.name);
}
});
return partList;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View file

@ -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<int, float>", 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<int,_float>");
assertEquals(2, structdt.getNumDefinedComponents());
}
//----------------------------------------------------------------------------------------------------
@Test

View file

@ -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<ns1::ns2::argclass>)
// 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<Namespace> 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);
}
}

View file

@ -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

View file

@ -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());
}
}

View file

@ -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.
* <p>
* Namespace "ns1::ns2::ns3" returns [ "ns1", "ns1::ns2", "ns1::ns2::ns3" ]
*
* @param namespace namespace to process
* @return list of namespaces
*/
public static List<Namespace> getNameSpaceParts(Namespace namespace) {
List<Namespace> result = new ArrayList<>();
while (!namespace.isGlobal()) {
result.add(0, namespace);
namespace = namespace.getParentNamespace();
}
return result;
}
}

View file

@ -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<String> 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);
}
/**

View file

@ -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)) {