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

View File

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

View File

@ -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 '--'.
*

View File

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

View File

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

View File

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

View File

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

View File

@ -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 "*";
}
}

View File

@ -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 "&";
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.symbol.Namespace;
import ghidra.util.StringUtilities;
public class GnuDemanglerParser {
@ -46,67 +47,85 @@ public class GnuDemanglerParser {
TYPEINFO_FN_FOR,
TYPEINFO_FOR);
private static final String NAMESPACE_DELIMITER = "::";
private static final String OPERATOR = "operator";
private static final String LAMBDA = "lambda";
private static final String VAR_ARGS = "...";
private static final String THUNK = "thunk";
private static final String CONST = " const";
private static final char NULL_CHAR = '\u0000';
/**
* <pre>
* Syntax: bob((Rect &, unsigned long))
/*
* Sample: bob((Rect &, unsigned long))
* bob(const(Rect &, bool))
*
* pattern: optional spaces followed by '()' with a capture group for the contents of the
* parens
* note: this pattern is used for matching the arguments string, in the above example it
* would be: (Rect &, unsigned long)
* Pattern: name(([const] [params]))
*
* Parts: -optional spaces
* -optional (const) (non-capture group)
* -followed by '()' with optinal parameter text (capture group 1)
*
* Also matches: bob(const(Rect &, bool))
* </pre>
* Note: this pattern is used for matching the arguments string, in the above examples it
* would be:
* Rect &, unsigned long
* and
* Rect &, bool
*
*/
private static final Pattern UNNECESSARY_PARENS_PATTERN =
Pattern.compile("\\s*(const){0,1}\\((.*)\\)\\s*");
Pattern.compile("\\s*(?:const){0,1}\\((.*)\\)\\s*");
/**
* <pre>
* Syntax: bob(short (&)[7])
/*
* Sample: bob(short (&)[7])
* bob(int const[8] (*) [12])
*
* typename[optional '*']<space>(*|&)[optional spaces][optional value]
* Pattern: name[optional '*']<space>(*|&)[optional spaces][optional value]
*
* pattern:
* -a word
* Parts:
* -a word (capture group 1)
* -followed by an optional pointer '*'
* -followed by a space
* -*optional: any other text (e.g., const[8])
* -followed by '()' that contain a '&' or a '*'
* -followed by one or more '[]' with optional interior text
* </pre>
* -*optional: any other text (e.g., const[8]) (non-capture group)
* -followed by '()' that contain a '&' or a '*' (capture group 2)
* -followed by one or more '[]' with optional interior text (capture group 3)
*
* Group Samples:
* short (&)[7]
* 1 short
* 2 &
* 3 [7]
*
* CanRxItem (&) [2][64u]
* 1 CanRxItem
* 2 &
* 3 [2][64u]
*
*/
private static final Pattern ARRAY_POINTER_REFERENCE_PATTERN =
Pattern.compile("([\\w:]+)\\*?\\s(.*)\\(([&*])\\)\\s*((?:\\[.*?\\])+)");
Pattern.compile("([\\w:]+)\\*?\\s(?:.*)\\(([&*])\\)\\s*((?:\\[.*?\\])+)");
/**
* <pre>
* Syntax: bob(short (&)[7])
/*
* Sample: bob(short (&)[7])
*
* (*|&)[optional spaces][optional value]
* Pattern: (*|&)[optional spaces][optional value]
*
* pattern: '()' that contain a '&' or a '*' followed by '[]' with optional text; a capture
* group for the contents of the parens
* Parts:
* -'()' that contain a '&' or a '*'
* -followed by '[]' with optional text
* </pre>
*/
private static final Pattern ARRAY_POINTER_REFERENCE_PIECE_PATTERN =
Pattern.compile("\\(([&*])\\)\\s*\\[.*?\\]");
Pattern.compile("\\([&*]\\)\\s*\\[.*?\\]");
/**
* <pre>
* Syntax: (unsigned)4294967295
/*
* Sample: (unsigned)4294967295
*
* (some text)[optional space]1 or more characters
* Pattern: (some text)[optional space]1 or more characters
*
* Regex:
*
* pattern:
* Parts:
* -parens containing text
* --the text can have "::" namespace separators (this is in a non-capturing group) and
* must be followed by more text
* --the text can have multiple words, such as (unsigned long)
* --the text can have "::" namespace separators (non-capturing group) and
* must be followed by more text
* --the text can have multiple words, such as (unsigned long)
* -optional space
* -optional '-' character (a negative sign character)
* -followed by more text (with optional spaces)
@ -115,91 +134,91 @@ public class GnuDemanglerParser {
private static final Pattern CAST_PATTERN =
Pattern.compile("\\((?:\\w+\\s)*\\w+(?:::\\w+)*\\)\\s*-{0,1}\\w+");
private static final String OPERATOR = "operator";
/**
* <pre>
* Syntax:
* Magick::operator<(Magick::Coordinate const&, Magick::Coordinate const&)
* std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&)
*
* [return_type] operator opeartor_character(s) (opeartor_params)
/*
* Sample: Magick::operator<(Magick::Coordinate const&, Magick::Coordinate const&)
* std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&)
* bool myContainer<int>::operator<< <double>(double)
*
* Pattern: [return_type] operator operator_character(s) (opeartor_params) [trailing text]
*
* Regex:
*
* pattern:
* -maybe a return type
* -operator
* -operator character(s)
* -parameters
* </pre>
*
*
* Parts:
* -optional a return type (capture group 1)
* -operator (capture group 2)
* -operator character(s) (capture group 3)
* -optional space
* -optional templates (capture group 4)
* -parameters (capture group 5)
* -trailing text (capture group 6)
*
* Note: this regex is generated from all known operator patterns and looks like:
* (.*operator(generated_text).*)\s*(\(.*\))(.*)
*/
private static final Pattern OVERLOAD_OPERATOR_PATTERN =
createOverloadedOperatorPattern();
/**
* <pre>
* Syntax: std::integral_constant<bool, false>::operator bool() const
* Magick::Color::operator std::basic_string<char, std::char_traits<char>, std::allocator<char> >() const
/*
* Sample: std::integral_constant<bool, false>::operator bool() const
* Magick::Color::operator std::basic_string<char, std::char_traits<char>, std::allocator<char> >() const
*
* pattern:
* -operator
* Pattern: operator type() [trailing text]
*
* Parts:
* -operator (capture group 1)
* -space
* -keyword for cast type
* -keyword for cast type (capture group 2)
* -optional keywords
*
* </pre>
*/
private static final Pattern CONVERSION_OPERATOR_PATTERN =
Pattern.compile("(.*" + OPERATOR + ") (.*)\\(\\).*");
/**
* <pre>
* Syntax: operator new(unsigned long)
* operator new(void*)
* operator new[](void*)
/*
* Sample: operator new(unsigned long)
* operator new(void*)
* operator new[](void*)
*
* pattern:
* -operator
* Pattern: operator new|delete[] ([parameters]) [trailing text]
*
* Parts:
* -operator (capture group 1)
* -space
* -keyword 'new' or 'delete'
* -optional array brackets
* -optional parameters
* -keyword 'new' or 'delete' (capture group 2)
* -optional array brackets (capture group 3)
* -optional parameters (capture group 4)
*
* </pre>
*/
private static final Pattern NEW_DELETE_OPERATOR_PATTERN =
Pattern.compile("(.*" + OPERATOR + ") (new|delete)(\\[\\])?\\((.*)\\).*");
private static final String LAMBDA = "lambda";
/**
/*
* Pattern for newer C++ lambda syntax:
*
* <pre>
* {lambda(void const*, unsigned int)#1}
* Sample: {lambda(void const*, unsigned int)#1}
*
* 1 - full text
* 2 - params
* 3 - trailing id
* </pre>
* Pattern: [optional text] brace lambda([parameters])#digits brace
*
* Parts:
* -full text without leading characters (capture group 1)
* -parameters of the lambda function (capture group 2)
* -trailing id (capture group 3)
*/
private static final Pattern LAMBDA_PATTERN =
Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})");
/**
* The c 'decltype' keyword pattern
*/
private static final Pattern DECLTYPE_RETURN_TYPE_PATTERN =
Pattern.compile("decltype \\(.*\\)");
// note: the '?' after the .* this is there to allow the trailing digits to match as many as
// possible
private static final Pattern ENDS_WITH_DIGITS_PATTERN = Pattern.compile("(.*?)\\d+");
/**
/*
* Sample: covariant return thunk to Foo::Bar::copy(Foo::CoolStructure*) const
*
* Pattern: text for|to text
*
* Parts:
* -required text (capture group 2)
* -a space
* -'for' or 'to' (capture group 3)
* -a space
* -optional text (capture group 4)
*
* Note: capture group 1 is the combination of groups 2 and 3
*
* Examples:
* construction vtable for
* vtable for
@ -211,12 +230,21 @@ public class GnuDemanglerParser {
* non-virtual thunk to
*/
private static final Pattern DESCRIPTIVE_PREFIX_PATTERN =
Pattern.compile("((.+ )+(for|to) )(.*)");
Pattern.compile("((.+ )+(for|to) )(.+)");
private static final char NULL_CHAR = '\u0000';
private static final String VAR_ARGS = "...";
private static final String THUNK = "thunk";
private static final String CONST_KEYWORD = " const";
/**
* The c 'decltype' keyword pattern
*/
private static final Pattern DECLTYPE_RETURN_TYPE_PATTERN =
Pattern.compile("decltype \\(.*\\)");
/**
* Simple pattern to match any text that is trailed by digits
*
* note: the '?' after the .* this is there to allow the trailing digits to match as many as
* possible
*/
private static final Pattern ENDS_WITH_DIGITS_PATTERN = Pattern.compile("(.*?)\\d+");
private static Pattern createOverloadedOperatorPattern() {
@ -228,16 +256,27 @@ public class GnuDemanglerParser {
"&", "|", ">>", "<<", "~", "^",
"&&", "||", "!",
"=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", ">>=", "<<=",
",", "()"
",", "()",
"\"\""
));
//@formatter:on
CollectionUtils.transform(operators, Pattern::quote);
String alternated = StringUtils.join(operators, "|");
return Pattern.compile("(.*" + OPERATOR + "(" + alternated + ").*)\\s*(\\(.*\\))(.*)");
String returnType = "(.* ){0,1}";
String operatorTemplates = "(<.+>){0,1}";
String operatorPrefix =
"(.*" + OPERATOR + "(" + alternated + ")\\s*" + operatorTemplates + ".*)\\s*";
String parameters = "(\\(.*\\))";
String trailing = "(.*)";
return Pattern.compile(returnType + operatorPrefix + parameters + trailing);
}
private String mangledSource;
private String demangledSource;
/**
* Parses the given demangled string and creates a {@link DemangledObject}
*
@ -249,44 +288,45 @@ public class GnuDemanglerParser {
public DemangledObject parse(String mangled, String demangled)
throws DemanglerParseException {
OperatorHandler operatorHandler = getOperatorHandler(demangled);
this.mangledSource = mangled;
this.demangledSource = demangled;
DemangledObjectBuilder builder = getSpecializedBuilder(demangled);
if (builder != null) {
return builder.build();
}
return parseFunctionOrVariable(demangled);
}
private DemangledObjectBuilder getSpecializedBuilder(String demangled) {
DemangledObjectBuilder operatorHandler = getOperatorHandler(demangled);
if (operatorHandler != null) {
DemangledObject dobj = operatorHandler.build();
dobj.setMangledString(mangled);
dobj.setOriginalDemangled(demangled);
return dobj;
return operatorHandler;
}
SpecialPrefixHandler handler = getSpecialPrefixHandler(mangled, demangled);
DemangledObjectBuilder handler = getSpecialPrefixHandler(mangledSource, demangled);
if (handler != null) {
String type = handler.getType();
DemangledObject dobj = doParse(type);
DemangledObject specialPrefixDobj = handler.build(dobj);
specialPrefixDobj.setMangledString(mangled);
specialPrefixDobj.setOriginalDemangled(demangled);
return specialPrefixDobj;
return handler;
}
DemangledObject dobj = doParse(demangled);
dobj.setMangledString(mangled);
dobj.setOriginalDemangled(demangled);
return dobj;
return null;
}
private OperatorHandler getOperatorHandler(String demangled) {
OperatorHandler handler = new OverloadOperatorHandler();
OperatorHandler handler = new OverloadOperatorHandler(demangled);
if (handler.matches(demangled)) {
return handler;
}
handler = new ConversionOperatorHandler();
handler = new ConversionOperatorHandler(demangled);
if (handler.matches(demangled)) {
return handler;
}
handler = new NewOrDeleteOperatorHandler();
handler = new NewOrDeleteOperatorHandler(demangled);
if (handler.matches(demangled)) {
return handler;
}
@ -321,7 +361,7 @@ public class GnuDemanglerParser {
return null;
}
private DemangledObject doParse(String demangled) {
private DemangledObject parseFunctionOrVariable(String demangled) {
ParameterLocator paramLocator = new ParameterLocator(demangled);
if (!paramLocator.hasParameters()) {
@ -341,20 +381,21 @@ public class GnuDemanglerParser {
int nameStart = Math.max(0, prefix.lastIndexOf(' '));
String name = prefix.substring(nameStart, prefix.length()).trim();
DemangledFunction function = new DemangledFunction(null);
DemangledFunction function = new DemangledFunction(mangledSource, demangled, null);
String simpleName = name;
LambdaName lambdaName = getLambdaName(demangled);
if (lambdaName != null) {
String uniqueName = lambdaName.getFullText();
String fullLambda = fixupInternalSeparators(uniqueName);
simpleName = name.replace("{lambda", fullLambda);
function = new DemangledLambda(null);
function = new DemangledLambda(mangledSource, demangled, null);
function.setSignature(lambdaName.getFullText());
}
// For GNU, we cannot leave the return type as null, because the DemangleCmd will fill in
// pointer to the class to accommodate windows demangling
function.setReturnType(new DemangledDataType("undefined"));
function.setReturnType(new DemangledDataType(mangledSource, demangled, "undefined"));
for (DemangledDataType parameter : parameters) {
function.addParameter(parameter);
}
@ -367,7 +408,7 @@ public class GnuDemanglerParser {
setReturnType(function, returnType);
}
if (demangled.endsWith(CONST_KEYWORD)) {
if (demangled.endsWith(CONST)) {
function.setConst(true);
}
@ -420,16 +461,16 @@ public class GnuDemanglerParser {
private DemangledObject parseItemInNamespace(String itemText) {
int pos = itemText.lastIndexOf(NAMESPACE_DELIMITER);
int pos = itemText.lastIndexOf(Namespace.DELIMITER);
if (pos == -1) {
throw new DemanglerParseException(
"Expected the demangled string to contain a namespace");
}
String parentText = itemText.substring(0, pos);
DemangledObject parent = doParse(parentText);
DemangledObject parent = parseFunctionOrVariable(parentText);
String name = itemText.substring(pos + 2);
DemangledObject item = doParse(name);
DemangledObject item = parseFunctionOrVariable(name);
item.setNamespace(parent);
return item;
}
@ -501,7 +542,7 @@ public class GnuDemanglerParser {
// when demangling functions that have const at the end, such as bob(param1, param2) const;
Matcher matcher = UNNECESSARY_PARENS_PATTERN.matcher(parameterString);
if (matcher.matches()) {
parameterString = matcher.group(2);
parameterString = matcher.group(1);
}
if (StringUtils.isBlank(parameterString)) {
@ -629,8 +670,7 @@ public class GnuDemanglerParser {
// special case: template parameter with a cast (just make the datatype
// be the name of the template parameter, since it will just be a display
// attribute for the templated type)
String value = castMatcher.group(0);// group 0 is the entire match
return new DemangledDataType(value);
return new DemangledDataType(mangledSource, demangledSource, fullDatatype);
}
DemangledDataType ddt = createTypeInNamespace(fullDatatype);
@ -660,7 +700,6 @@ public class GnuDemanglerParser {
}
if (ch == '<') {//start of template
int contentStart = i + 1;
// int templateEnd = getTemplateEndIndex(datatype, contentStart);
int templateEnd = findTemplateEnd(datatype, i);
if (templateEnd == -1 || templateEnd > datatype.length()) {
throw new DemanglerParseException("Did not find ending to template");
@ -684,7 +723,7 @@ public class GnuDemanglerParser {
if (arrayMatcher.matches()) {
Demangled namespace = ddt.getNamespace();
String name = arrayMatcher.group(1);// group 0 is the entire string
ddt = parseArrayPointerOrReference(datatype, name);
ddt = parseArrayPointerOrReference(datatype, name, arrayMatcher);
ddt.setNamespace(namespace);
i = arrayMatcher.end();
}
@ -878,7 +917,7 @@ public class GnuDemanglerParser {
}
String datatypeName = names.get(names.size() - 1);
DemangledDataType ddt = new DemangledDataType(datatypeName);
DemangledDataType ddt = new DemangledDataType(mangledSource, demangledSource, datatypeName);
ddt.setName(datatypeName);
ddt.setNamespace(namespace);
return ddt;
@ -907,8 +946,14 @@ public class GnuDemanglerParser {
object.setNamespace(convertToNamespaces(names));
}
private DemangledTemplate parseTemplate(String templateStr) {
List<DemangledDataType> parameters = parseParameters(templateStr);
private DemangledTemplate parseTemplate(String string) {
String contents = string;
if (string.startsWith("<") && string.endsWith(">")) {
contents = string.substring(1, string.length() - 1);
}
List<DemangledDataType> parameters = parseParameters(contents);
DemangledTemplate template = new DemangledTemplate();
for (DemangledDataType parameter : parameters) {
template.addParameter(parameter);
@ -916,14 +961,13 @@ public class GnuDemanglerParser {
return template;
}
private DemangledDataType parseArrayPointerOrReference(String datatype, String name) {
private DemangledDataType parseArrayPointerOrReference(String datatype, String name,
Matcher matcher) {
// int (*)[8]
// char (&)[7]
DemangledDataType ddt = new DemangledDataType(name);
Matcher matcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(datatype);
matcher.find();
String type = matcher.group(3);
DemangledDataType ddt = new DemangledDataType(mangledSource, demangledSource, name);
String type = matcher.group(2);
if (type.equals("*")) {
ddt.incrementPointerLevels();
}
@ -934,7 +978,7 @@ public class GnuDemanglerParser {
throw new DemanglerParseException("Unexpected charater inside of parens: " + type);
}
String arraySubscripts = matcher.group(4);
String arraySubscripts = matcher.group(3);
int n = StringUtilities.countOccurrences(arraySubscripts, '[');
ddt.setArray(n);
@ -976,7 +1020,7 @@ public class GnuDemanglerParser {
List<DemangledDataType> parameters = parseParameters(paramerterString);
DemangledFunctionPointer dfp = new DemangledFunctionPointer();
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
dfp.setReturnType(parseDataType(returnType));
for (DemangledDataType parameter : parameters) {
dfp.addParameter(parameter);
@ -994,7 +1038,8 @@ public class GnuDemanglerParser {
*/
String nameString = fixupInternalSeparators(demangled).trim();
DemangledVariable variable = new DemangledVariable((String) null);
DemangledVariable variable =
new DemangledVariable(mangledSource, demangledSource, (String) null);
setNameAndNamespace(variable, nameString);
return variable;
}
@ -1018,15 +1063,14 @@ public class GnuDemanglerParser {
int index = names.size() - 1;
String rawName = names.get(index);
String escapedName = fixupInternalSeparators(rawName);
DemangledType myNamespace = new DemangledType(escapedName);
myNamespace.setOriginalDemangled(rawName);
DemangledType myNamespace = new DemangledType(mangledSource, demangledSource, escapedName);
DemangledType namespace = myNamespace;
while (--index >= 0) {
rawName = names.get(index);
escapedName = fixupInternalSeparators(rawName);
DemangledType parentNamespace = new DemangledType(escapedName);
myNamespace.setOriginalDemangled(rawName);
DemangledType parentNamespace =
new DemangledType(mangledSource, demangledSource, escapedName);
namespace.setNamespace(parentNamespace);
namespace = parentNamespace;
}
@ -1037,16 +1081,48 @@ public class GnuDemanglerParser {
// Inner Classes
//==================================================================================================
private abstract class SpecialPrefixHandler {
private abstract class DemangledObjectBuilder {
protected String demangled;
DemangledObjectBuilder(String demangled) {
this.demangled = demangled;
}
abstract DemangledObject build();
}
private abstract class OperatorHandler extends DemangledObjectBuilder {
protected Matcher matcher;
OperatorHandler(String demangled) {
super(demangled);
}
abstract boolean matches(String s);
}
private abstract class SpecialPrefixHandler extends DemangledObjectBuilder {
protected String prefix;
protected String name;
protected String type;
abstract String getType();
SpecialPrefixHandler(String demangled) {
super(demangled);
}
abstract DemangledObject build(Demangled namespace);
@Override
DemangledObject build() {
DemangledObject dobj = parseFunctionOrVariable(type);
return doBuild(dobj);
}
abstract DemangledObject doBuild(Demangled namespace);
@Override
public String toString() {
@ -1063,23 +1139,20 @@ public class GnuDemanglerParser {
private class ItemInNamespaceHandler extends SpecialPrefixHandler {
ItemInNamespaceHandler(String demangled) {
super(demangled);
this.demangled = demangled;
this.type = demangled;
}
ItemInNamespaceHandler(String demangled, String prefix, String item) {
super(demangled);
this.demangled = demangled;
this.prefix = prefix;
this.type = item;
}
@Override
String getType() {
return type;
}
@Override
DemangledObject build(Demangled namespace) {
DemangledObject doBuild(Demangled namespace) {
DemangledObject demangledObject = parseItemInNamespace(type);
return demangledObject;
}
@ -1088,24 +1161,20 @@ public class GnuDemanglerParser {
private class ThunkHandler extends SpecialPrefixHandler {
ThunkHandler(String demangled, String prefix, String item) {
super(demangled);
this.demangled = demangled;
this.prefix = prefix;
this.type = item;
}
@Override
String getType() {
return type;
}
@Override
DemangledObject build(Demangled demangledObject) {
DemangledObject doBuild(Demangled demangledObject) {
DemangledFunction function = (DemangledFunction) demangledObject;
function.setSignature(type);
function.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
DemangledThunk thunk = new DemangledThunk(function);
DemangledThunk thunk = new DemangledThunk(mangledSource, demangledSource, function);
if (prefix.contains(COVARIANT_RETURN_THUNK)) {
thunk.setCovariantReturnThunk();
}
@ -1118,21 +1187,19 @@ public class GnuDemanglerParser {
private class TypeInfoNameHandler extends SpecialPrefixHandler {
TypeInfoNameHandler(String demangled, String prefix) {
super(demangled);
this.demangled = demangled;
this.prefix = prefix;
}
@Override
String getType() {
String classname = demangled.substring(prefix.length()).trim();
type = classname;
return type;
this.type = classname;
}
@Override
DemangledObject build(Demangled namespace) {
DemangledObject doBuild(Demangled namespace) {
DemangledString demangledString =
new DemangledString("typeinfo-name", type, -1/*unknown length*/, false);
new DemangledString(mangledSource, demangledSource, "typeinfo-name", type,
-1/*unknown length*/, false);
demangledString.setSpecialPrefix("typeinfo name for ");
String namespaceString = fixupInternalSeparators(type);
setNamespace(demangledString, namespaceString);
@ -1143,6 +1210,7 @@ public class GnuDemanglerParser {
private class AddressTableHandler extends SpecialPrefixHandler {
AddressTableHandler(String demangled, String prefix, String type) {
super(demangled);
this.demangled = demangled;
this.prefix = prefix;
this.type = type;
@ -1155,10 +1223,6 @@ public class GnuDemanglerParser {
int delta = oldLength - this.demangled.length();
this.type = type.substring(0, type.length() - delta);
}
}
@Override
String getType() {
/*
Samples:
@ -1176,31 +1240,26 @@ public class GnuDemanglerParser {
*/
int pos = prefix.trim().lastIndexOf(' ');
name = prefix.substring(0, pos).replace(' ', '-');
return type;
}
@Override
DemangledObject build(Demangled namespace) {
DemangledAddressTable addressTable = new DemangledAddressTable(name, true);
DemangledObject doBuild(Demangled namespace) {
DemangledAddressTable addressTable =
new DemangledAddressTable(mangledSource, demangled, name, true);
addressTable.setNamespace(namespace);
return addressTable;
}
}
private abstract class OperatorHandler {
protected Matcher matcher;
abstract boolean matches(String s);
abstract DemangledObject build();
}
private class OverloadOperatorHandler extends OperatorHandler {
OverloadOperatorHandler(String demangled) {
super(demangled);
}
@Override
boolean matches(String demangled) {
matcher = OVERLOAD_OPERATOR_PATTERN.matcher(demangled);
boolean matches(String text) {
matcher = OVERLOAD_OPERATOR_PATTERN.matcher(text);
return matcher.matches();
}
@ -1220,22 +1279,35 @@ public class GnuDemanglerParser {
// prefix: return_type operator operator_chars[templates]
// (everything before the parameters)
String operatorPrefix = matcher.group(1);
//String operatorChars = matcher.group(2);
String parametersText = matcher.group(3);
//String trailing = matcher.group(4);
String returnTypeText = matcher.group(1);
String operatorPrefix = matcher.group(2);
//String operatorChars = matcher.group(3);
String templates = matcher.group(4);
String parametersText = matcher.group(5);
//String trailing = matcher.group(6);
String returnTypeText = "undefined";
String operatorName = operatorPrefix;
operatorPrefix = fixupInternalSeparators(operatorPrefix);
if (returnTypeText == null) {
returnTypeText = "undefined";
}
returnTypeText = fixupInternalSeparators(returnTypeText);
DemangledDataType returnType = createTypeInNamespace(returnTypeText);
DemangledFunction function = new DemangledFunction((String) null);
DemangledFunction function =
new DemangledFunction(mangledSource, demangledSource, (String) null);
function.setOverloadedOperator(true);
function.setReturnType(returnType);
if (!StringUtils.isBlank(templates)) {
int templateIndex = operatorName.lastIndexOf(templates);
operatorName = operatorName.substring(0, templateIndex);
DemangledTemplate demangledTemplate = parseTemplate(templates);
function.setTemplate(demangledTemplate);
}
operatorName = fixupInternalSeparators(operatorName);
setNameAndNamespace(function, operatorName);
@ -1250,9 +1322,13 @@ public class GnuDemanglerParser {
private class ConversionOperatorHandler extends OperatorHandler {
ConversionOperatorHandler(String demangled) {
super(demangled);
}
@Override
boolean matches(String demangled) {
matcher = CONVERSION_OPERATOR_PATTERN.matcher(demangled);
boolean matches(String text) {
matcher = CONVERSION_OPERATOR_PATTERN.matcher(text);
return matcher.matches();
}
@ -1266,13 +1342,14 @@ public class GnuDemanglerParser {
String fullReturnType = matcher.group(2);
boolean isConst = false;
int index = fullReturnType.indexOf(CONST_KEYWORD);
int index = fullReturnType.indexOf(CONST);
if (index != -1) {
fullReturnType = fullReturnType.replace(CONST_KEYWORD, "");
fullReturnType = fullReturnType.replace(CONST, "");
isConst = true;
}
DemangledFunction method = new DemangledFunction((String) null);
DemangledFunction method =
new DemangledFunction(mangledSource, demangledSource, (String) null);
DemangledDataType returnType = parseDataType(fullReturnType);
if (isConst) {
returnType.setConst();
@ -1309,6 +1386,10 @@ public class GnuDemanglerParser {
private class NewOrDeleteOperatorHandler extends OperatorHandler {
NewOrDeleteOperatorHandler(String demangled) {
super(demangled);
}
@Override
boolean matches(String demangler) {
matcher = NEW_DELETE_OPERATOR_PATTERN.matcher(demangler);
@ -1323,9 +1404,11 @@ public class GnuDemanglerParser {
String arrayBrackets = matcher.group(3);
String parametersText = matcher.group(4);
DemangledFunction function = new DemangledFunction((String) null);
DemangledFunction function =
new DemangledFunction(mangledSource, demangledSource, (String) null);
function.setOverloadedOperator(true);
DemangledDataType returnType = new DemangledDataType("void");
DemangledDataType returnType =
new DemangledDataType(mangledSource, demangledSource, "void");
if (operatorName.startsWith("new")) {
returnType.incrementPointerLevels();
}
@ -1392,7 +1475,7 @@ public class GnuDemanglerParser {
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
return builder
.append("texf", text)
.append("text", text)
.append("paramStart", paramStart)
.append("paramEnd", paramEnd)
.toString();

View File

@ -0,0 +1,621 @@
/* ###
* 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 static org.junit.Assert.*;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.gnu.GnuDemanglerParser;
public class GnuDemanglerParser2Test extends AbstractGenericTest {
private GnuDemanglerParser parser = new GnuDemanglerParser();
//@Test
public void test1() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeC1Eii", "OpTestType::OpTestType(int, int)");
String name = object.getName();
assertEquals("", name);
}
//@Test
public void test2() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeC2Eii", "OpTestType::OpTestType(int, int)");
String name = object.getName();
assertEquals("", name);
}
@Test
public void test3() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeclEf", "OpTestType::operator()(float)");
String name = object.getName();
assertEquals("operator()", name);
}
@Test
public void test4() {
DemangledObject object = parser.parse("_ZN10OpTestTypeclEi", "OpTestType::operator()(int)");
String name = object.getName();
assertEquals("operator()", name);
}
//@Test
public void test5() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvN16Names", "_ZN10OpTestTypecvN16Names");
String name = object.getName();
assertEquals("", name);
}
@Test
public void test6() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvPKcEv", "OpTestType::operator char const*()");
String name = object.getName();
assertEquals("operator.cast.to.char*", name);
}
@Test
public void test7() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedaEPv", "OpTestType::operator delete[](void*)");
String name = object.getName();
assertEquals("operator.delete[]", name);
}
@Test
public void test8() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedlEPv", "OpTestType::operator delete(void*)");
String name = object.getName();
assertEquals("operator.delete", name);
}
@Test
public void test9() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemIERKS_", "OpTestType::operator-=(OpTestType const&)");
String name = object.getName();
assertEquals("operator-=", name);
}
@Test
public void test10() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemiERKS_", "OpTestType::operator-(OpTestType const&)");
String name = object.getName();
assertEquals("operator-", name);
}
@Test
public void test11() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEi", "OpTestType::operator--(int)");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void test12() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEv", "OpTestType::operator--()");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void test13() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenaEm", "OpTestType::operator new[](unsigned long)");
String name = object.getName();
assertEquals("operator.new[]", name);
}
@Test
public void test14() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenwEm", "OpTestType::operator new(unsigned long)");
String name = object.getName();
assertEquals("operator.new", name);
}
@Test
public void test15() {
DemangledObject object =
parser.parse("_ZN10OpTestTypepLERKS_", "OpTestType::operator+=(OpTestType const&)");
String name = object.getName();
assertEquals("operator+=", name);
}
@Test
public void test16() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeplERKS_", "OpTestType::operator+(OpTestType const&)");
String name = object.getName();
assertEquals("operator+", name);
}
@Test
public void test17() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEi", "OpTestType::operator++(int)");
String name = object.getName();
assertEquals("operator++", name);
}
@Test
public void test18() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEv", "OpTestType::operator++()");
String name = object.getName();
assertEquals("operator++", name);
}
//--------------------
//TODO: for the following, determine what arguments are needed.
@Test
public void testOperatorNew() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenwEm", "OpTestType::operator new(unsigned long)");
String name = object.getName();
assertEquals("operator.new", name);
}
@Test
public void testOperatorDelete() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedlEPv", "OpTestType::operator delete(void*)");
String name = object.getName();
assertEquals("operator.delete", name);
}
@Test
public void testOperatorAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator=()");
String name = object.getName();
assertEquals("operator=", name);
}
@Test
public void testOperatorRightShift() {
DemangledObject object = parser.parse("fake", "OpTestType::operator>>()");
String name = object.getName();
assertEquals("operator>>", name);
}
@Test
public void testOperatorLeftShift() {
DemangledObject object =
parser.parse("_ZN11myContainerIiElsEi", "myContainer<int>::operator<<(int)");
String name = object.getName();
assertEquals("operator<<", name);
}
@Test
public void testOperatorLeftShiftTemplated() {
DemangledObject object = parser.parse("_ZN11myContainerIiElsIdEEbT_",
"bool myContainer<int>::operator<< <double>(double)");
String name = object.getName();
assertEquals("operator<<", name);
assertEquals("bool myContainer<int>::operator<<<double>(double)",
object.getSignature());
}
@Test
public void testOperatorLogicalNot() {
DemangledObject object = parser.parse("fake", "OpTestType::operator!()");
String name = object.getName();
assertEquals("operator!", name);
}
@Test
public void testOperatorEquality() {
DemangledObject object = parser.parse("fake", "OpTestType::operator==()");
String name = object.getName();
assertEquals("operator==", name);
}
@Test
public void testOperatorInequality() {
DemangledObject object = parser.parse("fake", "OpTestType::operator!=()");
String name = object.getName();
assertEquals("operator!=", name);
}
@Test
public void testOperatorArraySubscript() {
DemangledObject object = parser.parse("fake", "OpTestType::operator[]()");
String name = object.getName();
assertEquals("operator[]", name);
}
@Test
public void testOperatorTypeCast() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvPKcEv", "OpTestType::operator char const*()");
String name = object.getName();
assertEquals("operator.cast.to.char*", name);
}
@Test
public void testOperatorTypeCast_WithNamespace() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvN16NamespaceOpTest116NamespaceOpTest210CastToTypeEEv",
"OpTestType::operator NamespaceOpTest1::NamespaceOpTest2::CastToType()");
assertName(object, "operator.cast.to.CastToType", "OpTestType");
assertEquals(
"NamespaceOpTest1::NamespaceOpTest2::CastToType OpTestType::operator.cast.to.CastToType(void)",
object.getSignature());
}
@Test
public void testOperatorPointerDereference() {
DemangledObject object = parser.parse("fake", "OpTestType::operator->()");
String name = object.getName();
assertEquals("operator->", name);
}
@Test
public void testOperatorMultiplication() {
DemangledObject object = parser.parse("fake", "OpTestType::operator*()");
String name = object.getName();
assertEquals("operator*", name);
}
//TODO: If laying down function signatures, then we need to investigate whether we can
// determine prefix vs. postfix increment. Postfix will have an argument and prefix will not.
// Same for prefix vs. postfix decrement.
@Test
public void testOperatorPrefixIncrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEv", "OpTestType::operator++()");
String name = object.getName();
assertEquals("operator++", name);
}
@Test
public void testOperatorPostfixIncrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEi", "OpTestType::operator++(int)");
String name = object.getName();
assertEquals("operator++", name);
}
@Test
public void testOperatorPrefixDecrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEv", "OpTestType::operator--()");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void testOperatorPostfixDecrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEi", "OpTestType::operator--(int)");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void testOperatorSubtraction() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemiERKS_", "OpTestType::operator-(OpTestType const&)");
String name = object.getName();
assertEquals("operator-", name);
}
@Test
public void testOperatorAddition() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeplERKS_", "OpTestType::operator+(OpTestType const&)");
String name = object.getName();
assertEquals("operator+", name);
}
@Test
public void testOperatorAddressOf() {
DemangledObject object = parser.parse("_ZN10SmallClassadEv", "SmallClass::operator&()");
String name = object.getName();
assertEquals("operator&", name);
}
@Test
public void testOperatorPointerToMemberSelection() {
DemangledObject object = parser.parse("fake", "OpTestType::operator->*()");
String name = object.getName();
assertEquals("operator->*", name);
}
@Test
public void testOperatorDivision() {
DemangledObject object = parser.parse("fake", "OpTestType::operator/()");
String name = object.getName();
assertEquals("operator/", name);
}
@Test
public void testOperatorModulus() {
DemangledObject object = parser.parse("fake", "OpTestType::operator%()");
String name = object.getName();
assertEquals("operator%", name);
}
@Test
public void testOperatorLessThan() {
DemangledObject object =
parser.parse("_ZN11myContainerIiEltEi", "myContainer<int>::operator<(int)");
String name = object.getName();
assertEquals("operator<", name);
}
@Test
public void testOperatorLessThanTemplated() {
DemangledObject object = parser.parse("_ZltI11myContainerIiEEbRKT_S4_",
"bool operator< <myContainer<int> >(myContainer<int> const&, myContainer<int> const&)");
String name = object.getName();
assertEquals("operator<", name);
assertEquals(
"bool operator<<myContainer<int>>(myContainer<int> const &,myContainer<int> const &)",
object.getSignature());
}
@Test
public void testOperatorLessThanOrEqualTo() {
DemangledObject object = parser.parse("fake", "OpTestType::operator<=()");
String name = object.getName();
assertEquals("operator<=", name);
}
@Test
public void testOperatorGreaterThan() {
DemangledObject object = parser.parse("_ZgtRK10complex_ldS1_",
"operator>(complex_ld const&, complex_ld const&)");
String name = object.getName();
assertEquals("operator>", name);
}
@Test
public void testOperatorGreaterThanOrEqualTo() {
DemangledObject object = parser.parse("fake", "OpTestType::operator>=()");
String name = object.getName();
assertEquals("operator>=", name);
}
@Test
public void testOperatorComma() {
DemangledObject object = parser.parse("fake", "OpTestType::operator,()");
String name = object.getName();
assertEquals("operator,", name);
}
@Test
public void testOperatorFunctionCall() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeclEf", "OpTestType::operator()(float)");
String name = object.getName();
assertEquals("operator()", name);
}
@Test
public void testOperatorOnesComplement() {
DemangledObject object = parser.parse("fake", "OpTestType::operator~()");
String name = object.getName();
assertEquals("operator~", name);
}
@Test
public void testOperatorExclusiveOr() {
DemangledObject object = parser.parse("fake", "OpTestType::operator^()");
String name = object.getName();
assertEquals("operator^", name);
}
@Test
public void testOperatorBitwiseInclusiveOr() {
DemangledObject object = parser.parse("fake", "OpTestType::operator|()");
String name = object.getName();
assertEquals("operator|", name);
}
@Test
public void testOperatorLogicalAnd() {
DemangledObject object = parser.parse("fake", "OpTestType::operator&&()");
String name = object.getName();
assertEquals("operator&&", name);
}
@Test
public void testOperatorLogicalOr() {
DemangledObject object = parser.parse("fake", "OpTestType::operator||()");
String name = object.getName();
assertEquals("operator||", name);
}
@Test
public void testOperatorMultiplicationAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator*=()");
String name = object.getName();
assertEquals("operator*=", name);
}
@Test
public void testOperatorAdditionAssignment() {
DemangledObject object =
parser.parse("_ZN10OpTestTypepLERKS_", "OpTestType::operator+=(OpTestType const&)");
String name = object.getName();
assertEquals("operator+=", name);
}
@Test
public void testOperatorSubtractionAssignment() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemIERKS_", "OpTestType::operator-=(OpTestType const&)");
String name = object.getName();
assertEquals("operator-=", name);
}
@Test
public void testOperatorDivisionAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator/=()");
String name = object.getName();
assertEquals("operator/=", name);
}
@Test
public void testOperatorModulusAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator%=()");
String name = object.getName();
assertEquals("operator%=", name);
}
@Test
public void testOperatorRightShiftAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator>>=()");
String name = object.getName();
assertEquals("operator>>=", name);
}
@Test
public void testOperatorLeftShiftAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator<<=()");
String name = object.getName();
assertEquals("operator<<=", name);
}
@Test
public void testOperatorBitwiseAndAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator&=()");
String name = object.getName();
assertEquals("operator&=", name);
}
@Test
public void testOperatorBitwiseOrAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator|=()");
String name = object.getName();
assertEquals("operator|=", name);
}
@Test
public void testOperatorExclusiveOrAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator^=()");
String name = object.getName();
assertEquals("operator^=", name);
}
@Test
public void testOperatorNewArray() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenaEm", "OpTestType::operator new[](unsigned long)");
String name = object.getName();
assertEquals("operator.new[]", name);
}
@Test
public void testOperatorDeleteArray() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedaEPv", "OpTestType::operator delete[](void*)");
String name = object.getName();
assertEquals("operator.delete[]", name);
}
@Test
public void testOperatorUserDefinedLiteral() {
DemangledObject object =
parser.parse("_Zli5_initPKcm", "operator\"\" _init(char const*, unsigned long)");
String name = object.getName();
assertEquals("operator\"\"__init", name);
}
private void assertName(DemangledObject demangledObj, String name, String... namespaces) {
assertEquals("Unexpected demangled name", name, demangledObj.getName());
Demangled namespace = demangledObj.getNamespace();
for (int i = namespaces.length - 1; i >= 0; i--) {
String expectedName = namespaces[i];
assertNotNull("Namespace mismatch", namespace);
String actualName = namespace.getNamespaceName();
assertEquals(expectedName, actualName);
namespace = namespace.getNamespace();
}
assertNull("Namespace mismatch", namespace);
}
}

View File

@ -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 + "; " +

View File

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

View File

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

View File

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

View File

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

View File

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