GP-2557 - Demangler anon funcs - CategoryPath changes

This commit is contained in:
ghizard 2022-09-16 10:53:37 -04:00
parent 0b1b8d5a36
commit de4affbc9b
4 changed files with 115 additions and 25 deletions

View file

@ -19,16 +19,16 @@ import ghidra.program.model.data.*;
import ghidra.util.InvalidNameException;
public class DataTypeNamingUtil {
private static final String ANONYMOUS_FUNCTION_DEF_PREFIX = "_func";
private DataTypeNamingUtil() {
// no construct
}
/**
* Generate a simple mangled function definition name and apply it to the specified functionDefinition.
* Generated name will start with {@code _function_}.
* Generate a simple mangled function definition name and apply it to the specified
* functionDefinition. Generated name will start with {@code _func}.
* @param functionDefinition function definition whose name should be set
* @return name applied to functionDefinition
* @throws IllegalArgumentException if generated name contains unsupported characters

View file

@ -32,10 +32,11 @@ import ghidra.program.model.symbol.Namespace;
*/
public class DemangledDataType extends DemangledType {
protected static final String DEMANGLER_ROOT_CATEGORY_PATH = "/Demangler";
protected static final CategoryPath DEMANGLER_ROOT_CATEGORY_PATH =
CategoryPath.ROOT.extend("Demangler");
protected static final CategoryPath DEMANGLER_ANONYMOUS_FUNCTION_CATEGORY_PATH =
new CategoryPath(DEMANGLER_ROOT_CATEGORY_PATH + "/!_anon_funcs_");
DEMANGLER_ROOT_CATEGORY_PATH.extend("!_anon_funcs_");
private static final Pattern ARRAY_SUBSCRIPT_PATTERN = Pattern.compile("\\[\\d*\\]");
@ -157,7 +158,7 @@ public class DemangledDataType extends DemangledType {
if (baseType == null || !(baseType instanceof Enum)) {
if (enumType == null || INT.equals(enumType) || UNSIGNED_INT.equals(enumType)) {
// Can't tell how big an enum is, just use the size of a pointer
// Can't tell how big an enum is, just use the size of a pointer
dt = new EnumDataType(getDemanglerCategoryPath(getNamespace()), name,
dataTypeManager.getDataOrganization().getIntegerSize());
}
@ -338,7 +339,7 @@ public class DemangledDataType extends DemangledType {
* Find non-builtin type
* @param dataTypeManager data type manager to be searched
* @param dtName name of data type
* @param namespace namespace associated with dtName or null if not applicable. If specified,
* @param namespace namespace associated with dtName or null if not applicable. If specified,
* a namespace-base category path will be given precedence.
* @return data type if found, otherwise null.
* @see DataTypeUtilities#findDataType(DataTypeManager, ghidra.program.model.symbol.Namespace, String, Class) for similar namespace
@ -399,18 +400,12 @@ public class DemangledDataType extends DemangledType {
return true;
}
private static String getNamespacePath(Demangled namespace) {
Demangled ns = namespace;
String namespacePath = "";
while (ns != null) {
namespacePath = "/" + ns.getName() + namespacePath;
ns = ns.getNamespace();
}
return namespacePath;
}
// Recursive method
protected static CategoryPath getDemanglerCategoryPath(Demangled namespace) {
return new CategoryPath(DEMANGLER_ROOT_CATEGORY_PATH + getNamespacePath(namespace));
if (namespace == null) {
return DEMANGLER_ROOT_CATEGORY_PATH;
}
return getDemanglerCategoryPath(namespace.getNamespace()).extend(namespace.getName());
}
static Structure createPlaceHolderStructure(String dtName, Demangled namespace) {
@ -697,7 +692,7 @@ public class DemangledDataType extends DemangledType {
}
}
// the order of __ptr64 and __restrict can vary--with fuzzing...
// the order of __ptr64 and __restrict can vary--with fuzzing...
// but what is the natural "real symbol" order?
if (isPointer64) {
buffer.append(SPACE + PTR64);

View file

@ -18,6 +18,7 @@ package ghidra.program.model.data;
import java.util.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
/**
* A category path is the full path to a particular data type
@ -52,7 +53,7 @@ public class CategoryPath implements Comparable<CategoryPath> {
/**
* Converts an escaped String suitable for being passed in as a component of a single category
* path string into an non-escaped string.
* path string into an non-escaped string.
* @param escapedString String that might need unescaping for characters used for delimiting
* @return non-escaped String
* @see #escapeString(String)
@ -76,7 +77,8 @@ public class CategoryPath implements Comparable<CategoryPath> {
*
* @param parent the parent CategoryPath. Choose {@code ROOT} if needed.
* @param subPathElements the array of names of sub-categories of the parent.
* @throws IllegalArgumentException if the given array is null or empty.
* @throws IllegalArgumentException if the parent is null, the elements list is null or empty,
* or an individual element is null
*/
public CategoryPath(CategoryPath parent, String... subPathElements) {
this(parent, Arrays.asList(subPathElements));
@ -88,15 +90,21 @@ public class CategoryPath implements Comparable<CategoryPath> {
*
* @param parent the parent CategoryPath. Choose {@code ROOT} if needed.
* @param subPathElements the hierarchical array of sub-categories of the parent.
* @throws IllegalArgumentException if the given list is null or empty.
* @throws IllegalArgumentException if the parent is null, the elements list is null or empty,
* or an individual element is null
*/
public CategoryPath(CategoryPath parent, List<String> subPathElements) {
Objects.requireNonNull(parent);
if (parent == null) {
throw new IllegalArgumentException("Parent category must not be null!");
}
if (CollectionUtils.isEmpty(subPathElements)) {
throw new IllegalArgumentException(
"Category list must contain at least one string name!");
}
name = subPathElements.get(subPathElements.size() - 1);
if (name == null) {
throw new IllegalArgumentException("A category element must not be null!");
}
if (subPathElements.size() == 1) {
this.parent = parent;
}
@ -106,6 +114,36 @@ public class CategoryPath implements Comparable<CategoryPath> {
}
}
/**
* Returns a CategoryPath that extends the current path using a hierarchical array of strings
* where each string is the name of a category in the category path extension.
*
* @param subPathElements the array of names of sub-categories of the parent.
* @return the extended CategoryPath
* @throws IllegalArgumentException if an element is null
*/
public CategoryPath extend(String... subPathElements) {
if (ArrayUtils.isEmpty(subPathElements)) {
return this;
}
return new CategoryPath(this, subPathElements);
}
/**
* Returns a CategoryPath that extends the current path using a hierarchical list of strings
* where each string is the name of a category in the category path extension.
*
* @param subPathElements the hierarchical array of sub-categories of the parent.
* @return the extended CategoryPath
* @throws IllegalArgumentException if an element is null
*/
public CategoryPath extend(List<String> subPathElements) {
if (CollectionUtils.isEmpty(subPathElements)) {
return this;
}
return new CategoryPath(this, subPathElements);
}
/**
* Creates a category path given a forward-slash-delimited string (e.g., {@code "/aa/bb"}).
* If an individual path component has one or more '/' characters in it, then it can be
@ -121,7 +159,7 @@ public class CategoryPath implements Comparable<CategoryPath> {
*/
// NOTE: We purposefully did not create a constructor that takes varags only, as that
// constructor, called with a single argument that would not be escaped, would conflict with
// this constructor, which requires an escaped argument.
// this constructor, which requires an escaped argument.
public CategoryPath(String path) {
if (path == null || path.length() == 0 || path.equals(DELIMITER_STRING)) {
// parent can only be null for ROOT

View file

@ -116,6 +116,20 @@ public class CategoryPathTest extends AbstractGTest {
assertEquals("mango", c.getName());
}
@Test(expected = IllegalArgumentException.class)
public void testConstructorNullParent() {
List<String> list = new ArrayList<>();
list.add("element");
new CategoryPath(null, list);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructorNullElement() {
List<String> list = new ArrayList<>();
list.add(null);
new CategoryPath(CategoryPath.ROOT, list);
}
@Test
public void testConstructorParentAndList() {
CategoryPath parent = new CategoryPath("/universe/earth");
@ -159,6 +173,49 @@ public class CategoryPathTest extends AbstractGTest {
assertTrue(c.isRoot());
}
@Test
public void testExtendList() {
CategoryPath parent = new CategoryPath("/universe/earth");
List<String> list = new ArrayList<>();
list.add("boy");
list.add("bad");
CategoryPath c = parent.extend(list);
assertEquals("/universe/earth/boy/bad", c.getPath());
assertEquals("bad", c.getName());
}
@Test
public void testExtendVarargsArray() {
CategoryPath parent = new CategoryPath("/apple/peaches");
CategoryPath c = parent.extend(new String[] { "pumpkin", "pie" });
assertEquals("pie", c.getName());
c = c.getParent();
assertEquals("pumpkin", c.getName());
c = c.getParent();
assertEquals("peaches", c.getName());
c = c.getParent();
assertEquals("apple", c.getName());
c = c.getParent();
assertEquals("", c.getName());
assertTrue(c.isRoot());
}
@Test
public void testExtendVarargs() {
CategoryPath parent = new CategoryPath("/apple/peaches");
CategoryPath c = parent.extend("pumpkin", "pie");
assertEquals("pie", c.getName());
c = c.getParent();
assertEquals("pumpkin", c.getName());
c = c.getParent();
assertEquals("peaches", c.getName());
c = c.getParent();
assertEquals("apple", c.getName());
c = c.getParent();
assertEquals("", c.getName());
assertTrue(c.isRoot());
}
@Test(expected = IllegalArgumentException.class)
public void testConstructorBadCtorParam_empty_path_element() {
new CategoryPath("//");