mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-29 07:55:53 +08:00
Merge remote-tracking branch
'origin/GT-3545-dragonmacher-gnu-demangler-parsing-bugs' Fixes #1457 Fixes #1569
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
+1
-1
@@ -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) {
|
||||||
|
|||||||
+330
@@ -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();
|
||||||
|
}
|
||||||
+21
-14
@@ -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
|
||||||
|
|||||||
+81
-167
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+115
-107
@@ -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);
|
||||||
|
|||||||
+5
-348
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-351
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-330
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-39
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+13
-8
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+61
-150
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-57
@@ -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 != ' ')) {
|
||||||
|
|||||||
+4
-26
@@ -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.
|
||||||
|
|||||||
+24
-28
@@ -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();
|
|
||||||
}
|
|
||||||
+1
-2
@@ -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");
|
||||||
|
|||||||
+7
-4
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-7
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
+935
-639
File diff suppressed because it is too large
Load Diff
+621
File diff suppressed because it is too large
Load Diff
+543
-242
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -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) {
|
||||||
|
|||||||
-16
@@ -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
|
|
||||||
-2280
File diff suppressed because it is too large
Load Diff
+6
-3
@@ -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.
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-9
@@ -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 {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-57
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-59
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-579
File diff suppressed because it is too large
Load Diff
-64
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-241
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-273
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user