mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch
'origin/GT-3545-dragonmacher-gnu-demangler-parsing-bugs' Fixes #1457 Fixes #1569
This commit is contained in:
commit
f1782a7629
59 changed files with 3255 additions and 7594 deletions
|
@ -24,7 +24,6 @@ dependencies {
|
||||||
compile project(':Graph')
|
compile project(':Graph')
|
||||||
compile project(':SoftwareModeling')
|
compile project(':SoftwareModeling')
|
||||||
compile project(':DB')
|
compile project(':DB')
|
||||||
compile project(':Demangler')
|
|
||||||
compile project(':Help')
|
compile project(':Help')
|
||||||
|
|
||||||
compileOnly "junit:junit:4.12"
|
compileOnly "junit:junit:4.12"
|
||||||
|
|
|
@ -233,7 +233,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
log.appendMsg(getName(),
|
log.appendMsg(getName(),
|
||||||
"Failed to apply mangled symbol at " + address + "; name: " +
|
"Failed to apply mangled symbol at " + address + "; name: " +
|
||||||
demangled.getMangledName() + failMessage);
|
demangled.getMangledString() + failMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String cleanSymbol(Address address, String name) {
|
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.program.model.symbol.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.demangler.GenericDemangledAddressTable;
|
|
||||||
|
|
||||||
public class DemangledAddressTable extends DemangledObject {
|
public class DemangledAddressTable extends DemangledObject {
|
||||||
|
|
||||||
|
private boolean calculateLength;
|
||||||
private int length;
|
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);
|
setName(name);
|
||||||
this.length = length;
|
this.calculateLength = calculateLength;
|
||||||
}
|
|
||||||
|
|
||||||
DemangledAddressTable(GenericDemangledAddressTable generic) {
|
|
||||||
super(generic);
|
|
||||||
|
|
||||||
length = generic.getLength();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +62,7 @@ public class DemangledAddressTable extends DemangledObject {
|
||||||
buffer.append(specialPrefix);
|
buffer.append(specialPrefix);
|
||||||
buffer.append(' ');
|
buffer.append(' ');
|
||||||
}
|
}
|
||||||
String namespaceStr = namespace.toSignature();
|
String namespaceStr = namespace.getNamespaceString();
|
||||||
buffer.append(namespaceStr);
|
buffer.append(namespaceStr);
|
||||||
if (!namespaceStr.endsWith(NAMESPACE_SEPARATOR)) {
|
if (!namespaceStr.endsWith(NAMESPACE_SEPARATOR)) {
|
||||||
buffer.append(NAMESPACE_SEPARATOR);
|
buffer.append(NAMESPACE_SEPARATOR);
|
||||||
|
@ -83,15 +88,16 @@ public class DemangledAddressTable extends DemangledObject {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Listing listing = program.getListing();
|
||||||
if (MemoryBlock.isExternalBlockAddress(address, program)) {
|
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");
|
"WARNING: Unable to apply demangled Address Table");
|
||||||
return true; // don't complain
|
return true; // don't complain
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == -1) {
|
if (calculateLength) {
|
||||||
// determine length of address table
|
// determine length of address table
|
||||||
Data d = program.getListing().getDefinedDataAt(address);
|
Data d = listing.getDefinedDataAt(address);
|
||||||
if (d != null && Undefined.isUndefinedArray(d.getDataType())) {
|
if (d != null && Undefined.isUndefinedArray(d.getDataType())) {
|
||||||
// use length of Undefined array at start of table to indicate length
|
// use length of Undefined array at start of table to indicate length
|
||||||
length = d.getLength();
|
length = d.getLength();
|
||||||
|
@ -102,6 +108,7 @@ public class DemangledAddressTable extends DemangledObject {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
calculateLength = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUndefinedInRange(program, address, address.add(length - 1))) {
|
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
|
* 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.
|
* 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
|
* @param address start of address table
|
||||||
* @return maximum length of table or -1 if address does not reside
|
* @return maximum length of table or -1 if address does not reside
|
||||||
* within an initialized memory block
|
* within an initialized memory block
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
package ghidra.app.util.demangler;
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.Enum;
|
import ghidra.program.model.data.Enum;
|
||||||
import util.demangler.*;
|
import ghidra.program.model.symbol.Namespace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to represent a demangled data type.
|
* 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 WCHAR_T = "wchar_t";
|
||||||
public final static String SHORT = "short";
|
public final static String SHORT = "short";
|
||||||
public final static String INT = "int";
|
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";
|
||||||
public final static String LONG_LONG = "long long";
|
public final static String LONG_LONG = "long long";
|
||||||
public final static String FLOAT = "float";
|
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 INT16 = "__int16";
|
||||||
public final static String INT32 = "__int32";
|
public final static String INT32 = "__int32";
|
||||||
public final static String INT64 = "__int64";
|
public final static String INT64 = "__int64";
|
||||||
public final static String INT128 = "__int128";//TODO
|
public final static String INT128 = "__int128";
|
||||||
public final static String FLOAT128 = "__float128";//TODO
|
public final static String FLOAT128 = "__float128";
|
||||||
public final static String LONG_DOUBLE = "long double";
|
public final static String LONG_DOUBLE = "long double";
|
||||||
public final static String PTR64 = "__ptr64";
|
public final static String PTR64 = "__ptr64";
|
||||||
public final static String STRING = "string";
|
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 UNALIGNED = "__unaligned";
|
||||||
public static final String RESTRICT = "__restrict";
|
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,
|
public final static String[] PRIMITIVES = { VOID, BOOL, CHAR, WCHAR_T, SHORT, INT, INT0_T, LONG,
|
||||||
LONG_LONG, FLOAT, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
|
LONG_LONG, FLOAT, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
|
||||||
|
|
||||||
|
@ -84,14 +90,13 @@ public class DemangledDataType extends DemangledType {
|
||||||
private boolean isEnum;
|
private boolean isEnum;
|
||||||
private boolean isPointer64;
|
private boolean isPointer64;
|
||||||
private boolean isReference;
|
private boolean isReference;
|
||||||
private boolean isSigned;//explicitly signed!
|
private boolean isSigned;
|
||||||
private boolean isStruct;
|
private boolean isStruct;
|
||||||
private boolean isTemplate;
|
private boolean isTemplate;
|
||||||
private boolean isUnaligned;
|
private boolean isUnaligned;
|
||||||
private boolean isUnion;
|
private boolean isUnion;
|
||||||
private boolean isUnsigned;
|
private boolean isUnsigned;
|
||||||
private boolean isVarArgs;
|
private boolean isVarArgs;
|
||||||
// private boolean isVolatile;
|
|
||||||
private int pointerLevels = 0;
|
private int pointerLevels = 0;
|
||||||
private String enumType;
|
private String enumType;
|
||||||
private boolean isRestrict;
|
private boolean isRestrict;
|
||||||
|
@ -100,101 +105,13 @@ public class DemangledDataType extends DemangledType {
|
||||||
private boolean isCoclass;
|
private boolean isCoclass;
|
||||||
private boolean isCointerface;
|
private boolean isCointerface;
|
||||||
|
|
||||||
/**
|
public DemangledDataType(String mangled, String originaDemangled, String name) {
|
||||||
* Constructs a new demangled datatype.
|
super(mangled, originaDemangled, name);
|
||||||
* @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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts this demangled datatype into the corresponding Ghidra datatype.
|
* Converts this demangled datatype into the corresponding Ghidra datatype
|
||||||
* @param dataTypeManager the data type manager to be searched and whose data organization
|
* @param dataTypeManager the manager to search and whose data organization should be used
|
||||||
* should be used
|
|
||||||
* @return the Ghidra datatype corresponding to the demangled datatype
|
* @return the Ghidra datatype corresponding to the demangled datatype
|
||||||
*/
|
*/
|
||||||
public DataType getDataType(DataTypeManager dataTypeManager) {
|
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||||
|
@ -210,11 +127,6 @@ public class DemangledDataType extends DemangledType {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dt == null) {
|
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);
|
dt = findDataType(dataTypeManager, namespace, name);
|
||||||
|
|
||||||
DataType baseType = dt;
|
DataType baseType = dt;
|
||||||
|
@ -235,25 +147,23 @@ public class DemangledDataType extends DemangledType {
|
||||||
}
|
}
|
||||||
else if (isEnum()) {
|
else if (isEnum()) {
|
||||||
if (baseType == null || !(baseType instanceof Enum)) {
|
if (baseType == null || !(baseType instanceof Enum)) {
|
||||||
// TODO: Can't tell how big an enum is,
|
|
||||||
// Just use the size of a pointer
|
if (enumType == null || INT.equals(enumType) || UNSIGNED_INT.equals(enumType)) {
|
||||||
// 20170522: Modified following code to allow "some" sizing from MSFT.
|
// Can't tell how big an enum is, just use the size of a pointer
|
||||||
if ((enumType == null) || "int".equals(enumType) ||
|
|
||||||
"unsigned int".equals(enumType)) {
|
|
||||||
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||||
dataTypeManager.getDataOrganization().getIntegerSize());
|
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,
|
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||||
dataTypeManager.getDataOrganization().getCharSize());
|
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,
|
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||||
dataTypeManager.getDataOrganization().getShortSize());
|
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,
|
dt = new EnumDataType(getDemanglerCategoryPath(name, getNamespace()), name,
|
||||||
dataTypeManager.getDataOrganization().getLongSize());
|
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)) {
|
if (baseType == null || !(baseType instanceof Structure)) {
|
||||||
// try creating empty structures for unknown types instead.
|
// try creating empty structures for unknown types instead.
|
||||||
dt = createPlaceHolderStructure(name, getNamespace());
|
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
|
// I don't know what this is
|
||||||
// If it isn't pointed to, or isn't a referent, then assume typedef.
|
// 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) {
|
private DataType getBuiltInType(DataTypeManager dataTypeManager) {
|
||||||
DataType dt = null;
|
DataType dt = null;
|
||||||
String name = getName();
|
String name = getDemangledName();
|
||||||
if (BOOL.equals(name)) {
|
if (BOOL.equals(name)) {
|
||||||
dt = BooleanDataType.dataType;
|
dt = BooleanDataType.dataType;
|
||||||
}
|
}
|
||||||
|
@ -351,6 +261,9 @@ public class DemangledDataType extends DemangledType {
|
||||||
else if (FLOAT.equals(name)) {
|
else if (FLOAT.equals(name)) {
|
||||||
dt = FloatDataType.dataType;
|
dt = FloatDataType.dataType;
|
||||||
}
|
}
|
||||||
|
else if (FLOAT128.equals(name)) {
|
||||||
|
dt = new TypedefDataType(FLOAT128, Float16DataType.dataType);
|
||||||
|
}
|
||||||
else if (DOUBLE.equals(name)) {
|
else if (DOUBLE.equals(name)) {
|
||||||
dt = DoubleDataType.dataType;
|
dt = DoubleDataType.dataType;
|
||||||
}
|
}
|
||||||
|
@ -397,6 +310,16 @@ public class DemangledDataType extends DemangledType {
|
||||||
AbstractIntegerDataType.getSignedDataType(8, dataTypeManager));
|
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)) {
|
else if (UNDEFINED.equals(name)) {
|
||||||
dt = DataType.DEFAULT;
|
dt = DataType.DEFAULT;
|
||||||
}
|
}
|
||||||
|
@ -408,49 +331,51 @@ public class DemangledDataType extends DemangledType {
|
||||||
* @param dataTypeManager data type manager to be searched
|
* @param dataTypeManager data type manager to be searched
|
||||||
* @param dtName name of data type
|
* @param dtName name of data type
|
||||||
* @param namespace namespace associated with dtName or null if not applicable. If specified,
|
* @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.
|
* @return data type if found, otherwise null.
|
||||||
* @see DataTypeUtilities#findDataType(DataTypeManager, ghidra.program.model.symbol.Namespace, String, Class) for similar namespace
|
* @see DataTypeUtilities#findDataType(DataTypeManager, ghidra.program.model.symbol.Namespace, String, Class) for similar namespace
|
||||||
* based search.
|
* based search.
|
||||||
*/
|
*/
|
||||||
static DataType findDataType(DataTypeManager dataTypeManager, DemangledType namespace,
|
static DataType findDataType(DataTypeManager dataTypeManager, Demangled namespace,
|
||||||
String dtName) {
|
String dtName) {
|
||||||
// TODO: Should be able to search archives somehow
|
|
||||||
ArrayList<DataType> list = new ArrayList<>();
|
List<DataType> list = new ArrayList<>();
|
||||||
dataTypeManager.findDataTypes(dtName, list);
|
dataTypeManager.findDataTypes(dtName, list);
|
||||||
if (!list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
//use the datatype that exists in the root category,
|
return null;
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
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) {
|
if (namespace == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
DemangledType ns = namespace;
|
|
||||||
|
Demangled ns = namespace;
|
||||||
CategoryPath categoryPath = dt.getCategoryPath();
|
CategoryPath categoryPath = dt.getCategoryPath();
|
||||||
while (ns != null) {
|
while (ns != null) {
|
||||||
if (categoryPath.equals(CategoryPath.ROOT) ||
|
if (categoryPath.equals(CategoryPath.ROOT) ||
|
||||||
|
@ -463,8 +388,8 @@ public class DemangledDataType extends DemangledType {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getNamespacePath(String dtName, DemangledType namespace) {
|
private static String getNamespacePath(String dtName, Demangled namespace) {
|
||||||
DemangledType ns = namespace;
|
Demangled ns = namespace;
|
||||||
String namespacePath = "";
|
String namespacePath = "";
|
||||||
while (ns != null) {
|
while (ns != null) {
|
||||||
namespacePath = "/" + ns.getName() + namespacePath;
|
namespacePath = "/" + ns.getName() + namespacePath;
|
||||||
|
@ -473,15 +398,14 @@ public class DemangledDataType extends DemangledType {
|
||||||
return namespacePath;
|
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));
|
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);
|
StructureDataType structDT = new StructureDataType(dtName, 0);
|
||||||
structDT.setDescription("PlaceHolder Structure");
|
structDT.setDescription("PlaceHolder Structure");
|
||||||
structDT.setCategoryPath(getDemanglerCategoryPath(dtName, namespace));
|
structDT.setCategoryPath(getDemanglerCategoryPath(dtName, namespace));
|
||||||
|
|
||||||
return structDT;
|
return structDT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,10 +485,6 @@ public class DemangledDataType extends DemangledType {
|
||||||
isVarArgs = true;
|
isVarArgs = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setVolatile() {
|
|
||||||
// isVolatile = true;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
public void setEnumType(String enumType) {
|
public void setEnumType(String enumType) {
|
||||||
this.enumType = enumType;
|
this.enumType = enumType;
|
||||||
}
|
}
|
||||||
|
@ -669,10 +589,6 @@ public class DemangledDataType extends DemangledType {
|
||||||
boolean isPrimitiveDT =
|
boolean isPrimitiveDT =
|
||||||
!isArray() && !isClass && !isComplex && !isEnum && !isPointer() && !isPointer64 &&
|
!isArray() && !isClass && !isComplex && !isEnum && !isPointer() && !isPointer64 &&
|
||||||
!isSigned && !isTemplate && !isUnion && !isCoclass && !isCointerface && !isVarArgs;
|
!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) {
|
if (isPrimitiveDT) {
|
||||||
for (String primitiveNames : PRIMITIVES) {
|
for (String primitiveNames : PRIMITIVES) {
|
||||||
if (getName().equals(primitiveNames)) {
|
if (getName().equals(primitiveNames)) {
|
||||||
|
@ -684,8 +600,8 @@ public class DemangledDataType extends DemangledType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toSignature() {
|
public String getSignature() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
|
||||||
if (isUnion) {
|
if (isUnion) {
|
||||||
buffer.append(UNION + SPACE);
|
buffer.append(UNION + SPACE);
|
||||||
|
@ -711,9 +627,6 @@ public class DemangledDataType extends DemangledType {
|
||||||
if (isComplex) {
|
if (isComplex) {
|
||||||
buffer.append(COMPLEX + SPACE);
|
buffer.append(COMPLEX + SPACE);
|
||||||
}
|
}
|
||||||
// if (isVolatile) {
|
|
||||||
// buffer.append(VOLATILE + SPACE);
|
|
||||||
// }
|
|
||||||
if (isSigned) {
|
if (isSigned) {
|
||||||
buffer.append(SIGNED + SPACE);
|
buffer.append(SIGNED + SPACE);
|
||||||
}
|
}
|
||||||
|
@ -722,7 +635,8 @@ public class DemangledDataType extends DemangledType {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getNamespace() != null) {
|
if (getNamespace() != null) {
|
||||||
buffer.append(getNamespace().toNamespace());
|
buffer.append(getNamespace().getNamespaceString());
|
||||||
|
buffer.append(Namespace.DELIMITER);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(getDemangledName());
|
buffer.append(getDemangledName());
|
||||||
|
@ -735,7 +649,6 @@ public class DemangledDataType extends DemangledType {
|
||||||
buffer.append(SPACE + CONST);
|
buffer.append(SPACE + CONST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: The output of volatile belongs here, not above, so I put the commented code here for now.
|
|
||||||
if (isVolatile()) {
|
if (isVolatile()) {
|
||||||
buffer.append(SPACE + VOLATILE);
|
buffer.append(SPACE + VOLATILE);
|
||||||
}
|
}
|
||||||
|
@ -760,7 +673,8 @@ public class DemangledDataType extends DemangledType {
|
||||||
buffer.append(SPACE + REF_NOTATION);
|
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) {
|
if (isPointer64) {
|
||||||
buffer.append(SPACE + PTR64);
|
buffer.append(SPACE + PTR64);
|
||||||
}
|
}
|
||||||
|
@ -787,7 +701,7 @@ public class DemangledDataType extends DemangledType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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.disassemble.DisassembleCommand;
|
||||||
import ghidra.app.cmd.function.*;
|
import ghidra.app.cmd.function.*;
|
||||||
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.PrototypeModel;
|
import ghidra.program.model.lang.PrototypeModel;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.demangler.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to represent a demangled function.
|
* 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 VOLATILE = "volatile";
|
||||||
public static final String CONST = "const";
|
public static final String CONST = "const";
|
||||||
|
@ -64,36 +65,11 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
private boolean isTypeCast;
|
private boolean isTypeCast;
|
||||||
private String throwAttribute;
|
private String throwAttribute;
|
||||||
|
|
||||||
/**
|
public DemangledFunction(String mangled, String originalDemangled, String name) {
|
||||||
* Constructs a new demangled function.
|
super(mangled, originalDemangled);
|
||||||
* @param name the name of the function
|
|
||||||
*/
|
|
||||||
public DemangledFunction(String name) {
|
|
||||||
setName(name);
|
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.
|
* Sets the function return type.
|
||||||
* @param returnType the function return type
|
* @param returnType the function return type
|
||||||
|
@ -127,18 +103,10 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
this.isOverloadedOperator = isOverloadedOperator;
|
this.isOverloadedOperator = isOverloadedOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.util.demangler.ParameterReceiver
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addParameter(DemangledDataType parameter) {
|
public void addParameter(DemangledDataType parameter) {
|
||||||
parameters.add(parameter);
|
parameters.add(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.util.demangler.ParameterReceiver
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<DemangledDataType> getParameters() {
|
public List<DemangledDataType> getParameters() {
|
||||||
return new ArrayList<>(parameters);
|
return new ArrayList<>(parameters);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +127,10 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
return callingConvention;
|
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) {
|
public void setTemplatedConstructorType(String type) {
|
||||||
this.templatedConstructorType = type;
|
this.templatedConstructorType = type;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +189,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSignature(boolean format) {
|
public String getSignature(boolean format) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
|
||||||
if (!(returnType instanceof DemangledFunctionPointer)) {
|
if (!(returnType instanceof DemangledFunctionPointer)) {
|
||||||
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
|
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
|
||||||
|
@ -227,7 +198,6 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
}
|
}
|
||||||
buffer.append(
|
buffer.append(
|
||||||
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
|
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
|
||||||
// if (virtual) {
|
|
||||||
if (isVirtual) {
|
if (isVirtual) {
|
||||||
buffer.append("virtual ");
|
buffer.append("virtual ");
|
||||||
}
|
}
|
||||||
|
@ -235,37 +205,26 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
buffer.append("static ");
|
buffer.append("static ");
|
||||||
}
|
}
|
||||||
if (!isTypeCast()) {
|
if (!isTypeCast()) {
|
||||||
buffer.append(returnType == null ? "" : returnType.toSignature() + " ");
|
buffer.append(returnType == null ? "" : returnType.getSignature() + " ");
|
||||||
}
|
}
|
||||||
// buffer.append(returnType == null ? "" : returnType.toSignature() + " ");
|
// buffer.append(returnType == null ? "" : returnType.toSignature() + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(callingConvention == null ? "" : callingConvention + " ");
|
buffer.append(callingConvention == null ? "" : callingConvention + " ");
|
||||||
if (namespace != null) {
|
if (namespace != null) {
|
||||||
buffer.append(namespace.toNamespace());
|
buffer.append(namespace.getNamespaceString());
|
||||||
|
buffer.append(NAMESPACE_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(getDemangledName());
|
buffer.append(getDemangledName());
|
||||||
if (isTypeCast()) {
|
if (isTypeCast()) {
|
||||||
buffer.append(returnType == null ? "" : " " + returnType.toSignature() + " ");
|
buffer.append(returnType == null ? "" : " " + returnType.getSignature() + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template != null) {
|
if (template != null) {
|
||||||
buffer.append(template.toTemplate());
|
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) {
|
if (templatedConstructorType != null) {
|
||||||
buffer.append('<').append(templatedConstructorType).append('>');
|
buffer.append('<').append(templatedConstructorType).append('>');
|
||||||
}
|
}
|
||||||
|
@ -278,7 +237,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
}
|
}
|
||||||
|
|
||||||
while (paramIterator.hasNext()) {
|
while (paramIterator.hasNext()) {
|
||||||
buffer.append(paramIterator.next().toSignature());
|
buffer.append(paramIterator.next().getSignature());
|
||||||
if (paramIterator.hasNext()) {
|
if (paramIterator.hasNext()) {
|
||||||
buffer.append(',');
|
buffer.append(',');
|
||||||
if (format) {
|
if (format) {
|
||||||
|
@ -290,26 +249,19 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
|
|
||||||
buffer.append(')');
|
buffer.append(')');
|
||||||
buffer.append(storageClass == null ? "" : " " + storageClass);
|
buffer.append(storageClass == null ? "" : " " + storageClass);
|
||||||
// }
|
|
||||||
|
|
||||||
if (returnType instanceof DemangledFunctionPointer) {
|
if (returnType instanceof DemangledFunctionPointer) {
|
||||||
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) returnType;
|
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) returnType;
|
||||||
String partialSig = funcPtr.toSignature(buffer.toString());
|
String partialSig = funcPtr.toSignature(buffer.toString());
|
||||||
buffer = new StringBuffer();
|
buffer = new StringBuilder();
|
||||||
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
|
buffer.append(specialPrefix == null ? "" : specialPrefix + " ");
|
||||||
buffer.append(
|
buffer.append(
|
||||||
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
|
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
|
||||||
//if (virtual || super.isVirtual) {
|
|
||||||
if (isVirtual) {
|
if (isVirtual) {
|
||||||
buffer.append("virtual ");
|
buffer.append("virtual ");
|
||||||
}
|
}
|
||||||
buffer.append(partialSig);
|
buffer.append(partialSig);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (specialSuffix != null) {
|
|
||||||
buffer.append(specialSuffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTrailingConst()) {
|
if (isTrailingConst()) {
|
||||||
if (buffer.length() > 2) {
|
if (buffer.length() > 2) {
|
||||||
|
@ -351,12 +303,17 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceName() {
|
||||||
|
return getName() + getParameterString();
|
||||||
|
}
|
||||||
|
|
||||||
public String getParameterString() {
|
public String getParameterString() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
buffer.append('(');
|
buffer.append('(');
|
||||||
Iterator<DemangledDataType> dditer = parameters.iterator();
|
Iterator<DemangledDataType> dditer = parameters.iterator();
|
||||||
while (dditer.hasNext()) {
|
while (dditer.hasNext()) {
|
||||||
buffer.append(dditer.next().toSignature());
|
buffer.append(dditer.next().getSignature());
|
||||||
if (dditer.hasNext()) {
|
if (dditer.hasNext()) {
|
||||||
buffer.append(',');
|
buffer.append(',');
|
||||||
}
|
}
|
||||||
|
@ -467,13 +424,13 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
for (int i = 0; i < args.size(); i++) {
|
for (int i = 0; i < args.size(); i++) {
|
||||||
if (args.get(i).getLength() > pointerSize) {
|
if (args.get(i).getLength() > pointerSize) {
|
||||||
bookmarkManager.setBookmark(address, BookmarkType.ANALYSIS, "Demangler",
|
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");
|
"large to fit in a parameter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bookmarkManager.setBookmark(address, BookmarkType.ANALYSIS, "Demangler",
|
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");
|
") 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.
|
// If something is returned as a Union, Structure, or Class return.
|
||||||
// It appears that is passed as an additional parameter. Essentially, it accesses
|
// It appears that is passed as an additional parameter. Essentially, it accesses
|
||||||
// the stack assuming there is reserved space.
|
// 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 returnType is null check for constructor or destructor names
|
||||||
if (THIS_CALL.equals(func.getCallingConventionName())) {
|
if (THIS_CALL.equals(function.getCallingConventionName())) {
|
||||||
String n = getName();
|
String n = getName();
|
||||||
if (n.equals("~" + namespace.getName()) || n.equals(namespace.getName())) {
|
if (n.equals("~" + namespace.getName()) || n.equals(namespace.getName())) {
|
||||||
// constructor && destructor
|
// constructor && destructor
|
||||||
|
@ -522,45 +480,50 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Structure maybeUpdateCallingConventionAndCreateClass(Program program, Function func) {
|
private Structure maybeUpdateCallingConventionAndCreateClass(Program program,
|
||||||
try {
|
Function function) {
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isThisCall(func)) {
|
String convention = validateCallingConvention(program, function);
|
||||||
func.setCallingConvention(THIS_CALL);
|
if (convention == null) {
|
||||||
return createClassStructure(program, func);
|
if (!isThisCall(function)) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
// Leave the calling convention to someone else to figure out
|
convention = THIS_CALL;
|
||||||
// else {
|
}
|
||||||
// String defaultConvention = getDefaultCallingConvention(program);
|
|
||||||
// if (defaultConvention != null) {
|
try {
|
||||||
// func.setCallingConvention(defaultConvention);
|
function.setCallingConvention(convention);
|
||||||
// }
|
return maybeCreateClassStructure(program, function, convention);
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
e.printStackTrace();
|
Msg.error(this, "Unexpected exception setting calling convention", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
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) {
|
private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) {
|
||||||
|
|
||||||
List<ParameterDefinitionImpl> args = new ArrayList<>();
|
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
|
// 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())) {
|
if (n.startsWith(namespace.getName())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -699,7 +662,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
|
||||||
return true;
|
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!
|
// But is also could be a static member function!
|
||||||
// The only way to really tell is compare the number of detected parameters
|
// 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
|
// 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
|
* @return true if it is in the std namespace
|
||||||
*/
|
*/
|
||||||
private boolean isInStdNameSpace() {
|
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 my immediate namespace is "std", then I am just a function in the std namespace.
|
||||||
if (ns == null) {
|
if (ns == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ns.getName().toLowerCase().equals(STD_NAMESPACE)) {
|
if (ns.getName().equalsIgnoreCase(STD_NAMESPACE)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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) {
|
TaskMonitor monitor) {
|
||||||
Listing listing = prog.getListing();
|
Listing listing = prog.getListing();
|
||||||
Function func = listing.getFunctionAt(addr);
|
Function func = listing.getFunctionAt(addr);
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
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
|
* 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
|
* 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
|
* is still an indirect definition (not a regular function definition). The
|
||||||
* function indirect is prevalent in the Microsoft model, if not other models.
|
* 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";
|
public DemangledFunctionIndirect(String mangled, String originalDemangled) {
|
||||||
private static final String NAMESPACE_DELIMITER = "::";
|
super(mangled, originalDemangled);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DemangledDataType copy() {
|
protected String getTypeString() {
|
||||||
DemangledFunctionIndirect copy = new DemangledFunctionIndirect();
|
return EMPTY_STRING;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,362 +15,17 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
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";
|
public DemangledFunctionPointer(String mangled, String originalDemangled) {
|
||||||
private static final Object NAMESPACE_DELIMITER = "::";
|
super(mangled, originalDemangled);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DemangledDataType copy() {
|
protected String getTypeString() {
|
||||||
DemangledFunctionPointer copy = new DemangledFunctionPointer();
|
return "*";
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,341 +15,17 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
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";
|
public DemangledFunctionReference(String mangled, String originalDemangled) {
|
||||||
private static final Object NAMESPACE_DELIMITER = "::";
|
super(mangled, originalDemangled);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DemangledDataType copy() {
|
protected String getTypeString() {
|
||||||
DemangledFunctionReference copy = new DemangledFunctionReference();
|
return "&";
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,16 +15,22 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
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 DemangledLambda(String mangled, String originalDemangled, String name) {
|
||||||
|
super(mangled, originalDemangled, name);
|
||||||
public DemangledMethod(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DemangledMethod(GenericDemangledMethod generic) {
|
@Override
|
||||||
super(generic);
|
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.cmd.label.SetLabelPrimaryCmd;
|
||||||
import ghidra.app.util.NamespaceUtils;
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.demangler.GenericDemangledObject;
|
|
||||||
import util.demangler.GenericDemangledType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to represent a demangled object.
|
* 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 String SPACE = " ";
|
||||||
protected static final Pattern SPACE_PATTERN = Pattern.compile(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 NAMESPACE_SEPARATOR = Namespace.DELIMITER;
|
||||||
protected static final String EMPTY_STRING = "";
|
protected static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
protected String originalMangled;
|
protected final String mangled; // original mangled string
|
||||||
protected String utilDemangled;
|
protected final String originalDemangled;
|
||||||
protected String specialPrefix;
|
protected String specialPrefix;
|
||||||
protected String specialMidfix;
|
protected Demangled namespace;
|
||||||
protected String specialSuffix;
|
|
||||||
protected DemangledType namespace;
|
|
||||||
protected String visibility;//public, protected, etc.
|
protected String visibility;//public, protected, etc.
|
||||||
|
|
||||||
//TODO: storageClass refers to things such as "static" but const and volatile are
|
//TODO: storageClass refers to things such as "static" but const and volatile are
|
||||||
|
@ -73,62 +70,17 @@ public abstract class DemangledObject {
|
||||||
|
|
||||||
private String signature;
|
private String signature;
|
||||||
|
|
||||||
DemangledObject() {
|
DemangledObject(String mangled, String originalDemangled) {
|
||||||
// default
|
this.mangled = mangled;
|
||||||
|
this.originalDemangled = originalDemangled;
|
||||||
}
|
}
|
||||||
|
|
||||||
DemangledObject(GenericDemangledObject other) {
|
@Override
|
||||||
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
|
|
||||||
*/
|
|
||||||
public String getDemangledName() {
|
public String getDemangledName() {
|
||||||
return demangledName;
|
return demangledName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +169,7 @@ public abstract class DemangledObject {
|
||||||
* Sets the name of the demangled object
|
* Sets the name of the demangled object
|
||||||
* @param name the new name
|
* @param name the new name
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.demangledName = name;
|
this.demangledName = name;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -228,39 +181,23 @@ public abstract class DemangledObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the original mangled name
|
public String getMangledString() {
|
||||||
* @param mangled the original mangled name
|
return mangled;
|
||||||
*/
|
|
||||||
public void setOriginalMangled(String mangled) {
|
|
||||||
this.originalMangled = mangled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the demangled output from a supplemental utility.
|
public String getOriginalDemangled() {
|
||||||
* @param utilDemangled the demangled string
|
return originalDemangled;
|
||||||
*/
|
|
||||||
public void setUtilDemangled(String utilDemangled) {
|
|
||||||
this.utilDemangled = utilDemangled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the demangled output from a supplemental utility.
|
public Demangled getNamespace() {
|
||||||
* @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() {
|
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNamespace(DemangledType namespace) {
|
@Override
|
||||||
|
public void setNamespace(Demangled namespace) {
|
||||||
this.namespace = namespace;
|
this.namespace = namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,22 +225,6 @@ public abstract class DemangledObject {
|
||||||
this.specialPrefix = 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.
|
* Returns a complete signature for the demangled symbol.
|
||||||
* <br>For example:
|
* <br>For example:
|
||||||
|
@ -317,6 +238,20 @@ public abstract class DemangledObject {
|
||||||
*/
|
*/
|
||||||
public abstract String getSignature(boolean format);
|
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
|
* Sets the signature. Calling this method will
|
||||||
* override the auto-generated signature.
|
* override the auto-generated signature.
|
||||||
|
@ -331,6 +266,17 @@ public abstract class DemangledObject {
|
||||||
return getSignature(false);
|
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
|
* 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
|
* 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,
|
public boolean applyTo(Program program, Address address, DemanglerOptions options,
|
||||||
TaskMonitor monitor) throws Exception {
|
TaskMonitor monitor) throws Exception {
|
||||||
if (originalMangled.equals(name)) {
|
if (mangled.equals(name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String comment = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address);
|
String comment = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address);
|
||||||
|
@ -382,8 +328,8 @@ public abstract class DemangledObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String generatePlateComment() {
|
protected String generatePlateComment() {
|
||||||
if (utilDemangled != null) {
|
if (originalDemangled != null) {
|
||||||
return utilDemangled;
|
return originalDemangled;
|
||||||
}
|
}
|
||||||
return (signature == null) ? getSignature(true) : signature;
|
return (signature == null) ? getSignature(true) : signature;
|
||||||
}
|
}
|
||||||
|
@ -432,7 +378,7 @@ public abstract class DemangledObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol updateExternalSymbol(Program program, Address externalAddr, String symbolName,
|
private Symbol updateExternalSymbol(Program program, Address externalAddr, String symbolName,
|
||||||
DemangledType demangledNamespace) {
|
Demangled demangledNamespace) {
|
||||||
|
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
Symbol s = symbolTable.getPrimarySymbol(externalAddr);
|
Symbol s = symbolTable.getPrimarySymbol(externalAddr);
|
||||||
|
@ -461,30 +407,28 @@ public abstract class DemangledObject {
|
||||||
* @param typeNamespace demangled namespace object
|
* @param typeNamespace demangled namespace object
|
||||||
* @return list of namespace names
|
* @return list of namespace names
|
||||||
*/
|
*/
|
||||||
private static List<String> getNamespaceList(DemangledType typeNamespace) {
|
private static List<String> getNamespaceList(Demangled typeNamespace) {
|
||||||
ArrayList<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
DemangledType ns = typeNamespace;
|
Demangled ns = typeNamespace;
|
||||||
while (ns != null) {
|
while (ns != null) {
|
||||||
list.add(0, ns.getName());
|
list.add(0, ns.getNamespaceName());
|
||||||
ns = ns.getNamespace();
|
ns = ns.getNamespace();
|
||||||
}
|
}
|
||||||
return list;
|
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
|
* 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
|
* namespace if errors occurred. The caller should check the returned namespace and adjust
|
||||||
* any symbol creation accordingly. Caller should use
|
* any symbol creation accordingly.
|
||||||
* <code>getResidualNamespacePath(DemangledType, Namespace)</code> to handle the case where
|
*
|
||||||
* only a partial namespace has been returned.
|
* @param program the program
|
||||||
* @param program
|
|
||||||
* @param typeNamespace demangled namespace
|
* @param typeNamespace demangled namespace
|
||||||
* @param parentNamespace root namespace to be used (e.g., library, global, etc.)
|
* @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
|
* @param functionPermitted if true an existing function may be used as a namespace
|
||||||
* @return namespace or partial namespace if error occurs
|
* @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 parentNamespace, boolean functionPermitted) {
|
||||||
|
|
||||||
Namespace namespace = parentNamespace;
|
Namespace namespace = parentNamespace;
|
||||||
|
@ -572,37 +516,4 @@ public abstract class DemangledObject {
|
||||||
return buffy.toString();
|
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.Msg;
|
||||||
import ghidra.util.StringUtilities;
|
import ghidra.util.StringUtilities;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.demangler.GenericDemangledString;
|
|
||||||
|
|
||||||
public class DemangledString extends DemangledObject {
|
public class DemangledString extends DemangledObject {
|
||||||
private String string;
|
private String string;
|
||||||
|
@ -31,6 +30,8 @@ public class DemangledString extends DemangledObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct demangled string.
|
* Construct demangled string.
|
||||||
|
* @param mangled the source mangled string
|
||||||
|
* @param originalDemangled the original demangled string
|
||||||
* @param name name associated with this object
|
* @param name name associated with this object
|
||||||
* @param string string text associated with this object or null. This is used to establish
|
* @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.
|
* 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.
|
* assumes null terminated string.
|
||||||
* @param unicode true if string is a Unicode 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);
|
setName(name);
|
||||||
this.string = string;
|
this.string = string;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.unicode = unicode;
|
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
|
@Override
|
||||||
public String getSignature(boolean format) {
|
public String getSignature(boolean format) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
if (specialPrefix != null) {
|
if (specialPrefix != null) {
|
||||||
buffer.append(specialPrefix + " for ");
|
buffer.append(specialPrefix);
|
||||||
}
|
}
|
||||||
buffer.append(string);
|
buffer.append(string);
|
||||||
if (specialSuffix != null) {
|
|
||||||
buffer.append(" " + specialSuffix);
|
|
||||||
}
|
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +73,9 @@ public class DemangledString extends DemangledObject {
|
||||||
public boolean applyTo(Program program, Address address, DemanglerOptions options,
|
public boolean applyTo(Program program, Address address, DemanglerOptions options,
|
||||||
TaskMonitor monitor) throws Exception {
|
TaskMonitor monitor) throws Exception {
|
||||||
|
|
||||||
String label = SymbolUtilities.replaceInvalidChars(string, false);
|
String label = buildStringLabel();
|
||||||
if (hasLabel(program, address, label)) {
|
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)) {
|
if (!super.applyTo(program, address, options, monitor)) {
|
||||||
|
@ -100,24 +89,24 @@ public class DemangledString extends DemangledObject {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should we be using length ?
|
|
||||||
CreateStringCmd cmd = new CreateStringCmd(address, -1, isUnicode());
|
CreateStringCmd cmd = new CreateStringCmd(address, -1, isUnicode());
|
||||||
cmd.applyTo(program);
|
cmd.applyTo(program);
|
||||||
|
|
||||||
// unclear what demangled name should be used so apply
|
|
||||||
// fabricated string label which is more useful than mangled name
|
|
||||||
Symbol demangledSymbol =
|
Symbol demangledSymbol =
|
||||||
applyDemangledName(buildStringLabel(), address, true, false, program);
|
applyDemangledName(label, address, true, false, program);
|
||||||
return (demangledSymbol != null);
|
return (demangledSymbol != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildStringLabel() {
|
private String buildStringLabel() {
|
||||||
// build string label consistent with dynamic label formatting
|
|
||||||
if (specialPrefix != null) {
|
if (specialPrefix != null) {
|
||||||
|
// a 'special prefix' implies that the author wishes to apply the string exactly as-is
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build string label consistent with dynamic label formatting
|
||||||
int len = string.length();
|
int len = string.length();
|
||||||
StringBuffer buf = new StringBuffer(len);
|
StringBuilder buf = new StringBuilder(len);
|
||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i) {
|
||||||
char c = string.charAt(i);
|
char c = string.charAt(i);
|
||||||
if (StringUtilities.isDisplayable(c) && (c != ' ')) {
|
if (StringUtilities.isDisplayable(c) && (c != ' ')) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,48 +15,27 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import util.demangler.GenericDemangledDataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import util.demangler.GenericDemangledTemplate;
|
|
||||||
|
|
||||||
public class DemangledTemplate implements ParameterReceiver {
|
public class DemangledTemplate {
|
||||||
private List<DemangledDataType> parameters = new ArrayList<DemangledDataType>();
|
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) {
|
public void addParameter(DemangledDataType parameter) {
|
||||||
parameters.add(parameter);
|
parameters.add(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DemangledDataType> getParameters() {
|
public List<DemangledDataType> getParameters() {
|
||||||
return new ArrayList<DemangledDataType>(parameters);
|
return new ArrayList<DemangledDataType>(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toTemplate() {
|
public String toTemplate() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuilder buffer = new StringBuilder();
|
||||||
buffer.append('<');
|
buffer.append('<');
|
||||||
for (int i = 0; i < parameters.size(); ++i) {
|
for (int i = 0; i < parameters.size(); ++i) {
|
||||||
try {
|
buffer.append(parameters.get(i).getSignature());
|
||||||
buffer.append(parameters.get(i).toSignature());
|
|
||||||
}
|
|
||||||
catch (Error e) {
|
|
||||||
Msg.error(this, "Unexpected Error: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
if (i < parameters.size() - 1) {
|
if (i < parameters.size() - 1) {
|
||||||
buffer.append(',');
|
buffer.append(',');
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ public class DemangledThunk extends DemangledObject {
|
||||||
|
|
||||||
private boolean covariantReturnThunk = false;
|
private boolean covariantReturnThunk = false;
|
||||||
|
|
||||||
public DemangledThunk(DemangledFunction thunkedFunctionObject) {
|
public DemangledThunk(String mangled, String originalDemangled,
|
||||||
|
DemangledFunction thunkedFunctionObject) {
|
||||||
|
super(mangled, originalDemangled);
|
||||||
this.thunkedFunctionObject = thunkedFunctionObject;
|
this.thunkedFunctionObject = thunkedFunctionObject;
|
||||||
this.namespace = thunkedFunctionObject.getNamespace();
|
this.namespace = thunkedFunctionObject.getNamespace();
|
||||||
setName(thunkedFunctionObject.getName());
|
setName(thunkedFunctionObject.getName());
|
||||||
|
@ -106,7 +108,7 @@ public class DemangledThunk extends DemangledObject {
|
||||||
function = function.getThunkedFunction(false);
|
function = function.getThunkedFunction(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thunkedFunction != null && originalMangled.equals(function.getName()) &&
|
if (thunkedFunction != null && mangled.equals(function.getName()) &&
|
||||||
!function.isThunk()) {
|
!function.isThunk()) {
|
||||||
function.setThunkedFunction(thunkedFunction);
|
function.setThunkedFunction(thunkedFunction);
|
||||||
}
|
}
|
||||||
|
@ -115,14 +117,6 @@ public class DemangledThunk extends DemangledObject {
|
||||||
return s != null;
|
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,
|
private Function createPreThunkFunction(Program prog, Address addr, boolean doDisassembly,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) {
|
||||||
|
|
||||||
|
@ -147,8 +141,9 @@ public class DemangledThunk extends DemangledObject {
|
||||||
while (instr != null) {
|
while (instr != null) {
|
||||||
// This is done in a way to handle potential delay slots
|
// This is done in a way to handle potential delay slots
|
||||||
InstructionContext instructionContext = instr.getInstructionContext();
|
InstructionContext instructionContext = instr.getInstructionContext();
|
||||||
Address fallThru = instructionContext.getAddress().add(
|
Address fallThru = instructionContext.getAddress()
|
||||||
instr.getPrototype().getFallThroughOffset(instructionContext));
|
.add(
|
||||||
|
instr.getPrototype().getFallThroughOffset(instructionContext));
|
||||||
Address maxAddr = fallThru.previous();
|
Address maxAddr = fallThru.previous();
|
||||||
if (maxAddr.compareTo(instr.getMinAddress()) < 0) {
|
if (maxAddr.compareTo(instr.getMinAddress()) < 0) {
|
||||||
// just in case we wrapped
|
// just in case we wrapped
|
||||||
|
@ -181,7 +176,7 @@ public class DemangledThunk extends DemangledObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
|
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
|
||||||
thunkedFunctionObject.originalMangled, err -> Msg.warn(this, err));
|
mangled, err -> Msg.warn(this, err));
|
||||||
|
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
Address thunkedAddr =
|
Address thunkedAddr =
|
||||||
|
|
|
@ -15,102 +15,43 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
|
||||||
import ghidra.program.model.symbol.Namespace;
|
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 demangledName;
|
||||||
private String name;
|
private String name; // 'safe' name
|
||||||
protected String originalMangled;
|
|
||||||
protected DemangledType namespace;
|
protected Demangled namespace;
|
||||||
protected DemangledTemplate template;
|
protected DemangledTemplate template;
|
||||||
private boolean isConst;
|
private boolean isConst;
|
||||||
private boolean isVolatile;
|
private boolean isVolatile;
|
||||||
|
|
||||||
/**
|
public DemangledType(String mangled, String originaDemangled, String name) {
|
||||||
* Takes a {@link DemangledType} with a name that contains namespace elements
|
this.mangled = mangled;
|
||||||
* (such as Foo::Bar) and breaks it into a hierarchy of types where each type
|
this.originalDemangled = originaDemangled;
|
||||||
* 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) {
|
|
||||||
setName(name);
|
setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
DemangledType(GenericDemangledType toCopy) {
|
@Override
|
||||||
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
|
|
||||||
*/
|
|
||||||
public String getDemangledName() {
|
public String getDemangledName() {
|
||||||
return demangledName;
|
return demangledName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the name of the demangled type object.
|
|
||||||
* @param name the new name
|
|
||||||
*/
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
demangledName = name;
|
demangledName = name;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -120,20 +61,14 @@ public class DemangledType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the original mangled name
|
public String getOriginalDemangled() {
|
||||||
* @param mangled the original mangled name
|
return originalDemangled;
|
||||||
*/
|
|
||||||
public void setOriginalMangled(String mangled) {
|
|
||||||
this.originalMangled = mangled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the original mangled name
|
public String getMangledString() {
|
||||||
* @return the original mangled name
|
return mangled;
|
||||||
*/
|
|
||||||
public String getOriginalMangled() {
|
|
||||||
return originalMangled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConst() {
|
public boolean isConst() {
|
||||||
|
@ -144,10 +79,6 @@ public class DemangledType {
|
||||||
isConst = true;
|
isConst = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFunction() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVolatile() {
|
public boolean isVolatile() {
|
||||||
return isVolatile;
|
return isVolatile;
|
||||||
}
|
}
|
||||||
|
@ -156,11 +87,13 @@ public class DemangledType {
|
||||||
isVolatile = true;
|
isVolatile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DemangledType getNamespace() {
|
@Override
|
||||||
|
public Demangled getNamespace() {
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNamespace(DemangledType namespace) {
|
@Override
|
||||||
|
public void setNamespace(Demangled namespace) {
|
||||||
if (this == namespace) {
|
if (this == namespace) {
|
||||||
throw new IllegalArgumentException("Attempt to set this.namespace == this!");
|
throw new IllegalArgumentException("Attempt to set this.namespace == this!");
|
||||||
}
|
}
|
||||||
|
@ -175,15 +108,23 @@ public class DemangledType {
|
||||||
this.template = template;
|
this.template = template;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toSignature() {
|
@Override
|
||||||
return toNamespace();
|
public String getSignature() {
|
||||||
|
return getNamespaceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toNamespace() {
|
@Override
|
||||||
StringBuffer buffer = new StringBuffer();
|
public String getNamespaceString() {
|
||||||
if (namespace != null) {
|
return getName(true);
|
||||||
buffer.append(namespace.toNamespace());
|
}
|
||||||
|
|
||||||
|
private String getName(boolean includeNamespace) {
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
if (includeNamespace && namespace != null) {
|
||||||
|
buffer.append(namespace.getNamespaceString());
|
||||||
|
buffer.append(Namespace.DELIMITER);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(demangledName);
|
buffer.append(demangledName);
|
||||||
if (template != null) {
|
if (template != null) {
|
||||||
buffer.append(template.toTemplate());
|
buffer.append(template.toTemplate());
|
||||||
|
@ -193,12 +134,16 @@ public class DemangledType {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(Namespace.DELIMITER);
|
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return toNamespace();
|
return getNamespaceString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,38 +26,16 @@ import ghidra.program.model.symbol.SymbolUtilities;
|
||||||
*/
|
*/
|
||||||
public class DemangledUnknown extends DemangledObject {
|
public class DemangledUnknown extends DemangledObject {
|
||||||
|
|
||||||
public DemangledUnknown() {
|
public DemangledUnknown(String mangled, String originalDemangled, String name) {
|
||||||
}
|
super(mangled, originalDemangled);
|
||||||
|
|
||||||
public DemangledUnknown(String name) {
|
|
||||||
setName(name);
|
setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DemangledUnknown(GenericDemangledVariable other) {
|
|
||||||
// super(other);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
@Override
|
@Override
|
||||||
public String getSignature(boolean format) {
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
//These items likely do not have names or data types, so return the signature.
|
//These items likely do not have names or data types, so return the signature.
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.app.cmd.data.CreateDataCmd;
|
import ghidra.app.cmd.data.CreateDataCmd;
|
||||||
import ghidra.app.util.PseudoDisassembler;
|
import ghidra.app.util.PseudoDisassembler;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
@ -27,8 +29,6 @@ import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.demangler.GenericDemangledDataType;
|
|
||||||
import util.demangler.GenericDemangledVariable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface to represent a demangled global variable.
|
* An interface to represent a demangled global variable.
|
||||||
|
@ -36,19 +36,11 @@ import util.demangler.GenericDemangledVariable;
|
||||||
public class DemangledVariable extends DemangledObject {
|
public class DemangledVariable extends DemangledObject {
|
||||||
private DemangledDataType datatype;
|
private DemangledDataType datatype;
|
||||||
|
|
||||||
public DemangledVariable(String name) {
|
public DemangledVariable(String mangled, String originalDemangled, String name) {
|
||||||
|
super(mangled, originalDemangled);
|
||||||
setName(name);
|
setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
DemangledVariable(GenericDemangledVariable other) {
|
|
||||||
super(other);
|
|
||||||
|
|
||||||
GenericDemangledDataType otherDatatype = other.getDataType();
|
|
||||||
if (otherDatatype != null) {
|
|
||||||
datatype = (DemangledDataType) DemangledObjectFactory.convert(otherDatatype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDatatype(DemangledDataType datatype) {
|
public void setDatatype(DemangledDataType datatype) {
|
||||||
this.datatype = datatype;
|
this.datatype = datatype;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +62,7 @@ public class DemangledVariable extends DemangledObject {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSignature(boolean format) {
|
public String getSignature(boolean format) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuilder buffer = new StringBuilder();
|
||||||
buffer.append(specialPrefix == null ? EMPTY_STRING : specialPrefix + SPACE);
|
buffer.append(specialPrefix == null ? EMPTY_STRING : specialPrefix + SPACE);
|
||||||
buffer.append(
|
buffer.append(
|
||||||
visibility == null || "global".equals(visibility) ? EMPTY_STRING : visibility + SPACE);
|
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);
|
buffer.append(isVirtual ? "virtual" + SPACE : EMPTY_STRING);
|
||||||
|
|
||||||
String n = getDemangledName();
|
String n = getDemangledName();
|
||||||
boolean hasName = (n != null) && !n.isEmpty();
|
boolean hasName = !StringUtils.isBlank(n);
|
||||||
|
|
||||||
StringBuffer datatypeBuffer = new StringBuffer();
|
StringBuffer datatypeBuffer = new StringBuffer();
|
||||||
String spacer = EMPTY_STRING;
|
String spacer = EMPTY_STRING;
|
||||||
|
@ -88,7 +80,7 @@ public class DemangledVariable extends DemangledObject {
|
||||||
!(datatype instanceof DemangledFunctionReference) &&
|
!(datatype instanceof DemangledFunctionReference) &&
|
||||||
!(datatype instanceof DemangledFunctionIndirect)) {
|
!(datatype instanceof DemangledFunctionIndirect)) {
|
||||||
if (datatype != null) {
|
if (datatype != null) {
|
||||||
datatypeBuffer.append(datatype.toSignature());
|
datatypeBuffer.append(datatype.getSignature());
|
||||||
spacer = SPACE;
|
spacer = SPACE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,11 +131,10 @@ public class DemangledVariable extends DemangledObject {
|
||||||
datatypeBuffer.append(spacer);
|
datatypeBuffer.append(spacer);
|
||||||
spacer = EMPTY_STRING;
|
spacer = EMPTY_STRING;
|
||||||
|
|
||||||
datatypeBuffer.append(namespace.toNamespace());
|
datatypeBuffer.append(namespace.getNamespaceString());
|
||||||
|
|
||||||
if (!hasName) {
|
if (hasName) {
|
||||||
int end = buffer.length();
|
datatypeBuffer.append(NAMESPACE_SEPARATOR);
|
||||||
datatypeBuffer.delete(end - 2, end); // strip off the last namespace characters
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,22 +144,16 @@ public class DemangledVariable extends DemangledObject {
|
||||||
datatypeBuffer.append(getName());
|
datatypeBuffer.append(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
datatypeBuffer.append(specialMidfix == null ? EMPTY_STRING : specialMidfix + SPACE);
|
|
||||||
datatypeBuffer.append(specialSuffix == null ? EMPTY_STRING : SPACE + specialSuffix);
|
|
||||||
|
|
||||||
if (datatype instanceof DemangledFunctionPointer) {
|
if (datatype instanceof DemangledFunctionPointer) {
|
||||||
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) datatype;
|
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) datatype;
|
||||||
//return funcPtr.toSignature(buffer.toString());
|
|
||||||
return buffer.append(funcPtr.toSignature(datatypeBuffer.toString())).toString();
|
return buffer.append(funcPtr.toSignature(datatypeBuffer.toString())).toString();
|
||||||
}
|
}
|
||||||
else if (datatype instanceof DemangledFunctionReference) {
|
else if (datatype instanceof DemangledFunctionReference) {
|
||||||
DemangledFunctionReference funcRef = (DemangledFunctionReference) datatype;
|
DemangledFunctionReference funcRef = (DemangledFunctionReference) datatype;
|
||||||
//return funcRef.toSignature(buffer.toString());
|
|
||||||
return buffer.append(funcRef.toSignature(datatypeBuffer.toString())).toString();
|
return buffer.append(funcRef.toSignature(datatypeBuffer.toString())).toString();
|
||||||
}
|
}
|
||||||
else if (datatype instanceof DemangledFunctionIndirect) {
|
else if (datatype instanceof DemangledFunctionIndirect) {
|
||||||
DemangledFunctionIndirect funcDef = (DemangledFunctionIndirect) datatype;
|
DemangledFunctionIndirect funcDef = (DemangledFunctionIndirect) datatype;
|
||||||
//return funcDef.toSignature(buffer.toString());
|
|
||||||
return buffer.append(funcDef.toSignature(datatypeBuffer.toString())).toString();
|
return buffer.append(funcDef.toSignature(datatypeBuffer.toString())).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +162,20 @@ public class DemangledVariable extends DemangledObject {
|
||||||
return buffer.toString();
|
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
|
@Override
|
||||||
protected boolean isAlreadyDemangled(Program program, Address address) {
|
protected boolean isAlreadyDemangled(Program program, Address address) {
|
||||||
Data data = program.getListing().getDefinedDataAt(address);
|
Data data = program.getListing().getDefinedDataAt(address);
|
||||||
|
@ -199,9 +198,6 @@ public class DemangledVariable extends DemangledObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol demangledSymbol = applyDemangledName(address, true, true, program);
|
Symbol demangledSymbol = applyDemangledName(address, true, true, program);
|
||||||
|
|
||||||
//TODO replace existing datatype?
|
|
||||||
|
|
||||||
DataType demangledDT = getProgramDataType(program);
|
DataType demangledDT = getProgramDataType(program);
|
||||||
|
|
||||||
if (address.isExternalAddress()) {
|
if (address.isExternalAddress()) {
|
||||||
|
|
|
@ -101,31 +101,6 @@ public class DemanglerUtil {
|
||||||
return ClassSearcher.getInstances(Demangler.class);
|
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
|
* Remove superfluous function signature spaces from specified string
|
||||||
* @param str string
|
* @param str string
|
||||||
|
@ -146,13 +121,4 @@ public class DemanglerUtil {
|
||||||
matcher.appendTail(buffy);
|
matcher.appendTail(buffy);
|
||||||
return buffy.toString();
|
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();
|
ActionContext context = getActionContext();
|
||||||
performAction(setColorAction, context, false);
|
performAction(setColorAction, context, false);
|
||||||
|
|
||||||
Window chooserWindow = waitForWindow(null, ColorizingServiceProvider.COLOR_CHOOSER_TITLE,
|
Window chooserWindow = waitForWindow(ColorizingServiceProvider.COLOR_CHOOSER_TITLE);
|
||||||
DEFAULT_WINDOW_TIMEOUT);
|
|
||||||
assertNotNull("Did not find Color Chooser", chooserWindow);
|
assertNotNull("Did not find Color Chooser", chooserWindow);
|
||||||
GhidraColorChooser colorChooser = findComponent(chooserWindow, GhidraColorChooser.class);
|
GhidraColorChooser colorChooser = findComponent(chooserWindow, GhidraColorChooser.class);
|
||||||
JButton okButton = findButtonByText(chooserWindow, "OK");
|
JButton okButton = findButtonByText(chooserWindow, "OK");
|
||||||
|
|
|
@ -13,11 +13,14 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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 {
|
public DemanglerParseException(String message) {
|
||||||
super(name);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -113,9 +113,9 @@ public class GnuDemangler implements Demangler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalPrefix != null) {
|
if (globalPrefix != null) {
|
||||||
// TODO: may need better naming convention for demangled function
|
|
||||||
DemangledFunction dfunc =
|
DemangledFunction dfunc =
|
||||||
new DemangledFunction(globalPrefix + demangledObject.getName());
|
new DemangledFunction(originalMangled, demangled,
|
||||||
|
globalPrefix + demangledObject.getName());
|
||||||
dfunc.setNamespace(demangledObject.getNamespace());
|
dfunc.setNamespace(demangledObject.getNamespace());
|
||||||
demangledObject = dfunc;
|
demangledObject = dfunc;
|
||||||
}
|
}
|
||||||
|
@ -123,14 +123,12 @@ public class GnuDemangler implements Demangler {
|
||||||
demangledObject.setSignature(demangled);
|
demangledObject.setSignature(demangled);
|
||||||
}
|
}
|
||||||
|
|
||||||
demangledObject.setOriginalMangled(originalMangled);
|
|
||||||
|
|
||||||
if (isDwarf) {
|
if (isDwarf) {
|
||||||
DemangledAddressTable dat = new DemangledAddressTable((String) null, 1);
|
DemangledAddressTable dat =
|
||||||
|
new DemangledAddressTable(originalMangled, demangled, (String) null, false);
|
||||||
dat.setSpecialPrefix("DWARF Debug ");
|
dat.setSpecialPrefix("DWARF Debug ");
|
||||||
dat.setName(demangledObject.getName());
|
dat.setName(demangledObject.getName());
|
||||||
dat.setNamespace(demangledObject.getNamespace());
|
dat.setNamespace(demangledObject.getNamespace());
|
||||||
dat.setOriginalMangled(originalMangled);
|
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +207,7 @@ public class GnuDemangler implements Demangler {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
GnuDemanglerParser parser = new GnuDemanglerParser(process);
|
GnuDemanglerParser parser = new GnuDemanglerParser();
|
||||||
DemangledObject demangledObject = parser.parse(mangled, demangled);
|
DemangledObject demangledObject = parser.parse(mangled, demangled);
|
||||||
return demangledObject;
|
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"));
|
Symbol s = symbolTable.getPrimarySymbol(addr("01001000"));
|
||||||
assertNotNull(s);
|
assertNotNull(s);
|
||||||
assertEquals("typeinfo_name", s.getName());
|
assertEquals("typeinfo-name", s.getName());
|
||||||
assertEquals("AP_HAL::HAL::Callbacks", s.getParentNamespace().getName(true));
|
assertEquals("AP_HAL::HAL::Callbacks", s.getParentNamespace().getName(true));
|
||||||
|
|
||||||
assertEquals("typeinfo name for AP_HAL::HAL::Callbacks",
|
assertEquals("typeinfo name for AP_HAL::HAL::Callbacks",
|
||||||
|
@ -238,6 +238,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
||||||
String demanglerName = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
|
String demanglerName = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
|
||||||
String applicationArguments = "-s MrBob";
|
String applicationArguments = "-s MrBob";
|
||||||
try {
|
try {
|
||||||
|
setErrorsExpected(true);
|
||||||
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
|
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
|
||||||
applicationArguments);
|
applicationArguments);
|
||||||
fail("Expected an exception when passing unknown arguments to the native demangler");
|
fail("Expected an exception when passing unknown arguments to the native demangler");
|
||||||
|
@ -246,7 +247,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
||||||
// expected
|
// expected
|
||||||
Msg.error(this, "Test error", e);
|
Msg.error(this, "Test error", e);
|
||||||
}
|
}
|
||||||
|
setErrorsExpected(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address addr(String address) {
|
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) {
|
if (descriptorName == null) {
|
||||||
return 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;
|
DemangledType parentNamespace = getParentNamespace(); // Can be null;
|
||||||
if (parentNamespace != null) {
|
if (parentNamespace != null) {
|
||||||
typeNamespace.setNamespace(parentNamespace);
|
typeNamespace.setNamespace(parentNamespace);
|
||||||
|
@ -614,8 +617,8 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNamespaceDeleted(Namespace namespace2) {
|
private boolean isNamespaceDeleted(Namespace other) {
|
||||||
Symbol nsSymbol = namespace2.getSymbol();
|
Symbol nsSymbol = other.getSymbol();
|
||||||
if (nsSymbol == null) {
|
if (nsSymbol == null) {
|
||||||
return false; // global namespace.
|
return false; // global namespace.
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import ghidra.app.util.opinion.PeLoader;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import mdemangler.MDException;
|
import mdemangler.MDException;
|
||||||
import mdemangler.MDMangGhidra;
|
import mdemangler.MDMangGhidra;
|
||||||
import util.demangler.GenericDemangledException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for demangling debug symbols created using Microsoft Visual Studio.
|
* 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);
|
DemangledObject demangled = demangleMS(mangled, demangleOnlyKnownPatterns);
|
||||||
return demangled;
|
return demangled;
|
||||||
}
|
}
|
||||||
catch (GenericDemangledException e) {
|
catch (DemangledException e) {
|
||||||
throw new DemangledException(true);
|
throw new DemangledException(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,15 +58,15 @@ public class MicrosoftDemangler implements Demangler {
|
||||||
DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns());
|
DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns());
|
||||||
return demangled;
|
return demangled;
|
||||||
}
|
}
|
||||||
catch (GenericDemangledException e) {
|
catch (DemangledException e) {
|
||||||
throw new DemangledException(true);
|
throw new DemangledException(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns)
|
private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns)
|
||||||
throws GenericDemangledException {
|
throws DemangledException {
|
||||||
if (mangled == null || mangled.length() == 0) {
|
if (mangled == null || mangled.length() == 0) {
|
||||||
throw new GenericDemangledException(true);
|
throw new DemangledException(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MDMangGhidra demangler = new MDMangGhidra();
|
MDMangGhidra demangler = new MDMangGhidra();
|
||||||
|
@ -77,10 +76,10 @@ public class MicrosoftDemangler implements Demangler {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
catch (MDException e) {
|
catch (MDException e) {
|
||||||
GenericDemangledException gde =
|
DemangledException de =
|
||||||
new GenericDemangledException("Unable to demangle symbol: " + mangled);
|
new DemangledException("Unable to demangle symbol: " + mangled);
|
||||||
gde.initCause(e);
|
de.initCause(e);
|
||||||
throw gde;
|
throw de;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ public class MDMangGhidra extends MDMang {
|
||||||
private DemangledObject objectResult;
|
private DemangledObject objectResult;
|
||||||
private DemangledDataType dataTypeResult;
|
private DemangledDataType dataTypeResult;
|
||||||
|
|
||||||
|
private String mangledSource;
|
||||||
|
private String demangledSource;
|
||||||
|
|
||||||
public DemangledObject getObject() {
|
public DemangledObject getObject() {
|
||||||
return objectResult;
|
return objectResult;
|
||||||
}
|
}
|
||||||
|
@ -46,31 +49,6 @@ public class MDMangGhidra extends MDMang {
|
||||||
return dataTypeResult;
|
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
|
@Override
|
||||||
public MDParsableItem demangle(String mangledArg, boolean demangleOnlyKnownPatterns)
|
public MDParsableItem demangle(String mangledArg, boolean demangleOnlyKnownPatterns)
|
||||||
throws MDException {
|
throws MDException {
|
||||||
|
@ -83,16 +61,47 @@ public class MDMangGhidra extends MDMang {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.mangledSource = mangledArg;
|
||||||
|
|
||||||
MDParsableItem returnedItem = super.demangle(mangledArg, true);
|
MDParsableItem returnedItem = super.demangle(mangledArg, true);
|
||||||
|
|
||||||
|
this.demangledSource = item.toString();
|
||||||
|
|
||||||
objectResult = processItem();
|
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;
|
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() {
|
private DemangledObject processItem() {
|
||||||
objectResult = null;
|
objectResult = null;
|
||||||
if (item instanceof MDObjectReserved) {
|
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.
|
//TODO: put other objectReserved derivative types here and return something that Ghidra can use.
|
||||||
else {
|
else {
|
||||||
object = new DemangledUnknown();
|
object = new DemangledUnknown(mangledSource, demangledSource, null);
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
@ -175,10 +184,10 @@ public class MDMangGhidra extends MDMang {
|
||||||
MDType mdtype = variableInfo.getMDType();
|
MDType mdtype = variableInfo.getMDType();
|
||||||
DemangledDataType dt = processDataType(null, (MDDataType) mdtype);
|
DemangledDataType dt = processDataType(null, (MDDataType) mdtype);
|
||||||
if ("std::nullptr_t".equals(dt.getName())) {
|
if ("std::nullptr_t".equals(dt.getName())) {
|
||||||
variable = new DemangledVariable("");
|
variable = new DemangledVariable(mangledSource, demangledSource, "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
variable = new DemangledVariable(
|
variable = new DemangledVariable(mangledSource, demangledSource,
|
||||||
objectCPP.getName());
|
objectCPP.getName());
|
||||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
}
|
}
|
||||||
|
@ -200,7 +209,7 @@ public class MDMangGhidra extends MDMang {
|
||||||
}
|
}
|
||||||
else if (typeinfo instanceof MDFunctionInfo) {
|
else if (typeinfo instanceof MDFunctionInfo) {
|
||||||
DemangledFunction function =
|
DemangledFunction function =
|
||||||
new DemangledFunction(objectCPP.getName());
|
new DemangledFunction(mangledSource, demangledSource, objectCPP.getName());
|
||||||
function.setNamespace(processNamespace(objectCPP.getQualfication()));
|
function.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
resultObject = function;
|
resultObject = function;
|
||||||
objectResult = processFunction((MDFunctionInfo) typeinfo, 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
|
else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
|
||||||
MDVxTable vxtable = (MDVxTable) typeinfo;
|
MDVxTable vxtable = (MDVxTable) typeinfo;
|
||||||
DemangledVariable variable =
|
DemangledVariable variable =
|
||||||
new DemangledVariable(objectCPP.getName());
|
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
variable.setConst(vxtable.isConst());
|
variable.setConst(vxtable.isConst());
|
||||||
variable.setVolatile(vxtable.isVolatile());
|
variable.setVolatile(vxtable.isVolatile());
|
||||||
|
@ -241,7 +250,7 @@ public class MDMangGhidra extends MDMang {
|
||||||
}
|
}
|
||||||
else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
|
else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
|
||||||
DemangledVariable variable =
|
DemangledVariable variable =
|
||||||
new DemangledVariable(objectCPP.getName());
|
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
resultObject = variable;
|
resultObject = variable;
|
||||||
// The following code would be an alternative, depending on whether we get
|
// 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) {
|
else if (typeinfo instanceof MDGuard) {
|
||||||
DemangledVariable variable =
|
DemangledVariable variable =
|
||||||
new DemangledVariable(objectCPP.getName());
|
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
resultObject = variable;
|
resultObject = variable;
|
||||||
// The following code would be an alternative, depending on whether we get
|
// The following code would be an alternative, depending on whether we get
|
||||||
|
@ -260,7 +269,7 @@ public class MDMangGhidra extends MDMang {
|
||||||
else {
|
else {
|
||||||
// Any others (e.g., case '9')
|
// Any others (e.g., case '9')
|
||||||
DemangledVariable variable =
|
DemangledVariable variable =
|
||||||
new DemangledVariable(objectCPP.getName());
|
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
|
||||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
resultObject = variable;
|
resultObject = variable;
|
||||||
// The following code would be an alternative, depending on whether we get
|
// 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();
|
String baseName = objectCPP.getName();
|
||||||
if (objectCPP.isString()) {
|
if (objectCPP.isString()) {
|
||||||
MDString mstring = objectCPP.getMDString();
|
MDString mstring = objectCPP.getMDString();
|
||||||
DemangledString demangledString = new DemangledString(mstring.getName(),
|
DemangledString demangledString =
|
||||||
mstring.toString(), mstring.getLength(), mstring.isUnicode());
|
new DemangledString(mangledSource, demangledSource, mstring.getName(),
|
||||||
|
mstring.toString(), mstring.getLength(), mstring.isUnicode());
|
||||||
resultObject = demangledString;
|
resultObject = demangledString;
|
||||||
}
|
}
|
||||||
else if (baseName.length() != 0) {
|
else if (baseName.length() != 0) {
|
||||||
DemangledVariable variable;
|
DemangledVariable variable;
|
||||||
variable = new DemangledVariable(baseName);
|
variable = new DemangledVariable(mangledSource, demangledSource, baseName);
|
||||||
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
|
||||||
resultObject = variable;
|
resultObject = variable;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +324,8 @@ public class MDMangGhidra extends MDMang {
|
||||||
// doesn't match
|
// doesn't match
|
||||||
// well to the current DemangledObject hierarchy.
|
// well to the current DemangledObject hierarchy.
|
||||||
private DemangledVariable processTemplate(MDTemplateNameAndArguments template) {
|
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);
|
// NO NAMESPACE for high level template: variable.setNamespace(XXX);
|
||||||
// DemangledTemplate objectTemplate = new DemangledTemplate();
|
// DemangledTemplate objectTemplate = new DemangledTemplate();
|
||||||
// DemangledDataType dataType = new DemangledDataType((String) null);
|
// DemangledDataType dataType = new DemangledDataType((String) null);
|
||||||
|
@ -397,7 +408,8 @@ public class MDMangGhidra extends MDMang {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DemangledFunctionPointer processDemangledFunctionPointer(MDPointerType pointerType) {
|
private DemangledFunctionPointer processDemangledFunctionPointer(MDPointerType pointerType) {
|
||||||
DemangledFunctionPointer functionPointer = new DemangledFunctionPointer();
|
DemangledFunctionPointer functionPointer =
|
||||||
|
new DemangledFunctionPointer(mangledSource, demangledSource);
|
||||||
MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
|
MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
|
||||||
functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
|
functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
|
||||||
functionPointer.setModifier(pointerType.getCVMod().toString());
|
functionPointer.setModifier(pointerType.getCVMod().toString());
|
||||||
|
@ -432,7 +444,8 @@ public class MDMangGhidra extends MDMang {
|
||||||
if (!((refType instanceof MDReferenceType) || (refType instanceof MDDataRefRefType))) {
|
if (!((refType instanceof MDReferenceType) || (refType instanceof MDDataRefRefType))) {
|
||||||
return null; // Not planning on anything else yet.
|
return null; // Not planning on anything else yet.
|
||||||
}
|
}
|
||||||
DemangledFunctionReference functionReference = new DemangledFunctionReference();
|
DemangledFunctionReference functionReference =
|
||||||
|
new DemangledFunctionReference(mangledSource, demangledSource);
|
||||||
MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
|
MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
|
||||||
functionReference.setCallingConvention(functionType.getCallingConvention().toString());
|
functionReference.setCallingConvention(functionType.getCallingConvention().toString());
|
||||||
functionReference.setModifier(refType.getCVMod().toString());
|
functionReference.setModifier(refType.getCVMod().toString());
|
||||||
|
@ -447,7 +460,8 @@ public class MDMangGhidra extends MDMang {
|
||||||
|
|
||||||
private DemangledFunctionIndirect processDemangledFunctionIndirect(
|
private DemangledFunctionIndirect processDemangledFunctionIndirect(
|
||||||
MDFunctionIndirectType functionIndirectType) {
|
MDFunctionIndirectType functionIndirectType) {
|
||||||
DemangledFunctionIndirect functionDefinition = new DemangledFunctionIndirect();
|
DemangledFunctionIndirect functionDefinition =
|
||||||
|
new DemangledFunctionIndirect(mangledSource, demangledSource);
|
||||||
MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
|
MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
|
||||||
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
|
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
|
||||||
functionDefinition.setModifier(functionIndirectType.getCVMod().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.
|
// indirect might be clouded between the real, two underlying types.
|
||||||
private DemangledFunctionIndirect processDemangledFunctionQuestion(
|
private DemangledFunctionIndirect processDemangledFunctionQuestion(
|
||||||
MDModifierType modifierType) {
|
MDModifierType modifierType) {
|
||||||
DemangledFunctionIndirect functionDefinition = new DemangledFunctionIndirect();
|
DemangledFunctionIndirect functionDefinition =
|
||||||
|
new DemangledFunctionIndirect(mangledSource, demangledSource);
|
||||||
MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
|
MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
|
||||||
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
|
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
|
||||||
functionDefinition.setModifier(modifierType.getCVMod().toString());
|
functionDefinition.setModifier(modifierType.getCVMod().toString());
|
||||||
|
@ -488,7 +503,8 @@ public class MDMangGhidra extends MDMang {
|
||||||
private DemangledDataType processDataType(DemangledDataType resultDataType,
|
private DemangledDataType processDataType(DemangledDataType resultDataType,
|
||||||
MDDataType datatype) {
|
MDDataType datatype) {
|
||||||
if (resultDataType == null) {
|
if (resultDataType == null) {
|
||||||
resultDataType = new DemangledDataType(datatype.getTypeName());
|
resultDataType =
|
||||||
|
new DemangledDataType(mangledSource, demangledSource, datatype.getTypeName());
|
||||||
}
|
}
|
||||||
if (datatype.isSpecifiedSigned()) {
|
if (datatype.isSpecifiedSigned()) {
|
||||||
// Returns true if default signed or specified signed. TODO: There is no place to
|
// 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;
|
package mdemangler;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import mdemangler.datatype.MDDataType;
|
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 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 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.
|
* @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,
|
public void demangleAndTest(String mangledArg, String mdtruth, String mstruth, String ghtruth,
|
||||||
String ms2013truth) throws Exception {
|
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 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)).
|
// expect the output to be that which we desire ("truth".equals(demangled)).
|
||||||
if ((truth.equals(mangledArg)) && isMangled(mangledArg)) {
|
if ((truth.equals(mangledArg)) && isMangled(mangledArg)) {
|
||||||
assert (demangled.isEmpty());
|
assertTrue(demangled.isEmpty());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(truth.equals(demangled));
|
assertEquals(truth, demangled);
|
||||||
}
|
}
|
||||||
if (mangledArg.startsWith(".?A")) {
|
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) {
|
private boolean isMangled(String s) {
|
||||||
if (mangled.charAt(0) == '?') {
|
if (s.charAt(0) == '?') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (mangled.startsWith("__")) {
|
else if (s.startsWith("__")) {
|
||||||
return true;
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package mdemangler;
|
package mdemangler;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class MDMangExtraTests extends AbstractGenericTest {
|
||||||
String demangled = item.toString();
|
String demangled = item.toString();
|
||||||
assertEquals(wholeTruth, demangled);
|
assertEquals(wholeTruth, demangled);
|
||||||
DemangledObject obj = demangler.getObject();
|
DemangledObject obj = demangler.getObject();
|
||||||
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getOriginalMangled();
|
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getMangledString();
|
||||||
assertEquals(functionNamespaceMangledTruth, mangledFunctionNamespace);
|
assertEquals(functionNamespaceMangledTruth, mangledFunctionNamespace);
|
||||||
|
|
||||||
item = demangler.demangle(mangledFunctionNamespace, true);
|
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;
|
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.AWTEvent;
|
||||||
import java.awt.datatransfer.*;
|
import java.awt.AWTException;
|
||||||
import java.awt.event.*;
|
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.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
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.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.stream.Collectors;
|
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 javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
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.DockingActionIf;
|
||||||
import docking.action.ToggleDockingActionIf;
|
import docking.action.ToggleDockingActionIf;
|
||||||
import docking.actions.DockingToolActions;
|
import docking.actions.DockingToolActions;
|
||||||
|
@ -55,7 +104,9 @@ import generic.test.ConcurrentTestExceptionHandler;
|
||||||
import generic.util.image.ImageUtils;
|
import generic.util.image.ImageUtils;
|
||||||
import ghidra.GhidraTestApplicationLayout;
|
import ghidra.GhidraTestApplicationLayout;
|
||||||
import ghidra.framework.ApplicationConfiguration;
|
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.exception.AssertException;
|
||||||
import ghidra.util.task.SwingUpdateManager;
|
import ghidra.util.task.SwingUpdateManager;
|
||||||
import ghidra.util.worker.Worker;
|
import ghidra.util.worker.Worker;
|
||||||
|
@ -217,25 +268,9 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Window waitForWindowByTitleContaining(String text) {
|
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
|
// try at least one time
|
||||||
Window window = getWindowByTitleContaining(parentWindow, text);
|
Window window = getWindowByTitleContaining(null, text);
|
||||||
if (window != null) {
|
if (window != null) {
|
||||||
return window;// we found it...no waiting required
|
return window;// we found it...no waiting required
|
||||||
}
|
}
|
||||||
|
@ -244,7 +279,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
int timeout = DEFAULT_WAIT_TIMEOUT;
|
int timeout = DEFAULT_WAIT_TIMEOUT;
|
||||||
while (totalTime <= timeout) {
|
while (totalTime <= timeout) {
|
||||||
|
|
||||||
window = getWindowByTitleContaining(parentWindow, text);
|
window = getWindowByTitleContaining(null, text);
|
||||||
if (window != null) {
|
if (window != null) {
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
@ -256,43 +291,6 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
"Timed-out waiting for window containg title '" + text + "'");
|
"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.
|
* 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,
|
public static Set<DockingActionIf> getActionsByOwnerAndName(Tool tool, String owner,
|
||||||
String name) {
|
String name) {
|
||||||
Set<DockingActionIf> ownerActions = tool.getDockingActionsByOwnerName(owner);
|
Set<DockingActionIf> ownerActions = tool.getDockingActionsByOwnerName(owner);
|
||||||
return ownerActions.stream()
|
return ownerActions.stream().filter(action -> action.getName().equals(name)).collect(
|
||||||
.filter(action -> action.getName().equals(name))
|
Collectors.toSet());
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1840,25 +1837,6 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
useErrorGUI = enable;
|
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
|
* Turns off the gui displays for errors. This does not change the "isUseErrorGUI()" value for
|
||||||
* other tests in the TestCase.
|
* other tests in the TestCase.
|
||||||
|
|
|
@ -248,8 +248,9 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
||||||
*/
|
*/
|
||||||
public static Set<Window> getAllWindows() {
|
public static Set<Window> getAllWindows() {
|
||||||
Set<Window> set = new HashSet<>();
|
Set<Window> set = new HashSet<>();
|
||||||
Frame sharedOwnerFrame = (Frame) AppContext.getAppContext().get(
|
Frame sharedOwnerFrame = (Frame) AppContext.getAppContext()
|
||||||
new StringBuffer("SwingUtilities.sharedOwnerFrame"));
|
.get(
|
||||||
|
new StringBuffer("SwingUtilities.sharedOwnerFrame"));
|
||||||
if (sharedOwnerFrame != null) {
|
if (sharedOwnerFrame != null) {
|
||||||
set.addAll(getAllWindows(sharedOwnerFrame));
|
set.addAll(getAllWindows(sharedOwnerFrame));
|
||||||
}
|
}
|
||||||
|
@ -1515,6 +1516,29 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
||||||
UIManager.put("TextArea.font", f);
|
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
|
* Waits for the Swing thread to process any pending events. This method
|
||||||
* also waits for any {@link SwingUpdateManager}s that have pending events
|
* also waits for any {@link SwingUpdateManager}s that have pending events
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package help.screenshot;
|
package help.screenshot;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
@ -148,7 +148,7 @@ public class CodeBrowserPluginScreenShots extends GhidraScreenShotGenerator {
|
||||||
makeSelection(0x0406be1, 0x0406bf1);
|
makeSelection(0x0406be1, 0x0406bf1);
|
||||||
|
|
||||||
performAction("Create Table From Selection", "CodeBrowserPlugin", true);
|
performAction("Create Table From Selection", "CodeBrowserPlugin", true);
|
||||||
Window window = waitForWindowByTitleContaining(null, "Selection Table", 2000);
|
Window window = waitForWindowByTitleContaining("Selection Table");
|
||||||
Point loc = plugin.getListingPanel().getLocationOnScreen();
|
Point loc = plugin.getListingPanel().getLocationOnScreen();
|
||||||
Dimension size = window.getSize();
|
Dimension size = window.getSize();
|
||||||
window.setBounds(loc.x + 300, loc.y + 150, size.width, 300);
|
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");
|
JWindow popup = (JWindow) waitForWindowByName("ListingHoverProvider");
|
||||||
paintFix(popup);
|
paintFix(popup);
|
||||||
captureProvider(CodeViewerProvider.class);
|
captureProvider(CodeViewerProvider.class);
|
||||||
|
|
||||||
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
|
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
|
||||||
captureProviderWithScreenShot(provider);
|
captureProviderWithScreenShot(provider);
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ public class NavigationScreenShots extends GhidraScreenShotGenerator {
|
||||||
setGotoText(dialog, "LAB*");
|
setGotoText(dialog, "LAB*");
|
||||||
pressOkOnDialog();
|
pressOkOnDialog();
|
||||||
Window window =
|
Window window =
|
||||||
waitForWindowByTitleContaining(null, "Search Limit Exceeded!", DEFAULT_WINDOW_TIMEOUT);
|
waitForWindowByTitleContaining("Search Limit Exceeded!");
|
||||||
assertNotNull(window);
|
assertNotNull(window);
|
||||||
pressButtonByText(window, "OK");
|
pressButtonByText(window, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
program.endTransaction(txID, false);
|
program.endTransaction(txID, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Test that the DemangledFunction will properly create a cascade of namespaces for
|
* 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.
|
* 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.
|
* 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));
|
assertEquals("ATL", ns.getName(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Test that the DemangledFunction will properly update a thunk function
|
* Test that the DemangledFunction will properly update a thunk function
|
||||||
* with its namespace, and ripple through to the underlying default thunked
|
* with its namespace, and ripple through to the underlying default thunked
|
||||||
* function. The thunk 'this' parameter should utilize the Class
|
* 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
|
* 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.
|
* functions that live inside of a class that lives inside of a namespace.
|
||||||
* This test applies a demangled name where the mangled name exists.
|
* 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));
|
assertEquals("ATL", ns.getName(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Test that the DemangledFunction will properly create a cascade of namespaces for
|
* 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.
|
* 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.
|
* 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));
|
assertEquals("ATL", ns.getName(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Test that the DemangledFunction will properly create a cascade of namespaces for
|
* 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.
|
* 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
|
* 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));
|
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
|
* 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.
|
* 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
|
* 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) {
|
private void assertSimpleNamespaceExists(String name) {
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
Namespace ns = symbolTable.getNamespace(name, program.getGlobalNamespace());
|
Namespace ns = symbolTable.getNamespace(name, program.getGlobalNamespace());
|
||||||
assertNotNull(ns);
|
assertNotNull("Namespace not created: " + name, ns);
|
||||||
assertEquals(SymbolType.NAMESPACE, ns.getSymbol().getSymbolType());
|
assertEquals(SymbolType.NAMESPACE, ns.getSymbol().getSymbolType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertFunction(String name, Address addr) {
|
private Function assertFunction(String name, Address addr) {
|
||||||
FunctionManager fm = program.getFunctionManager();
|
FunctionManager fm = program.getFunctionManager();
|
||||||
Function function = fm.getFunctionAt(addr);
|
Function function = fm.getFunctionAt(addr);
|
||||||
assertNotNull("Expected function to get created at " + addr, function);
|
assertNotNull("Expected function to get created at " + addr, function);
|
||||||
assertEquals(name, function.getName());
|
assertEquals(name, function.getName());
|
||||||
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address addr(String addr) {
|
private Address addr(String addr) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
|
||||||
String mangled = "MyFunction__11MyNamespacePQ215$ParamNamespace9paramName";
|
String mangled = "MyFunction__11MyNamespacePQ215$ParamNamespace9paramName";
|
||||||
|
|
||||||
GnuDemangler demangler = new GnuDemangler();
|
GnuDemangler demangler = new GnuDemangler();
|
||||||
demangler.canDemangle(program);// this perform initialization
|
demangler.canDemangle(program);// this performs initialization
|
||||||
|
|
||||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||||
options.setDemangleOnlyKnownPatterns(false);
|
options.setDemangleOnlyKnownPatterns(false);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue