mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
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:
parent
d2a0235fdd
commit
8a407a1169
13 changed files with 354 additions and 100 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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")) → 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);
|
||||
|
|
|
@ -170,21 +170,13 @@ public class DWARFParser {
|
|||
if (origRoot.equals(cp)) {
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
String origRootPath = origRoot.getPath();
|
||||
if (!CategoryPath.ROOT.equals(origRoot)) {
|
||||
origRootPath += "/";
|
||||
List<String> origRootParts = origRoot.asList();
|
||||
List<String> 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()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue