mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-22 10:02:49 +08:00
GT-3545 - GNU Demangler - Fix Parsing Issues - review fixes; bug fixes
This commit is contained in:
+330
@@ -0,0 +1,330 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.demangler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* Parent base class for types that represent things that refer to functions
|
||||
*/
|
||||
public abstract class AbstractDemangledFunctionDefinitionDataType extends DemangledDataType {
|
||||
|
||||
protected static final String DEFAULT_NAME_PREFIX = "FuncDef";
|
||||
protected static final String EMPTY_STRING = "";
|
||||
protected static int ID = 0;
|
||||
protected DemangledDataType returnType;
|
||||
protected String callingConvention;// __cdecl, __thiscall, etc.
|
||||
protected List<DemangledDataType> parameters = new ArrayList<>();
|
||||
protected String modifier;// namespace::, etc.
|
||||
protected boolean isConstPointer;
|
||||
|
||||
protected String parentName;
|
||||
protected boolean isTrailingPointer64;
|
||||
protected boolean isTrailingUnaligned;
|
||||
protected boolean isTrailingRestrict;
|
||||
|
||||
/** display parens in front of parameter list */
|
||||
protected boolean displayFunctionPointerParens = true;
|
||||
|
||||
AbstractDemangledFunctionDefinitionDataType(String mangled, String originalDemangled) {
|
||||
super(mangled, originalDemangled, DEFAULT_NAME_PREFIX + nextId());
|
||||
}
|
||||
|
||||
private synchronized static int nextId() {
|
||||
return ID++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for this type of reference (e.g., * or &)
|
||||
* @return the string
|
||||
*/
|
||||
abstract protected String getTypeString();
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
return toSignature(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return type
|
||||
* @param returnType the return type
|
||||
*/
|
||||
public void setReturnType(DemangledDataType returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type
|
||||
* @return the return type
|
||||
*/
|
||||
public DemangledDataType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function calling convention. For example, "__cdecl"
|
||||
* @param callingConvention the function calling convention
|
||||
*/
|
||||
public void setCallingConvention(String callingConvention) {
|
||||
this.callingConvention = callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calling convention or null, if unspecified
|
||||
* @return the calling convention or null, if unspecified
|
||||
*/
|
||||
public String getCallingConvention() {
|
||||
return callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function __ modifier. For example, "namespace::".
|
||||
* @param modifier the function modifier
|
||||
*/
|
||||
public void setModifier(String modifier) {
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public boolean isConstPointer() {
|
||||
return isConstPointer;
|
||||
}
|
||||
|
||||
public void setConstPointer() {
|
||||
isConstPointer = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingPointer64() {
|
||||
return isTrailingPointer64;
|
||||
}
|
||||
|
||||
public void setTrailingPointer64() {
|
||||
isTrailingPointer64 = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingUnaligned() {
|
||||
return isTrailingUnaligned;
|
||||
}
|
||||
|
||||
public void setTrailingUnaligned() {
|
||||
isTrailingUnaligned = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingRestrict() {
|
||||
return isTrailingRestrict;
|
||||
}
|
||||
|
||||
public void setTrailingRestrict() {
|
||||
isTrailingRestrict = true;
|
||||
}
|
||||
|
||||
public void setDisplayFunctionPointerParens(boolean b) {
|
||||
this.displayFunctionPointerParens = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameters to the end of the parameter list for this demangled function
|
||||
* @param parameter the new parameter to add
|
||||
*/
|
||||
public void addParameter(DemangledDataType parameter) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the parameters for this demangled functions.
|
||||
* @return a list of the parameters for this demangled functions
|
||||
*/
|
||||
public List<DemangledDataType> getParameters() {
|
||||
return new ArrayList<>(parameters);
|
||||
}
|
||||
|
||||
public String toSignature(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
StringBuilder buffer1 = new StringBuilder();
|
||||
String s = getConventionPointerNameString(name);
|
||||
if (s.contains(" ") || s.isEmpty()) {
|
||||
// spaces--add parens
|
||||
addFunctionPointerParens(buffer1, s);
|
||||
}
|
||||
else { // this allows the '__cdecl' in templates to not have parens
|
||||
buffer1.append(s);
|
||||
}
|
||||
|
||||
buffer1.append('(');
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
buffer1.append(parameters.get(i).getSignature());
|
||||
if (i < parameters.size() - 1) {
|
||||
buffer1.append(',');
|
||||
}
|
||||
}
|
||||
buffer1.append(')');
|
||||
|
||||
if (returnType instanceof DemangledFunctionPointer) {
|
||||
DemangledFunctionPointer dfp = (DemangledFunctionPointer) returnType;
|
||||
buffer.append(dfp.toSignature(buffer1.toString())).append(SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionReference) {
|
||||
DemangledFunctionReference dfr = (DemangledFunctionReference) returnType;
|
||||
buffer.append(dfr.toSignature(buffer1.toString())).append(SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionIndirect) {
|
||||
DemangledFunctionIndirect dfi = (DemangledFunctionIndirect) returnType;
|
||||
buffer.append(dfi.toSignature(buffer1.toString())).append(SPACE);
|
||||
}
|
||||
else {
|
||||
buffer.append(returnType.getSignature()).append(SPACE);
|
||||
buffer.append(buffer1);
|
||||
}
|
||||
|
||||
if (isConst()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isVolatile()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(VOLATILE);
|
||||
}
|
||||
|
||||
if (isTrailingUnaligned) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(UNALIGNED);
|
||||
}
|
||||
|
||||
if (isTrailingPointer64) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (isTrailingRestrict) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(RESTRICT);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
protected String getConventionPointerNameString(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
|
||||
|
||||
int pointerLevels = getPointerLevels();
|
||||
if (pointerLevels > 0) {
|
||||
if (callingConvention != null) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
|
||||
addParentName(buffer);
|
||||
|
||||
for (int i = 0; i < pointerLevels; ++i) {
|
||||
buffer.append(getTypeString());
|
||||
}
|
||||
}
|
||||
|
||||
if ((modifier != null) && (modifier.length() != 0)) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(modifier);
|
||||
}
|
||||
|
||||
if (isConstPointer) {
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isPointer64()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
if ((buffer.length() > 2) && (buffer.charAt(buffer.length() - 1) != SPACE)) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(name);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
protected void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
if (!displayFunctionPointerParens) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append('(').append(s).append(')');
|
||||
}
|
||||
|
||||
protected void addParentName(StringBuilder buffer) {
|
||||
if (parentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.length() > 2) {
|
||||
char lastChar = buffer.charAt(buffer.length() - 1);
|
||||
if (SPACE != lastChar) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
}
|
||||
buffer.append(parentName).append(Namespace.DELIMITER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||
|
||||
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
|
||||
|
||||
if (returnType != null) {
|
||||
fddt.setReturnType(returnType.getDataType(dataTypeManager));
|
||||
}
|
||||
|
||||
if (parameters.size() != 1 ||
|
||||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
|
||||
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
params[i] = new ParameterDefinitionImpl(null,
|
||||
parameters.get(i).getDataType(dataTypeManager), null);
|
||||
}
|
||||
fddt.setArguments(params);
|
||||
}
|
||||
|
||||
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
|
||||
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
|
||||
dt = fddt;
|
||||
}
|
||||
|
||||
return new PointerDataType(dt, dataTypeManager);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ package ghidra.app.util.demangler;
|
||||
* A unifying top-level interface for all {@link DemangledObject}s and {@link DemangledType}s
|
||||
*
|
||||
* <p>This class and its children have many overlapping concepts that we wish to refine at a
|
||||
* future date. Below is a listing of know uses:
|
||||
* future date. Below is a listing of known uses:
|
||||
* <TABLE>
|
||||
* <TR>
|
||||
* <TH ALIGN="left">Method</TH><TH ALIGN="left">Description</TH>
|
||||
@@ -38,7 +38,7 @@ package ghidra.app.util.demangler;
|
||||
* {@link #getDemangledName()}
|
||||
* </TD>
|
||||
* <TD>
|
||||
* The unmodified name that was set upon this object.
|
||||
* The unmodified <b>name</b> that was set upon this object.
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
@@ -46,9 +46,12 @@ package ghidra.app.util.demangler;
|
||||
* {@link #getNamespaceName()}
|
||||
* </TD>
|
||||
* <TD>
|
||||
* The name of this object when it is used as a namespace name. This usually has
|
||||
* The 'safe' name of this object when it is used as a namespace name. This usually has
|
||||
* parameter and template information. Further, some characters within templates and
|
||||
* function signatures are replaced, such as spaces and namespace separators.
|
||||
* <P>
|
||||
* Given this full demangled string: {@code Foo::Bar::Baz<int>}, this method will return
|
||||
* {@code Baz<int>}.
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
@@ -56,7 +59,13 @@ package ghidra.app.util.demangler;
|
||||
* {@link #getNamespaceString()}
|
||||
* </TD>
|
||||
* <TD>
|
||||
* Similar to {@link #getNamespaceName()}, but contains all parent namespaces as well.
|
||||
* This returns the unmodified name of this item, along with any unmodified parent
|
||||
* namespace names, all separated by a namespace delimiter. Unlike
|
||||
* {@link #getNamespaceName()}, the spaces and internal namespace tokens will not be
|
||||
* replaced.
|
||||
* <P>
|
||||
* Given this full demangled string: {@code Foo::Bar::Baz<int>}, this method will return
|
||||
* {@code Foo::Bar::Baz<int>}.
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
@@ -73,7 +82,8 @@ package ghidra.app.util.demangler;
|
||||
* {@link #getOriginalDemangled()}
|
||||
* </TD>
|
||||
* <TD>
|
||||
* The original unmodified demangled string.
|
||||
* The original unmodified demangled string. This is the full demangled string returned
|
||||
* from the demangling service.
|
||||
* </TD>
|
||||
* </TR>
|
||||
* </TABLE>
|
||||
@@ -86,24 +96,12 @@ public interface Demangled {
|
||||
*/
|
||||
public String getMangledString();
|
||||
|
||||
/**
|
||||
* Sets the original mangled string
|
||||
* @param mangled the mangled string
|
||||
*/
|
||||
public void setMangledString(String mangled);
|
||||
|
||||
/**
|
||||
* Returns the original demangled string returned by the demangling service
|
||||
* @return the original demangled string
|
||||
*/
|
||||
public String getOriginalDemangled();
|
||||
|
||||
/**
|
||||
* Sets the original demangles string returned by the demangling service
|
||||
* @param originalDemangled the original demangled string
|
||||
*/
|
||||
public void setOriginalDemangled(String originalDemangled);
|
||||
|
||||
/**
|
||||
* Returns the demangled name of this object.
|
||||
* NOTE: unsupported symbol characters, like whitespace, will be converted to an underscore.
|
||||
@@ -147,7 +145,7 @@ public interface Demangled {
|
||||
public String getNamespaceString();
|
||||
|
||||
/**
|
||||
* Returns a this object's namespace name without the full-qualified parent path. The
|
||||
* Returns this object's namespace name without the fully-qualified parent path. The
|
||||
* value returned here may have had some special characters replaced, such as ' ' replaced
|
||||
* with '_' and '::' replaced with '--'.
|
||||
*
|
||||
|
||||
+14
-2
@@ -29,8 +29,20 @@ public class DemangledAddressTable extends DemangledObject {
|
||||
private boolean calculateLength;
|
||||
private int length;
|
||||
|
||||
public DemangledAddressTable(String name, boolean calculateLength) {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param mangled the source mangled string
|
||||
* @param originalDemangled the original demangled string
|
||||
* @param name the name of the address table
|
||||
* @param calculateLength true if the length of this address table should be calculdated at
|
||||
* analysis time
|
||||
*/
|
||||
public DemangledAddressTable(String mangled, String originalDemangled, String name,
|
||||
boolean calculateLength) {
|
||||
super(mangled, originalDemangled);
|
||||
setName(name);
|
||||
this.calculateLength = calculateLength;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +122,7 @@ public class DemangledAddressTable extends DemangledObject {
|
||||
/**
|
||||
* Perform a best guess at the length of an address table assuming that
|
||||
* another label (or end of block) can be used to identify the end.
|
||||
* @param program
|
||||
* @param program the program
|
||||
* @param address start of address table
|
||||
* @return maximum length of table or -1 if address does not reside
|
||||
* within an initialized memory block
|
||||
|
||||
+34
-63
@@ -58,7 +58,7 @@ public class DemangledDataType extends DemangledType {
|
||||
public final static String WCHAR_T = "wchar_t";
|
||||
public final static String SHORT = "short";
|
||||
public final static String INT = "int";
|
||||
public final static String INT0_T = "int0_t";//TODO
|
||||
public final static String INT0_T = "int0_t";
|
||||
public final static String LONG = "long";
|
||||
public final static String LONG_LONG = "long long";
|
||||
public final static String FLOAT = "float";
|
||||
@@ -67,8 +67,8 @@ public class DemangledDataType extends DemangledType {
|
||||
public final static String INT16 = "__int16";
|
||||
public final static String INT32 = "__int32";
|
||||
public final static String INT64 = "__int64";
|
||||
public final static String INT128 = "__int128";//TODO
|
||||
public final static String FLOAT128 = "__float128";//TODO
|
||||
public final static String INT128 = "__int128";
|
||||
public final static String FLOAT128 = "__float128";
|
||||
public final static String LONG_DOUBLE = "long double";
|
||||
public final static String PTR64 = "__ptr64";
|
||||
public final static String STRING = "string";
|
||||
@@ -76,6 +76,11 @@ public class DemangledDataType extends DemangledType {
|
||||
public static final String UNALIGNED = "__unaligned";
|
||||
public static final String RESTRICT = "__restrict";
|
||||
|
||||
private static final String UNSIGNED_CHAR = "unsigned char";
|
||||
private static final String UNSIGNED_SHORT = "unsigned short";
|
||||
private static final String UNSIGNED_INT = "unsigned int";
|
||||
private static final String UNSIGNED_LONG = "unsigned long";
|
||||
|
||||
public final static String[] PRIMITIVES = { VOID, BOOL, CHAR, WCHAR_T, SHORT, INT, INT0_T, LONG,
|
||||
LONG_LONG, FLOAT, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
|
||||
|
||||
@@ -100,54 +105,13 @@ public class DemangledDataType extends DemangledType {
|
||||
private boolean isCoclass;
|
||||
private boolean isCointerface;
|
||||
|
||||
/**
|
||||
* Constructs a new demangled datatype.
|
||||
* @param name the name of the datatype
|
||||
*/
|
||||
public DemangledDataType(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public DemangledDataType copy() {
|
||||
DemangledDataType copy = new DemangledDataType(getName());
|
||||
copy(this, copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
protected void copy(DemangledDataType source, DemangledDataType destination) {
|
||||
destination.arrayDimensions = source.arrayDimensions;
|
||||
destination.isClass = source.isClass;
|
||||
destination.isComplex = source.isComplex;
|
||||
destination.isEnum = source.isEnum;
|
||||
destination.isPointer64 = source.isPointer64;
|
||||
destination.isReference = source.isReference;
|
||||
destination.isSigned = source.isSigned;
|
||||
destination.isStruct = source.isStruct;
|
||||
destination.isTemplate = source.isTemplate;
|
||||
destination.isUnion = source.isUnion;
|
||||
destination.isUnsigned = source.isUnsigned;
|
||||
destination.isVarArgs = source.isVarArgs;
|
||||
destination.pointerLevels = source.pointerLevels;
|
||||
|
||||
destination.isUnaligned = source.isUnaligned();
|
||||
destination.isRestrict = source.isRestrict();
|
||||
destination.basedName = source.getBasedName();
|
||||
destination.memberScope = source.getMemberScope();
|
||||
|
||||
destination.setNamespace(source.getNamespace());
|
||||
destination.setTemplate(source.getTemplate());
|
||||
destination.isCoclass = source.isCoclass;
|
||||
destination.isCointerface = source.isCointerface;
|
||||
|
||||
if (source.isConst()) {
|
||||
destination.setConst();
|
||||
}
|
||||
public DemangledDataType(String mangled, String originaDemangled, String name) {
|
||||
super(mangled, originaDemangled, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this demangled datatype into the corresponding Ghidra datatype.
|
||||
* @param dataTypeManager the data type manager to be searched and whose data organization
|
||||
* should be used
|
||||
* Converts this demangled datatype into the corresponding Ghidra datatype
|
||||
* @param dataTypeManager the manager to search and whose data organization should be used
|
||||
* @return the Ghidra datatype corresponding to the demangled datatype
|
||||
*/
|
||||
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||
@@ -163,11 +127,6 @@ public class DemangledDataType extends DemangledType {
|
||||
}
|
||||
|
||||
if (dt == null) {
|
||||
|
||||
// If custom type, look for it first
|
||||
// TODO: this find method could be subject to name mismatch, although
|
||||
// presence of namespace could help this if it existing and contained within
|
||||
// an appropriate namespace category
|
||||
dt = findDataType(dataTypeManager, namespace, name);
|
||||
|
||||
DataType baseType = dt;
|
||||
@@ -188,25 +147,23 @@ public class DemangledDataType extends DemangledType {
|
||||
}
|
||||
else if (isEnum()) {
|
||||
if (baseType == null || !(baseType instanceof Enum)) {
|
||||
// TODO: Can't tell how big an enum is,
|
||||
// Just use the size of a pointer
|
||||
// 20170522: Modified following code to allow "some" sizing from MSFT.
|
||||
if ((enumType == null) || "int".equals(enumType) ||
|
||||
"unsigned int".equals(enumType)) {
|
||||
|
||||
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
|
||||
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||
dataTypeManager.getDataOrganization().getIntegerSize());
|
||||
}
|
||||
else if ("char".equals(enumType) || "unsigned char".equals(enumType)) {
|
||||
else if (CHAR.equals(enumType) || UNSIGNED_CHAR.equals(enumType)) {
|
||||
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||
dataTypeManager.getDataOrganization().getCharSize());
|
||||
|
||||
}
|
||||
else if ("short".equals(enumType) || "unsigned short".equals(enumType)) {
|
||||
else if (SHORT.equals(enumType) || UNSIGNED_SHORT.equals(enumType)) {
|
||||
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||
dataTypeManager.getDataOrganization().getShortSize());
|
||||
|
||||
}
|
||||
else if ("long".equals(enumType) || "unsigned long".equals(enumType)) {
|
||||
else if (LONG.equals(enumType) || UNSIGNED_LONG.equals(enumType)) {
|
||||
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||
dataTypeManager.getDataOrganization().getLongSize());
|
||||
}
|
||||
@@ -216,7 +173,7 @@ public class DemangledDataType extends DemangledType {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isClass() || name.equals(STRING)) {//TODO - class datatypes??
|
||||
else if (isClass() || name.equals(STRING)) {
|
||||
if (baseType == null || !(baseType instanceof Structure)) {
|
||||
// try creating empty structures for unknown types instead.
|
||||
dt = createPlaceHolderStructure(name, getNamespace());
|
||||
@@ -251,7 +208,7 @@ public class DemangledDataType extends DemangledType {
|
||||
|
||||
private DataType getBuiltInType(DataTypeManager dataTypeManager) {
|
||||
DataType dt = null;
|
||||
String name = getName();
|
||||
String name = getDemangledName();
|
||||
if (BOOL.equals(name)) {
|
||||
dt = BooleanDataType.dataType;
|
||||
}
|
||||
@@ -304,6 +261,9 @@ public class DemangledDataType extends DemangledType {
|
||||
else if (FLOAT.equals(name)) {
|
||||
dt = FloatDataType.dataType;
|
||||
}
|
||||
else if (FLOAT128.equals(name)) {
|
||||
dt = new TypedefDataType(FLOAT128, Float16DataType.dataType);
|
||||
}
|
||||
else if (DOUBLE.equals(name)) {
|
||||
dt = DoubleDataType.dataType;
|
||||
}
|
||||
@@ -350,6 +310,16 @@ public class DemangledDataType extends DemangledType {
|
||||
AbstractIntegerDataType.getSignedDataType(8, dataTypeManager));
|
||||
}
|
||||
}
|
||||
else if (INT128.equals(name)) {
|
||||
if (isUnsigned()) {
|
||||
dt = new TypedefDataType("__uint128",
|
||||
AbstractIntegerDataType.getUnsignedDataType(16, dataTypeManager));
|
||||
}
|
||||
else {
|
||||
dt = new TypedefDataType(INT128,
|
||||
AbstractIntegerDataType.getSignedDataType(16, dataTypeManager));
|
||||
}
|
||||
}
|
||||
else if (UNDEFINED.equals(name)) {
|
||||
dt = DataType.DEFAULT;
|
||||
}
|
||||
@@ -629,6 +599,7 @@ public class DemangledDataType extends DemangledType {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
|
||||
@@ -65,11 +65,8 @@ public class DemangledFunction extends DemangledObject {
|
||||
private boolean isTypeCast;
|
||||
private String throwAttribute;
|
||||
|
||||
/**
|
||||
* Constructs a new demangled function.
|
||||
* @param name the name of the function
|
||||
*/
|
||||
public DemangledFunction(String name) {
|
||||
public DemangledFunction(String mangled, String originalDemangled, String name) {
|
||||
super(mangled, originalDemangled);
|
||||
setName(name);
|
||||
}
|
||||
|
||||
|
||||
+5
-328
@@ -15,11 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.demangler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* A class to represent a demangled function indirect. A function indirect is
|
||||
* similar to a function pointer or a function reference except that it does
|
||||
@@ -27,332 +22,14 @@ import ghidra.program.model.data.*;
|
||||
* is still an indirect definition (not a regular function definition). The
|
||||
* function indirect is prevalent in the Microsoft model, if not other models.
|
||||
*/
|
||||
public class DemangledFunctionIndirect extends DemangledDataType {
|
||||
public class DemangledFunctionIndirect extends AbstractDemangledFunctionDefinitionDataType {
|
||||
|
||||
private static final String DEFAULT_NAME_PREFIX = "FuncDef";
|
||||
private static final String NAMESPACE_DELIMITER = "::";
|
||||
private static final String EMPTY_STRING = "";
|
||||
private static int ID = 0;
|
||||
private DemangledDataType returnType;
|
||||
protected String callingConvention;// __cdecl, __thiscall, etc.
|
||||
private List<DemangledDataType> parameters = new ArrayList<>();
|
||||
protected String modifier;// namespace::, etc.
|
||||
protected boolean isConstPointer;
|
||||
|
||||
private String parentName;
|
||||
private boolean isTrailingPointer64;
|
||||
private boolean isTrailingUnaligned;
|
||||
private boolean isTrailingRestrict;
|
||||
|
||||
/** display parens in front of parameter list */
|
||||
private boolean displayFunctionPointerParens = true;
|
||||
|
||||
/**
|
||||
* Constructs a new demangled function definition.
|
||||
*/
|
||||
public DemangledFunctionIndirect() {
|
||||
super("FuncDef" + nextID());
|
||||
}
|
||||
|
||||
private synchronized static int nextID() {
|
||||
return ID++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type.
|
||||
* @return the return type
|
||||
*/
|
||||
public DemangledDataType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return type.
|
||||
* @param returnType the return type
|
||||
*/
|
||||
public void setReturnType(DemangledDataType returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calling convention or null, if unspecified.
|
||||
* @return the calling convention or null, if unspecified
|
||||
*/
|
||||
public String getCallingConvention() {
|
||||
return callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function calling convention. For example, "__cdecl".
|
||||
* @param callingConvention the function calling convention
|
||||
*/
|
||||
public void setCallingConvention(String callingConvention) {
|
||||
this.callingConvention = callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function __ modifier. For example, "namespace::".
|
||||
* @param modifier the function modifier
|
||||
*/
|
||||
public void setModifier(String modifier) {
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public boolean isConstPointer() {
|
||||
return isConstPointer;
|
||||
}
|
||||
|
||||
public void setConstPointer() {
|
||||
isConstPointer = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingPointer64() {
|
||||
return isTrailingPointer64;
|
||||
}
|
||||
|
||||
public void setTrailingPointer64() {
|
||||
isTrailingPointer64 = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingUnaligned() {
|
||||
return isTrailingUnaligned;
|
||||
}
|
||||
|
||||
public void setTrailingUnaligned() {
|
||||
isTrailingUnaligned = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingRestrict() {
|
||||
return isTrailingRestrict;
|
||||
}
|
||||
|
||||
public void setTrailingRestrict() {
|
||||
isTrailingRestrict = true;
|
||||
}
|
||||
|
||||
public void setDisplayFunctionPointerParens(boolean b) {
|
||||
this.displayFunctionPointerParens = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameters to the end of the parameter list for this demangled function
|
||||
* @param parameter the new parameter to add
|
||||
*/
|
||||
public void addParameter(DemangledDataType parameter) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the parameters for this demangled functions
|
||||
* @return a list of the parameters for this demangled functions
|
||||
*/
|
||||
public List<DemangledDataType> getParameters() {
|
||||
return new ArrayList<>(parameters);
|
||||
public DemangledFunctionIndirect(String mangled, String originalDemangled) {
|
||||
super(mangled, originalDemangled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DemangledDataType copy() {
|
||||
DemangledFunctionIndirect copy = new DemangledFunctionIndirect();
|
||||
copy(this, copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void copy(DemangledDataType source, DemangledDataType destination) {
|
||||
super.copy(source, destination);
|
||||
if ((source instanceof DemangledFunctionIndirect) &&
|
||||
(destination instanceof DemangledFunctionIndirect)) {
|
||||
DemangledFunctionIndirect copySource = (DemangledFunctionIndirect) source;
|
||||
DemangledFunctionIndirect copyDestination = (DemangledFunctionIndirect) destination;
|
||||
|
||||
copyDestination.returnType = copySource.returnType.copy();
|
||||
for (DemangledDataType parameter : copySource.parameters) {
|
||||
copyDestination.parameters.add(parameter.copy());
|
||||
}
|
||||
|
||||
copyDestination.callingConvention = copySource.callingConvention;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
return toSignature(null);
|
||||
}
|
||||
|
||||
public String toSignature(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
StringBuilder buffer1 = new StringBuilder();
|
||||
String s = getConventionPointerNameString(name);
|
||||
if (s.contains(" ") || s.isEmpty()) {
|
||||
// spaces--add parens
|
||||
addFunctionPointerParens(buffer1, s);
|
||||
}
|
||||
else { // this allows the '__cdecl' in templates to not have parens
|
||||
buffer1.append(s);
|
||||
}
|
||||
|
||||
buffer1.append('(');
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
buffer1.append(parameters.get(i).getSignature());
|
||||
if (i < parameters.size() - 1) {
|
||||
buffer1.append(',');
|
||||
}
|
||||
}
|
||||
buffer1.append(')');
|
||||
|
||||
if (returnType instanceof DemangledFunctionPointer) {
|
||||
buffer.append(
|
||||
((DemangledFunctionPointer) returnType).toSignature(buffer1.toString()))
|
||||
.append(
|
||||
SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionReference) {
|
||||
buffer.append(
|
||||
((DemangledFunctionReference) returnType).toSignature(buffer1.toString()))
|
||||
.append(
|
||||
SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionIndirect) {
|
||||
buffer.append(
|
||||
((DemangledFunctionIndirect) returnType).toSignature(buffer1.toString()))
|
||||
.append(
|
||||
SPACE);
|
||||
}
|
||||
else {
|
||||
buffer.append(returnType.getSignature()).append(SPACE);
|
||||
buffer.append(buffer1);
|
||||
}
|
||||
|
||||
if (isConst()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isVolatile()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(VOLATILE);
|
||||
}
|
||||
|
||||
if (isTrailingUnaligned) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(UNALIGNED);
|
||||
}
|
||||
|
||||
if (isTrailingPointer64) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (isTrailingRestrict) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(RESTRICT);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
if (!displayFunctionPointerParens) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append('(').append(s).append(')');
|
||||
}
|
||||
|
||||
private String getConventionPointerNameString(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
|
||||
|
||||
int pointerLevels = getPointerLevels();
|
||||
if (pointerLevels > 0) {
|
||||
// if (callingConvention != null) {
|
||||
// buffer.append(SPACE);
|
||||
// }
|
||||
|
||||
addParentName(buffer);
|
||||
|
||||
// for (int i = 0; i < pointerLevels; ++i) {
|
||||
// buffer.append('*');
|
||||
// }
|
||||
}
|
||||
|
||||
if ((modifier != null) && (modifier.length() != 0)) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(modifier);
|
||||
}
|
||||
|
||||
if (isConstPointer) {
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isPointer64()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
if ((buffer.length() > 2) && (buffer.charAt(buffer.length() - 1) != SPACE)) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(name);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void addParentName(StringBuilder buffer) {
|
||||
if (parentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.length() > 2) {
|
||||
char lastChar = buffer.charAt(buffer.length() - 1);
|
||||
if (SPACE != lastChar) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
}
|
||||
buffer.append(parentName).append(NAMESPACE_DELIMITER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||
|
||||
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
|
||||
fddt.setReturnType(returnType.getDataType(dataTypeManager));
|
||||
|
||||
if (parameters.size() != 1 ||
|
||||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
|
||||
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
params[i] = new ParameterDefinitionImpl(null,
|
||||
parameters.get(i).getDataType(dataTypeManager), null);
|
||||
}
|
||||
fddt.setArguments(params);
|
||||
}
|
||||
|
||||
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
|
||||
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
|
||||
dt = fddt;
|
||||
}
|
||||
|
||||
return new PointerDataType(dt, dataTypeManager);
|
||||
protected String getTypeString() {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-326
@@ -15,337 +15,17 @@
|
||||
*/
|
||||
package ghidra.app.util.demangler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* A class to represent a demangled function pointer.
|
||||
* A class to represent a demangled function pointer
|
||||
*/
|
||||
public class DemangledFunctionPointer extends DemangledDataType {
|
||||
public class DemangledFunctionPointer extends AbstractDemangledFunctionDefinitionDataType {
|
||||
|
||||
private static final String DEFAULT_NAME_PREFIX = "FuncDef";
|
||||
private static final Object NAMESPACE_DELIMITER = "::";
|
||||
private static final String EMPTY_STRING = "";
|
||||
private static int ID = 0;
|
||||
private DemangledDataType returnType;
|
||||
protected String callingConvention;// __cdecl, __thiscall, etc.
|
||||
private List<DemangledDataType> parameters = new ArrayList<>();
|
||||
protected String modifier;// namespace::, etc.
|
||||
protected boolean isConstPointer;
|
||||
|
||||
private String parentName;
|
||||
private boolean isTrailingPointer64;
|
||||
private boolean isTrailingUnaligned;
|
||||
private boolean isTrailingRestrict;
|
||||
|
||||
/** display parens in front of parameter list */
|
||||
private boolean displayFunctionPointerParens = true;
|
||||
|
||||
/**
|
||||
* Constructs a new demangled function pointer.
|
||||
*/
|
||||
public DemangledFunctionPointer() {
|
||||
super("FuncDef" + nextID());
|
||||
}
|
||||
|
||||
private synchronized static int nextID() {
|
||||
return ID++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type.
|
||||
* @return the return type
|
||||
*/
|
||||
public DemangledDataType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return type.
|
||||
* @param returnType the return type
|
||||
*/
|
||||
public void setReturnType(DemangledDataType returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calling convention or null, if unspecified.
|
||||
* @return the calling convention or null, if unspecified
|
||||
*/
|
||||
public String getCallingConvention() {
|
||||
return callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function calling convention. For example, "__cdecl".
|
||||
* @param callingConvention the function calling convention
|
||||
*/
|
||||
public void setCallingConvention(String callingConvention) {
|
||||
this.callingConvention = callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function __ modifier. For example, "namespace::".
|
||||
* @param modifier the function modifier
|
||||
*/
|
||||
public void setModifier(String modifier) {
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public boolean isConstPointer() {
|
||||
return isConstPointer;
|
||||
}
|
||||
|
||||
public void setConstPointer() {
|
||||
isConstPointer = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingPointer64() {
|
||||
return isTrailingPointer64;
|
||||
}
|
||||
|
||||
public void setTrailingPointer64() {
|
||||
isTrailingPointer64 = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingUnaligned() {
|
||||
return isTrailingUnaligned;
|
||||
}
|
||||
|
||||
public void setTrailingUnaligned() {
|
||||
isTrailingUnaligned = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingRestrict() {
|
||||
return isTrailingRestrict;
|
||||
}
|
||||
|
||||
public void setTrailingRestrict() {
|
||||
isTrailingRestrict = true;
|
||||
}
|
||||
|
||||
public void setDisplayFunctionPointerParens(boolean b) {
|
||||
this.displayFunctionPointerParens = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameters to the end of the parameter list for this demangled function
|
||||
* @param parameter the new parameter to add
|
||||
*/
|
||||
public void addParameter(DemangledDataType parameter) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the parameters for this demangled functions.
|
||||
* @return a list of the parameters for this demangled functions
|
||||
*/
|
||||
public List<DemangledDataType> getParameters() {
|
||||
return new ArrayList<>(parameters);
|
||||
public DemangledFunctionPointer(String mangled, String originalDemangled) {
|
||||
super(mangled, originalDemangled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DemangledDataType copy() {
|
||||
DemangledFunctionPointer copy = new DemangledFunctionPointer();
|
||||
copy(this, copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void copy(DemangledDataType source, DemangledDataType destination) {
|
||||
super.copy(source, destination);
|
||||
if ((source instanceof DemangledFunctionPointer) &&
|
||||
(destination instanceof DemangledFunctionPointer)) {
|
||||
DemangledFunctionPointer copySource = (DemangledFunctionPointer) source;
|
||||
DemangledFunctionPointer copyDestination = (DemangledFunctionPointer) destination;
|
||||
|
||||
copyDestination.returnType = copySource.returnType.copy();
|
||||
for (DemangledDataType parameter : copySource.parameters) {
|
||||
copyDestination.parameters.add(parameter.copy());
|
||||
}
|
||||
|
||||
copyDestination.callingConvention = copySource.callingConvention;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
return toSignature(null);
|
||||
}
|
||||
|
||||
public String toSignature(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
StringBuilder buffer1 = new StringBuilder();
|
||||
String s = getConventionPointerNameString(name);
|
||||
if (s.contains(" ") || s.isEmpty()) {
|
||||
// spaces--add parens
|
||||
addFunctionPointerParens(buffer1, s);
|
||||
}
|
||||
else { // this allows the '__cdecl' in templates to not have parens
|
||||
buffer1.append(s);
|
||||
}
|
||||
|
||||
buffer1.append('(');
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
buffer1.append(parameters.get(i).getSignature());
|
||||
if (i < parameters.size() - 1) {
|
||||
buffer1.append(',');
|
||||
}
|
||||
}
|
||||
buffer1.append(')');
|
||||
|
||||
if (returnType instanceof DemangledFunctionPointer) {
|
||||
DemangledFunctionPointer dfp = (DemangledFunctionPointer) returnType;
|
||||
buffer.append(dfp.toSignature(buffer1.toString())).append(SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionReference) {
|
||||
DemangledFunctionReference dfr = (DemangledFunctionReference) returnType;
|
||||
buffer.append(dfr.toSignature(buffer1.toString())).append(SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionIndirect) {
|
||||
DemangledFunctionIndirect dfi = (DemangledFunctionIndirect) returnType;
|
||||
buffer.append(dfi.toSignature(buffer1.toString())).append(SPACE);
|
||||
}
|
||||
else {
|
||||
buffer.append(returnType.getSignature()).append(SPACE);
|
||||
buffer.append(buffer1);
|
||||
}
|
||||
|
||||
if (isConst()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isVolatile()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(VOLATILE);
|
||||
}
|
||||
|
||||
if (isTrailingUnaligned) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(UNALIGNED);
|
||||
}
|
||||
|
||||
if (isTrailingPointer64) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (isTrailingRestrict) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(RESTRICT);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
if (!displayFunctionPointerParens) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append('(').append(s).append(')');
|
||||
}
|
||||
|
||||
private String getConventionPointerNameString(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
|
||||
|
||||
int pointerLevels = getPointerLevels();
|
||||
if (pointerLevels > 0) {
|
||||
if (callingConvention != null) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
|
||||
addParentName(buffer);
|
||||
|
||||
for (int i = 0; i < pointerLevels; ++i) {
|
||||
buffer.append('*');
|
||||
}
|
||||
}
|
||||
|
||||
if ((modifier != null) && (modifier.length() != 0)) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(modifier);
|
||||
}
|
||||
|
||||
if (isConstPointer) {
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isPointer64()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(name);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void addParentName(StringBuilder buffer) {
|
||||
if (parentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.length() > 2) {
|
||||
char lastChar = buffer.charAt(buffer.length() - 1);
|
||||
if (SPACE != lastChar) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
}
|
||||
buffer.append(parentName).append(NAMESPACE_DELIMITER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||
|
||||
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
|
||||
|
||||
if (returnType != null) {
|
||||
fddt.setReturnType(returnType.getDataType(dataTypeManager));
|
||||
}
|
||||
|
||||
if (parameters.size() != 1 ||
|
||||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
|
||||
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
params[i] = new ParameterDefinitionImpl(null,
|
||||
parameters.get(i).getDataType(dataTypeManager), null);
|
||||
}
|
||||
fddt.setArguments(params);
|
||||
}
|
||||
|
||||
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
|
||||
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
|
||||
dt = fddt;
|
||||
}
|
||||
|
||||
return new PointerDataType(dt, dataTypeManager);
|
||||
protected String getTypeString() {
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
|
||||
+6
-330
@@ -15,341 +15,17 @@
|
||||
*/
|
||||
package ghidra.app.util.demangler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* A class to represent a demangled function reference.
|
||||
* A class to represent a demangled function reference
|
||||
*/
|
||||
public class DemangledFunctionReference extends DemangledDataType {
|
||||
public class DemangledFunctionReference extends AbstractDemangledFunctionDefinitionDataType {
|
||||
|
||||
private static final String DEFAULT_NAME_PREFIX = "FuncDef";
|
||||
private static final Object NAMESPACE_DELIMITER = "::";
|
||||
private static final String EMPTY_STRING = "";
|
||||
private static int ID = 0;
|
||||
private DemangledDataType returnType;
|
||||
protected String callingConvention;// __cdecl, __thiscall, etc.
|
||||
private List<DemangledDataType> parameters = new ArrayList<>();
|
||||
protected String modifier;// namespace::, etc.
|
||||
protected boolean isConstPointer;
|
||||
|
||||
private String parentName;
|
||||
private boolean isTrailingPointer64;
|
||||
private boolean isTrailingUnaligned;
|
||||
private boolean isTrailingRestrict;
|
||||
|
||||
/** display parens in front of parameter list */
|
||||
private boolean displayFunctionPointerParens = true;
|
||||
|
||||
/**
|
||||
* Constructs a new demangled function reference.
|
||||
*/
|
||||
public DemangledFunctionReference() {
|
||||
super("FuncDef" + nextID());
|
||||
}
|
||||
|
||||
private synchronized static int nextID() {
|
||||
return ID++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type.
|
||||
* @return the return type
|
||||
*/
|
||||
public DemangledDataType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the return type.
|
||||
* @param returnType the return type
|
||||
*/
|
||||
public void setReturnType(DemangledDataType returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calling convention or null, if unspecified.
|
||||
* @return the calling convention or null, if unspecified
|
||||
*/
|
||||
public String getCallingConvention() {
|
||||
return callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function calling convention. For example, "__cdecl".
|
||||
* @param callingConvention the function calling convention
|
||||
*/
|
||||
public void setCallingConvention(String callingConvention) {
|
||||
this.callingConvention = callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function __ modifier. For example, "namespace::".
|
||||
* @param modifier the function modifier
|
||||
*/
|
||||
public void setModifier(String modifier) {
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public boolean isConstPointer() {
|
||||
return isConstPointer;
|
||||
}
|
||||
|
||||
public void setConstPointer() {
|
||||
isConstPointer = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingPointer64() {
|
||||
return isTrailingPointer64;
|
||||
}
|
||||
|
||||
public void setTrailingPointer64() {
|
||||
isTrailingPointer64 = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingUnaligned() {
|
||||
return isTrailingUnaligned;
|
||||
}
|
||||
|
||||
public void setTrailingUnaligned() {
|
||||
isTrailingUnaligned = true;
|
||||
}
|
||||
|
||||
public boolean isTrailingRestrict() {
|
||||
return isTrailingRestrict;
|
||||
}
|
||||
|
||||
public void setTrailingRestrict() {
|
||||
isTrailingRestrict = true;
|
||||
}
|
||||
|
||||
public void setDisplayFunctionPointerParens(boolean b) {
|
||||
this.displayFunctionPointerParens = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameters to the end of the parameter list for this demangled function
|
||||
* @param parameter the new parameter to add
|
||||
*/
|
||||
public void addParameter(DemangledDataType parameter) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the parameters for this demangled functions.
|
||||
* @return a list of the parameters for this demangled functions
|
||||
*/
|
||||
public List<DemangledDataType> getParameters() {
|
||||
return new ArrayList<>(parameters);
|
||||
public DemangledFunctionReference(String mangled, String originalDemangled) {
|
||||
super(mangled, originalDemangled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DemangledDataType copy() {
|
||||
DemangledFunctionReference copy = new DemangledFunctionReference();
|
||||
copy(this, copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void copy(DemangledDataType source, DemangledDataType destination) {
|
||||
super.copy(source, destination);
|
||||
if ((source instanceof DemangledFunctionReference) &&
|
||||
(destination instanceof DemangledFunctionReference)) {
|
||||
DemangledFunctionReference copySource = (DemangledFunctionReference) source;
|
||||
DemangledFunctionReference copyDestination = (DemangledFunctionReference) destination;
|
||||
|
||||
copyDestination.returnType = copySource.returnType.copy();
|
||||
for (DemangledDataType parameter : copySource.parameters) {
|
||||
copyDestination.parameters.add(parameter.copy());
|
||||
}
|
||||
|
||||
copyDestination.callingConvention = copySource.callingConvention;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
return toSignature(null);
|
||||
}
|
||||
|
||||
public String toSignature(String name) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuffer buffer1 = new StringBuffer();
|
||||
String s = getConventionPointerNameString(name);
|
||||
if (s.contains(" ") || s.isEmpty()) {
|
||||
// spaces--add parens
|
||||
addFunctionPointerParens(buffer1, s);
|
||||
}
|
||||
else { // this allows the '__cdecl' in templates to not have parens
|
||||
buffer1.append(s);
|
||||
}
|
||||
|
||||
buffer1.append('(');
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
buffer1.append(parameters.get(i).getSignature());
|
||||
if (i < parameters.size() - 1) {
|
||||
buffer1.append(',');
|
||||
}
|
||||
}
|
||||
buffer1.append(')');
|
||||
|
||||
if (returnType instanceof DemangledFunctionPointer) {
|
||||
buffer.append(
|
||||
((DemangledFunctionPointer) returnType).toSignature(buffer1.toString()))
|
||||
.append(
|
||||
SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionReference) {
|
||||
buffer.append(
|
||||
((DemangledFunctionReference) returnType).toSignature(buffer1.toString()))
|
||||
.append(
|
||||
SPACE);
|
||||
}
|
||||
else if (returnType instanceof DemangledFunctionIndirect) {
|
||||
buffer.append(
|
||||
((DemangledFunctionIndirect) returnType).toSignature(buffer1.toString()))
|
||||
.append(
|
||||
SPACE);
|
||||
}
|
||||
else {
|
||||
buffer.append(returnType.getSignature()).append(SPACE);
|
||||
buffer.append(buffer1);
|
||||
}
|
||||
|
||||
if (isConst()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isVolatile()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(VOLATILE);
|
||||
}
|
||||
|
||||
if (isTrailingUnaligned) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(UNALIGNED);
|
||||
}
|
||||
|
||||
if (isTrailingPointer64) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (isTrailingRestrict) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(RESTRICT);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void addFunctionPointerParens(StringBuffer buffer, String s) {
|
||||
if (!displayFunctionPointerParens) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append('(').append(s).append(')');
|
||||
}
|
||||
|
||||
private String getConventionPointerNameString(String name) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
|
||||
|
||||
int pointerLevels = getPointerLevels();
|
||||
if (pointerLevels > 0) {
|
||||
if (callingConvention != null) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
|
||||
addParentName(buffer);
|
||||
|
||||
buffer.append('&');
|
||||
// for (int i = 0; i < pointerLevels; ++i) {
|
||||
// buffer.append('*');
|
||||
// }
|
||||
}
|
||||
|
||||
if ((modifier != null) && (modifier.length() != 0)) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(modifier);
|
||||
}
|
||||
|
||||
if (isConstPointer) {
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
||||
if (isPointer64()) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(PTR64);
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(name);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void addParentName(StringBuilder buffer) {
|
||||
if (parentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.length() > 2) {
|
||||
char lastChar = buffer.charAt(buffer.length() - 1);
|
||||
if (SPACE != lastChar) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
}
|
||||
buffer.append(parentName).append(NAMESPACE_DELIMITER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||
|
||||
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
|
||||
fddt.setReturnType(returnType.getDataType(dataTypeManager));
|
||||
|
||||
if (parameters.size() != 1 ||
|
||||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
|
||||
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
params[i] = new ParameterDefinitionImpl(null,
|
||||
parameters.get(i).getDataType(dataTypeManager), null);
|
||||
}
|
||||
fddt.setArguments(params);
|
||||
}
|
||||
|
||||
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
|
||||
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
|
||||
dt = fddt;
|
||||
}
|
||||
|
||||
return new PointerDataType(dt, dataTypeManager);
|
||||
protected String getTypeString() {
|
||||
return "&";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ package ghidra.app.util.demangler;
|
||||
*/
|
||||
public class DemangledLambda extends DemangledFunction {
|
||||
|
||||
public DemangledLambda(String name) {
|
||||
super(name);
|
||||
public DemangledLambda(String mangled, String originalDemangled, String name) {
|
||||
super(mangled, originalDemangled, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,8 +41,8 @@ public abstract class DemangledObject implements Demangled {
|
||||
protected static final String NAMESPACE_SEPARATOR = Namespace.DELIMITER;
|
||||
protected static final String EMPTY_STRING = "";
|
||||
|
||||
protected String mangled; // original mangled string
|
||||
protected String originalDemangled;
|
||||
protected final String mangled; // original mangled string
|
||||
protected final String originalDemangled;
|
||||
protected String specialPrefix;
|
||||
protected Demangled namespace;
|
||||
protected String visibility;//public, protected, etc.
|
||||
@@ -70,8 +70,9 @@ public abstract class DemangledObject implements Demangled {
|
||||
|
||||
private String signature;
|
||||
|
||||
DemangledObject() {
|
||||
// default
|
||||
DemangledObject(String mangled, String originalDemangled) {
|
||||
this.mangled = mangled;
|
||||
this.originalDemangled = originalDemangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -180,21 +181,11 @@ public abstract class DemangledObject implements Demangled {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMangledString(String mangled) {
|
||||
this.mangled = mangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMangledString() {
|
||||
return mangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOriginalDemangled(String originalDemangled) {
|
||||
this.originalDemangled = originalDemangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalDemangled() {
|
||||
return originalDemangled;
|
||||
@@ -248,7 +239,7 @@ public abstract class DemangledObject implements Demangled {
|
||||
public abstract String getSignature(boolean format);
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
public final String getSignature() {
|
||||
return getSignature(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ public class DemangledString extends DemangledObject {
|
||||
|
||||
/**
|
||||
* Construct demangled string.
|
||||
* @param mangled the source mangled string
|
||||
* @param originalDemangled the original demangled string
|
||||
* @param name name associated with this object
|
||||
* @param string string text associated with this object or null. This is used to establish
|
||||
* label and plate comment if specified. If null, name will be used as symbol name.
|
||||
@@ -37,7 +39,9 @@ public class DemangledString extends DemangledObject {
|
||||
* assumes null terminated string.
|
||||
* @param unicode true if string is a Unicode string.
|
||||
*/
|
||||
public DemangledString(String name, String string, int length, boolean unicode) {
|
||||
public DemangledString(String mangled, String originalDemangled, String name, String string,
|
||||
int length, boolean unicode) {
|
||||
super(mangled, originalDemangled);
|
||||
setName(name);
|
||||
this.string = string;
|
||||
this.length = length;
|
||||
|
||||
@@ -34,7 +34,9 @@ public class DemangledThunk extends DemangledObject {
|
||||
|
||||
private boolean covariantReturnThunk = false;
|
||||
|
||||
public DemangledThunk(DemangledFunction thunkedFunctionObject) {
|
||||
public DemangledThunk(String mangled, String originalDemangled,
|
||||
DemangledFunction thunkedFunctionObject) {
|
||||
super(mangled, originalDemangled);
|
||||
this.thunkedFunctionObject = thunkedFunctionObject;
|
||||
this.namespace = thunkedFunctionObject.getNamespace();
|
||||
setName(thunkedFunctionObject.getName());
|
||||
@@ -115,14 +117,6 @@ public class DemangledThunk extends DemangledObject {
|
||||
return s != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create normal function where thunk resides
|
||||
* @param prog program
|
||||
* @param addr thunk function address
|
||||
* @param doDisassembly
|
||||
* @param monitor
|
||||
* @return function
|
||||
*/
|
||||
private Function createPreThunkFunction(Program prog, Address addr, boolean doDisassembly,
|
||||
TaskMonitor monitor) {
|
||||
|
||||
@@ -182,7 +176,7 @@ public class DemangledThunk extends DemangledObject {
|
||||
}
|
||||
|
||||
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
|
||||
thunkedFunctionObject.mangled, err -> Msg.warn(this, err));
|
||||
mangled, err -> Msg.warn(this, err));
|
||||
|
||||
if (s == null) {
|
||||
Address thunkedAddr =
|
||||
|
||||
@@ -24,16 +24,20 @@ import ghidra.program.model.symbol.Namespace;
|
||||
* to compose its internal state for namespace information, return types and parameters.
|
||||
*/
|
||||
public class DemangledType implements Demangled {
|
||||
private String demangledName;
|
||||
private String name;
|
||||
|
||||
protected String mangled; // the original mangled string
|
||||
private String originalDemangled;
|
||||
private String demangledName;
|
||||
private String name; // 'safe' name
|
||||
|
||||
protected Demangled namespace;
|
||||
protected DemangledTemplate template;
|
||||
private boolean isConst;
|
||||
private boolean isVolatile;
|
||||
private String originalDemangled;
|
||||
|
||||
public DemangledType(String name) {
|
||||
public DemangledType(String mangled, String originaDemangled, String name) {
|
||||
this.mangled = mangled;
|
||||
this.originalDemangled = originaDemangled;
|
||||
setName(name);
|
||||
}
|
||||
|
||||
@@ -57,21 +61,11 @@ public class DemangledType implements Demangled {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOriginalDemangled(String originalDemangled) {
|
||||
this.originalDemangled = originalDemangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalDemangled() {
|
||||
return originalDemangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMangledString(String mangled) {
|
||||
this.mangled = mangled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMangledString() {
|
||||
return mangled;
|
||||
@@ -145,7 +139,7 @@ public class DemangledType implements Demangled {
|
||||
|
||||
@Override
|
||||
public String getNamespaceName() {
|
||||
return getName(false);
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,10 +26,8 @@ import ghidra.program.model.symbol.SymbolUtilities;
|
||||
*/
|
||||
public class DemangledUnknown extends DemangledObject {
|
||||
|
||||
public DemangledUnknown() {
|
||||
}
|
||||
|
||||
public DemangledUnknown(String name) {
|
||||
public DemangledUnknown(String mangled, String originalDemangled, String name) {
|
||||
super(mangled, originalDemangled);
|
||||
setName(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class DemangledVariable extends DemangledObject {
|
||||
private DemangledDataType datatype;
|
||||
|
||||
public DemangledVariable(String name) {
|
||||
public DemangledVariable(String mangled, String originalDemangled, String name) {
|
||||
super(mangled, originalDemangled);
|
||||
setName(name);
|
||||
}
|
||||
|
||||
|
||||
+4
-6
@@ -113,9 +113,9 @@ public class GnuDemangler implements Demangler {
|
||||
}
|
||||
|
||||
if (globalPrefix != null) {
|
||||
// TODO: may need better naming convention for demangled function
|
||||
DemangledFunction dfunc =
|
||||
new DemangledFunction(globalPrefix + demangledObject.getName());
|
||||
new DemangledFunction(originalMangled, demangled,
|
||||
globalPrefix + demangledObject.getName());
|
||||
dfunc.setNamespace(demangledObject.getNamespace());
|
||||
demangledObject = dfunc;
|
||||
}
|
||||
@@ -123,14 +123,12 @@ public class GnuDemangler implements Demangler {
|
||||
demangledObject.setSignature(demangled);
|
||||
}
|
||||
|
||||
demangledObject.setMangledString(originalMangled);
|
||||
|
||||
if (isDwarf) {
|
||||
DemangledAddressTable dat = new DemangledAddressTable((String) null, false);
|
||||
DemangledAddressTable dat =
|
||||
new DemangledAddressTable(originalMangled, demangled, (String) null, false);
|
||||
dat.setSpecialPrefix("DWARF Debug ");
|
||||
dat.setName(demangledObject.getName());
|
||||
dat.setNamespace(demangledObject.getNamespace());
|
||||
dat.setMangledString(originalMangled);
|
||||
return dat;
|
||||
}
|
||||
|
||||
|
||||
+290
-207
File diff suppressed because it is too large
Load Diff
+621
File diff suppressed because it is too large
Load Diff
+44
-8
@@ -38,14 +38,22 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverloadedShiftOperatorParsingBug() {
|
||||
parser = new GnuDemanglerParser();
|
||||
DemangledObject object = parser.parse(null,
|
||||
"std::basic_istream<char, std::char_traits<char> >& " +
|
||||
"std::operator>><char, std::char_traits<char> >" +
|
||||
"(std::basic_istream<char, std::char_traits<char> >&, char&)");
|
||||
String name = object.getName();
|
||||
assertEquals("operator>><char,std--char_traits<char>>", name);
|
||||
public void testParse_ArrayPointerReferencePattern_ConstArray() throws Exception {
|
||||
|
||||
// bob(int const[8] (*) [12])
|
||||
|
||||
String demangled =
|
||||
"bob(int const[8] (*) [12])";
|
||||
DemangledObject object = parser.parse("fake", demangled);
|
||||
assertType(object, DemangledFunction.class);
|
||||
assertName(object, "bob");
|
||||
|
||||
DemangledFunction function = (DemangledFunction) object;
|
||||
List<DemangledDataType> parameters = function.getParameters();
|
||||
assertEquals(1, parameters.size());
|
||||
DemangledDataType p1 = parameters.get(0);
|
||||
assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled());
|
||||
assertEquals("undefined bob(int *[])", object.getSignature(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -532,6 +540,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
//
|
||||
String mangled = "CalcPortExposedRect__13LScrollerViewCFR4Rectb";
|
||||
|
||||
// use an older demangler; the current demangler cannot handle this string
|
||||
process = GnuDemanglerNativeProcess
|
||||
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
|
||||
@@ -556,6 +565,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
//
|
||||
String mangled = "__dt__Q26MsoDAL9VertFrameFv";
|
||||
|
||||
// use an older demangler; the current demangler cannot handle this string
|
||||
process = GnuDemanglerNativeProcess
|
||||
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
|
||||
@@ -596,6 +606,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
//
|
||||
String mangled = "GetColWidths__13CDataRendererCFRA7_s";
|
||||
|
||||
// use an older demangler; the current demangler cannot handle this string
|
||||
process = GnuDemanglerNativeProcess
|
||||
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
|
||||
@@ -620,6 +631,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
//
|
||||
String mangled = "GetColWidths__13CDataRendererCFPA7_s";
|
||||
|
||||
// use an older demangler; the current demangler cannot handle this string
|
||||
process = GnuDemanglerNativeProcess
|
||||
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
|
||||
@@ -678,6 +690,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
//
|
||||
String mangled = "_gmStage2__FP12SECTION_INFOPiPA12_iiPCs";
|
||||
|
||||
// use an older demangler; the current demangler cannot handle this string
|
||||
process = GnuDemanglerNativeProcess
|
||||
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
|
||||
@@ -712,6 +725,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
//
|
||||
String mangled = "__ct__Q24CStr6BufferFR4CStrUl";
|
||||
|
||||
// use an older demangler; the current demangler cannot handle this string
|
||||
process = GnuDemanglerNativeProcess
|
||||
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
|
||||
@@ -805,6 +819,22 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
assertEquals("Magick::Coordinate const &", parameters.get(1).getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverloadedShiftOperatorParsingBug() {
|
||||
parser = new GnuDemanglerParser();
|
||||
DemangledObject object = parser.parse(null,
|
||||
"std::basic_istream<char, std::char_traits<char> >& " +
|
||||
"std::operator>><char, std::char_traits<char> >" +
|
||||
"(std::basic_istream<char, std::char_traits<char> >&, char&)");
|
||||
String name = object.getName();
|
||||
assertEquals("operator>>", name);
|
||||
assertEquals(
|
||||
"std::basic_istream<char,std--char_traits<char>>& " +
|
||||
"std::operator>><char,std::char_traits<char>>" +
|
||||
"(std::basic_istream<char,std::char_traits<char>> &,char &)",
|
||||
object.getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperator_Functor() throws Exception {
|
||||
|
||||
@@ -1399,6 +1429,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
assertEquals("undefined wrap_360_cd<int>(int)", signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDataType_LongLong() throws Exception {
|
||||
assertNotNull(
|
||||
new DemangledDataType("fake", "fake", DemangledDataType.LONG_LONG).getDataType(null));
|
||||
}
|
||||
|
||||
private void assertType(Demangled o, Class<?> c) {
|
||||
assertTrue("Wrong demangled type. " +
|
||||
"\nExpected " + c + "; " +
|
||||
|
||||
+4
-1
@@ -602,7 +602,10 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
|
||||
if (descriptorName == null) {
|
||||
return null;
|
||||
}
|
||||
DemangledType typeNamespace = new DemangledType(descriptorName);
|
||||
|
||||
String demangledSource = mdComplexType.toString();
|
||||
DemangledType typeNamespace =
|
||||
new DemangledType(originalTypeName, demangledSource, descriptorName);
|
||||
DemangledType parentNamespace = getParentNamespace(); // Can be null;
|
||||
if (parentNamespace != null) {
|
||||
typeNamespace.setNamespace(parentNamespace);
|
||||
|
||||
+3
-3
@@ -76,10 +76,10 @@ public class MicrosoftDemangler implements Demangler {
|
||||
return object;
|
||||
}
|
||||
catch (MDException e) {
|
||||
DemangledException gde =
|
||||
DemangledException de =
|
||||
new DemangledException("Unable to demangle symbol: " + mangled);
|
||||
gde.initCause(e);
|
||||
throw gde;
|
||||
de.initCause(e);
|
||||
throw de;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ public class MDMangGhidra extends MDMang {
|
||||
private DemangledObject objectResult;
|
||||
private DemangledDataType dataTypeResult;
|
||||
|
||||
private String mangledSource;
|
||||
private String demangledSource;
|
||||
|
||||
public DemangledObject getObject() {
|
||||
return objectResult;
|
||||
}
|
||||
@@ -46,31 +49,6 @@ public class MDMangGhidra extends MDMang {
|
||||
return dataTypeResult;
|
||||
}
|
||||
|
||||
public DemangledType processNamespace(MDQualifiedName qualifiedName) {
|
||||
return processNamespace(qualifiedName.getQualification());
|
||||
}
|
||||
|
||||
private DemangledType processNamespace(MDQualification qualification) {
|
||||
Iterator<MDQualifier> it = qualification.iterator();
|
||||
if (!it.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MDQualifier qual = it.next();
|
||||
DemangledType type = new DemangledType(qual.toString());
|
||||
DemangledType parentType = type;
|
||||
while (it.hasNext()) {
|
||||
qual = it.next();
|
||||
DemangledType newType = new DemangledType(qual.toString());
|
||||
if (qual.isNested()) {
|
||||
newType.setMangledString(qual.getNested().getMangled());
|
||||
}
|
||||
parentType.setNamespace(newType);
|
||||
parentType = newType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MDParsableItem demangle(String mangledArg, boolean demangleOnlyKnownPatterns)
|
||||
throws MDException {
|
||||
@@ -83,16 +61,47 @@ public class MDMangGhidra extends MDMang {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
this.mangledSource = mangledArg;
|
||||
|
||||
MDParsableItem returnedItem = super.demangle(mangledArg, true);
|
||||
|
||||
this.demangledSource = item.toString();
|
||||
|
||||
objectResult = processItem();
|
||||
if (objectResult != null) {
|
||||
objectResult.setMangledString(mangledArg);
|
||||
// Make our version of the demangled string available (could be large).
|
||||
objectResult.setOriginalDemangled(item.toString());
|
||||
}
|
||||
return returnedItem;
|
||||
}
|
||||
|
||||
public DemangledType processNamespace(MDQualifiedName qualifiedName) {
|
||||
return processNamespace(qualifiedName.getQualification());
|
||||
}
|
||||
|
||||
private DemangledType processNamespace(MDQualification qualification) {
|
||||
Iterator<MDQualifier> it = qualification.iterator();
|
||||
if (!it.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MDQualifier qual = it.next();
|
||||
DemangledType type = new DemangledType(mangledSource, demangledSource, qual.toString());
|
||||
DemangledType parentType = type;
|
||||
while (it.hasNext()) {
|
||||
qual = it.next();
|
||||
DemangledType newType;
|
||||
if (qual.isNested()) {
|
||||
String subMangled = qual.getNested().getMangled();
|
||||
newType = new DemangledType(subMangled, demangledSource, qual.toString());
|
||||
}
|
||||
else {
|
||||
newType =
|
||||
new DemangledType(mangledSource, demangledSource, qual.toString());
|
||||
}
|
||||
parentType.setNamespace(newType);
|
||||
parentType = newType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private DemangledObject processItem() {
|
||||
objectResult = null;
|
||||
if (item instanceof MDObjectReserved) {
|
||||
@@ -137,7 +146,7 @@ public class MDMangGhidra extends MDMang {
|
||||
}
|
||||
//TODO: put other objectReserved derivative types here and return something that Ghidra can use.
|
||||
else {
|
||||
object = new DemangledUnknown();
|
||||
object = new DemangledUnknown(mangledSource, demangledSource, null);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
@@ -175,10 +184,10 @@ public class MDMangGhidra extends MDMang {
|
||||
MDType mdtype = variableInfo.getMDType();
|
||||
DemangledDataType dt = processDataType(null, (MDDataType) mdtype);
|
||||
if ("std::nullptr_t".equals(dt.getName())) {
|
||||
variable = new DemangledVariable("");
|
||||
variable = new DemangledVariable(mangledSource, demangledSource, "");
|
||||
}
|
||||
else {
|
||||
variable = new DemangledVariable(
|
||||
variable = new DemangledVariable(mangledSource, demangledSource,
|
||||
objectCPP.getName());
|
||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
}
|
||||
@@ -200,7 +209,7 @@ public class MDMangGhidra extends MDMang {
|
||||
}
|
||||
else if (typeinfo instanceof MDFunctionInfo) {
|
||||
DemangledFunction function =
|
||||
new DemangledFunction(objectCPP.getName());
|
||||
new DemangledFunction(mangledSource, demangledSource, objectCPP.getName());
|
||||
function.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
resultObject = function;
|
||||
objectResult = processFunction((MDFunctionInfo) typeinfo, function);
|
||||
@@ -229,7 +238,7 @@ public class MDMangGhidra extends MDMang {
|
||||
else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
|
||||
MDVxTable vxtable = (MDVxTable) typeinfo;
|
||||
DemangledVariable variable =
|
||||
new DemangledVariable(objectCPP.getName());
|
||||
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
variable.setConst(vxtable.isConst());
|
||||
variable.setVolatile(vxtable.isVolatile());
|
||||
@@ -241,7 +250,7 @@ public class MDMangGhidra extends MDMang {
|
||||
}
|
||||
else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
|
||||
DemangledVariable variable =
|
||||
new DemangledVariable(objectCPP.getName());
|
||||
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
resultObject = variable;
|
||||
// The following code would be an alternative, depending on whether we get
|
||||
@@ -250,7 +259,7 @@ public class MDMangGhidra extends MDMang {
|
||||
}
|
||||
else if (typeinfo instanceof MDGuard) {
|
||||
DemangledVariable variable =
|
||||
new DemangledVariable(objectCPP.getName());
|
||||
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
resultObject = variable;
|
||||
// The following code would be an alternative, depending on whether we get
|
||||
@@ -260,7 +269,7 @@ public class MDMangGhidra extends MDMang {
|
||||
else {
|
||||
// Any others (e.g., case '9')
|
||||
DemangledVariable variable =
|
||||
new DemangledVariable(objectCPP.getName());
|
||||
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
resultObject = variable;
|
||||
// The following code would be an alternative, depending on whether we get
|
||||
@@ -287,13 +296,14 @@ public class MDMangGhidra extends MDMang {
|
||||
String baseName = objectCPP.getName();
|
||||
if (objectCPP.isString()) {
|
||||
MDString mstring = objectCPP.getMDString();
|
||||
DemangledString demangledString = new DemangledString(mstring.getName(),
|
||||
mstring.toString(), mstring.getLength(), mstring.isUnicode());
|
||||
DemangledString demangledString =
|
||||
new DemangledString(mangledSource, demangledSource, mstring.getName(),
|
||||
mstring.toString(), mstring.getLength(), mstring.isUnicode());
|
||||
resultObject = demangledString;
|
||||
}
|
||||
else if (baseName.length() != 0) {
|
||||
DemangledVariable variable;
|
||||
variable = new DemangledVariable(baseName);
|
||||
variable = new DemangledVariable(mangledSource, demangledSource, baseName);
|
||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||
resultObject = variable;
|
||||
}
|
||||
@@ -314,7 +324,8 @@ public class MDMangGhidra extends MDMang {
|
||||
// doesn't match
|
||||
// well to the current DemangledObject hierarchy.
|
||||
private DemangledVariable processTemplate(MDTemplateNameAndArguments template) {
|
||||
DemangledVariable variable = new DemangledVariable(template.toString());
|
||||
DemangledVariable variable =
|
||||
new DemangledVariable(mangledSource, demangledSource, template.toString());
|
||||
// NO NAMESPACE for high level template: variable.setNamespace(XXX);
|
||||
// DemangledTemplate objectTemplate = new DemangledTemplate();
|
||||
// DemangledDataType dataType = new DemangledDataType((String) null);
|
||||
@@ -397,7 +408,8 @@ public class MDMangGhidra extends MDMang {
|
||||
}
|
||||
|
||||
private DemangledFunctionPointer processDemangledFunctionPointer(MDPointerType pointerType) {
|
||||
DemangledFunctionPointer functionPointer = new DemangledFunctionPointer();
|
||||
DemangledFunctionPointer functionPointer =
|
||||
new DemangledFunctionPointer(mangledSource, demangledSource);
|
||||
MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
|
||||
functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
|
||||
functionPointer.setModifier(pointerType.getCVMod().toString());
|
||||
@@ -432,7 +444,8 @@ public class MDMangGhidra extends MDMang {
|
||||
if (!((refType instanceof MDReferenceType) || (refType instanceof MDDataRefRefType))) {
|
||||
return null; // Not planning on anything else yet.
|
||||
}
|
||||
DemangledFunctionReference functionReference = new DemangledFunctionReference();
|
||||
DemangledFunctionReference functionReference =
|
||||
new DemangledFunctionReference(mangledSource, demangledSource);
|
||||
MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
|
||||
functionReference.setCallingConvention(functionType.getCallingConvention().toString());
|
||||
functionReference.setModifier(refType.getCVMod().toString());
|
||||
@@ -447,7 +460,8 @@ public class MDMangGhidra extends MDMang {
|
||||
|
||||
private DemangledFunctionIndirect processDemangledFunctionIndirect(
|
||||
MDFunctionIndirectType functionIndirectType) {
|
||||
DemangledFunctionIndirect functionDefinition = new DemangledFunctionIndirect();
|
||||
DemangledFunctionIndirect functionDefinition =
|
||||
new DemangledFunctionIndirect(mangledSource, demangledSource);
|
||||
MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
|
||||
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
|
||||
functionDefinition.setModifier(functionIndirectType.getCVMod().toString());
|
||||
@@ -466,7 +480,8 @@ public class MDMangGhidra extends MDMang {
|
||||
// indirect might be clouded between the real, two underlying types.
|
||||
private DemangledFunctionIndirect processDemangledFunctionQuestion(
|
||||
MDModifierType modifierType) {
|
||||
DemangledFunctionIndirect functionDefinition = new DemangledFunctionIndirect();
|
||||
DemangledFunctionIndirect functionDefinition =
|
||||
new DemangledFunctionIndirect(mangledSource, demangledSource);
|
||||
MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
|
||||
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
|
||||
functionDefinition.setModifier(modifierType.getCVMod().toString());
|
||||
@@ -488,7 +503,8 @@ public class MDMangGhidra extends MDMang {
|
||||
private DemangledDataType processDataType(DemangledDataType resultDataType,
|
||||
MDDataType datatype) {
|
||||
if (resultDataType == null) {
|
||||
resultDataType = new DemangledDataType(datatype.getTypeName());
|
||||
resultDataType =
|
||||
new DemangledDataType(mangledSource, demangledSource, datatype.getTypeName());
|
||||
}
|
||||
if (datatype.isSpecifiedSigned()) {
|
||||
// Returns true if default signed or specified signed. TODO: There is no place to
|
||||
|
||||
+10
-8
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package mdemangler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import mdemangler.datatype.MDDataType;
|
||||
|
||||
@@ -65,7 +67,7 @@ public class MDBaseTestConfiguration {
|
||||
* @param mstruth Truth that was output from one of the Microsoft tools (e.g., undname).
|
||||
* @param ghtruth Truth that we would like to see for Ghidra version of the tool.
|
||||
* @param ms2013truth Like mstruth, but from Visual Studio 2013 version of tool.
|
||||
* @throws Exception
|
||||
* @throws Exception if any exceptions are thrown
|
||||
*/
|
||||
public void demangleAndTest(String mangledArg, String mdtruth, String mstruth, String ghtruth,
|
||||
String ms2013truth) throws Exception {
|
||||
@@ -105,24 +107,24 @@ public class MDBaseTestConfiguration {
|
||||
// expect to be able to demangle the input (truth not equal to mangleArg), then we
|
||||
// expect the output to be that which we desire ("truth".equals(demangled)).
|
||||
if ((truth.equals(mangledArg)) && isMangled(mangledArg)) {
|
||||
assert (demangled.isEmpty());
|
||||
assertTrue(demangled.isEmpty());
|
||||
}
|
||||
else {
|
||||
assert(truth.equals(demangled));
|
||||
assertEquals(truth, demangled);
|
||||
}
|
||||
if (mangledArg.startsWith(".?A")) {
|
||||
assert ((demangItem != null) && (demangItem instanceof MDDataType)); // Test for data type.
|
||||
assertTrue((demangItem != null) && (demangItem instanceof MDDataType)); // Test for data type.
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMangled(String mangled) {
|
||||
if (mangled.charAt(0) == '?') {
|
||||
private boolean isMangled(String s) {
|
||||
if (s.charAt(0) == '?') {
|
||||
return true;
|
||||
}
|
||||
else if (mangled.startsWith("__")) {
|
||||
else if (s.startsWith("__")) {
|
||||
return true;
|
||||
}
|
||||
else if ((mangled.charAt(0) == '_') || Character.isUpperCase(mangled.charAt(1))) {
|
||||
else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
+46
-1
@@ -243,6 +243,50 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
assertEquals("ATL", ns.getName(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionThisPointer() throws Exception {
|
||||
|
||||
//
|
||||
// Test a function within a class that has a 'this' pointer
|
||||
//
|
||||
|
||||
String mangled =
|
||||
"??$?0V?$A@_NABW4B@C@@@D@E@@@?$F@V?$G@U?$H@Q6A_NABW4B@C@@@Z$0A@@D@E@@_NABW4B@C@@@D@E@@@E@@QAE@ABV?$F@V?$A@_NABW4B@C@@@D@E@@@1@@Z";
|
||||
Address addr = addr("0x0101");
|
||||
|
||||
SymbolTable symbolTable = program.getSymbolTable();
|
||||
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
|
||||
|
||||
DemangledObject demangled = DemanglerUtil.demangle(mangled);
|
||||
assertTrue(demangled instanceof DemangledFunction);
|
||||
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
|
||||
|
||||
String className =
|
||||
"F<class_E::D::G<struct_E::D::H<bool_(__cdecl*const)(enum_C::B_const&),0>,bool,enum_C::B_const&>_>";
|
||||
String functionName =
|
||||
className + "<class_E::D::A<bool,enum_C::B_const&>_>";
|
||||
|
||||
Function function = assertFunction(functionName, addr);
|
||||
assertNoBookmarkAt(addr);
|
||||
|
||||
Symbol[] symbols = symbolTable.getSymbols(addr);
|
||||
assertEquals(2, symbols.length);
|
||||
assertEquals(functionName, symbols[0].getName());
|
||||
assertEquals(mangled, symbols[1].getName());
|
||||
|
||||
// Check for the Class 'this' pointer
|
||||
Parameter[] parameters = function.getParameters();
|
||||
assertEquals(2, parameters.length);
|
||||
Parameter p1 = parameters[0];
|
||||
assertEquals("this", p1.getName());
|
||||
assertEquals(className + " *", p1.getDataType().toString());
|
||||
|
||||
Namespace ns = symbols[0].getParentNamespace();
|
||||
assertEquals(className, ns.getName(false));
|
||||
ns = ns.getParentNamespace();
|
||||
assertEquals("E", ns.getName(false));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the DemangledFunction will properly create a cascade of namespaces for
|
||||
* functions that live inside of a class that lives inside of a namespace.
|
||||
@@ -343,11 +387,12 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
assertEquals(SymbolType.NAMESPACE, ns.getSymbol().getSymbolType());
|
||||
}
|
||||
|
||||
private void assertFunction(String name, Address addr) {
|
||||
private Function assertFunction(String name, Address addr) {
|
||||
FunctionManager fm = program.getFunctionManager();
|
||||
Function function = fm.getFunctionAt(addr);
|
||||
assertNotNull("Expected function to get created at " + addr, function);
|
||||
assertEquals(name, function.getName());
|
||||
return function;
|
||||
}
|
||||
|
||||
private Address addr(String addr) {
|
||||
|
||||
Reference in New Issue
Block a user