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