mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-10 14:11:59 +00:00
Merge remote-tracking branch
'origin/GT-3545-dragonmacher-gnu-demangler-parsing-bugs' Fixes #1457 Fixes #1569
This commit is contained in:
commit
f1782a7629
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 "*";
|
||||
}
|
||||
}
|
||||
|
@ -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 "&";
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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 != ' ')) {
|
||||
|
@ -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(',');
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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) {
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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')
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
##VERSION: 2.0
|
||||
Module.manifest||GHIDRA||reviewed||END|
|
||||
build.gradle||GHIDRA||||END|
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user