Merge remote-tracking branch

'origin/GT-3545-dragonmacher-gnu-demangler-parsing-bugs'

Fixes #1457 Fixes #1569
This commit is contained in:
ghidorahrex 2020-03-13 12:51:40 -04:00
commit f1782a7629
59 changed files with 3255 additions and 7594 deletions

View File

@ -24,7 +24,6 @@ dependencies {
compile project(':Graph')
compile project(':SoftwareModeling')
compile project(':DB')
compile project(':Demangler')
compile project(':Help')
compileOnly "junit:junit:4.12"

View File

@ -233,7 +233,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
log.appendMsg(getName(),
"Failed to apply mangled symbol at " + address + "; name: " +
demangled.getMangledName() + failMessage);
demangled.getMangledString() + failMessage);
}
protected String cleanSymbol(Address address, String name) {

View File

@ -0,0 +1,330 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.*;
import ghidra.program.model.symbol.Namespace;
/**
* Parent base class for types that represent things that refer to functions
*/
public abstract class AbstractDemangledFunctionDefinitionDataType extends DemangledDataType {
protected static final String DEFAULT_NAME_PREFIX = "FuncDef";
protected static final String EMPTY_STRING = "";
protected static int ID = 0;
protected DemangledDataType returnType;
protected String callingConvention;// __cdecl, __thiscall, etc.
protected List<DemangledDataType> parameters = new ArrayList<>();
protected String modifier;// namespace::, etc.
protected boolean isConstPointer;
protected String parentName;
protected boolean isTrailingPointer64;
protected boolean isTrailingUnaligned;
protected boolean isTrailingRestrict;
/** display parens in front of parameter list */
protected boolean displayFunctionPointerParens = true;
AbstractDemangledFunctionDefinitionDataType(String mangled, String originalDemangled) {
super(mangled, originalDemangled, DEFAULT_NAME_PREFIX + nextId());
}
private synchronized static int nextId() {
return ID++;
}
/**
* Returns the string for this type of reference (e.g., * or &)
* @return the string
*/
abstract protected String getTypeString();
@Override
public String getSignature() {
return toSignature(null);
}
/**
* Sets the return type
* @param returnType the return type
*/
public void setReturnType(DemangledDataType returnType) {
this.returnType = returnType;
}
/**
* Returns the return type
* @return the return type
*/
public DemangledDataType getReturnType() {
return returnType;
}
/**
* Sets the function calling convention. For example, "__cdecl"
* @param callingConvention the function calling convention
*/
public void setCallingConvention(String callingConvention) {
this.callingConvention = callingConvention;
}
/**
* Returns the calling convention or null, if unspecified
* @return the calling convention or null, if unspecified
*/
public String getCallingConvention() {
return callingConvention;
}
/**
* Sets the function __ modifier. For example, "namespace::".
* @param modifier the function modifier
*/
public void setModifier(String modifier) {
this.modifier = modifier;
}
public boolean isConstPointer() {
return isConstPointer;
}
public void setConstPointer() {
isConstPointer = true;
}
public boolean isTrailingPointer64() {
return isTrailingPointer64;
}
public void setTrailingPointer64() {
isTrailingPointer64 = true;
}
public boolean isTrailingUnaligned() {
return isTrailingUnaligned;
}
public void setTrailingUnaligned() {
isTrailingUnaligned = true;
}
public boolean isTrailingRestrict() {
return isTrailingRestrict;
}
public void setTrailingRestrict() {
isTrailingRestrict = true;
}
public void setDisplayFunctionPointerParens(boolean b) {
this.displayFunctionPointerParens = b;
}
/**
* Adds a parameters to the end of the parameter list for this demangled function
* @param parameter the new parameter to add
*/
public void addParameter(DemangledDataType parameter) {
parameters.add(parameter);
}
/**
* Returns a list of the parameters for this demangled functions.
* @return a list of the parameters for this demangled functions
*/
public List<DemangledDataType> getParameters() {
return new ArrayList<>(parameters);
}
public String toSignature(String name) {
StringBuilder buffer = new StringBuilder();
StringBuilder buffer1 = new StringBuilder();
String s = getConventionPointerNameString(name);
if (s.contains(" ") || s.isEmpty()) {
// spaces--add parens
addFunctionPointerParens(buffer1, s);
}
else { // this allows the '__cdecl' in templates to not have parens
buffer1.append(s);
}
buffer1.append('(');
for (int i = 0; i < parameters.size(); ++i) {
buffer1.append(parameters.get(i).getSignature());
if (i < parameters.size() - 1) {
buffer1.append(',');
}
}
buffer1.append(')');
if (returnType instanceof DemangledFunctionPointer) {
DemangledFunctionPointer dfp = (DemangledFunctionPointer) returnType;
buffer.append(dfp.toSignature(buffer1.toString())).append(SPACE);
}
else if (returnType instanceof DemangledFunctionReference) {
DemangledFunctionReference dfr = (DemangledFunctionReference) returnType;
buffer.append(dfr.toSignature(buffer1.toString())).append(SPACE);
}
else if (returnType instanceof DemangledFunctionIndirect) {
DemangledFunctionIndirect dfi = (DemangledFunctionIndirect) returnType;
buffer.append(dfi.toSignature(buffer1.toString())).append(SPACE);
}
else {
buffer.append(returnType.getSignature()).append(SPACE);
buffer.append(buffer1);
}
if (isConst()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(CONST);
}
if (isVolatile()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(VOLATILE);
}
if (isTrailingUnaligned) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(UNALIGNED);
}
if (isTrailingPointer64) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(PTR64);
}
if (isTrailingRestrict) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(RESTRICT);
}
return buffer.toString();
}
protected String getConventionPointerNameString(String name) {
StringBuilder buffer = new StringBuilder();
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
int pointerLevels = getPointerLevels();
if (pointerLevels > 0) {
if (callingConvention != null) {
buffer.append(SPACE);
}
addParentName(buffer);
for (int i = 0; i < pointerLevels; ++i) {
buffer.append(getTypeString());
}
}
if ((modifier != null) && (modifier.length() != 0)) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(modifier);
}
if (isConstPointer) {
buffer.append(CONST);
}
if (isPointer64()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(PTR64);
}
if (name != null) {
if ((buffer.length() > 2) && (buffer.charAt(buffer.length() - 1) != SPACE)) {
buffer.append(SPACE);
}
buffer.append(name);
}
return buffer.toString();
}
protected void addFunctionPointerParens(StringBuilder buffer, String s) {
if (!displayFunctionPointerParens) {
return;
}
buffer.append('(').append(s).append(')');
}
protected void addParentName(StringBuilder buffer) {
if (parentName == null) {
return;
}
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
return;
}
if (buffer.length() > 2) {
char lastChar = buffer.charAt(buffer.length() - 1);
if (SPACE != lastChar) {
buffer.append(SPACE);
}
}
buffer.append(parentName).append(Namespace.DELIMITER);
}
@Override
public DataType getDataType(DataTypeManager dataTypeManager) {
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
if (returnType != null) {
fddt.setReturnType(returnType.getDataType(dataTypeManager));
}
if (parameters.size() != 1 ||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
for (int i = 0; i < parameters.size(); ++i) {
params[i] = new ParameterDefinitionImpl(null,
parameters.get(i).getDataType(dataTypeManager), null);
}
fddt.setArguments(params);
}
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
dt = fddt;
}
return new PointerDataType(dt, dataTypeManager);
}
}

View File

@ -0,0 +1,162 @@
/* ###
* 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;
/**
* 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 known uses:
* <TABLE>
* <TR>
* <TH ALIGN="left">Method</TH><TH ALIGN="left">Description</TH>
* </TR>
* <TR>
* <TD>
* {@link #getName()}
* </TD>
* <TD>
* A 'safe' name that is the {@link #getDemangledName()}, but with some characters
* changed to be valid for use within Ghidra.
* </TD>
* </TR>
* <TR>
* <TD>
* {@link #getDemangledName()}
* </TD>
* <TD>
* The unmodified <b>name</b> that was set upon this object.
* </TD>
* </TR>
* <TR>
* <TD>
* {@link #getNamespaceName()}
* </TD>
* <TD>
* 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>
* <TD>
* {@link #getNamespaceString()}
* </TD>
* <TD>
* 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>
* <TD>
* {@link #getSignature()}
* </TD>
* <TD>
* Returns the complete string form of this object, with most known attributes. For
* functions, this will be a complete signature.
* </TD>
* </TR>
* <TR>
* <TD>
* {@link #getOriginalDemangled()}
* </TD>
* <TD>
* The original unmodified demangled string. This is the full demangled string returned
* from the demangling service.
* </TD>
* </TR>
* </TABLE>
*/
public interface Demangled {
/**
* Returns the original mangled string
* @return the string
*/
public String getMangledString();
/**
* Returns the original demangled string returned by the demangling service
* @return the original demangled string
*/
public String getOriginalDemangled();
/**
* Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be converted to an underscore.
* @return name of this DemangledObject with unsupported characters converted to underscore
* @see #getDemangledName()
*/
public String getName();
/**
* Sets the name for this object
* @param name the name
*/
public void setName(String name);
/**
* Returns the unmodified demangled name of this object. This name may contain whitespace
* and other characters not supported for symbol or data type creation. See {@link #getName()}
* for the same name modified for use within Ghidra.
* @return name of this DemangledObject
*/
public String getDemangledName();
/**
* Returns the namespace containing this demangled object
* @return the namespace containing this demangled object
*/
public Demangled getNamespace();
/**
* Sets the namespace of this demangled object
* @param ns the namespace
*/
public void setNamespace(Demangled ns);
/**
* Returns a representation of this object as fully-qualified namespace. The
* value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'.
* @return the full namespace
*/
public String getNamespaceString();
/**
* 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 '--'.
*
* @return the name
*/
public String getNamespaceName();
/**
* Generates a complete representation of this object to include all know attributes of this
* object
* @return the signature
*/
public String getSignature();
}

View File

@ -23,21 +23,26 @@ import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
import util.demangler.GenericDemangledAddressTable;
public class DemangledAddressTable extends DemangledObject {
private boolean calculateLength;
private int length;
public DemangledAddressTable(String name, int length) {
/**
* 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.length = length;
}
DemangledAddressTable(GenericDemangledAddressTable generic) {
super(generic);
length = generic.getLength();
this.calculateLength = calculateLength;
}
/**
@ -57,7 +62,7 @@ public class DemangledAddressTable extends DemangledObject {
buffer.append(specialPrefix);
buffer.append(' ');
}
String namespaceStr = namespace.toSignature();
String namespaceStr = namespace.getNamespaceString();
buffer.append(namespaceStr);
if (!namespaceStr.endsWith(NAMESPACE_SEPARATOR)) {
buffer.append(NAMESPACE_SEPARATOR);
@ -83,15 +88,16 @@ public class DemangledAddressTable extends DemangledObject {
return false;
}
Listing listing = program.getListing();
if (MemoryBlock.isExternalBlockAddress(address, program)) {
program.getListing().setComment(address, CodeUnit.EOL_COMMENT,
listing.setComment(address, CodeUnit.EOL_COMMENT,
"WARNING: Unable to apply demangled Address Table");
return true; // don't complain
}
if (length == -1) {
if (calculateLength) {
// determine length of address table
Data d = program.getListing().getDefinedDataAt(address);
Data d = listing.getDefinedDataAt(address);
if (d != null && Undefined.isUndefinedArray(d.getDataType())) {
// use length of Undefined array at start of table to indicate length
length = d.getLength();
@ -102,6 +108,7 @@ public class DemangledAddressTable extends DemangledObject {
return false;
}
}
calculateLength = false;
}
if (isUndefinedInRange(program, address, address.add(length - 1))) {
@ -115,7 +122,7 @@ public class DemangledAddressTable extends DemangledObject {
/**
* Perform a best guess at the length of an address table assuming that
* another label (or end of block) can be used to identify the end.
* @param program
* @param program the program
* @param address start of address table
* @return maximum length of table or -1 if address does not reside
* within an initialized memory block

View File

@ -16,13 +16,14 @@
package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import util.demangler.*;
import ghidra.program.model.symbol.Namespace;
/**
* A class to represent a demangled data type.
@ -57,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";
@ -66,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";
@ -75,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, };
@ -84,14 +90,13 @@ public class DemangledDataType extends DemangledType {
private boolean isEnum;
private boolean isPointer64;
private boolean isReference;
private boolean isSigned;//explicitly signed!
private boolean isSigned;
private boolean isStruct;
private boolean isTemplate;
private boolean isUnaligned;
private boolean isUnion;
private boolean isUnsigned;
private boolean isVarArgs;
// private boolean isVolatile;
private int pointerLevels = 0;
private String enumType;
private boolean isRestrict;
@ -100,101 +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);
}
DemangledDataType(GenericDemangledDataType source) {
super(source);
if (source.isArray()) {
// TODO GenericDemangledDataType should go away; if so, we don't need to worry
// about array dimension impedance
arrayDimensions = 1;
}
isClass = source.isClass();
isComplex = source.isComplex();
isEnum = source.isEnum();
isPointer64 = source.isPointer64();
isReference = source.isReference();
isSigned = source.isSigned();
isStruct = source.isStruct();
isTemplate = source.isTemplate();
isUnaligned = source.isUnaligned();
isUnion = source.isUnion();
isUnsigned = source.isUnsigned();
isVarArgs = source.isVarArgs();
// isVolatile = source.isVolatile();
pointerLevels = source.getPointerLevels();
//enumType = source.getEnumType();
isRestrict = source.isRestrict();
basedName = source.getBasedName();
memberScope = source.getMemberScope();
isCoclass = source.isCoclass();
isCointerface = source.isCointerface();
GenericDemangledType otherNamespace = source.getNamespace();
if (otherNamespace != null) {
namespace = DemangledType.convertToNamespace(source.getNamespace());
}
GenericDemangledTemplate otherTemplate = source.getTemplate();
if (otherTemplate != null) {
template = new DemangledTemplate(otherTemplate);
}
if (source.isConst()) {
setConst();
}
}
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.isVolatile = source.isVolatile;
destination.pointerLevels = source.pointerLevels;
//destination.enumType = source.enumType;
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) {
@ -210,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;
@ -235,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());
}
@ -263,13 +173,13 @@ 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());
}
}
else if (dt == null) { // TODO: Is using whatever was found OK ??
else if (dt == null) {
// I don't know what this is
// If it isn't pointed to, or isn't a referent, then assume typedef.
@ -298,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;
}
@ -351,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;
}
@ -397,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;
}
@ -408,49 +331,51 @@ public class DemangledDataType extends DemangledType {
* @param dataTypeManager data type manager to be searched
* @param dtName name of data type
* @param namespace namespace associated with dtName or null if not applicable. If specified,
* a namespace-base category path will be given precendence.
* a namespace-base category path will be given precedence.
* @return data type if found, otherwise null.
* @see DataTypeUtilities#findDataType(DataTypeManager, ghidra.program.model.symbol.Namespace, String, Class) for similar namespace
* based search.
*/
static DataType findDataType(DataTypeManager dataTypeManager, DemangledType namespace,
static DataType findDataType(DataTypeManager dataTypeManager, Demangled namespace,
String dtName) {
// TODO: Should be able to search archives somehow
ArrayList<DataType> list = new ArrayList<>();
List<DataType> list = new ArrayList<>();
dataTypeManager.findDataTypes(dtName, list);
if (!list.isEmpty()) {
//use the datatype that exists in the root category,
//otherwise just pick the first one...
DataType anyDt = null;
DataType preferredDataType = null;
for (DataType existingDT : list) {
if (existingDT instanceof BuiltIn) {
continue; // TODO: not sure if this is good - built-ins handled explicitly
// by DemangledDataType.getDataType method
}
if (namespace == null) {
if (existingDT.getCategoryPath().equals(CategoryPath.ROOT)) {
return existingDT;
}
anyDt = existingDT;
}
if (isNamespaceCategoryMatch(existingDT, namespace)) {
preferredDataType = existingDT;
}
}
if (preferredDataType != null) {
return preferredDataType;
}
return anyDt;
if (list.isEmpty()) {
return null;
}
return null;
//use the datatype that exists in the root category,
//otherwise just pick the first one...
DataType anyDt = null;
DataType preferredDataType = null;
for (DataType existingDT : list) {
if (existingDT instanceof BuiltIn) {
// not sure if this is good - built-ins handled explicitly by getDataType()
continue;
}
if (namespace == null) {
if (existingDT.getCategoryPath().equals(CategoryPath.ROOT)) {
return existingDT;
}
anyDt = existingDT;
}
if (isNamespaceCategoryMatch(existingDT, namespace)) {
preferredDataType = existingDT;
}
}
if (preferredDataType != null) {
return preferredDataType;
}
return anyDt;
}
private static boolean isNamespaceCategoryMatch(DataType dt, DemangledType namespace) {
private static boolean isNamespaceCategoryMatch(DataType dt, Demangled namespace) {
if (namespace == null) {
return true;
}
DemangledType ns = namespace;
Demangled ns = namespace;
CategoryPath categoryPath = dt.getCategoryPath();
while (ns != null) {
if (categoryPath.equals(CategoryPath.ROOT) ||
@ -463,8 +388,8 @@ public class DemangledDataType extends DemangledType {
return true;
}
private static String getNamespacePath(String dtName, DemangledType namespace) {
DemangledType ns = namespace;
private static String getNamespacePath(String dtName, Demangled namespace) {
Demangled ns = namespace;
String namespacePath = "";
while (ns != null) {
namespacePath = "/" + ns.getName() + namespacePath;
@ -473,15 +398,14 @@ public class DemangledDataType extends DemangledType {
return namespacePath;
}
private static CategoryPath getDemanglerCategoryPath(String dtName, DemangledType namespace) {
private static CategoryPath getDemanglerCategoryPath(String dtName, Demangled namespace) {
return new CategoryPath("/Demangler" + getNamespacePath(dtName, namespace));
}
static Structure createPlaceHolderStructure(String dtName, DemangledType namespace) {
static Structure createPlaceHolderStructure(String dtName, Demangled namespace) {
StructureDataType structDT = new StructureDataType(dtName, 0);
structDT.setDescription("PlaceHolder Structure");
structDT.setCategoryPath(getDemanglerCategoryPath(dtName, namespace));
return structDT;
}
@ -561,10 +485,6 @@ public class DemangledDataType extends DemangledType {
isVarArgs = true;
}
// public void setVolatile() {
// isVolatile = true;
// }
//
public void setEnumType(String enumType) {
this.enumType = enumType;
}
@ -669,10 +589,6 @@ public class DemangledDataType extends DemangledType {
boolean isPrimitiveDT =
!isArray() && !isClass && !isComplex && !isEnum && !isPointer() && !isPointer64 &&
!isSigned && !isTemplate && !isUnion && !isCoclass && !isCointerface && !isVarArgs;
// boolean isPrimitiveDT = !isArray && !isClass && !isComplex && !isEnum && !isPointer() &&
// !isPointer64 && !isSigned && !isTemplate && !isUnion && !isVarArgs;
// boolean isPrimitiveDT = !isArray && !isClass && !isComplex && !isEnum && !isPointer() &&
// !isPointer64 && !isSigned && !isTemplate && !isUnion && !isVarArgs && !isVolatile;
if (isPrimitiveDT) {
for (String primitiveNames : PRIMITIVES) {
if (getName().equals(primitiveNames)) {
@ -684,8 +600,8 @@ public class DemangledDataType extends DemangledType {
}
@Override
public String toSignature() {
StringBuffer buffer = new StringBuffer();
public String getSignature() {
StringBuilder buffer = new StringBuilder();
if (isUnion) {
buffer.append(UNION + SPACE);
@ -711,9 +627,6 @@ public class DemangledDataType extends DemangledType {
if (isComplex) {
buffer.append(COMPLEX + SPACE);
}
// if (isVolatile) {
// buffer.append(VOLATILE + SPACE);
// }
if (isSigned) {
buffer.append(SIGNED + SPACE);
}
@ -722,7 +635,8 @@ public class DemangledDataType extends DemangledType {
}
if (getNamespace() != null) {
buffer.append(getNamespace().toNamespace());
buffer.append(getNamespace().getNamespaceString());
buffer.append(Namespace.DELIMITER);
}
buffer.append(getDemangledName());
@ -735,7 +649,6 @@ public class DemangledDataType extends DemangledType {
buffer.append(SPACE + CONST);
}
// TODO: The output of volatile belongs here, not above, so I put the commented code here for now.
if (isVolatile()) {
buffer.append(SPACE + VOLATILE);
}
@ -760,7 +673,8 @@ public class DemangledDataType extends DemangledType {
buffer.append(SPACE + REF_NOTATION);
}
//Order of __ptr64 and __restrict can vary--with fuzzing... but what is the natural "real symbol" order?
// the order of __ptr64 and __restrict can vary--with fuzzing...
// but what is the natural "real symbol" order?
if (isPointer64) {
buffer.append(SPACE + PTR64);
}
@ -787,7 +701,7 @@ public class DemangledDataType extends DemangledType {
@Override
public String toString() {
return toSignature();
return getSignature();
}
}

View File

@ -21,22 +21,23 @@ import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.*;
import ghidra.app.util.NamespaceUtils;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import util.demangler.*;
/**
* A class to represent a demangled function.
*/
public class DemangledFunction extends DemangledObject implements ParameterReceiver {
public class DemangledFunction extends DemangledObject {
public static final String VOLATILE = "volatile";
public static final String CONST = "const";
@ -64,36 +65,11 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
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);
}
DemangledFunction(GenericDemangledFunction other) {
super(other);
GenericDemangledDataType otherReturnType = other.getReturnType();
if (otherReturnType != null) {
returnType = (DemangledDataType) DemangledObjectFactory.convert(otherReturnType);
}
callingConvention = other.getCallingConvention();
thisPassedOnStack = other.isPassedOnStack();
GenericDemangledTemplate otherTemplate = other.getTemplate();
if (otherTemplate != null) {
template = new DemangledTemplate(otherTemplate);
}
isOverloadedOperator = other.isOverloadedOperator();
List<GenericDemangledDataType> otherParams = other.getParameters();
for (GenericDemangledDataType parameter : otherParams) {
parameters.add((DemangledDataType) DemangledObjectFactory.convert(parameter));
}
}
/**
* Sets the function return type.
* @param returnType the function return type
@ -127,18 +103,10 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
this.isOverloadedOperator = isOverloadedOperator;
}
/**
* @see ghidra.app.util.demangler.ParameterReceiver
*/
@Override
public void addParameter(DemangledDataType parameter) {
parameters.add(parameter);
}
/**
* @see ghidra.app.util.demangler.ParameterReceiver
*/
@Override
public List<DemangledDataType> getParameters() {
return new ArrayList<>(parameters);
}
@ -159,7 +127,10 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
return callingConvention;
}
/** Special constructor where it has a templated type before the parameter list */
/**
* Special constructor where it has a templated type before the parameter list
* @param type the type
*/
public void setTemplatedConstructorType(String type) {
this.templatedConstructorType = type;
}
@ -218,7 +189,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
StringBuilder buffer = new StringBuilder();
if (!(returnType instanceof DemangledFunctionPointer)) {
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
@ -227,7 +198,6 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
}
buffer.append(
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
// if (virtual) {
if (isVirtual) {
buffer.append("virtual ");
}
@ -235,37 +205,26 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
buffer.append("static ");
}
if (!isTypeCast()) {
buffer.append(returnType == null ? "" : returnType.toSignature() + " ");
buffer.append(returnType == null ? "" : returnType.getSignature() + " ");
}
// buffer.append(returnType == null ? "" : returnType.toSignature() + " ");
}
buffer.append(callingConvention == null ? "" : callingConvention + " ");
if (namespace != null) {
buffer.append(namespace.toNamespace());
buffer.append(namespace.getNamespaceString());
buffer.append(NAMESPACE_SEPARATOR);
}
buffer.append(getDemangledName());
if (isTypeCast()) {
buffer.append(returnType == null ? "" : " " + returnType.toSignature() + " ");
buffer.append(returnType == null ? "" : " " + returnType.getSignature() + " ");
}
if (template != null) {
buffer.append(template.toTemplate());
}
if (specialMidfix != null) {
buffer.append('[').append(specialMidfix).append(']');
}
// check for special case of 'conversion operator' where we only want to display '()' and
// not (void)
// if (name.endsWith("()")) {
// if (name.equals("operator")) {
// buffer.append("()");
// }
// }
// else {
if (templatedConstructorType != null) {
buffer.append('<').append(templatedConstructorType).append('>');
}
@ -278,7 +237,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
}
while (paramIterator.hasNext()) {
buffer.append(paramIterator.next().toSignature());
buffer.append(paramIterator.next().getSignature());
if (paramIterator.hasNext()) {
buffer.append(',');
if (format) {
@ -290,26 +249,19 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
buffer.append(')');
buffer.append(storageClass == null ? "" : " " + storageClass);
// }
if (returnType instanceof DemangledFunctionPointer) {
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) returnType;
String partialSig = funcPtr.toSignature(buffer.toString());
buffer = new StringBuffer();
buffer = new StringBuilder();
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
buffer.append(
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
//if (virtual || super.isVirtual) {
if (isVirtual) {
buffer.append("virtual ");
}
buffer.append(partialSig);
}
else {
if (specialSuffix != null) {
buffer.append(specialSuffix);
}
}
if (isTrailingConst()) {
if (buffer.length() > 2) {
@ -351,12 +303,17 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
return buffer.toString();
}
@Override
public String getNamespaceName() {
return getName() + getParameterString();
}
public String getParameterString() {
StringBuffer buffer = new StringBuffer();
buffer.append('(');
Iterator<DemangledDataType> dditer = parameters.iterator();
while (dditer.hasNext()) {
buffer.append(dditer.next().toSignature());
buffer.append(dditer.next().getSignature());
if (dditer.hasNext()) {
buffer.append(',');
}
@ -467,13 +424,13 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
for (int i = 0; i < args.size(); i++) {
if (args.get(i).getLength() > pointerSize) {
bookmarkManager.setBookmark(address, BookmarkType.ANALYSIS, "Demangler",
"Couldn't Apply demangled signature - probably due to datatype that is too " +
"Couldn't apply demangled signature - probably due to datatype that is too " +
"large to fit in a parameter");
}
}
bookmarkManager.setBookmark(address, BookmarkType.ANALYSIS, "Demangler",
"Couldn't Apply demangled signature - bad parameter number match (" + args.size() +
"Couldn't apply demangled signature - bad parameter number match (" + args.size() +
") in a function in a namespace");
}
@ -503,7 +460,8 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
}
}
private DataType resolveReturnType(Program program, Function func, Structure classDataType) {
private DataType resolveReturnType(Program program, Function function,
Structure classDataType) {
// If something is returned as a Union, Structure, or Class return.
// It appears that is passed as an additional parameter. Essentially, it accesses
// the stack assuming there is reserved space.
@ -512,7 +470,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
}
// If returnType is null check for constructor or destructor names
if (THIS_CALL.equals(func.getCallingConventionName())) {
if (THIS_CALL.equals(function.getCallingConventionName())) {
String n = getName();
if (n.equals("~" + namespace.getName()) || n.equals(namespace.getName())) {
// constructor && destructor
@ -522,45 +480,50 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
return null;
}
private Structure maybeUpdateCallingConventionAndCreateClass(Program program, Function func) {
try {
// If the calling convention is known, should use it!
if (callingConvention != null) {
if (program.getCompilerSpec().getCallingConvention(callingConvention) == null) {
// warn that calling convention not found. Datatypes are still good,
// the real calling convention can be figured out later
// For example X64 can have __cdecl, __fastcall, __stdcall, that are accepted but ignored
program.getBookmarkManager().setBookmark(func.getEntryPoint(),
BookmarkType.ANALYSIS, "Demangler", "Warning calling convention \"" +
callingConvention + "\" not defined in Compiler Spec (.cspec)");
}
else {
func.setCallingConvention(callingConvention);
if (THIS_CALL.equals(callingConvention)) {
return createClassStructure(program, func);
}
return null;
}
}
private Structure maybeUpdateCallingConventionAndCreateClass(Program program,
Function function) {
if (isThisCall(func)) {
func.setCallingConvention(THIS_CALL);
return createClassStructure(program, func);
String convention = validateCallingConvention(program, function);
if (convention == null) {
if (!isThisCall(function)) {
return null;
}
// Leave the calling convention to someone else to figure out
// else {
// String defaultConvention = getDefaultCallingConvention(program);
// if (defaultConvention != null) {
// func.setCallingConvention(defaultConvention);
// }
// }
convention = THIS_CALL;
}
try {
function.setCallingConvention(convention);
return maybeCreateClassStructure(program, function, convention);
}
catch (InvalidInputException e) {
e.printStackTrace();
Msg.error(this, "Unexpected exception setting calling convention", e);
}
return null;
}
private String validateCallingConvention(Program program, Function function) {
if (callingConvention == null) {
return null;
}
if (program.getCompilerSpec().getCallingConvention(callingConvention) == null) {
// warn that calling convention not found. Datatypes are still good,
// the real calling convention can be figured out later
// For example X64 can have __cdecl, __fastcall, __stdcall, that
// are accepted but ignored
BookmarkManager bm = program.getBookmarkManager();
Address entry = function.getEntryPoint();
bm.setBookmark(entry, BookmarkType.ANALYSIS, "Demangler",
"Could not apply calling convention \"" + callingConvention +
"\" not defined in Compiler Spec (.cspec)");
return null;
}
return callingConvention;
}
private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) {
List<ParameterDefinitionImpl> args = new ArrayList<>();
@ -674,7 +637,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
}
// if the function name is the same name as it's namespace
// TODO: this seems too flexible - why not use equals?
// TODO: this seems too flexible - why not use equals?
if (n.startsWith(namespace.getName())) {
return true;
}
@ -699,7 +662,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
return true;
}
// TODO: It STILL COULD be a this call, we just don't know!
// It STILL COULD be a this call, we just don't know!
// But is also could be a static member function!
// The only way to really tell is compare the number of detected parameters
// to the number of parameters we have, OR, to detect the calling convention
@ -714,19 +677,64 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
* @return true if it is in the std namespace
*/
private boolean isInStdNameSpace() {
DemangledType ns = namespace;
Demangled ns = namespace;
// if my immediate namespace is "std", then I am just a function in the std namespace.
if (ns == null) {
return false;
}
if (ns.getName().toLowerCase().equals(STD_NAMESPACE)) {
if (ns.getName().equalsIgnoreCase(STD_NAMESPACE)) {
return true;
}
return false;
}
static Function createFunction(Program prog, Address addr, boolean doDisassembly,
protected Structure maybeCreateClassStructure(Program program, Function function,
String convention) {
if (!THIS_CALL.equals(convention)) {
return null;
}
if (namespace == null) {
return null;
}
String className = namespace.getName();
Symbol parentSymbol = function.getSymbol().getParentSymbol();
if (parentSymbol.getSymbolType() == SymbolType.NAMESPACE) {
try {
NamespaceUtils.convertNamespaceToClass((Namespace) parentSymbol.getObject());
}
catch (InvalidInputException e) {
throw new AssertException(e); // unexpected condition
}
}
// Store class structure in parent namespace
Demangled classNamespace = namespace.getNamespace();
DataTypeManager dataTypeManager = program.getDataTypeManager();
DataType existingType =
DemangledDataType.findDataType(dataTypeManager, classNamespace, className);
if (existingType != null && !(existingType instanceof Structure)) {
BookmarkManager bm = program.getBookmarkManager();
Address entry = function.getEntryPoint();
bm.setBookmark(entry, BookmarkType.ANALYSIS, "Demangler",
"Could not create class structure, data type already exists: " + existingType);
return null;
}
Structure structure = (Structure) existingType;
if (structure == null) {
structure = DemangledDataType.createPlaceHolderStructure(className,
classNamespace);
}
structure = (Structure) dataTypeManager.resolve(structure,
DataTypeConflictHandler.DEFAULT_HANDLER);
return structure;
}
protected Function createFunction(Program prog, Address addr, boolean doDisassembly,
TaskMonitor monitor) {
Listing listing = prog.getListing();
Function func = listing.getFunctionAt(addr);

View File

@ -15,11 +15,6 @@
*/
package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.*;
/**
* A class to represent a demangled function indirect. A function indirect is
* similar to a function pointer or a function reference except that it does
@ -27,352 +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 implements ParameterReceiver {
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++;
}
// DemangledFunctionDefinition(GenericDemangledFunctionDefinition generic) {
// super(generic);
//
// ID = generic.getID();
// returnType = (DemangledDataType) DemangledObjectFactory.convert(generic.getReturnType());
// callingConvention = generic.getCallingConvention();
// isConstPointer = generic.isConstPointer();
//
// parentName = generic.getParentName();
// isTrailingPointer64 = generic.isTrailingPointer64();
//
// List<GenericDemangledDataType> genericParameters = generic.getParameters();
// for (GenericDemangledDataType parameter : genericParameters) {
// parameters.add((DemangledDataType) DemangledObjectFactory.convert(parameter));
// }
// }
/**
* 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
*/
@Override
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
*/
@Override
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 toSignature() {
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).toSignature());
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.toSignature()).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);
// 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);
// }
if ((buffer.length() > 2) && (buffer.charAt(buffer.length() - 1) != SPACE)) {
buffer.append(SPACE);
}
buffer.append(name);
}
return buffer.toString();
}
private void addParentName(StringBuilder buffer) {
if (parentName == null) {
return;
}
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
return;
}
if (buffer.length() > 2) {
char lastChar = buffer.charAt(buffer.length() - 1);
if (SPACE != lastChar) {
buffer.append(SPACE);
}
}
buffer.append(parentName).append(NAMESPACE_DELIMITER);
}
@Override
public DataType getDataType(DataTypeManager dataTypeManager) {
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
fddt.setReturnType(returnType.getDataType(dataTypeManager));
if (parameters.size() != 1 ||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
for (int i = 0; i < parameters.size(); ++i) {
params[i] = new ParameterDefinitionImpl(null,
parameters.get(i).getDataType(dataTypeManager), null);
}
fddt.setArguments(params);
}
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
dt = fddt;
}
return new PointerDataType(dt, dataTypeManager);
protected String getTypeString() {
return EMPTY_STRING;
}
}

View File

@ -15,362 +15,17 @@
*/
package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.*;
import util.demangler.GenericDemangledDataType;
import util.demangler.GenericDemangledFunctionPointer;
/**
* A class to represent a demangled function pointer.
* A class to represent a demangled function pointer
*/
public class DemangledFunctionPointer extends DemangledDataType implements ParameterReceiver {
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++;
}
DemangledFunctionPointer(GenericDemangledFunctionPointer generic) {
super(generic);
ID = generic.getID();
returnType = (DemangledDataType) DemangledObjectFactory.convert(generic.getReturnType());
callingConvention = generic.getCallingConvention();
isConstPointer = generic.isConstPointer();
parentName = generic.getParentName();
isTrailingPointer64 = generic.isTrailingPointer64();
List<GenericDemangledDataType> genericParameters = generic.getParameters();
for (GenericDemangledDataType parameter : genericParameters) {
parameters.add((DemangledDataType) DemangledObjectFactory.convert(parameter));
}
}
/**
* 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
*/
@Override
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
*/
@Override
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 toSignature() {
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).toSignature());
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.toSignature()).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);
for (int i = 0; i < pointerLevels; ++i) {
buffer.append('*');
}
}
if ((modifier != null) && (modifier.length() != 0)) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(modifier);
}
if (isConstPointer) {
buffer.append(CONST);
}
if (isPointer64()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(PTR64);
}
if (name != null) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(name);
}
return buffer.toString();
}
private void addParentName(StringBuilder buffer) {
if (parentName == null) {
return;
}
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
return;
}
if (buffer.length() > 2) {
char lastChar = buffer.charAt(buffer.length() - 1);
if (SPACE != lastChar) {
buffer.append(SPACE);
}
}
buffer.append(parentName).append(NAMESPACE_DELIMITER);
}
@Override
public DataType getDataType(DataTypeManager dataTypeManager) {
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
if (returnType != null) {
fddt.setReturnType(returnType.getDataType(dataTypeManager));
}
if (parameters.size() != 1 ||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
for (int i = 0; i < parameters.size(); ++i) {
params[i] = new ParameterDefinitionImpl(null,
parameters.get(i).getDataType(dataTypeManager), null);
}
fddt.setArguments(params);
}
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
dt = fddt;
}
return new PointerDataType(dt, dataTypeManager);
protected String getTypeString() {
return "*";
}
}

View File

@ -15,341 +15,17 @@
*/
package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.*;
/**
* A class to represent a demangled function reference.
* A class to represent a demangled function reference
*/
public class DemangledFunctionReference extends DemangledDataType implements ParameterReceiver {
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
*/
@Override
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
*/
@Override
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 toSignature() {
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).toSignature());
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.toSignature()).append(SPACE);
buffer.append(buffer1);
}
if (isConst()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(CONST);
}
if (isVolatile()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(VOLATILE);
}
if (isTrailingUnaligned) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(UNALIGNED);
}
if (isTrailingPointer64) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(PTR64);
}
if (isTrailingRestrict) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(RESTRICT);
}
return buffer.toString();
}
private void addFunctionPointerParens(StringBuffer buffer, String s) {
if (!displayFunctionPointerParens) {
return;
}
buffer.append('(').append(s).append(')');
}
private String getConventionPointerNameString(String name) {
StringBuilder buffer = new StringBuilder();
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
int pointerLevels = getPointerLevels();
if (pointerLevels > 0) {
if (callingConvention != null) {
buffer.append(SPACE);
}
addParentName(buffer);
buffer.append('&');
// for (int i = 0; i < pointerLevels; ++i) {
// buffer.append('*');
// }
}
if ((modifier != null) && (modifier.length() != 0)) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(modifier);
}
if (isConstPointer) {
buffer.append(CONST);
}
if (isPointer64()) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(PTR64);
}
if (name != null) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(name);
}
return buffer.toString();
}
private void addParentName(StringBuilder buffer) {
if (parentName == null) {
return;
}
if (parentName.startsWith(DEFAULT_NAME_PREFIX)) {
return;
}
if (buffer.length() > 2) {
char lastChar = buffer.charAt(buffer.length() - 1);
if (SPACE != lastChar) {
buffer.append(SPACE);
}
}
buffer.append(parentName).append(NAMESPACE_DELIMITER);
}
@Override
public DataType getDataType(DataTypeManager dataTypeManager) {
FunctionDefinitionDataType fddt = new FunctionDefinitionDataType(getName());
fddt.setReturnType(returnType.getDataType(dataTypeManager));
if (parameters.size() != 1 ||
!(parameters.get(0).getDataType(dataTypeManager) instanceof VoidDataType)) {
ParameterDefinition[] params = new ParameterDefinition[parameters.size()];
for (int i = 0; i < parameters.size(); ++i) {
params[i] = new ParameterDefinitionImpl(null,
parameters.get(i).getDataType(dataTypeManager), null);
}
fddt.setArguments(params);
}
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
dt = fddt;
}
return new PointerDataType(dt, dataTypeManager);
protected String getTypeString() {
return "&";
}
}

View File

@ -1,39 +0,0 @@
/* ###
* 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;
/**
* An extension of {@link DemangledType} that signals that the type is function and can provide
* more info, like the function signature.
*/
public class DemangledFunctionType extends DemangledType {
private String signature;
public DemangledFunctionType(String name, String signature) {
super(name);
this.signature = signature;
}
@Override
public boolean isFunction() {
return true;
}
public String getSignature() {
return signature;
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,16 +15,22 @@
*/
package ghidra.app.util.demangler;
import util.demangler.GenericDemangledMethod;
/**
* Represents a demangled lambda function
*/
public class DemangledLambda extends DemangledFunction {
public class DemangledMethod extends DemangledFunction {
public DemangledMethod(String name) {
super(name);
public DemangledLambda(String mangled, String originalDemangled, String name) {
super(mangled, originalDemangled, name);
}
DemangledMethod(GenericDemangledMethod generic) {
super(generic);
@Override
public String getNamespaceName() {
return getName();
}
@Override
public String toString() {
return getName();
}
}

View File

@ -22,19 +22,18 @@ import java.util.regex.Pattern;
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
import ghidra.app.util.NamespaceUtils;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import util.demangler.GenericDemangledObject;
import util.demangler.GenericDemangledType;
/**
* A class to represent a demangled object.
*/
public abstract class DemangledObject {
public abstract class DemangledObject implements Demangled {
protected static final String SPACE = " ";
protected static final Pattern SPACE_PATTERN = Pattern.compile(SPACE);
@ -42,12 +41,10 @@ public abstract class DemangledObject {
protected static final String NAMESPACE_SEPARATOR = Namespace.DELIMITER;
protected static final String EMPTY_STRING = "";
protected String originalMangled;
protected String utilDemangled;
protected final String mangled; // original mangled string
protected final String originalDemangled;
protected String specialPrefix;
protected String specialMidfix;
protected String specialSuffix;
protected DemangledType namespace;
protected Demangled namespace;
protected String visibility;//public, protected, etc.
//TODO: storageClass refers to things such as "static" but const and volatile are
@ -73,62 +70,17 @@ public abstract class DemangledObject {
private String signature;
DemangledObject() {
// default
DemangledObject(String mangled, String originalDemangled) {
this.mangled = mangled;
this.originalDemangled = originalDemangled;
}
DemangledObject(GenericDemangledObject other) {
originalMangled = other.getOriginalMangled();
specialPrefix = other.getSpecialPrefix();
specialMidfix = other.getSpecialMidfix();
specialSuffix = other.getSpecialSuffix();
GenericDemangledType otherNamespace = other.getNamespace();
if (otherNamespace != null) {
namespace = DemangledType.convertToNamespace(otherNamespace);
}
visibility = other.getVisibility();
storageClass = other.getStorageClass();
setName(other.getName());
isConst = other.isConst();
isVolatile = other.isVolatile();
isPointer64 = other.isPointer64();
isStatic = other.isStatic();
isVirtual = other.isVirtual();
isThunk = other.isThunk();
isUnaligned = other.isUnaligned();
isRestrict = other.isRestrict();
basedName = other.getBasedName();
memberScope = other.getMemberScope();
}
/**
* Returns the unmodified demangled name of this object.
* This name may contain whitespace and other characters not
* supported for symbol or data type creation. See {@link #getName()}
* for the same name modified for use within Ghidra.
* @return name of this DemangledObject
*/
@Override
public String getDemangledName() {
return demangledName;
}
/**
* Returns the original mangled name
* @return the name
*/
public String getMangledName() {
return originalMangled;
}
/**
* Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be
* converted to an underscore.
* @return name of this DemangledObject with unsupported characters converted to underscore
*/
@Override
public String getName() {
return name;
}
@ -217,6 +169,7 @@ public abstract class DemangledObject {
* Sets the name of the demangled object
* @param name the new name
*/
@Override
public void setName(String name) {
this.demangledName = name;
this.name = name;
@ -228,39 +181,23 @@ public abstract class DemangledObject {
}
}
/**
* Sets the original mangled name
* @param mangled the original mangled name
*/
public void setOriginalMangled(String mangled) {
this.originalMangled = mangled;
@Override
public String getMangledString() {
return mangled;
}
/**
* Sets the demangled output from a supplemental utility.
* @param utilDemangled the demangled string
*/
public void setUtilDemangled(String utilDemangled) {
this.utilDemangled = utilDemangled;
@Override
public String getOriginalDemangled() {
return originalDemangled;
}
/**
* Gets the demangled output from a supplemental utility.
* @return the demangled String created for this object.
*/
public String getUtilDemangled() {
return utilDemangled;
}
/**
* Returns the namespace containing this demangled object.
* @return the namespace containing this demangled object
*/
public DemangledType getNamespace() {
@Override
public Demangled getNamespace() {
return namespace;
}
public void setNamespace(DemangledType namespace) {
@Override
public void setNamespace(Demangled namespace) {
this.namespace = namespace;
}
@ -288,22 +225,6 @@ public abstract class DemangledObject {
this.specialPrefix = special;
}
public String getSpecialMidfix() {
return specialMidfix;
}
public void setSpecialMidfix(String chargeType) {
this.specialMidfix = chargeType;
}
public String getSpecialSuffix() {
return specialSuffix;
}
public void setSpecialSuffix(String specialSuffix) {
this.specialSuffix = specialSuffix;
}
/**
* Returns a complete signature for the demangled symbol.
* <br>For example:
@ -317,6 +238,20 @@ public abstract class DemangledObject {
*/
public abstract String getSignature(boolean format);
@Override
public final String getSignature() {
return getSignature(false);
}
/**
* Returns a signature that contains only the name (and parameter list for functions)
* @return the signature
*/
@Override
public String getNamespaceName() {
return getSignature(false);
}
/**
* Sets the signature. Calling this method will
* override the auto-generated signature.
@ -331,6 +266,17 @@ public abstract class DemangledObject {
return getSignature(false);
}
@Override
public String getNamespaceString() {
StringBuilder buffer = new StringBuilder();
if (namespace != null) {
buffer.append(namespace.getNamespaceString());
buffer.append(Namespace.DELIMITER);
}
buffer.append(getNamespaceName());
return buffer.toString();
}
/**
* Determine if the symbol at address has already been demangled. While memory symbols
* check for presence of demangledName, external symbols simply check if demangled/alternate
@ -364,7 +310,7 @@ public abstract class DemangledObject {
public boolean applyTo(Program program, Address address, DemanglerOptions options,
TaskMonitor monitor) throws Exception {
if (originalMangled.equals(name)) {
if (mangled.equals(name)) {
return false;
}
String comment = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address);
@ -382,8 +328,8 @@ public abstract class DemangledObject {
}
protected String generatePlateComment() {
if (utilDemangled != null) {
return utilDemangled;
if (originalDemangled != null) {
return originalDemangled;
}
return (signature == null) ? getSignature(true) : signature;
}
@ -432,7 +378,7 @@ public abstract class DemangledObject {
}
private Symbol updateExternalSymbol(Program program, Address externalAddr, String symbolName,
DemangledType demangledNamespace) {
Demangled demangledNamespace) {
SymbolTable symbolTable = program.getSymbolTable();
Symbol s = symbolTable.getPrimarySymbol(externalAddr);
@ -461,30 +407,28 @@ public abstract class DemangledObject {
* @param typeNamespace demangled namespace object
* @return list of namespace names
*/
private static List<String> getNamespaceList(DemangledType typeNamespace) {
ArrayList<String> list = new ArrayList<>();
DemangledType ns = typeNamespace;
private static List<String> getNamespaceList(Demangled typeNamespace) {
List<String> list = new ArrayList<>();
Demangled ns = typeNamespace;
while (ns != null) {
list.add(0, ns.getName());
list.add(0, ns.getNamespaceName());
ns = ns.getNamespace();
}
return list;
}
// TODO needs updating. Couldn't determine what getResigualNamespacePath was changed to.
/**
* Get or create the specified typeNamespace. The returned namespace may only be a partial
* namespace if errors occurred. The caller should check the returned namespace and adjust
* any symbol creation accordingly. Caller should use
* <code>getResidualNamespacePath(DemangledType, Namespace)</code> to handle the case where
* only a partial namespace has been returned.
* @param program
* any symbol creation accordingly.
*
* @param program the program
* @param typeNamespace demangled namespace
* @param parentNamespace root namespace to be used (e.g., library, global, etc.)
* @param functionPermitted if true an existing function may be used as a namespace
* @return namespace or partial namespace if error occurs
*/
public static Namespace createNamespace(Program program, DemangledType typeNamespace,
public static Namespace createNamespace(Program program, Demangled typeNamespace,
Namespace parentNamespace, boolean functionPermitted) {
Namespace namespace = parentNamespace;
@ -572,37 +516,4 @@ public abstract class DemangledObject {
return buffy.toString();
}
protected Structure createClassStructure(Program prog, Function func) {
DataTypeManager dataTypeManager = prog.getDataTypeManager();
if (namespace == null) {
// unexpected
return null;
}
String structureName = namespace.getName();
Symbol parentSymbol = func.getSymbol().getParentSymbol();
if (parentSymbol.getSymbolType() == SymbolType.NAMESPACE) {
try {
NamespaceUtils.convertNamespaceToClass((Namespace) parentSymbol.getObject());
}
catch (InvalidInputException e) {
throw new AssertException(e); // unexpected condition
}
}
// Store class structure in parent namespace
DemangledType classStructureNamespace = namespace.getNamespace();
Structure classStructure = (Structure) DemangledDataType.findDataType(dataTypeManager,
classStructureNamespace, structureName);
if (classStructure == null) {
classStructure = DemangledDataType.createPlaceHolderStructure(structureName,
classStructureNamespace);
}
classStructure = (Structure) dataTypeManager.resolve(classStructure,
DataTypeConflictHandler.DEFAULT_HANDLER);
return classStructure;
}
}

View File

@ -1,57 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 util.demangler.*;
public class DemangledObjectFactory {
private DemangledObjectFactory() {
// factory
}
public static DemangledObject convert(GenericDemangledObject generic) throws DemangledException {
if (generic instanceof GenericDemangledVariable) {
return new DemangledVariable((GenericDemangledVariable) generic);
}
else if (generic instanceof GenericDemangledString) {
return new DemangledString((GenericDemangledString) generic);
}
else if (generic instanceof GenericDemangledMethod) {
return new DemangledMethod((GenericDemangledMethod) generic);
}
else if (generic instanceof GenericDemangledFunction) {
return new DemangledFunction((GenericDemangledFunction) generic);
}
else if (generic instanceof GenericDemangledAddressTable) {
return new DemangledAddressTable((GenericDemangledAddressTable) generic);
}
throw new DemangledException("Unknown GenericDemangledObject: " + generic.getClass());
}
public static DemangledType convert(GenericDemangledType generic) {
if (generic instanceof GenericDemangledFunctionPointer) {
return new DemangledFunctionPointer((GenericDemangledFunctionPointer) generic);
}
else if (generic instanceof GenericDemangledDataType) {
return new DemangledDataType((GenericDemangledDataType) generic);
}
return new DemangledType(generic);
}
}

View File

@ -22,7 +22,6 @@ import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.StringUtilities;
import ghidra.util.task.TaskMonitor;
import util.demangler.GenericDemangledString;
public class DemangledString extends DemangledObject {
private String string;
@ -31,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.
@ -38,34 +39,22 @@ 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;
this.unicode = unicode;
}
/**
* Construct demangled string from a GenericDemangledString
* @param generic generic demangled string
*/
DemangledString(GenericDemangledString generic) {
super(generic);
string = generic.getString();
length = generic.getLength();
unicode = generic.isUnicode();
}
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
if (specialPrefix != null) {
buffer.append(specialPrefix + " for ");
buffer.append(specialPrefix);
}
buffer.append(string);
if (specialSuffix != null) {
buffer.append(" " + specialSuffix);
}
return buffer.toString();
}
@ -84,9 +73,9 @@ public class DemangledString extends DemangledObject {
public boolean applyTo(Program program, Address address, DemanglerOptions options,
TaskMonitor monitor) throws Exception {
String label = SymbolUtilities.replaceInvalidChars(string, false);
String label = buildStringLabel();
if (hasLabel(program, address, label)) {
return true; // Desired symbol already exists here.
return true; // This string has already been applied
}
if (!super.applyTo(program, address, options, monitor)) {
@ -100,24 +89,24 @@ public class DemangledString extends DemangledObject {
return false;
}
// TODO: should we be using length ?
CreateStringCmd cmd = new CreateStringCmd(address, -1, isUnicode());
cmd.applyTo(program);
// unclear what demangled name should be used so apply
// fabricated string label which is more useful than mangled name
Symbol demangledSymbol =
applyDemangledName(buildStringLabel(), address, true, false, program);
applyDemangledName(label, address, true, false, program);
return (demangledSymbol != null);
}
private String buildStringLabel() {
// build string label consistent with dynamic label formatting
if (specialPrefix != null) {
// a 'special prefix' implies that the author wishes to apply the string exactly as-is
return getName();
}
// build string label consistent with dynamic label formatting
int len = string.length();
StringBuffer buf = new StringBuffer(len);
StringBuilder buf = new StringBuilder(len);
for (int i = 0; i < len; ++i) {
char c = string.charAt(i);
if (StringUtilities.isDisplayable(c) && (c != ' ')) {

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,48 +15,27 @@
*/
package ghidra.app.util.demangler;
import ghidra.program.model.data.DataType;
import ghidra.util.Msg;
import java.util.ArrayList;
import java.util.List;
import util.demangler.GenericDemangledDataType;
import util.demangler.GenericDemangledTemplate;
import ghidra.program.model.data.DataType;
public class DemangledTemplate implements ParameterReceiver {
public class DemangledTemplate {
private List<DemangledDataType> parameters = new ArrayList<DemangledDataType>();
public DemangledTemplate() {
}
DemangledTemplate(GenericDemangledTemplate template) {
List<GenericDemangledDataType> genericParameters = template.getParameters();
for (GenericDemangledDataType parameter : genericParameters) {
parameters.add((DemangledDataType) DemangledObjectFactory.convert(parameter));
}
}
@Override
public void addParameter(DemangledDataType parameter) {
parameters.add(parameter);
}
@Override
public List<DemangledDataType> getParameters() {
return new ArrayList<DemangledDataType>(parameters);
}
public String toTemplate() {
StringBuffer buffer = new StringBuffer();
StringBuilder buffer = new StringBuilder();
buffer.append('<');
for (int i = 0; i < parameters.size(); ++i) {
try {
buffer.append(parameters.get(i).toSignature());
}
catch (Error e) {
Msg.error(this, "Unexpected Error: " + e.getMessage(), e);
}
buffer.append(parameters.get(i).getSignature());
if (i < parameters.size() - 1) {
buffer.append(',');
}

View File

@ -34,7 +34,9 @@ public class DemangledThunk extends DemangledObject {
private boolean covariantReturnThunk = false;
public DemangledThunk(DemangledFunction thunkedFunctionObject) {
public DemangledThunk(String mangled, String originalDemangled,
DemangledFunction thunkedFunctionObject) {
super(mangled, originalDemangled);
this.thunkedFunctionObject = thunkedFunctionObject;
this.namespace = thunkedFunctionObject.getNamespace();
setName(thunkedFunctionObject.getName());
@ -106,7 +108,7 @@ public class DemangledThunk extends DemangledObject {
function = function.getThunkedFunction(false);
}
if (thunkedFunction != null && originalMangled.equals(function.getName()) &&
if (thunkedFunction != null && mangled.equals(function.getName()) &&
!function.isThunk()) {
function.setThunkedFunction(thunkedFunction);
}
@ -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) {
@ -147,8 +141,9 @@ public class DemangledThunk extends DemangledObject {
while (instr != null) {
// This is done in a way to handle potential delay slots
InstructionContext instructionContext = instr.getInstructionContext();
Address fallThru = instructionContext.getAddress().add(
instr.getPrototype().getFallThroughOffset(instructionContext));
Address fallThru = instructionContext.getAddress()
.add(
instr.getPrototype().getFallThroughOffset(instructionContext));
Address maxAddr = fallThru.previous();
if (maxAddr.compareTo(instr.getMinAddress()) < 0) {
// just in case we wrapped
@ -181,7 +176,7 @@ public class DemangledThunk extends DemangledObject {
}
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
thunkedFunctionObject.originalMangled, err -> Msg.warn(this, err));
mangled, err -> Msg.warn(this, err));
if (s == null) {
Address thunkedAddr =

View File

@ -15,102 +15,43 @@
*/
package ghidra.app.util.demangler;
import java.util.List;
import ghidra.app.util.SymbolPath;
import ghidra.program.model.symbol.Namespace;
import util.demangler.GenericDemangledTemplate;
import util.demangler.GenericDemangledType;
public class DemangledType {
/**
* Represents a demangled string. This class is really just a placeholder for demangled
* information. See {@link DemangledObject} for a class that represents software concepts that
* can be applied to a program. The {@link DemangledObject} may use instances of this class
* to compose its internal state for namespace information, return types and parameters.
*/
public class DemangledType implements Demangled {
protected String mangled; // the original mangled string
private String originalDemangled;
private String demangledName;
private String name;
protected String originalMangled;
protected DemangledType namespace;
private String name; // 'safe' name
protected Demangled namespace;
protected DemangledTemplate template;
private boolean isConst;
private boolean isVolatile;
/**
* Takes a {@link DemangledType} with a name that contains namespace elements
* (such as Foo::Bar) and breaks it into a hierarchy of types where each type
* represents one item in the list of namespace elements.
*
* @param otherNamespace the type to convert
* @return the original type if the name does not represent a namespace; a new type
* that contains a child, that contains a child and so on, representing the
* split-up of the original namespace string.
*/
public static DemangledType convertToNamespace(GenericDemangledType otherNamespace) {
if (otherNamespace == null) {
return null;
}
DemangledType newNamespace = new DemangledType(otherNamespace);
String demangledName = newNamespace.getName();
SymbolPath symbolPath = new SymbolPath(demangledName);
if (symbolPath.getParent() == null) {
return newNamespace;
}
List<String> names = symbolPath.asList();
DemangledType lastParent = new DemangledType(names.get(0));
for (int i = 1; i < names.size(); i++) {
DemangledType child = new DemangledType(names.get(i));
child.setNamespace(lastParent);
lastParent = child;
}
return lastParent;
}
public DemangledType(String name) {
public DemangledType(String mangled, String originaDemangled, String name) {
this.mangled = mangled;
this.originalDemangled = originaDemangled;
setName(name);
}
DemangledType(GenericDemangledType toCopy) {
GenericDemangledType otherNamespace = toCopy.getNamespace();
if (otherNamespace != null) {
namespace = convertToNamespace(otherNamespace);
}
setName(toCopy.getName());
GenericDemangledTemplate otherTemplate = toCopy.getTemplate();
if (otherTemplate != null) {
template = new DemangledTemplate(otherTemplate);
}
isConst = toCopy.isConst();
isVolatile = toCopy.isVolatile();
}
/**
* Returns the unmodified demangled name of this object.
* This name may contain whitespace and other characters not
* supported for symbol or data type creation. See {@link #getName()}
* for the same name modified for use within Ghidra.
* @return name of this DemangledObject
*/
@Override
public String getDemangledName() {
return demangledName;
}
/**
* Get the name of this type.
* NOTE: unsupported symbol characters, like whitespace, will be
* converted to an underscore.
* @return name of this DemangledType suitable for namespace creation.
*/
@Override
public String getName() {
return name;
}
/**
* Sets the name of the demangled type object.
* @param name the new name
*/
@Override
public void setName(String name) {
demangledName = name;
this.name = name;
@ -120,20 +61,14 @@ public class DemangledType {
}
}
/**
* Sets the original mangled name
* @param mangled the original mangled name
*/
public void setOriginalMangled(String mangled) {
this.originalMangled = mangled;
@Override
public String getOriginalDemangled() {
return originalDemangled;
}
/**
* Gets the original mangled name
* @return the original mangled name
*/
public String getOriginalMangled() {
return originalMangled;
@Override
public String getMangledString() {
return mangled;
}
public boolean isConst() {
@ -144,10 +79,6 @@ public class DemangledType {
isConst = true;
}
public boolean isFunction() {
return false;
}
public boolean isVolatile() {
return isVolatile;
}
@ -156,11 +87,13 @@ public class DemangledType {
isVolatile = true;
}
public DemangledType getNamespace() {
@Override
public Demangled getNamespace() {
return namespace;
}
public void setNamespace(DemangledType namespace) {
@Override
public void setNamespace(Demangled namespace) {
if (this == namespace) {
throw new IllegalArgumentException("Attempt to set this.namespace == this!");
}
@ -175,15 +108,23 @@ public class DemangledType {
this.template = template;
}
public String toSignature() {
return toNamespace();
@Override
public String getSignature() {
return getNamespaceName();
}
public String toNamespace() {
StringBuffer buffer = new StringBuffer();
if (namespace != null) {
buffer.append(namespace.toNamespace());
@Override
public String getNamespaceString() {
return getName(true);
}
private String getName(boolean includeNamespace) {
StringBuilder buffer = new StringBuilder();
if (includeNamespace && namespace != null) {
buffer.append(namespace.getNamespaceString());
buffer.append(Namespace.DELIMITER);
}
buffer.append(demangledName);
if (template != null) {
buffer.append(template.toTemplate());
@ -193,12 +134,16 @@ public class DemangledType {
return "";
}
buffer.append(Namespace.DELIMITER);
return buffer.toString();
}
@Override
public String getNamespaceName() {
return name;
}
@Override
public String toString() {
return toNamespace();
return getNamespaceString();
}
}

View File

@ -26,38 +26,16 @@ 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);
}
// DemangledUnknown(GenericDemangledVariable other) {
// super(other);
// }
//
@Override
public String getSignature(boolean format) {
return utilDemangled;
return originalDemangled;
}
// @Override
// protected boolean isAlreadyDemangled(Program program, Address address) {
// return !utilDemangled.isEmpty();
// }
//
// @Override
// public boolean applyTo(Program program, Address address, DemanglerOptions options,
// TaskMonitor monitor) throws Exception {
//
// if (isAlreadyDemangled(program, address)) {
// return true;
// }
//
// return super.applyTo(program, address, options, monitor);
// }
//
@Override
public String getName() {
//These items likely do not have names or data types, so return the signature.

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.demangler;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.util.PseudoDisassembler;
import ghidra.program.model.address.Address;
@ -27,8 +29,6 @@ import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.task.TaskMonitor;
import util.demangler.GenericDemangledDataType;
import util.demangler.GenericDemangledVariable;
/**
* An interface to represent a demangled global variable.
@ -36,19 +36,11 @@ import util.demangler.GenericDemangledVariable;
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);
}
DemangledVariable(GenericDemangledVariable other) {
super(other);
GenericDemangledDataType otherDatatype = other.getDataType();
if (otherDatatype != null) {
datatype = (DemangledDataType) DemangledObjectFactory.convert(otherDatatype);
}
}
public void setDatatype(DemangledDataType datatype) {
this.datatype = datatype;
}
@ -70,7 +62,7 @@ public class DemangledVariable extends DemangledObject {
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
StringBuilder buffer = new StringBuilder();
buffer.append(specialPrefix == null ? EMPTY_STRING : specialPrefix + SPACE);
buffer.append(
visibility == null || "global".equals(visibility) ? EMPTY_STRING : visibility + SPACE);
@ -80,7 +72,7 @@ public class DemangledVariable extends DemangledObject {
buffer.append(isVirtual ? "virtual" + SPACE : EMPTY_STRING);
String n = getDemangledName();
boolean hasName = (n != null) && !n.isEmpty();
boolean hasName = !StringUtils.isBlank(n);
StringBuffer datatypeBuffer = new StringBuffer();
String spacer = EMPTY_STRING;
@ -88,7 +80,7 @@ public class DemangledVariable extends DemangledObject {
!(datatype instanceof DemangledFunctionReference) &&
!(datatype instanceof DemangledFunctionIndirect)) {
if (datatype != null) {
datatypeBuffer.append(datatype.toSignature());
datatypeBuffer.append(datatype.getSignature());
spacer = SPACE;
}
}
@ -139,11 +131,10 @@ public class DemangledVariable extends DemangledObject {
datatypeBuffer.append(spacer);
spacer = EMPTY_STRING;
datatypeBuffer.append(namespace.toNamespace());
datatypeBuffer.append(namespace.getNamespaceString());
if (!hasName) {
int end = buffer.length();
datatypeBuffer.delete(end - 2, end); // strip off the last namespace characters
if (hasName) {
datatypeBuffer.append(NAMESPACE_SEPARATOR);
}
}
@ -153,22 +144,16 @@ public class DemangledVariable extends DemangledObject {
datatypeBuffer.append(getName());
}
datatypeBuffer.append(specialMidfix == null ? EMPTY_STRING : specialMidfix + SPACE);
datatypeBuffer.append(specialSuffix == null ? EMPTY_STRING : SPACE + specialSuffix);
if (datatype instanceof DemangledFunctionPointer) {
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) datatype;
//return funcPtr.toSignature(buffer.toString());
return buffer.append(funcPtr.toSignature(datatypeBuffer.toString())).toString();
}
else if (datatype instanceof DemangledFunctionReference) {
DemangledFunctionReference funcRef = (DemangledFunctionReference) datatype;
//return funcRef.toSignature(buffer.toString());
return buffer.append(funcRef.toSignature(datatypeBuffer.toString())).toString();
}
else if (datatype instanceof DemangledFunctionIndirect) {
DemangledFunctionIndirect funcDef = (DemangledFunctionIndirect) datatype;
//return funcDef.toSignature(buffer.toString());
return buffer.append(funcDef.toSignature(datatypeBuffer.toString())).toString();
}
@ -177,6 +162,20 @@ public class DemangledVariable extends DemangledObject {
return buffer.toString();
}
@Override
public String getNamespaceName() {
String n = getDemangledName();
if (!StringUtils.isBlank(n)) {
return n;
}
if (datatype != null) {
return datatype.getSignature();
}
return "<no name>"; // shouldn't happen
}
@Override
protected boolean isAlreadyDemangled(Program program, Address address) {
Data data = program.getListing().getDefinedDataAt(address);
@ -199,9 +198,6 @@ public class DemangledVariable extends DemangledObject {
}
Symbol demangledSymbol = applyDemangledName(address, true, true, program);
//TODO replace existing datatype?
DataType demangledDT = getProgramDataType(program);
if (address.isExternalAddress()) {

View File

@ -101,31 +101,6 @@ public class DemanglerUtil {
return ClassSearcher.getInstances(Demangler.class);
}
/**
* Converts the list of names into a namespace demangled type.
* Given names = { "A", "B", "C" }, which represents "A::B::C".
* The following will be created {@literal "Namespace{A}->Namespace{B}->Namespace{C}"}
* and Namespace{C} will be returned.
*
* NOTE: the list will be empty after the call.
* @param names the names to convert
* @return the newly created type
*/
public static DemangledType convertToNamespaces(List<String> names) {
if (names.size() == 0) {
return null;
}
int index = names.size() - 1;
DemangledType myNamespace = new DemangledType(names.get(index));
DemangledType namespace = myNamespace;
while (--index >= 0) {
DemangledType parentNamespace = new DemangledType(names.get(index));
namespace.setNamespace(parentNamespace);
namespace = parentNamespace;
}
return myNamespace;
}
/**
* Remove superfluous function signature spaces from specified string
* @param str string
@ -146,13 +121,4 @@ public class DemanglerUtil {
matcher.appendTail(buffy);
return buffy.toString();
}
public static void setNamespace(DemangledType dt, DemangledType namespace) {
if (dt.getNamespace() == null) {
dt.setNamespace(namespace);
}
else {
setNamespace(dt.getNamespace(), namespace);
}
}
}

View File

@ -1,37 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.List;
/**
* A generic interface to represent
* object that support parameters.
*/
public interface ParameterReceiver {
/**
* Adds the specified parameter to this object.
* @param parameter the parameter to add
*/
public void addParameter(DemangledDataType parameter);
/**
* Returns the parameters added to this object.
* @return the parameters added to this object
*/
public List<DemangledDataType> getParameters();
}

View File

@ -400,8 +400,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest {
ActionContext context = getActionContext();
performAction(setColorAction, context, false);
Window chooserWindow = waitForWindow(null, ColorizingServiceProvider.COLOR_CHOOSER_TITLE,
DEFAULT_WINDOW_TIMEOUT);
Window chooserWindow = waitForWindow(ColorizingServiceProvider.COLOR_CHOOSER_TITLE);
assertNotNull("Did not find Color Chooser", chooserWindow);
GhidraColorChooser colorChooser = findComponent(chooserWindow, GhidraColorChooser.class);
JButton okButton = findButtonByText(chooserWindow, "OK");

View File

@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package util.demangler;
package ghidra.app.util.demangler.gnu;
public class GenericDemangledMethod extends GenericDemangledFunction {
/**
* Exception to signal a problem parsing a demangled string
*/
public class DemanglerParseException extends RuntimeException {
public GenericDemangledMethod(String name) throws GenericDemangledException {
super(name);
public DemanglerParseException(String message) {
super(message);
}
}

View File

@ -113,9 +113,9 @@ public class GnuDemangler implements Demangler {
}
if (globalPrefix != null) {
// TODO: may need better naming convention for demangled function
DemangledFunction dfunc =
new DemangledFunction(globalPrefix + demangledObject.getName());
new DemangledFunction(originalMangled, demangled,
globalPrefix + demangledObject.getName());
dfunc.setNamespace(demangledObject.getNamespace());
demangledObject = dfunc;
}
@ -123,14 +123,12 @@ public class GnuDemangler implements Demangler {
demangledObject.setSignature(demangled);
}
demangledObject.setOriginalMangled(originalMangled);
if (isDwarf) {
DemangledAddressTable dat = new DemangledAddressTable((String) null, 1);
DemangledAddressTable dat =
new DemangledAddressTable(originalMangled, demangled, (String) null, false);
dat.setSpecialPrefix("DWARF Debug ");
dat.setName(demangledObject.getName());
dat.setNamespace(demangledObject.getNamespace());
dat.setOriginalMangled(originalMangled);
return dat;
}
@ -209,7 +207,7 @@ public class GnuDemangler implements Demangler {
return null;
}
GnuDemanglerParser parser = new GnuDemanglerParser(process);
GnuDemanglerParser parser = new GnuDemanglerParser();
DemangledObject demangledObject = parser.parse(mangled, demangled);
return demangledObject;
}

View File

@ -0,0 +1,621 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler;
import static org.junit.Assert.*;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.gnu.GnuDemanglerParser;
public class GnuDemanglerParser2Test extends AbstractGenericTest {
private GnuDemanglerParser parser = new GnuDemanglerParser();
//@Test
public void test1() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeC1Eii", "OpTestType::OpTestType(int, int)");
String name = object.getName();
assertEquals("", name);
}
//@Test
public void test2() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeC2Eii", "OpTestType::OpTestType(int, int)");
String name = object.getName();
assertEquals("", name);
}
@Test
public void test3() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeclEf", "OpTestType::operator()(float)");
String name = object.getName();
assertEquals("operator()", name);
}
@Test
public void test4() {
DemangledObject object = parser.parse("_ZN10OpTestTypeclEi", "OpTestType::operator()(int)");
String name = object.getName();
assertEquals("operator()", name);
}
//@Test
public void test5() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvN16Names", "_ZN10OpTestTypecvN16Names");
String name = object.getName();
assertEquals("", name);
}
@Test
public void test6() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvPKcEv", "OpTestType::operator char const*()");
String name = object.getName();
assertEquals("operator.cast.to.char*", name);
}
@Test
public void test7() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedaEPv", "OpTestType::operator delete[](void*)");
String name = object.getName();
assertEquals("operator.delete[]", name);
}
@Test
public void test8() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedlEPv", "OpTestType::operator delete(void*)");
String name = object.getName();
assertEquals("operator.delete", name);
}
@Test
public void test9() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemIERKS_", "OpTestType::operator-=(OpTestType const&)");
String name = object.getName();
assertEquals("operator-=", name);
}
@Test
public void test10() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemiERKS_", "OpTestType::operator-(OpTestType const&)");
String name = object.getName();
assertEquals("operator-", name);
}
@Test
public void test11() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEi", "OpTestType::operator--(int)");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void test12() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEv", "OpTestType::operator--()");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void test13() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenaEm", "OpTestType::operator new[](unsigned long)");
String name = object.getName();
assertEquals("operator.new[]", name);
}
@Test
public void test14() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenwEm", "OpTestType::operator new(unsigned long)");
String name = object.getName();
assertEquals("operator.new", name);
}
@Test
public void test15() {
DemangledObject object =
parser.parse("_ZN10OpTestTypepLERKS_", "OpTestType::operator+=(OpTestType const&)");
String name = object.getName();
assertEquals("operator+=", name);
}
@Test
public void test16() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeplERKS_", "OpTestType::operator+(OpTestType const&)");
String name = object.getName();
assertEquals("operator+", name);
}
@Test
public void test17() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEi", "OpTestType::operator++(int)");
String name = object.getName();
assertEquals("operator++", name);
}
@Test
public void test18() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEv", "OpTestType::operator++()");
String name = object.getName();
assertEquals("operator++", name);
}
//--------------------
//TODO: for the following, determine what arguments are needed.
@Test
public void testOperatorNew() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenwEm", "OpTestType::operator new(unsigned long)");
String name = object.getName();
assertEquals("operator.new", name);
}
@Test
public void testOperatorDelete() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedlEPv", "OpTestType::operator delete(void*)");
String name = object.getName();
assertEquals("operator.delete", name);
}
@Test
public void testOperatorAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator=()");
String name = object.getName();
assertEquals("operator=", name);
}
@Test
public void testOperatorRightShift() {
DemangledObject object = parser.parse("fake", "OpTestType::operator>>()");
String name = object.getName();
assertEquals("operator>>", name);
}
@Test
public void testOperatorLeftShift() {
DemangledObject object =
parser.parse("_ZN11myContainerIiElsEi", "myContainer<int>::operator<<(int)");
String name = object.getName();
assertEquals("operator<<", name);
}
@Test
public void testOperatorLeftShiftTemplated() {
DemangledObject object = parser.parse("_ZN11myContainerIiElsIdEEbT_",
"bool myContainer<int>::operator<< <double>(double)");
String name = object.getName();
assertEquals("operator<<", name);
assertEquals("bool myContainer<int>::operator<<<double>(double)",
object.getSignature());
}
@Test
public void testOperatorLogicalNot() {
DemangledObject object = parser.parse("fake", "OpTestType::operator!()");
String name = object.getName();
assertEquals("operator!", name);
}
@Test
public void testOperatorEquality() {
DemangledObject object = parser.parse("fake", "OpTestType::operator==()");
String name = object.getName();
assertEquals("operator==", name);
}
@Test
public void testOperatorInequality() {
DemangledObject object = parser.parse("fake", "OpTestType::operator!=()");
String name = object.getName();
assertEquals("operator!=", name);
}
@Test
public void testOperatorArraySubscript() {
DemangledObject object = parser.parse("fake", "OpTestType::operator[]()");
String name = object.getName();
assertEquals("operator[]", name);
}
@Test
public void testOperatorTypeCast() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvPKcEv", "OpTestType::operator char const*()");
String name = object.getName();
assertEquals("operator.cast.to.char*", name);
}
@Test
public void testOperatorTypeCast_WithNamespace() {
DemangledObject object =
parser.parse("_ZN10OpTestTypecvN16NamespaceOpTest116NamespaceOpTest210CastToTypeEEv",
"OpTestType::operator NamespaceOpTest1::NamespaceOpTest2::CastToType()");
assertName(object, "operator.cast.to.CastToType", "OpTestType");
assertEquals(
"NamespaceOpTest1::NamespaceOpTest2::CastToType OpTestType::operator.cast.to.CastToType(void)",
object.getSignature());
}
@Test
public void testOperatorPointerDereference() {
DemangledObject object = parser.parse("fake", "OpTestType::operator->()");
String name = object.getName();
assertEquals("operator->", name);
}
@Test
public void testOperatorMultiplication() {
DemangledObject object = parser.parse("fake", "OpTestType::operator*()");
String name = object.getName();
assertEquals("operator*", name);
}
//TODO: If laying down function signatures, then we need to investigate whether we can
// determine prefix vs. postfix increment. Postfix will have an argument and prefix will not.
// Same for prefix vs. postfix decrement.
@Test
public void testOperatorPrefixIncrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEv", "OpTestType::operator++()");
String name = object.getName();
assertEquals("operator++", name);
}
@Test
public void testOperatorPostfixIncrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypeppEi", "OpTestType::operator++(int)");
String name = object.getName();
assertEquals("operator++", name);
}
@Test
public void testOperatorPrefixDecrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEv", "OpTestType::operator--()");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void testOperatorPostfixDecrement() {
DemangledObject object = parser.parse("_ZN10OpTestTypemmEi", "OpTestType::operator--(int)");
String name = object.getName();
assertEquals("operator--", name);
}
@Test
public void testOperatorSubtraction() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemiERKS_", "OpTestType::operator-(OpTestType const&)");
String name = object.getName();
assertEquals("operator-", name);
}
@Test
public void testOperatorAddition() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeplERKS_", "OpTestType::operator+(OpTestType const&)");
String name = object.getName();
assertEquals("operator+", name);
}
@Test
public void testOperatorAddressOf() {
DemangledObject object = parser.parse("_ZN10SmallClassadEv", "SmallClass::operator&()");
String name = object.getName();
assertEquals("operator&", name);
}
@Test
public void testOperatorPointerToMemberSelection() {
DemangledObject object = parser.parse("fake", "OpTestType::operator->*()");
String name = object.getName();
assertEquals("operator->*", name);
}
@Test
public void testOperatorDivision() {
DemangledObject object = parser.parse("fake", "OpTestType::operator/()");
String name = object.getName();
assertEquals("operator/", name);
}
@Test
public void testOperatorModulus() {
DemangledObject object = parser.parse("fake", "OpTestType::operator%()");
String name = object.getName();
assertEquals("operator%", name);
}
@Test
public void testOperatorLessThan() {
DemangledObject object =
parser.parse("_ZN11myContainerIiEltEi", "myContainer<int>::operator<(int)");
String name = object.getName();
assertEquals("operator<", name);
}
@Test
public void testOperatorLessThanTemplated() {
DemangledObject object = parser.parse("_ZltI11myContainerIiEEbRKT_S4_",
"bool operator< <myContainer<int> >(myContainer<int> const&, myContainer<int> const&)");
String name = object.getName();
assertEquals("operator<", name);
assertEquals(
"bool operator<<myContainer<int>>(myContainer<int> const &,myContainer<int> const &)",
object.getSignature());
}
@Test
public void testOperatorLessThanOrEqualTo() {
DemangledObject object = parser.parse("fake", "OpTestType::operator<=()");
String name = object.getName();
assertEquals("operator<=", name);
}
@Test
public void testOperatorGreaterThan() {
DemangledObject object = parser.parse("_ZgtRK10complex_ldS1_",
"operator>(complex_ld const&, complex_ld const&)");
String name = object.getName();
assertEquals("operator>", name);
}
@Test
public void testOperatorGreaterThanOrEqualTo() {
DemangledObject object = parser.parse("fake", "OpTestType::operator>=()");
String name = object.getName();
assertEquals("operator>=", name);
}
@Test
public void testOperatorComma() {
DemangledObject object = parser.parse("fake", "OpTestType::operator,()");
String name = object.getName();
assertEquals("operator,", name);
}
@Test
public void testOperatorFunctionCall() {
DemangledObject object =
parser.parse("_ZN10OpTestTypeclEf", "OpTestType::operator()(float)");
String name = object.getName();
assertEquals("operator()", name);
}
@Test
public void testOperatorOnesComplement() {
DemangledObject object = parser.parse("fake", "OpTestType::operator~()");
String name = object.getName();
assertEquals("operator~", name);
}
@Test
public void testOperatorExclusiveOr() {
DemangledObject object = parser.parse("fake", "OpTestType::operator^()");
String name = object.getName();
assertEquals("operator^", name);
}
@Test
public void testOperatorBitwiseInclusiveOr() {
DemangledObject object = parser.parse("fake", "OpTestType::operator|()");
String name = object.getName();
assertEquals("operator|", name);
}
@Test
public void testOperatorLogicalAnd() {
DemangledObject object = parser.parse("fake", "OpTestType::operator&&()");
String name = object.getName();
assertEquals("operator&&", name);
}
@Test
public void testOperatorLogicalOr() {
DemangledObject object = parser.parse("fake", "OpTestType::operator||()");
String name = object.getName();
assertEquals("operator||", name);
}
@Test
public void testOperatorMultiplicationAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator*=()");
String name = object.getName();
assertEquals("operator*=", name);
}
@Test
public void testOperatorAdditionAssignment() {
DemangledObject object =
parser.parse("_ZN10OpTestTypepLERKS_", "OpTestType::operator+=(OpTestType const&)");
String name = object.getName();
assertEquals("operator+=", name);
}
@Test
public void testOperatorSubtractionAssignment() {
DemangledObject object =
parser.parse("_ZN10OpTestTypemIERKS_", "OpTestType::operator-=(OpTestType const&)");
String name = object.getName();
assertEquals("operator-=", name);
}
@Test
public void testOperatorDivisionAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator/=()");
String name = object.getName();
assertEquals("operator/=", name);
}
@Test
public void testOperatorModulusAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator%=()");
String name = object.getName();
assertEquals("operator%=", name);
}
@Test
public void testOperatorRightShiftAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator>>=()");
String name = object.getName();
assertEquals("operator>>=", name);
}
@Test
public void testOperatorLeftShiftAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator<<=()");
String name = object.getName();
assertEquals("operator<<=", name);
}
@Test
public void testOperatorBitwiseAndAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator&=()");
String name = object.getName();
assertEquals("operator&=", name);
}
@Test
public void testOperatorBitwiseOrAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator|=()");
String name = object.getName();
assertEquals("operator|=", name);
}
@Test
public void testOperatorExclusiveOrAssignment() {
DemangledObject object = parser.parse("fake", "OpTestType::operator^=()");
String name = object.getName();
assertEquals("operator^=", name);
}
@Test
public void testOperatorNewArray() {
DemangledObject object =
parser.parse("_ZN10OpTestTypenaEm", "OpTestType::operator new[](unsigned long)");
String name = object.getName();
assertEquals("operator.new[]", name);
}
@Test
public void testOperatorDeleteArray() {
DemangledObject object =
parser.parse("_ZN10OpTestTypedaEPv", "OpTestType::operator delete[](void*)");
String name = object.getName();
assertEquals("operator.delete[]", name);
}
@Test
public void testOperatorUserDefinedLiteral() {
DemangledObject object =
parser.parse("_Zli5_initPKcm", "operator\"\" _init(char const*, unsigned long)");
String name = object.getName();
assertEquals("operator\"\"__init", name);
}
private void assertName(DemangledObject demangledObj, String name, String... namespaces) {
assertEquals("Unexpected demangled name", name, demangledObj.getName());
Demangled namespace = demangledObj.getNamespace();
for (int i = namespaces.length - 1; i >= 0; i--) {
String expectedName = namespaces[i];
assertNotNull("Namespace mismatch", namespace);
String actualName = namespace.getNamespaceName();
assertEquals(expectedName, actualName);
namespace = namespace.getNamespace();
}
assertNull("Namespace mismatch", namespace);
}
}

View File

@ -145,7 +145,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
Symbol s = symbolTable.getPrimarySymbol(addr("01001000"));
assertNotNull(s);
assertEquals("typeinfo_name", s.getName());
assertEquals("typeinfo-name", s.getName());
assertEquals("AP_HAL::HAL::Callbacks", s.getParentNamespace().getName(true));
assertEquals("typeinfo name for AP_HAL::HAL::Callbacks",
@ -238,6 +238,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
String demanglerName = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
String applicationArguments = "-s MrBob";
try {
setErrorsExpected(true);
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationArguments);
fail("Expected an exception when passing unknown arguments to the native demangler");
@ -246,7 +247,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
// expected
Msg.error(this, "Test error", e);
}
setErrorsExpected(false);
}
private Address addr(String address) {

View File

@ -1,16 +0,0 @@
__ZTV15_IOConfigThread #
__ZN8IOSyncer9metaClassE #
__ZN8IOSyncer10superClassE #
__ZN12KLDBootstrapD1Ev #
__ZN12KLDBootstrapD2Ev #
__ZN12KLDBootstrapC1Ev #
__ZN12KLDBootstrapC2Ev #
__ZL26kCharsetNameISOLatinHebrew
__ZN9__gnu_cxxL16__stl_prime_listE
__ZNSs6appendERKSs
__ZTV21MmsMessageClassHeader
__ZL30addRecipientsFromMmsWithHeaderPKcP10MmsMessageP9CTMessage # addRecipientsFromMmsWithHeader(char const*, MmsMessage*, CTMessage*)
__ZZN13MmsPduDecoder21_decodeMessageHeadersEP10MmsMessageE15requiredHeaders

View File

@ -602,7 +602,10 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
if (descriptorName == null) {
return null;
}
DemangledType typeNamespace = new DemangledType(descriptorName);
String demangledSource = mdComplexType.toString();
DemangledType typeNamespace =
new DemangledType(originalTypeName, demangledSource, descriptorName);
DemangledType parentNamespace = getParentNamespace(); // Can be null;
if (parentNamespace != null) {
typeNamespace.setNamespace(parentNamespace);
@ -614,8 +617,8 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
return namespace;
}
private boolean isNamespaceDeleted(Namespace namespace2) {
Symbol nsSymbol = namespace2.getSymbol();
private boolean isNamespaceDeleted(Namespace other) {
Symbol nsSymbol = other.getSymbol();
if (nsSymbol == null) {
return false; // global namespace.
}

View File

@ -21,7 +21,6 @@ import ghidra.app.util.opinion.PeLoader;
import ghidra.program.model.listing.Program;
import mdemangler.MDException;
import mdemangler.MDMangGhidra;
import util.demangler.GenericDemangledException;
/**
* A class for demangling debug symbols created using Microsoft Visual Studio.
@ -46,7 +45,7 @@ public class MicrosoftDemangler implements Demangler {
DemangledObject demangled = demangleMS(mangled, demangleOnlyKnownPatterns);
return demangled;
}
catch (GenericDemangledException e) {
catch (DemangledException e) {
throw new DemangledException(true);
}
}
@ -59,15 +58,15 @@ public class MicrosoftDemangler implements Demangler {
DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns());
return demangled;
}
catch (GenericDemangledException e) {
catch (DemangledException e) {
throw new DemangledException(true);
}
}
private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns)
throws GenericDemangledException {
throws DemangledException {
if (mangled == null || mangled.length() == 0) {
throw new GenericDemangledException(true);
throw new DemangledException(true);
}
MDMangGhidra demangler = new MDMangGhidra();
@ -77,10 +76,10 @@ public class MicrosoftDemangler implements Demangler {
return object;
}
catch (MDException e) {
GenericDemangledException gde =
new GenericDemangledException("Unable to demangle symbol: " + mangled);
gde.initCause(e);
throw gde;
DemangledException de =
new DemangledException("Unable to demangle symbol: " + mangled);
de.initCause(e);
throw de;
}
}
}

View File

@ -38,6 +38,9 @@ public class MDMangGhidra extends MDMang {
private DemangledObject objectResult;
private DemangledDataType dataTypeResult;
private String mangledSource;
private String demangledSource;
public DemangledObject getObject() {
return objectResult;
}
@ -46,31 +49,6 @@ public class MDMangGhidra extends MDMang {
return dataTypeResult;
}
public DemangledType processNamespace(MDQualifiedName qualifiedName) {
return processNamespace(qualifiedName.getQualification());
}
private DemangledType processNamespace(MDQualification qualification) {
Iterator<MDQualifier> it = qualification.iterator();
if (!it.hasNext()) {
return null;
}
MDQualifier qual = it.next();
DemangledType type = new DemangledType(qual.toString());
DemangledType parentType = type;
while (it.hasNext()) {
qual = it.next();
DemangledType newType = new DemangledType(qual.toString());
if (qual.isNested()) {
newType.setOriginalMangled(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.setOriginalMangled(mangledArg);
// Make our version of the demangled string available (could be large).
objectResult.setUtilDemangled(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
@ -805,4 +821,3 @@ public class MDMangGhidra extends MDMang {
/******************************************************************************/
/******************************************************************************/

View File

@ -15,6 +15,8 @@
*/
package mdemangler;
import static org.junit.Assert.*;
import ghidra.util.Msg;
import mdemangler.datatype.MDDataType;
@ -65,7 +67,7 @@ public class MDBaseTestConfiguration {
* @param mstruth Truth that was output from one of the Microsoft tools (e.g., undname).
* @param ghtruth Truth that we would like to see for Ghidra version of the tool.
* @param ms2013truth Like mstruth, but from Visual Studio 2013 version of tool.
* @throws Exception
* @throws Exception if any exceptions are thrown
*/
public void demangleAndTest(String mangledArg, String mdtruth, String mstruth, String ghtruth,
String ms2013truth) throws Exception {
@ -105,24 +107,24 @@ public class MDBaseTestConfiguration {
// expect to be able to demangle the input (truth not equal to mangleArg), then we
// expect the output to be that which we desire ("truth".equals(demangled)).
if ((truth.equals(mangledArg)) && isMangled(mangledArg)) {
assert (demangled.isEmpty());
assertTrue(demangled.isEmpty());
}
else {
assert(truth.equals(demangled));
assertEquals(truth, demangled);
}
if (mangledArg.startsWith(".?A")) {
assert ((demangItem != null) && (demangItem instanceof MDDataType)); // Test for data type.
assertTrue((demangItem != null) && (demangItem instanceof MDDataType)); // Test for data type.
}
}
private boolean isMangled(String mangled) {
if (mangled.charAt(0) == '?') {
private boolean isMangled(String s) {
if (s.charAt(0) == '?') {
return true;
}
else if (mangled.startsWith("__")) {
else if (s.startsWith("__")) {
return true;
}
else if ((mangled.charAt(0) == '_') || Character.isUpperCase(mangled.charAt(1))) {
else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
return true;
}
return false;

View File

@ -15,7 +15,7 @@
*/
package mdemangler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import org.junit.Test;
@ -46,7 +46,7 @@ public class MDMangExtraTests extends AbstractGenericTest {
String demangled = item.toString();
assertEquals(wholeTruth, demangled);
DemangledObject obj = demangler.getObject();
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getOriginalMangled();
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getMangledString();
assertEquals(functionNamespaceMangledTruth, mangledFunctionNamespace);
item = demangler.demangle(mangledFunctionNamespace, true);

View File

@ -1,12 +0,0 @@
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Framework Demangler'
dependencies {
compile project(':Utility')
}

View File

@ -1,3 +0,0 @@
##VERSION: 2.0
Module.manifest||GHIDRA||reviewed||END|
build.gradle||GHIDRA||||END|

View File

@ -1,249 +0,0 @@
/* ###
* 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 util.demangler;
/**
* A class for bidirectional iteration over a string.
*
* Iterators maintain a current character index, whose valid range is from
* 0 to string.length()-1.
*
* The current index can be retrieved by calling getIndex() and set directly
* by calling setIndex().
*
* The methods previous() and next() are used for iteration. They return DONE if
* they would move outside the range from 0 to string.length()-1.
*/
public class CharacterIterator {
/**
* Constant that is returned when the iterator has reached either the end
* or the beginning of the text. The value is '\\uFFFF', the "not a
* character" value which should not occur in any valid Unicode string.
*/
public static final char DONE = '\uFFFF';
private String string;
private int index;
/**
* Constructs a new character iterator using str.
* @param str the string to iterate
*/
public CharacterIterator(String str) {
this.string = str;
}
/**
* Returns the underlying string.
* @return the underlying string
*/
public String getString() {
return string;
}
/**
* Returns the current index.
* @return the current index.
*/
public int getIndex() {
return index;
}
/**
* Returns the length of the iterator.
* @return the length of the iterator
*/
public int getLength() {
return string.length();
}
/**
* Sets the position to the specified position in the text.
* @param index the position within the text.
* @throws IllegalArgumentException if index is not in range from 0 to string.length()-1
*/
public void setIndex(int index) {
if (index < 0 || index > string.length() - 1) {
throw new IllegalArgumentException();
}
this.index = index;
}
/**
* Returns true if there are more characters to read
* @return true if there are more characters to read
*/
public boolean hasNext() {
return index < string.length() - 1;
}
/**
* Returns the next character without incrementing the current index.
* @return the next character without incrementing the current index
*/
public char peek() {
try {
return string.charAt(index);
}
catch (IndexOutOfBoundsException e) {
return DONE;
}
}
/**
* Peeks at the character current index + lookAhead.
* Returns DONE if the computed position is out of range.
* @param lookAhead number of characters to look ahead
* @return the character at index+lookAhead
*/
public char peek(int lookAhead) {
try {
return string.charAt(index + lookAhead);
}
catch (IndexOutOfBoundsException e) {
return DONE;
}
}
/**
* Increments the current index by one and returns the character
* at the new index. If the resulting index is greater or equal
* to the end index, the current index is reset to the end index and
* a value of DONE is returned.
* @return the character at the new position or DONE
*/
public char next() {
try {
return string.charAt(++index);
}
catch (IndexOutOfBoundsException e) {
index = string.length();
return DONE;
}
}
/**
* Returns the character at the current index and then increments the index by one.
* If the resulting index is greater or equal
* to the end index, the current index is reset to the end index and
* a value of DONE is returned.
* @return the character at the new position or DONE
*/
public char getAndIncrement() {
try {
return string.charAt(index++);
}
catch (IndexOutOfBoundsException e) {
index = string.length();
return DONE;
}
}
/**
* Decrements the current index by one and returns the character
* at the new index. If the current index is 0, the index
* remains at 0 and a value of DONE is returned.
* @return the character at the new position or DONE
*/
public char previous() {
try {
return string.charAt(--index);
}
catch (IndexOutOfBoundsException e) {
index = 0;
return DONE;
}
}
/**
* Returns the next ascii string of the specified length starting
* at the current index.
* @param len the length of the string to read
* @return the next ascii string
*/
public String nextString(int len) {
String s = string.substring(index, index + len);
index = index + len;
return s;
}
/**
* Returns the next integer. The radix must be 10 (decimal).
* For example, given "...12fred..". If current index is pointing
* to the '1', then this value will return 12.
* @return the next base-10 integer.
*/
public int nextInteger() {
int origIndex = index;
while (Character.isDigit(peek())) {
getAndIncrement();
}
if (origIndex == index) {
return string.charAt(index) - '0';
}
String s = string.substring(origIndex, index);
try {
return Integer.parseInt(s);
}
catch (NumberFormatException e) {
index = origIndex;
throw e;
}
}
/**
* Looks for the next occurrence of 'c' starting
* at the current index. Returns the character
* position in the underlying string or -1 if 'c'
* is not found.
*/
public int find(char c) {
for (int i = index; i < string.length(); ++i) {
if (string.charAt(i) == c) {
return i;
}
}
return -1;
}
@Override
public String toString() {
return "currnt = " + peek() + "; next = " + peek(1);
}
public String getContext() {
StringBuilder buffy = new StringBuilder();
int amount = 5;
int start = index - amount;
start = Math.max(start, 0);
for (int i = start; i < index; i++) {
buffy.append(string.charAt(i));
}
buffy.append('[').append(string.charAt(index)).append(']');
int end = index + amount + 1;
end = Math.min(end, string.length());
for (int i = index + 1; i < end; i++) {
buffy.append(string.charAt(i));
}
buffy.append(" @ ").append(index);
return buffy.toString();
}
}

View File

@ -1,57 +0,0 @@
/* ###
* 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 util.demangler;
public class GenericDemangledAddressTable extends GenericDemangledObject {
private int length;
public GenericDemangledAddressTable(String name, int length) {
this.name = name;
this.length = length;
}
/**
* Returns the length of the address table.
* -1 indicates the length is unknown.
* @return the length of the address table
*/
public int getLength() {
return length;
}
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
if (specialPrefix != null) {
buffer.append(specialPrefix);
buffer.append(' ');
}
if (namespace != null) {
String namespaceStr = namespace.toSignature();
buffer.append(namespaceStr);
if (!namespaceStr.endsWith(NAMESPACE_SEPARATOR)) {
buffer.append(NAMESPACE_SEPARATOR);
}
}
buffer.append(name);
return buffer.toString();
}
}

View File

@ -1,191 +0,0 @@
/* ###
* 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 util.demangler;
import java.util.regex.Matcher;
public class GenericDemangledArray extends GenericDemangledDataType {
private String dataType;
public GenericDemangledArray(String name) {
super(name);
setArray();
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getDataType() {
return dataType;
}
@Override
public void copyInto(GenericDemangledVariable destination) {
super.copyInto(destination);
if (dataType != null) {
GenericDemangledDataType dt = new GenericDemangledDataType(dataType);
destination.setDatatype(dt);
}
}
/**
* Note: this code is a modified form of what was in the parent class, specifically to
* handle arrays. Also, feel free to jigger this around, as long as the tests pass, we are
* probably OK. There is probably a lot of code in this method that is not needed.
*/
@Override
public String toSignature() {
StringBuffer buffer = new StringBuffer();
if (isUnion) {
buffer.append(UNION).append(SPACE);
}
if (isStruct) {
buffer.append(STRUCT).append(SPACE);
}
if (isEnum) {
buffer.append(ENUM).append(SPACE);
}
if (isClass) {
buffer.append(CLASS).append(SPACE);
}
if (isComplex) {
buffer.append(COMPLEX).append(SPACE);
}
if (isVolatile) {
buffer.append(VOLATILE).append(SPACE);
}
if (isSigned) {
buffer.append(SIGNED).append(SPACE);
}
if (isUnsigned) {
buffer.append(UNSIGNED).append(SPACE);
}
String space = "";
if (dataType != null) {
buffer.append(space).append(dataType);
space = String.valueOf(SPACE);
}
if (isConst()) {
buffer.append(space).append(CONST);
space = String.valueOf(SPACE);
}
if (getNamespace() != null) {
buffer.append(getNamespace().toNamespace());
}
if (getName() != null) {
buffer.append(getName());
space = String.valueOf(SPACE);
}
if (getTemplate() != null) {
buffer.append(getTemplate().toTemplate());
space = String.valueOf(SPACE);
}
if (isUnaligned) {
buffer.append(space).append(UNALIGNED);
space = String.valueOf(SPACE);
}
if (isFar) {
buffer.append(space).append(FAR);
space = String.valueOf(SPACE);
}
if (isRestrict) {
buffer.append(space).append(RESTRICT);
space = String.valueOf(SPACE);
}
handlePointer(buffer, space);
if (isReference) {
// ugly, but MS does this
boolean hasPointers = pointerLevels >= 1;
if (isConst() && hasPointers) {
buffer.append(space).append(CONST);
space = String.valueOf(SPACE);
}
buffer.append(space).append(REF_NOTATION);
space = String.valueOf(SPACE);
}
handleTrailingPointer(buffer, space);
if (isArray) {
Matcher matcher = ARRAY_SUBSCRIPT_PATTERN.matcher(getName());
if (!matcher.find()) {
// only put subscript on if the name doesn't have it
buffer.append(ARR_NOTATION);
}
}
return buffer.toString();
}
private void handlePointer(StringBuffer buffer, String space) {
String myName = getName();
if (myName.contains("*")) {
return; // don't add pointer notation if it is already in the name
}
boolean hasPointers = pointerLevels >= 1;
if (hasPointers) {
buffer.append(space + PTR_NOTATION);
space = String.valueOf(SPACE);
}
}
private void handleTrailingPointer(StringBuffer buffer, String space) {
// not sure if we need this here
// String myName = getName();
// if (myName.contains("*")) {
// return; // don't add pointer notation if it is already in the name
// }
if (isPointer64) {
buffer.append(space).append(PTR64);
space = String.valueOf(SPACE);
}
for (int i = 1; i < pointerLevels; i++) {
// ugly, but MS does this
if (isConst()) {
buffer.append(space).append(CONST);
space = String.valueOf(SPACE);
}
buffer.append(space).append(PTR_NOTATION);
space = String.valueOf(SPACE);
// ugly, but MS does this
if (isPointer64) {
buffer.append(space).append(PTR64);
space = String.valueOf(SPACE);
}
}
}
}

View File

@ -1,59 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 util.demangler;
public final class GenericDemangledConstants {
public final static String VISIBILITY_public = "public";
public final static String VISIBILITY_protected = "protected";
public final static String VISIBILITY_private = "private";
public final static String VISIBILITY_static = "static";
public final static String VISIBILITY_global = "global";
public final static String VISIBILITY_virtual = "virtual";
public final static String[] VISIBILITY_ARR = { VISIBILITY_public, VISIBILITY_protected,
VISIBILITY_private, VISIBILITY_static, VISIBILITY_global, VISIBILITY_virtual, };
public final static boolean isVisibility(String visibility) {
return contains(VISIBILITY_ARR, visibility);
}
/////////////////////////////////////////////////////
public final static String STORAGE_CLASS_const = "const";
public final static String STORAGE_CLASS_volatile = "volatile";
public final static String STORAGE_CLASS_far = "far";
public final static String STORAGE_CLASS_restrict = "restrict";
public final static String[] STORAGE_CLASS_ARR = { STORAGE_CLASS_const, STORAGE_CLASS_volatile,
STORAGE_CLASS_far, STORAGE_CLASS_restrict, };
public final static boolean isStorageClass(String storageClass) {
return contains(STORAGE_CLASS_ARR, storageClass);
}
/////////////////////////////////////////////////////
private final static boolean contains(String[] array, String target) {
for (String element : array) {
if (element.equals(target)) {
return true;
}
}
return false;
}
}

View File

@ -1,579 +0,0 @@
/* ###
* 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 util.demangler;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A class to represent a demangled data type.
*/
public class GenericDemangledDataType extends GenericDemangledType {
protected static final Pattern ARRAY_SUBSCRIPT_PATTERN = Pattern.compile("\\[\\d*\\]");
public static final char SPACE = ' ';
private static final String STATIC = "static";
public static final String UNALIGNED = "__unaligned";
public static final String UNSIGNED = "unsigned";
public static final String SIGNED = "signed";
public static final String ARR_NOTATION = "[]";
public static final String REF_NOTATION = "&";
public static final String PTR_NOTATION = "*";
public static final String VOLATILE = "volatile";
public static final String COMPLEX = "complex";
public static final String CLASS = "class";
public static final String ENUM = "enum";
public static final String STRUCT = "struct";
public static final String UNION = "union";
public static final String COCLASS = "coclass";
public static final String COINTERFACE = "cointerface";
public static final String CONST = "const";
protected static final String FAR = "far";
protected static final String RESTRICT = "restrict";
public final static String VARARGS = "...";
public final static String VOID = "void";
public final static String BOOL = "bool";
public final static String CHAR = "char";
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 LONG = "long";
public final static String LONG_LONG = "long long";
public final static String FLOAT = "float";
public final static String DOUBLE = "double";
public final static String INT64 = "__int64";
public final static String INT128 = "__int128";//TODO
public final static String FLOAT128 = "__float128";//TODO
public final static String LONG_DOUBLE = "long double";
public final static String PTR64 = "__ptr64";
public final static String STRING = "string";
public final static String[] PRIMITIVES = { VOID, BOOL, CHAR, WCHAR_T, SHORT, INT, INT0_T, LONG,
LONG_LONG, FLOAT, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
/** private/protected/public */
protected String access;
protected boolean isStatic;
protected boolean isArray;
protected boolean isClass;
protected boolean isComplex;
protected boolean isEnum;
protected boolean isPointer64;
protected boolean isReference;
protected boolean isSigned;//explicitly signed!
protected boolean isStruct;
protected boolean isTemplate;
protected boolean isUnaligned;
protected boolean isUnion;
protected boolean isUnsigned;
protected boolean isVarArgs;
protected boolean isVolatile;
protected int pointerLevels = 0;
protected boolean isFar;
protected boolean isRestrict;
//This basedAttributte is an attribute on a modified type (such as a pointer) in the
// Microsoft model, which declares what the modified type is based on. Search the
// Internet for "Microsoft based pointer" to get a better explanation of its usage
// (I imagine that it is implemented as a hidden pointer index).
protected String basedAttribute;
protected String memberScope;
protected boolean isCoclass;
protected boolean isCointerface;
/**
* Constructs a new demangled datatype.
* @param name the name of the datatype
*/
public GenericDemangledDataType(String name) {
super(name);
}
public GenericDemangledDataType copy() {
GenericDemangledDataType copy = new GenericDemangledDataType(getName());
copyInto(copy);
return copy;
}
public void copyInto(GenericDemangledDataType destination) {
GenericDemangledDataType source = this;
// note: for now this copy is additive for the attributes in that it won't turn off
// an attribute that was already on. If this is not what we want, then we may
// need a second copy method.
destination.isStatic |= source.isStatic;
destination.isArray |= source.isArray;
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.isUnaligned |= source.isUnaligned;
destination.isUnion |= source.isUnion;
destination.isUnsigned |= source.isUnsigned;
destination.isVarArgs |= source.isVarArgs;
destination.isVolatile |= source.isVolatile;
destination.pointerLevels = destination.pointerLevels + source.pointerLevels; // ?
destination.isFar |= source.isFar;
destination.isRestrict |= source.isRestrict;
updateAccess(destination, source);
destination.setNamespace(source.getNamespace());
destination.setTemplate(source.getTemplate());
destination.basedAttribute = source.basedAttribute;
destination.memberScope = source.memberScope;
destination.isCoclass |= source.isCoclass;
destination.isCointerface |= source.isCointerface;
if (source.isConst()) {
destination.setConst();
}
if (source.isVolatile()) {
destination.setVolatile();
}
}
private void updateAccess(GenericDemangledDataType destination,
GenericDemangledDataType source) {
String currentAccess = destination.getAccess();
if (currentAccess != null && !currentAccess.trim().isEmpty()) {
// don't overwrite the current access (if we need to, we can write a combining algorithm)
return;
}
destination.setAccess(source.getAccess());
}
public void copyInto(GenericDemangledVariable destination) {
GenericDemangledDataType source = this;
List<String> list = new ArrayList<>();
if (source.isConst()) {
list.add("const");
}
if (source.isVolatile) {
list.add("volatile");
}
if (source.isFar) {
list.add("far");
}
if (source.isRestrict) {
list.add("restrict");
}
StringBuilder buffy = new StringBuilder();
for (String string : list) {
buffy.append(string).append(' ');
}
//
// Note: this method is crossing a bridge from one hierarchy to another. The values
// in the other type are not a one-to-one match, as is the case when copying
// into variables in this class's type hierarchy. So, we just add values to this
// method as we find them.
//
String storage = buffy.toString().trim();
destination.setStorageClass(storage.isEmpty() ? null : storage);
destination.setStatic(source.isStatic());
destination.setVisibilty(source.getAccess());
// TODO merge the hierarchies!! so that we don't have to different signature generation
// and this method becomes like the one above.
if (source.isStruct) {
destination.setStruct();
}
if (source.isUnsigned) {
destination.setUnsigned();
}
}
public int getPointerLevels() {
return pointerLevels;
}
public void setPointerLevels(int levels) {
this.pointerLevels = levels;
}
public void incrementPointerLevels() {
pointerLevels++;
}
public void setAccess(String access) {
this.access = access;
}
public String getAccess() {
return access;
}
public void setStatic() {
isStatic = true;
}
public boolean isStatic() {
return isStatic;
}
public void setArray() {
isArray = true;
}
public void setClass() {
isClass = true;
}
public void setComplex() {
isComplex = true;
}
public void setEnum() {
isEnum = true;
}
public void setPointer64() {
isPointer64 = true;
}
public void setReference() {
isReference = true;
}
public void setSigned() {
isSigned = true;
}
public void setStruct() {
isStruct = true;
}
public void setTemplate() {
isTemplate = true;
}
public void setUnion() {
isUnion = true;
}
public void setCoclass() {
isCoclass = true;
}
public void setCointerface() {
isCointerface = true;
}
public void setUnsigned() {
isUnsigned = true;
}
public void setUnaligned() {
isUnaligned = true;
}
public boolean isUnaligned() {
return isUnaligned;
}
public void setVarArgs() {
isVarArgs = true;
}
@Override
public void setVolatile() {
isVolatile = true;
}
public void setFar() {
isFar = true;
}
public boolean isFar() {
return isFar;
}
public void setRestrict() {
isRestrict = true;
}
public boolean isRestrict() {
return isRestrict;
}
public boolean isArray() {
return isArray;
}
public boolean isClass() {
return isClass;
}
public boolean isComplex() {
return isComplex;
}
public boolean isEnum() {
return isEnum;
}
public boolean isPointer() {
return pointerLevels > 0;
}
public boolean isPointer64() {
return isPointer64;
}
public boolean isReference() {
return isReference;
}
public boolean isSigned() {
return isSigned;
}
public boolean isStruct() {
return isStruct;
}
public boolean isTemplate() {
return isTemplate;
}
public boolean isUnion() {
return isUnion;
}
public boolean isCoclass() {
return isCoclass;
}
public boolean isCointerface() {
return isCointerface;
}
public boolean isUnsigned() {
return isUnsigned;
}
public boolean isVarArgs() {
return isVarArgs;
}
public boolean isVoid() {
return VOID.equals(getName());
}
@Override
public boolean isVolatile() {
return isVolatile;
}
public String getBasedName() {
return basedAttribute;
}
public void setBasedName(String basedName) {
this.basedAttribute = basedName;
}
public String getMemberScope() {
return memberScope;
}
public void setMemberScope(String memberScope) {
this.memberScope = memberScope;
}
public boolean isPrimitive() {
boolean isPrimitiveDT =
!(isArray || isClass || isComplex || isEnum || isPointer() || isPointer64 || isSigned ||
isTemplate || isUnion || isCoclass || isCointerface || isVarArgs || isVolatile);
if (isPrimitiveDT) {
for (String primitiveNames : PRIMITIVES) {
if (getName().equals(primitiveNames)) {
return true;
}
}
}
return false;
}
@Override
public String toSignature() {
StringBuffer buffer = new StringBuffer();
if (access != null) {
buffer.append(access).append(SPACE);
}
if (isStatic) {
buffer.append(STATIC).append(SPACE);
}
if (isUnion) {
buffer.append(UNION).append(SPACE);
}
if (isStruct) {
buffer.append(STRUCT).append(SPACE);
}
if (isEnum) {
buffer.append(ENUM).append(SPACE);
}
if (isClass) {
buffer.append(CLASS).append(SPACE);
}
if (isCoclass) {
buffer.append(COCLASS).append(SPACE);
}
if (isCointerface) {
buffer.append(COINTERFACE).append(SPACE);
}
if (isComplex) {
buffer.append(COMPLEX).append(SPACE);
}
if (isSigned) {
buffer.append(SIGNED).append(SPACE);
}
if (isUnsigned) {
buffer.append(UNSIGNED).append(SPACE);
}
if (getNamespace() != null) {
buffer.append(getNamespace().toNamespace());
}
String space = "";
if (getName() != null) {
buffer.append(getName());
space = String.valueOf(SPACE);
}
if (getTemplate() != null) {
buffer.append(getTemplate().toTemplate());
space = String.valueOf(SPACE);
}
if (isConst()) {
buffer.append(space).append(CONST);
space = String.valueOf(SPACE);
}
if (isVolatile()) {
buffer.append(space).append(VOLATILE);
space = String.valueOf(SPACE);
}
if (isUnaligned) {
buffer.append(space).append(UNALIGNED);
space = String.valueOf(SPACE);
}
if (isFar) {
buffer.append(space).append(FAR);
space = String.valueOf(SPACE);
}
if (isRestrict) {
buffer.append(space).append(RESTRICT);
space = String.valueOf(SPACE);
}
boolean hasPointers = pointerLevels >= 1;
if (hasPointers) {
buffer.append(space + PTR_NOTATION);
space = String.valueOf(SPACE);
}
if (isReference) {
// ugly, but MS does this
if (isConst() && hasPointers) {
buffer.append(space).append(CONST);
space = String.valueOf(SPACE);
}
if (isVolatile() && hasPointers) {
buffer.append(space).append(VOLATILE);
space = String.valueOf(SPACE);
}
buffer.append(space).append(REF_NOTATION);
space = String.valueOf(SPACE);
}
if (isPointer64) {
buffer.append(space).append(PTR64);
space = String.valueOf(SPACE);
}
for (int i = 1; i < pointerLevels; i++) {
// ugly, but MS does this
if (isConst()) {
buffer.append(space).append(CONST);
space = String.valueOf(SPACE);
}
if (isVolatile()) {
buffer.append(space).append(VOLATILE);
space = String.valueOf(SPACE);
}
buffer.append(space).append(PTR_NOTATION);
space = String.valueOf(SPACE);
// ugly, but MS does this
if (isPointer64) {
buffer.append(space).append(PTR64);
space = String.valueOf(SPACE);
}
}
if (isArray) {
Matcher matcher = ARRAY_SUBSCRIPT_PATTERN.matcher(getName());
if (!matcher.find()) {
// only put subscript on if the name doesn't have it
buffer.append(ARR_NOTATION);
}
}
return buffer.toString();
}
@Override
public String toString() {
return toSignature();
}
}

View File

@ -1,64 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 util.demangler;
/**
* A class to handle exceptions that occur demangling.
*/
public class GenericDemangledException extends Exception {
private boolean invalidMangledName;
/**
* Use this constructor to indicate a demangler exception
* due to an exception thrown during the demangling process.
* @param cause the exception thrown during the demangling process
*/
public GenericDemangledException(Exception cause) {
super(cause);
}
/**
* Use this constructor to indicate a demangler exception
* due to some general invalid or unsupported mangled string
* characteristic. For example, unrecognized datatype.
* @param message the invalid or unsupported mangled message
*/
public GenericDemangledException(String message) {
super(message);
}
/**
* Use this constructor to indicate the demangler failed
* because the string to demangle does not appear to represent
* a valid mangled name.
* @param invalidMangledName true to indicate the string to
* demangle does not appear to represent a valid mangled name
*/
public GenericDemangledException(boolean invalidMangledName) {
this.invalidMangledName = invalidMangledName;
}
/**
* Returns true if the string to demangle does not appear to represent
* a valid mangled name
* @return true if the string to demangle does not appear to represent
* a valid mangled name
*/
public boolean isInvalidMangledName() {
return invalidMangledName;
}
}

View File

@ -1,241 +0,0 @@
/* ###
* 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 util.demangler;
import java.util.*;
/**
* A class to represent a demangled function.
*/
public class GenericDemangledFunction extends GenericDemangledObject implements ParameterReceiver {
protected GenericDemangledDataType returnType;
protected String callingConvention;// __cdecl, __thiscall, etc.
protected boolean thisPassedOnStack = true;
protected List<GenericDemangledDataType> parameterList =
new ArrayList<GenericDemangledDataType>();
protected GenericDemangledTemplate template;
protected boolean isOverloadedOperator = false;
private boolean virtual = false;
/** Special constructor where it has a templated type before the parameter list */
private String templatedConstructorType;
/**
* Constructs a new demangled function.
* @param name the name of the function
*/
public GenericDemangledFunction(String name) throws GenericDemangledException {
if (name == null) {
throw new GenericDemangledException(
"Function name cannot be null; failed to parse mangled name properly");
}
this.name = name;
}
/**
* Sets the function return type.
* @param returnType the function return type
*/
public void setReturnType(GenericDemangledDataType returnType) {
this.returnType = returnType;
}
/**
* Sets the function calling convention. For example, "__cdecl".
* @param callingConvention the function calling convention
*/
public void setCallingConvention(String callingConvention) {
this.callingConvention = callingConvention;
}
/**
* 'this' is passed on the stack or false if in a register
*
*/
public void setThisPassedOnStack(boolean thisPassedOnStack) {
this.thisPassedOnStack = thisPassedOnStack;
}
public boolean isPassedOnStack() {
return thisPassedOnStack;
}
public void setTemplate(GenericDemangledTemplate template) {
this.template = template;
}
public GenericDemangledTemplate getTemplate() {
return template;
}
public void setVirtual() {
this.virtual = true;
}
public boolean isVirtual() {
return virtual;
}
/**
* Sets whether this demangled function represents
* an overloaded operator. For example, "operator+()".
* @param isOverloadedOperator true if overloaded operator
*/
public void setOverloadedOperator(boolean isOverloadedOperator) {
this.isOverloadedOperator = isOverloadedOperator;
}
public boolean isOverloadedOperator() {
return isOverloadedOperator;
}
/**
* @see ghidra.app.util.demangler.ParameterReceiver
*/
@Override
public void addParameter(GenericDemangledDataType parameter) {
parameterList.add(parameter);
}
/**
* @see ghidra.app.util.demangler.ParameterReceiver
*/
@Override
public List<GenericDemangledDataType> getParameters() {
return new ArrayList<GenericDemangledDataType>(parameterList);
}
/**
* Returns the return type or null, if unspecified.
* @return the return type or null, if unspecified
*/
public GenericDemangledDataType getReturnType() {
return returnType;
}
/**
* Returns the calling convention or null, if unspecified.
* @return the calling convention or null, if unspecified
*/
public String getCallingConvention() {
return callingConvention;
}
/** Special constructor where it has a templated type before the parameter list */
public void setTemplatedConstructorType(String type) {
this.templatedConstructorType = type;
}
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
if (!(returnType instanceof GenericDemangledFunctionPointer)) {
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
buffer.append(visibility == null || "global".equals(visibility) ? "" : visibility + " ");
if (isStatic()) {
buffer.append("static ");
}
if (virtual) {
buffer.append("virtual ");
}
buffer.append(returnType == null ? "" : returnType.toSignature() + " ");
}
buffer.append(callingConvention == null ? "" : callingConvention + " ");
if (namespace != null) {
buffer.append(namespace.toNamespace());
}
buffer.append(name);
if (template != null) {
buffer.append(template.toTemplate());
}
if (specialMidfix != null) {
buffer.append('[').append(specialMidfix).append(']');
}
// check for special case of 'conversion operator' where we only want to display '()' and
// not (void)
if (name.endsWith("()")) {
if (name.equals("operator")) {
buffer.append("()");
}
}
else {
if (templatedConstructorType != null) {
buffer.append('<').append(templatedConstructorType).append('>');
}
Iterator<GenericDemangledDataType> paramIterator = parameterList.iterator();
buffer.append('(');
String pad = format ? pad(buffer.length()) : "";
if (!paramIterator.hasNext()) {
buffer.append("void");
}
while (paramIterator.hasNext()) {
buffer.append(paramIterator.next().toSignature());
if (paramIterator.hasNext()) {
buffer.append(',');
if (format) {
buffer.append('\n');
}
buffer.append(pad);
}
}
buffer.append(')');
buffer.append(storageClass == null ? "" : " " + storageClass);
}
if (returnType instanceof GenericDemangledFunctionPointer) {
GenericDemangledFunctionPointer funcPtr = (GenericDemangledFunctionPointer) returnType;
String partialSig = funcPtr.toSignature(buffer.toString());
buffer = new StringBuffer();
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
buffer.append(visibility == null || "global".equals(visibility) ? "" : visibility + " ");
if (virtual) {
buffer.append("virtual ");
}
buffer.append(partialSig);
}
else {
if (specialSuffix != null) {
buffer.append(specialSuffix);
}
}
return buffer.toString();
}
public String getParameterString() {
StringBuffer buffer = new StringBuffer();
buffer.append('(');
Iterator<GenericDemangledDataType> dditer = parameterList.iterator();
while (dditer.hasNext()) {
buffer.append(dditer.next().toSignature());
if (dditer.hasNext()) {
buffer.append(',');
}
}
buffer.append(')');
return buffer.toString();
}
}

View File

@ -1,273 +0,0 @@
/* ###
* 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 util.demangler;
import java.util.ArrayList;
import java.util.List;
/**
* A class to represent a demangled function pointer.
*/
public class GenericDemangledFunctionPointer extends GenericDemangledDataType
implements ParameterReceiver {
private static final String DEFAULT_NAME_PREFIX = "FuncDef";
private static final String EMPTY_STRING = "";
private static final Object NAMESPACE_DELIMITER = "::";
private static int ID = 0;
private GenericDemangledDataType returnType;
protected String callingConvention;// __cdecl, __thiscall, etc.
private List<GenericDemangledDataType> parameters = new ArrayList<>();
private boolean isConstPointer;
private String parentName;
private boolean isTrailingPointer64;
/**
* Constructs a new demangled function pointer.
*/
public GenericDemangledFunctionPointer() {
super(DEFAULT_NAME_PREFIX + nextID());
}
/**
* Returns the return type.
* @return the return type
*/
public GenericDemangledDataType getReturnType() {
return returnType;
}
/**
* Sets the return type.
* @param returnType the return type
*/
public void setReturnType(GenericDemangledDataType 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;
}
/**
* Adds a parameters to the end of the parameter list for
* this demangled function.
* @param parameter the new parameter to add
*/
@Override
public void addParameter(GenericDemangledDataType parameter) {
parameters.add(parameter);
}
/**
* Returns a list of the parameters for this demangled functions.
* @return a list of the parameters for this demangled functions
*/
@Override
public List<GenericDemangledDataType> getParameters() {
return new ArrayList<>(parameters);
}
@Override
public GenericDemangledDataType copy() {
GenericDemangledFunctionPointer copy = new GenericDemangledFunctionPointer();
copyInto(copy);
return copy;
}
@Override
public void copyInto(GenericDemangledDataType destination) {
super.copyInto(destination);
GenericDemangledFunctionPointer source = this;
if (destination instanceof GenericDemangledFunctionPointer) {
GenericDemangledFunctionPointer copySource = source;
GenericDemangledFunctionPointer copyDestination =
(GenericDemangledFunctionPointer) destination;
if (copySource.returnType != null) {
copyDestination.returnType = copySource.returnType.copy();
}
for (GenericDemangledDataType parameter : copySource.parameters) {
copyDestination.parameters.add(parameter.copy());
}
copyDestination.callingConvention = copySource.callingConvention;
copyDestination.isConstPointer |= copySource.isConstPointer;
}
}
@Override
public String toSignature() {
return toSignature(null);
}
public String toSignature(String name) {
StringBuffer buffer = new StringBuffer();
if (returnType != null) {
buffer.append(returnType.toSignature()).append(SPACE);
}
String s = getConventionPointerNameString(name);
if (s.contains(" ") || s.isEmpty()) {
// spaces--add parens
buffer.append('(').append(s).append(')');
}
else {// this allows the '__cdecl' in templates to not have parens
buffer.append(s);
}
buffer.append('(');
for (int i = 0; i < parameters.size(); ++i) {
buffer.append(parameters.get(i).toSignature());
if (i < parameters.size() - 1) {
buffer.append(',');
}
}
buffer.append(')');
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 (isTrailingPointer64) {
if (buffer.length() > 2) {
buffer.append(SPACE);
}
buffer.append(PTR64);
}
return buffer.toString();
}
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 (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);
}
public void setConstPointer() {
isConstPointer = true;
}
public boolean isConstPointer() {
return isConstPointer;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
public String getParentName() {
return parentName;
}
public void setTrailingPointer64() {
this.isTrailingPointer64 = true;// TODO get real construct name for this method/field
}
public boolean isTrailingPointer64() {
return isTrailingPointer64;
}
public void clearPointer64() {
this.isPointer64 = false;
}
private synchronized static int nextID() {
return ID++;
}
public int getID() {
return ID;
}
}

View File

@ -1,263 +0,0 @@
/* ###
* 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 util.demangler;
/**
* A class to represent a demangled object.
*/
public abstract class GenericDemangledObject {
protected static final String NAMESPACE_SEPARATOR = "::";
protected static final String AT = "@";
protected static final String EMPTY_STRING = "";
protected static final String SPACE = " ";
protected String originalMangled;
protected String specialPrefix;
protected String specialMidfix;
protected String specialSuffix;
protected GenericDemangledType namespace;
protected String visibility;//public, protected, etc.
protected String storageClass;//const, volatile, etc
protected String name;
protected boolean isConst;
protected boolean isVolatile;
protected boolean isStatic;
protected boolean isVirtual;
protected boolean isThunk;
protected boolean isPointer64;
// temp
protected boolean isStruct;
protected boolean isUnsigned;
protected boolean isUnaligned;
protected boolean isRestrict;
protected String basedName;
protected String memberScope;
private String signature;
/**
* Returns the name of the demangled object.
* @return the name of the demangled object
*/
public String getName() {
return name;
}
public boolean isConst() {
return isConst;
}
public void setConst(boolean isConst) {
this.isConst = isConst;
}
public boolean isVolatile() {
return isVolatile;
}
public void setVolatile(boolean isVolatile) {
this.isVolatile = isVolatile;
}
public boolean isStatic() {
return isStatic;
}
public void setStatic(boolean isStatic) {
this.isStatic = isStatic;
}
public boolean isVirtual() {
return isVirtual;
}
public void setVirtual(boolean isVirtual) {
this.isVirtual = isVirtual;
}
public boolean isThunk() {
return isThunk;
}
public void setThunk(boolean isThunk) {
this.isThunk = isThunk;
}
public boolean isPointer64() {
return isPointer64;
}
public void setPointer64(boolean isPointer64) {
this.isPointer64 = isPointer64;
}
public void setUnsigned() {
isUnsigned = true;
}
public void setStruct() {
isStruct = true;
}
public void setUnaligned() {
isUnaligned = true;
}
public boolean isUnaligned() {
return isUnaligned;
}
public void setRestrict() {
isRestrict = true;
}
public boolean isRestrict() {
return isRestrict;
}
public String getBasedName() {
return basedName;
}
public void setBasedName(String basedName) {
this.basedName = basedName;
}
public String getMemberScope() {
return memberScope;
}
public void setMemberScope(String memberScope) {
this.memberScope = memberScope;
}
/**
* Sets the name of the demangled object
* @param name the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Sets the original mangled name
* @param mangled the original mangled name
*/
public void setOriginalMangled(String mangled) {
this.originalMangled = mangled;
}
public String getOriginalMangled() {
return originalMangled;
}
/**
* Returns the namespace containing this demangled object.
* @return the namespace containing this demangled object
*/
public GenericDemangledType getNamespace() {
return namespace;
}
/**
*
* @param namespace
*/
public void setNamespace(GenericDemangledType namespace) {
this.namespace = namespace;
}
public String getVisibility() {
return visibility;
}
public void setVisibilty(String visibility) {
this.visibility = visibility;
}
public String getStorageClass() {
return storageClass;
}
public void setStorageClass(String storageClass) {
this.storageClass = storageClass;
}
public String getSpecialPrefix() {
return specialPrefix;
}
public void setSpecialPrefix(String special) {
this.specialPrefix = special;
}
public String getSpecialMidfix() {
return specialMidfix;
}
public void setSpecialMidfix(String chargeType) {
this.specialMidfix = chargeType;
}
public String getSpecialSuffix() {
return specialSuffix;
}
public void setSpecialSuffix(String specialSuffix) {
this.specialSuffix = specialSuffix;
}
/**
* Returns a complete signature for the demangled symbol.
* <br>For example:
* {@code "unsigned long foo"
* "unsigned char * ClassA::getFoo(float, short *)"
* "void * getBar(int **, MyStruct &)"}
* <br><b>Note: based on the underlying mangling scheme, the
* return type may or may not be specified in the signature.</b>
* @param format true if signature should be pretty printed
* @return a complete signature for the demangled symbol
*/
public abstract String getSignature(boolean format);
/**
* Sets the signature. Calling this method will
* override the auto-generated signature.
* @param signature the signature
*/
public void setSignature(String signature) {
this.signature = signature;
}
@Override
public String toString() {
return getSignature(false);
}
protected String generatePlateComment() {
return (signature == null) ? getSignature(true) : signature;
}
protected String pad(int len) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < len; i++) {
buffer.append(' ');
}
return buffer.toString();
}
}

View File

@ -1,66 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 util.demangler;
public class GenericDemangledString extends GenericDemangledObject {
private String string;
private int length;
private boolean unicode;
public GenericDemangledString(String string, int length, boolean unicode) {
this.string = string;
this.length = length;
this.unicode = unicode;
}
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
if (specialPrefix != null) {
buffer.append(specialPrefix + " for ");
}
buffer.append(string);
if (specialSuffix != null) {
buffer.append(" " + specialSuffix);
}
return buffer.toString();
}
/**
* Returns the demangled string.
* @return the demangled string
*/
public String getString() {
return string;
}
/**
* Returns the length in bytes of the demangled string.
* @return the length in bytes of the demangled string
*/
public int getLength() {
return length;
}
/**
* Returns true if the demangled string is unicode.
* @return true if the demangled string is unicode
*/
public boolean isUnicode() {
return unicode;
}
}

View File

@ -1,55 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 util.demangler;
import java.util.ArrayList;
import java.util.List;
public class GenericDemangledTemplate implements ParameterReceiver {
private List<GenericDemangledDataType> parameters = new ArrayList<GenericDemangledDataType>();
public GenericDemangledTemplate() {
}
@Override
public void addParameter(GenericDemangledDataType parameter) {
parameters.add(parameter);
}
@Override
public List<GenericDemangledDataType> getParameters() {
return new ArrayList<GenericDemangledDataType>(parameters);
}
public String toTemplate() {
StringBuffer buffer = new StringBuffer();
buffer.append('<');
for (int i = 0; i < parameters.size(); ++i) {
buffer.append(parameters.get(i).toSignature());
if (i < parameters.size() - 1) {
buffer.append(',');
}
}
buffer.append('>');
return buffer.toString();
}
@Override
public String toString() {
return toTemplate();
}
}

View File

@ -1,101 +0,0 @@
/* ###
* 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 util.demangler;
public class GenericDemangledType {
private GenericDemangledType namespace;
private String name;
private GenericDemangledTemplate template;
private boolean isConst;
private boolean isVolatile;
public GenericDemangledType(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isConst() {
return isConst;
}
public void setConst() {
isConst = true;
}
public boolean isVolatile() {
return isVolatile;
}
public void setVolatile() {
isVolatile = true;
}
public GenericDemangledType getNamespace() {
return namespace;
}
public void setNamespace(GenericDemangledType namespace) {
if (this == namespace) {
throw new IllegalArgumentException("Attempt to set this.namespace == this!");
}
this.namespace = namespace;
}
public GenericDemangledTemplate getTemplate() {
return template;
}
public void setTemplate(GenericDemangledTemplate template) {
this.template = template;
}
public String toSignature() {
StringBuffer buffer = new StringBuffer();
if (namespace != null) {
buffer.append(namespace.toNamespace());
}
buffer.append(name);
if (template != null) {
buffer.append(template.toTemplate());
}
return buffer.toString();
}
public String toNamespace() {
StringBuffer buffer = new StringBuffer();
if (namespace != null) {
buffer.append(namespace.toNamespace());
}
buffer.append(name);
if (template != null) {
buffer.append(template.toTemplate());
}
buffer.append("::");
return buffer.toString();
}
@Override
public String toString() {
return toSignature();
}
}

View File

@ -1,116 +0,0 @@
/* ###
* 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 util.demangler;
/**
* An interface to represent a demangled global variable.
*/
public class GenericDemangledVariable extends GenericDemangledObject {
private GenericDemangledDataType datatype;
public GenericDemangledVariable(String name) {
this.name = name;
}
public void setDatatype(GenericDemangledDataType datatype) {
this.datatype = datatype;
}
/**
* Returns the data type of this variable.
* @return the data type of this variable
*/
public GenericDemangledDataType getDataType() {
return datatype;
}
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
buffer.append(visibility == null || "global".equals(visibility) ? EMPTY_STRING
: visibility + SPACE);
if (isStatic()) {
buffer.append("static ");
}
String spacer = EMPTY_STRING;
if (isUnsigned) {
buffer.append("unsigned");
spacer = SPACE;
}
if (isStruct) {
buffer.append("struct");
spacer = SPACE;
}
if (specialPrefix != null) {
buffer.append(specialPrefix);
spacer = SPACE;
}
boolean hasName = (name != null) && !name.isEmpty();
if (!(datatype instanceof GenericDemangledFunctionPointer)) {
if (datatype != null) {
buffer.append(spacer);
buffer.append(datatype.toSignature());
spacer = SPACE;
}
}
// e.g., 'const' - this appears after the data type in MS land
if (storageClass != null) {
buffer.append(spacer).append(storageClass);
spacer = SPACE;
}
if (namespace != null) {
buffer.append(spacer);
spacer = EMPTY_STRING;
buffer.append(namespace.toNamespace());
if (!hasName) {
int end = buffer.length();
buffer.delete(end - 2, end); // strip off the last namespace characters
}
}
if (hasName) {
buffer.append(spacer);
spacer = EMPTY_STRING;
buffer.append(name);
}
buffer.append(specialMidfix == null ? EMPTY_STRING : specialMidfix + SPACE);
buffer.append(specialSuffix == null ? EMPTY_STRING : SPACE + specialSuffix);
if (datatype instanceof GenericDemangledFunctionPointer) {
GenericDemangledFunctionPointer funcPtr = (GenericDemangledFunctionPointer) datatype;
return funcPtr.toSignature(buffer.toString());
}
if (isConst()) {
buffer.append(" const");
}
return buffer.toString().trim();
}
}

View File

@ -1,37 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 util.demangler;
import java.util.List;
/**
* A generic interface to represent
* object that support parameters.
*/
public interface ParameterReceiver {
/**
* Adds the specified parameter to this object.
* @param parameter the parameter to add
*/
public void addParameter(GenericDemangledDataType parameter);
/**
* Returns the parameters added to this object.
* @return the parameters added to this object
*/
public List<GenericDemangledDataType> getParameters();
}

View File

@ -15,29 +15,78 @@
*/
package docking.test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Window;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import javax.swing.*;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.*;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import docking.*;
import docking.ActionContext;
import docking.ComponentPlaceholder;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import docking.DockableComponent;
import docking.DockingDialog;
import docking.DockingErrorDisplay;
import docking.DockingWindowManager;
import docking.EmptyBorderToggleButton;
import docking.Tool;
import docking.action.DockingActionIf;
import docking.action.ToggleDockingActionIf;
import docking.actions.DockingToolActions;
@ -55,7 +104,9 @@ import generic.test.ConcurrentTestExceptionHandler;
import generic.util.image.ImageUtils;
import ghidra.GhidraTestApplicationLayout;
import ghidra.framework.ApplicationConfiguration;
import ghidra.util.*;
import ghidra.util.ConsoleErrorDisplay;
import ghidra.util.ErrorDisplay;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.task.SwingUpdateManager;
import ghidra.util.worker.Worker;
@ -217,25 +268,9 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
}
public static Window waitForWindowByTitleContaining(String text) {
return waitForWindowByTitleContaining(null, text, DEFAULT_WAIT_TIMEOUT);
}
/**
* Deprecated
* @param parentWindow the window; unused
* @param text the window title text part
* @param timeoutMS the timeout; unused
* @return window
* @deprecated Instead call one of the methods that does not take a timeout
* (we are standardizing timeouts). The timeouts passed to this method will
* be ignored in favor of the standard value.
*/
@Deprecated
public static Window waitForWindowByTitleContaining(Window parentWindow, String text,
int timeoutMS) {
// try at least one time
Window window = getWindowByTitleContaining(parentWindow, text);
Window window = getWindowByTitleContaining(null, text);
if (window != null) {
return window;// we found it...no waiting required
}
@ -244,7 +279,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
int timeout = DEFAULT_WAIT_TIMEOUT;
while (totalTime <= timeout) {
window = getWindowByTitleContaining(parentWindow, text);
window = getWindowByTitleContaining(null, text);
if (window != null) {
return window;
}
@ -256,43 +291,6 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
"Timed-out waiting for window containg title '" + text + "'");
}
/**
* Waits for a window with the given name. If <code>parentWindow</code> is not null, then it
* will be used to find subordinate windows. If <code>parentWindow</code> is null, then all
* existing frames will be searched.
*
* @param parentWindow The parent of the window for which to search, or null to search all
* open frames
* @param title The title of the window for which to search
* @param timeoutMS The timeout after which this method will wait no more
* @return The window, if found, null otherwise.
*
* @deprecated Instead call one of the methods that does not take a timeout
* (we are standardizing timeouts). The timeouts passed to this method will
* be ignored in favor of the standard value.
*/
@Deprecated
public static Window waitForWindow(Window parentWindow, String title, int timeoutMS) {
Window window = getWindowByTitle(parentWindow, title);
if (window != null) {
return window;// we found it...no waiting required
}
int totalTime = 0;
int timeout = DEFAULT_WAIT_TIMEOUT;
while (totalTime <= timeout) {
window = getWindowByTitle(parentWindow, title);
if (window != null) {
return window;
}
totalTime += sleep(DEFAULT_WAIT_DELAY);
}
throw new AssertionFailedError("Timed-out waiting for window with title '" + title + "'");
}
/**
* Waits for a window with the given name.
*
@ -1134,9 +1132,8 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
public static Set<DockingActionIf> getActionsByOwnerAndName(Tool tool, String owner,
String name) {
Set<DockingActionIf> ownerActions = tool.getDockingActionsByOwnerName(owner);
return ownerActions.stream()
.filter(action -> action.getName().equals(name))
.collect(Collectors.toSet());
return ownerActions.stream().filter(action -> action.getName().equals(name)).collect(
Collectors.toSet());
}
/**
@ -1840,25 +1837,6 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
useErrorGUI = enable;
}
/**
* Signals that the client expected the System Under Test (SUT) to report errors. Use this
* when you wish to verify that errors are reported and you do not want those errors to
* fail the test. The default value for this setting is false, which means that any
* errors reported will fail the running test.
*
* @param expected true if errors are expected.
*/
public static void setErrorsExpected(boolean expected) {
if (expected) {
Msg.error(AbstractDockingTest.class, ">>>>>>>>>>>>>>>> Expected Exception");
ConcurrentTestExceptionHandler.disable();
}
else {
Msg.error(AbstractDockingTest.class, "<<<<<<<<<<<<<<<< End Expected Exception");
ConcurrentTestExceptionHandler.enable();
}
}
/**
* Turns off the gui displays for errors. This does not change the "isUseErrorGUI()" value for
* other tests in the TestCase.

View File

@ -248,8 +248,9 @@ public abstract class AbstractGenericTest extends AbstractGTest {
*/
public static Set<Window> getAllWindows() {
Set<Window> set = new HashSet<>();
Frame sharedOwnerFrame = (Frame) AppContext.getAppContext().get(
new StringBuffer("SwingUtilities.sharedOwnerFrame"));
Frame sharedOwnerFrame = (Frame) AppContext.getAppContext()
.get(
new StringBuffer("SwingUtilities.sharedOwnerFrame"));
if (sharedOwnerFrame != null) {
set.addAll(getAllWindows(sharedOwnerFrame));
}
@ -1515,6 +1516,29 @@ public abstract class AbstractGenericTest extends AbstractGTest {
UIManager.put("TextArea.font", f);
}
/**
* Signals that the client expected the System Under Test (SUT) to report errors. Use this
* when you wish to verify that errors are reported and you do not want those errors to
* fail the test. The default value for this setting is false, which means that any
* errors reported will fail the running test.
*
* @param expected true if errors are expected.
*/
public static void setErrorsExpected(boolean expected) {
if (expected) {
Msg.error(AbstractGenericTest.class, ">>>>>>>>>>>>>>>> Expected Exception");
ConcurrentTestExceptionHandler.disable();
}
else {
Msg.error(AbstractGenericTest.class, "<<<<<<<<<<<<<<<< End Expected Exception");
ConcurrentTestExceptionHandler.enable();
}
}
//==================================================================================================
// Swing Methods
//==================================================================================================
/**
* Waits for the Swing thread to process any pending events. This method
* also waits for any {@link SwingUpdateManager}s that have pending events

View File

@ -15,7 +15,7 @@
*/
package help.screenshot;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import java.awt.*;
import java.awt.event.ActionListener;
@ -148,7 +148,7 @@ public class CodeBrowserPluginScreenShots extends GhidraScreenShotGenerator {
makeSelection(0x0406be1, 0x0406bf1);
performAction("Create Table From Selection", "CodeBrowserPlugin", true);
Window window = waitForWindowByTitleContaining(null, "Selection Table", 2000);
Window window = waitForWindowByTitleContaining("Selection Table");
Point loc = plugin.getListingPanel().getLocationOnScreen();
Dimension size = window.getSize();
window.setBounds(loc.x + 300, loc.y + 150, size.width, 300);
@ -240,7 +240,7 @@ public class CodeBrowserPluginScreenShots extends GhidraScreenShotGenerator {
JWindow popup = (JWindow) waitForWindowByName("ListingHoverProvider");
paintFix(popup);
captureProvider(CodeViewerProvider.class);
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
captureProviderWithScreenShot(provider);
}

View File

@ -142,7 +142,7 @@ public class NavigationScreenShots extends GhidraScreenShotGenerator {
setGotoText(dialog, "LAB*");
pressOkOnDialog();
Window window =
waitForWindowByTitleContaining(null, "Search Limit Exceeded!", DEFAULT_WINDOW_TIMEOUT);
waitForWindowByTitleContaining("Search Limit Exceeded!");
assertNotNull(window);
pressButtonByText(window, "OK");
waitForSwing();

View File

@ -51,7 +51,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
program.endTransaction(txID, 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.
* This test applies a demangled name where the mangled name does NOT exist.
@ -83,7 +83,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
assertEquals("ATL", ns.getName(false));
}
/**
/*
* Test that the DemangledFunction will properly update a thunk function
* with its namespace, and ripple through to the underlying default thunked
* function. The thunk 'this' parameter should utilize the Class
@ -132,7 +132,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
}
/**
/*
* 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.
* This test applies a demangled name where the mangled name exists.
@ -168,7 +168,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
assertEquals("ATL", 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.
* This test applies a demangled name where the mangled name exists with address suffix.
@ -205,7 +205,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
assertEquals("ATL", 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.
* This test applies a demangled name where both the mangled name exists and
@ -243,7 +243,51 @@ 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.
* This test applies a demangled name where the mangled name exists on an external
@ -339,15 +383,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
private void assertSimpleNamespaceExists(String name) {
SymbolTable symbolTable = program.getSymbolTable();
Namespace ns = symbolTable.getNamespace(name, program.getGlobalNamespace());
assertNotNull(ns);
assertNotNull("Namespace not created: " + name, ns);
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) {

View File

@ -57,7 +57,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
String mangled = "MyFunction__11MyNamespacePQ215$ParamNamespace9paramName";
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization
demangler.canDemangle(program);// this performs initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);