GT-3545 - GNU Demangler - Fix Parsing Issues - review fixes; bug fixes

This commit is contained in:
dragonmacher
2020-03-11 15:13:05 -04:00
parent 11619169b4
commit cb234b09a9
24 changed files with 1528 additions and 1401 deletions
@@ -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 '--'.
*
@@ -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
@@ -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);
}
@@ -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;
}
}
@@ -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 "*";
}
}
@@ -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);
}
@@ -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;
}
@@ -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 + "; " +
@@ -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);
@@ -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
@@ -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;
@@ -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) {