GT-3545 - GNU Demangler - Fix Parsing Issues - Checkpoint 1

All tests passing; major class model refactoring pending
This commit is contained in:
dragonmacher
2020-02-25 14:46:22 -05:00
parent 9faf39baed
commit 7d09241ef6
19 changed files with 1149 additions and 415 deletions
@@ -233,7 +233,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
log.appendMsg(getName(),
"Failed to apply mangled symbol at " + address + "; name: " +
demangled.getMangledName() + failMessage);
demangled.getMangledString() + failMessage);
}
protected String cleanSymbol(Address address, String name) {
@@ -0,0 +1,43 @@
/* ###
* 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;
// TODO better name
public interface Demangled {
public String getName();
/**
* Returns the namespace containing this demangled object
* @return the namespace containing this demangled object
*/
public Demangled getNamespace();
public void setNamespace(Demangled ns);
public String toNamespaceString();
// TODO doc difference
public String toNamespaceName();
/**
* Returns the original mangled string
* @return the string
*/
public String getMangledString();
public void setMangledString(String mangled);
}
@@ -27,11 +27,11 @@ import util.demangler.GenericDemangledAddressTable;
public class DemangledAddressTable extends DemangledObject {
private boolean calculateLength;
private int length;
public DemangledAddressTable(String name, int length) {
public DemangledAddressTable(String name, boolean calculateLength) {
setName(name);
this.length = length;
}
DemangledAddressTable(GenericDemangledAddressTable generic) {
@@ -57,7 +57,7 @@ public class DemangledAddressTable extends DemangledObject {
buffer.append(specialPrefix);
buffer.append(' ');
}
String namespaceStr = namespace.toSignature();
String namespaceStr = namespace.toNamespaceString();
buffer.append(namespaceStr);
if (!namespaceStr.endsWith(NAMESPACE_SEPARATOR)) {
buffer.append(NAMESPACE_SEPARATOR);
@@ -83,15 +83,16 @@ public class DemangledAddressTable extends DemangledObject {
return false;
}
Listing listing = program.getListing();
if (MemoryBlock.isExternalBlockAddress(address, program)) {
program.getListing().setComment(address, CodeUnit.EOL_COMMENT,
listing.setComment(address, CodeUnit.EOL_COMMENT,
"WARNING: Unable to apply demangled Address Table");
return true; // don't complain
}
if (length == -1) {
if (calculateLength) {
// determine length of address table
Data d = program.getListing().getDefinedDataAt(address);
Data d = listing.getDefinedDataAt(address);
if (d != null && Undefined.isUndefinedArray(d.getDataType())) {
// use length of Undefined array at start of table to indicate length
length = d.getLength();
@@ -102,6 +103,7 @@ public class DemangledAddressTable extends DemangledObject {
return false;
}
}
calculateLength = false;
}
if (isUndefinedInRange(program, address, address.add(length - 1))) {
@@ -22,6 +22,7 @@ import java.util.regex.Pattern;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.program.model.symbol.Namespace;
import util.demangler.*;
/**
@@ -84,14 +85,13 @@ public class DemangledDataType extends DemangledType {
private boolean isEnum;
private boolean isPointer64;
private boolean isReference;
private boolean isSigned;//explicitly signed!
private boolean isSigned;
private boolean isStruct;
private boolean isTemplate;
private boolean isUnaligned;
private boolean isUnion;
private boolean isUnsigned;
private boolean isVarArgs;
// private boolean isVolatile;
private int pointerLevels = 0;
private String enumType;
private boolean isRestrict;
@@ -408,12 +408,12 @@ public class DemangledDataType extends DemangledType {
* @param dataTypeManager data type manager to be searched
* @param dtName name of data type
* @param namespace namespace associated with dtName or null if not applicable. If specified,
* a namespace-base category path will be given precendence.
* a namespace-base category path will be given precedence.
* @return data type if found, otherwise null.
* @see DataTypeUtilities#findDataType(DataTypeManager, ghidra.program.model.symbol.Namespace, String, Class) for similar namespace
* based search.
*/
static DataType findDataType(DataTypeManager dataTypeManager, DemangledType namespace,
static DataType findDataType(DataTypeManager dataTypeManager, Demangled namespace,
String dtName) {
// TODO: Should be able to search archives somehow
ArrayList<DataType> list = new ArrayList<>();
@@ -446,11 +446,11 @@ public class DemangledDataType extends DemangledType {
return null;
}
private static boolean isNamespaceCategoryMatch(DataType dt, DemangledType namespace) {
private static boolean isNamespaceCategoryMatch(DataType dt, Demangled namespace) {
if (namespace == null) {
return true;
}
DemangledType ns = namespace;
Demangled ns = namespace;
CategoryPath categoryPath = dt.getCategoryPath();
while (ns != null) {
if (categoryPath.equals(CategoryPath.ROOT) ||
@@ -463,8 +463,8 @@ public class DemangledDataType extends DemangledType {
return true;
}
private static String getNamespacePath(String dtName, DemangledType namespace) {
DemangledType ns = namespace;
private static String getNamespacePath(String dtName, Demangled namespace) {
Demangled ns = namespace;
String namespacePath = "";
while (ns != null) {
namespacePath = "/" + ns.getName() + namespacePath;
@@ -473,11 +473,11 @@ public class DemangledDataType extends DemangledType {
return namespacePath;
}
private static CategoryPath getDemanglerCategoryPath(String dtName, DemangledType namespace) {
private static CategoryPath getDemanglerCategoryPath(String dtName, Demangled namespace) {
return new CategoryPath("/Demangler" + getNamespacePath(dtName, namespace));
}
static Structure createPlaceHolderStructure(String dtName, DemangledType namespace) {
static Structure createPlaceHolderStructure(String dtName, Demangled namespace) {
StructureDataType structDT = new StructureDataType(dtName, 0);
structDT.setDescription("PlaceHolder Structure");
structDT.setCategoryPath(getDemanglerCategoryPath(dtName, namespace));
@@ -561,10 +561,6 @@ public class DemangledDataType extends DemangledType {
isVarArgs = true;
}
// public void setVolatile() {
// isVolatile = true;
// }
//
public void setEnumType(String enumType) {
this.enumType = enumType;
}
@@ -685,7 +681,7 @@ public class DemangledDataType extends DemangledType {
@Override
public String toSignature() {
StringBuffer buffer = new StringBuffer();
StringBuilder buffer = new StringBuilder();
if (isUnion) {
buffer.append(UNION + SPACE);
@@ -722,7 +718,8 @@ public class DemangledDataType extends DemangledType {
}
if (getNamespace() != null) {
buffer.append(getNamespace().toNamespace());
buffer.append(getNamespace().toNamespaceString());
buffer.append(Namespace.DELIMITER);
}
buffer.append(getDemangledName());
@@ -159,7 +159,10 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
return callingConvention;
}
/** Special constructor where it has a templated type before the parameter list */
/**
* Special constructor where it has a templated type before the parameter list
* @param type the type
*/
public void setTemplatedConstructorType(String type) {
this.templatedConstructorType = type;
}
@@ -227,7 +230,6 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
}
buffer.append(
visibility == null || "global".equals(visibility) ? "" : visibility + " ");
// if (virtual) {
if (isVirtual) {
buffer.append("virtual ");
}
@@ -242,7 +244,8 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
buffer.append(callingConvention == null ? "" : callingConvention + " ");
if (namespace != null) {
buffer.append(namespace.toNamespace());
buffer.append(namespace.toNamespaceString());
buffer.append(NAMESPACE_SEPARATOR);
}
buffer.append(getDemangledName());
@@ -351,6 +354,11 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
return buffer.toString();
}
@Override
public String toNamespaceName() {
return getName() + getParameterString();
}
public String getParameterString() {
StringBuffer buffer = new StringBuffer();
buffer.append('(');
@@ -530,9 +538,11 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
// 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)");
program.getBookmarkManager()
.setBookmark(func.getEntryPoint(),
BookmarkType.ANALYSIS, "Demangler",
"Warning calling convention \"" +
callingConvention + "\" not defined in Compiler Spec (.cspec)");
}
else {
func.setCallingConvention(callingConvention);
@@ -714,7 +724,7 @@ public class DemangledFunction extends DemangledObject implements ParameterRecei
* @return true if it is in the std namespace
*/
private boolean isInStdNameSpace() {
DemangledType ns = namespace;
Demangled ns = namespace;
// if my immediate namespace is "std", then I am just a function in the std namespace.
if (ns == null) {
@@ -198,8 +198,8 @@ public class DemangledFunctionPointer extends DemangledDataType implements Param
}
public String toSignature(String name) {
StringBuffer buffer = new StringBuffer();
StringBuffer buffer1 = new StringBuffer();
StringBuilder buffer = new StringBuilder();
StringBuilder buffer1 = new StringBuilder();
String s = getConventionPointerNameString(name);
if (s.contains(" ") || s.isEmpty()) {
// spaces--add parens
@@ -220,18 +220,21 @@ public class DemangledFunctionPointer extends DemangledDataType implements Param
if (returnType instanceof DemangledFunctionPointer) {
buffer.append(
((DemangledFunctionPointer) returnType).toSignature(buffer1.toString())).append(
SPACE);
((DemangledFunctionPointer) returnType).toSignature(buffer1.toString()))
.append(
SPACE);
}
else if (returnType instanceof DemangledFunctionReference) {
buffer.append(
((DemangledFunctionReference) returnType).toSignature(buffer1.toString())).append(
SPACE);
((DemangledFunctionReference) returnType).toSignature(buffer1.toString()))
.append(
SPACE);
}
else if (returnType instanceof DemangledFunctionIndirect) {
buffer.append(
((DemangledFunctionIndirect) returnType).toSignature(buffer1.toString())).append(
SPACE);
((DemangledFunctionIndirect) returnType).toSignature(buffer1.toString()))
.append(
SPACE);
}
else {
buffer.append(returnType.toSignature()).append(SPACE);
@@ -276,7 +279,7 @@ public class DemangledFunctionPointer extends DemangledDataType implements Param
return buffer.toString();
}
private void addFunctionPointerParens(StringBuffer buffer, String s) {
private void addFunctionPointerParens(StringBuilder buffer, String s) {
if (!displayFunctionPointerParens) {
return;
}
@@ -28,11 +28,6 @@ public class DemangledFunctionType extends DemangledType {
this.signature = signature;
}
@Override
public boolean isFunction() {
return true;
}
public String getSignature() {
return signature;
}
@@ -0,0 +1,33 @@
/* ###
* 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;
public class DemangledLambda extends DemangledFunction {
public DemangledLambda(String name) {
super(name);
}
@Override
public String toNamespaceName() {
return getName();
}
@Override
public String toString() {
return getName();
}
}
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +17,7 @@ package ghidra.app.util.demangler;
import util.demangler.GenericDemangledMethod;
// TODO delete this
public class DemangledMethod extends DemangledFunction {
public DemangledMethod(String name) {
@@ -34,7 +34,7 @@ import util.demangler.GenericDemangledType;
/**
* A class to represent a demangled object.
*/
public abstract class DemangledObject {
public abstract class DemangledObject implements Demangled {
protected static final String SPACE = " ";
protected static final Pattern SPACE_PATTERN = Pattern.compile(SPACE);
@@ -42,12 +42,12 @@ public abstract class DemangledObject {
protected static final String NAMESPACE_SEPARATOR = Namespace.DELIMITER;
protected static final String EMPTY_STRING = "";
protected String originalMangled;
protected String mangled; // original mangled string
protected String utilDemangled;
protected String specialPrefix;
protected String specialMidfix;
protected String specialSuffix;
protected DemangledType namespace;
protected Demangled namespace;
protected String visibility;//public, protected, etc.
//TODO: storageClass refers to things such as "static" but const and volatile are
@@ -78,7 +78,7 @@ public abstract class DemangledObject {
}
DemangledObject(GenericDemangledObject other) {
originalMangled = other.getOriginalMangled();
mangled = other.getOriginalMangled();
specialPrefix = other.getSpecialPrefix();
specialMidfix = other.getSpecialMidfix();
specialSuffix = other.getSpecialSuffix();
@@ -115,20 +115,13 @@ public abstract class DemangledObject {
return demangledName;
}
/**
* Returns the original mangled name
* @return the name
*/
public String getMangledName() {
return originalMangled;
}
/**
* Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be
* converted to an underscore.
* @return name of this DemangledObject with unsupported characters converted to underscore
*/
@Override
public String getName() {
return name;
}
@@ -228,12 +221,14 @@ public abstract class DemangledObject {
}
}
/**
* Sets the original mangled name
* @param mangled the original mangled name
*/
public void setOriginalMangled(String mangled) {
this.originalMangled = mangled;
@Override
public void setMangledString(String mangled) {
this.mangled = mangled;
}
@Override
public String getMangledString() {
return mangled;
}
/**
@@ -252,15 +247,13 @@ public abstract class DemangledObject {
return utilDemangled;
}
/**
* Returns the namespace containing this demangled object.
* @return the namespace containing this demangled object
*/
public DemangledType getNamespace() {
@Override
public Demangled getNamespace() {
return namespace;
}
public void setNamespace(DemangledType namespace) {
@Override
public void setNamespace(Demangled namespace) {
this.namespace = namespace;
}
@@ -317,6 +310,15 @@ public abstract class DemangledObject {
*/
public abstract String getSignature(boolean format);
/**
* Returns a signature that contains only the name (and parameter list for functions)
* @return the signature
*/
@Override
public String toNamespaceName() {
return getSignature(false);
}
/**
* Sets the signature. Calling this method will
* override the auto-generated signature.
@@ -331,6 +333,17 @@ public abstract class DemangledObject {
return getSignature(false);
}
@Override
public String toNamespaceString() {
StringBuilder buffer = new StringBuilder();
if (namespace != null) {
buffer.append(namespace.toNamespaceString());
buffer.append(Namespace.DELIMITER);
}
buffer.append(toNamespaceName());
return buffer.toString();
}
/**
* Determine if the symbol at address has already been demangled. While memory symbols
* check for presence of demangledName, external symbols simply check if demangled/alternate
@@ -364,7 +377,7 @@ public abstract class DemangledObject {
public boolean applyTo(Program program, Address address, DemanglerOptions options,
TaskMonitor monitor) throws Exception {
if (originalMangled.equals(name)) {
if (mangled.equals(name)) {
return false;
}
String comment = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address);
@@ -432,7 +445,7 @@ public abstract class DemangledObject {
}
private Symbol updateExternalSymbol(Program program, Address externalAddr, String symbolName,
DemangledType demangledNamespace) {
Demangled demangledNamespace) {
SymbolTable symbolTable = program.getSymbolTable();
Symbol s = symbolTable.getPrimarySymbol(externalAddr);
@@ -461,9 +474,9 @@ public abstract class DemangledObject {
* @param typeNamespace demangled namespace object
* @return list of namespace names
*/
private static List<String> getNamespaceList(DemangledType typeNamespace) {
private static List<String> getNamespaceList(Demangled typeNamespace) {
ArrayList<String> list = new ArrayList<>();
DemangledType ns = typeNamespace;
Demangled ns = typeNamespace;
while (ns != null) {
list.add(0, ns.getName());
ns = ns.getNamespace();
@@ -478,13 +491,13 @@ public abstract class DemangledObject {
* any symbol creation accordingly. Caller should use
* <code>getResidualNamespacePath(DemangledType, Namespace)</code> to handle the case where
* only a partial namespace has been returned.
* @param program
* @param program the program
* @param typeNamespace demangled namespace
* @param parentNamespace root namespace to be used (e.g., library, global, etc.)
* @param functionPermitted if true an existing function may be used as a namespace
* @return namespace or partial namespace if error occurs
*/
public static Namespace createNamespace(Program program, DemangledType typeNamespace,
public static Namespace createNamespace(Program program, Demangled typeNamespace,
Namespace parentNamespace, boolean functionPermitted) {
Namespace namespace = parentNamespace;
@@ -592,7 +605,7 @@ public abstract class DemangledObject {
}
// Store class structure in parent namespace
DemangledType classStructureNamespace = namespace.getNamespace();
Demangled classStructureNamespace = namespace.getNamespace();
Structure classStructure = (Structure) DemangledDataType.findDataType(dataTypeManager,
classStructureNamespace, structureName);
@@ -106,7 +106,7 @@ public class DemangledThunk extends DemangledObject {
function = function.getThunkedFunction(false);
}
if (thunkedFunction != null && originalMangled.equals(function.getName()) &&
if (thunkedFunction != null && mangled.equals(function.getName()) &&
!function.isThunk()) {
function.setThunkedFunction(thunkedFunction);
}
@@ -147,8 +147,9 @@ public class DemangledThunk extends DemangledObject {
while (instr != null) {
// This is done in a way to handle potential delay slots
InstructionContext instructionContext = instr.getInstructionContext();
Address fallThru = instructionContext.getAddress().add(
instr.getPrototype().getFallThroughOffset(instructionContext));
Address fallThru = instructionContext.getAddress()
.add(
instr.getPrototype().getFallThroughOffset(instructionContext));
Address maxAddr = fallThru.previous();
if (maxAddr.compareTo(instr.getMinAddress()) < 0) {
// just in case we wrapped
@@ -181,7 +182,7 @@ public class DemangledThunk extends DemangledObject {
}
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
thunkedFunctionObject.originalMangled, err -> Msg.warn(this, err));
thunkedFunctionObject.mangled, err -> Msg.warn(this, err));
if (s == null) {
Address thunkedAddr =
@@ -22,11 +22,12 @@ import ghidra.program.model.symbol.Namespace;
import util.demangler.GenericDemangledTemplate;
import util.demangler.GenericDemangledType;
public class DemangledType {
// TODO maybe rename this to DemangledNamespace
public class DemangledType implements Demangled {
private String demangledName;
private String name;
protected String originalMangled;
protected DemangledType namespace;
protected String mangled; // the original mangled string
protected Demangled namespace;
protected DemangledTemplate template;
private boolean isConst;
private boolean isVolatile;
@@ -41,7 +42,7 @@ public class DemangledType {
* 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) {
public static Demangled convertToNamespace(GenericDemangledType otherNamespace) {
if (otherNamespace == null) {
return null;
}
@@ -103,6 +104,7 @@ public class DemangledType {
* converted to an underscore.
* @return name of this DemangledType suitable for namespace creation.
*/
@Override
public String getName() {
return name;
}
@@ -120,20 +122,14 @@ public class DemangledType {
}
}
/**
* Sets the original mangled name
* @param mangled the original mangled name
*/
public void setOriginalMangled(String mangled) {
this.originalMangled = mangled;
@Override
public void setMangledString(String mangled) {
this.mangled = mangled;
}
/**
* Gets the original mangled name
* @return the original mangled name
*/
public String getOriginalMangled() {
return originalMangled;
@Override
public String getMangledString() {
return mangled;
}
public boolean isConst() {
@@ -144,10 +140,6 @@ public class DemangledType {
isConst = true;
}
public boolean isFunction() {
return false;
}
public boolean isVolatile() {
return isVolatile;
}
@@ -156,11 +148,13 @@ public class DemangledType {
isVolatile = true;
}
public DemangledType getNamespace() {
@Override
public Demangled getNamespace() {
return namespace;
}
public void setNamespace(DemangledType namespace) {
@Override
public void setNamespace(Demangled namespace) {
if (this == namespace) {
throw new IllegalArgumentException("Attempt to set this.namespace == this!");
}
@@ -176,14 +170,21 @@ public class DemangledType {
}
public String toSignature() {
return toNamespace();
return toNamespaceString();
}
public String toNamespace() {
StringBuffer buffer = new StringBuffer();
if (namespace != null) {
buffer.append(namespace.toNamespace());
@Override
public String toNamespaceString() {
return getName(true);
}
private String getName(boolean includeNamespace) {
StringBuilder buffer = new StringBuilder();
if (includeNamespace && namespace != null) {
buffer.append(namespace.toNamespaceString());
buffer.append(Namespace.DELIMITER);
}
buffer.append(demangledName);
if (template != null) {
buffer.append(template.toTemplate());
@@ -193,12 +194,16 @@ public class DemangledType {
return "";
}
buffer.append(Namespace.DELIMITER);
return buffer.toString();
}
@Override
public String toNamespaceName() {
return getName(false);
}
@Override
public String toString() {
return toNamespace();
return toNamespaceString();
}
}
@@ -15,6 +15,8 @@
*/
package ghidra.app.util.demangler;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.util.PseudoDisassembler;
import ghidra.program.model.address.Address;
@@ -70,7 +72,7 @@ public class DemangledVariable extends DemangledObject {
@Override
public String getSignature(boolean format) {
StringBuffer buffer = new StringBuffer();
StringBuilder buffer = new StringBuilder();
buffer.append(specialPrefix == null ? EMPTY_STRING : specialPrefix + SPACE);
buffer.append(
visibility == null || "global".equals(visibility) ? EMPTY_STRING : visibility + SPACE);
@@ -80,7 +82,7 @@ public class DemangledVariable extends DemangledObject {
buffer.append(isVirtual ? "virtual" + SPACE : EMPTY_STRING);
String n = getDemangledName();
boolean hasName = (n != null) && !n.isEmpty();
boolean hasName = !StringUtils.isBlank(n);
StringBuffer datatypeBuffer = new StringBuffer();
String spacer = EMPTY_STRING;
@@ -139,11 +141,10 @@ public class DemangledVariable extends DemangledObject {
datatypeBuffer.append(spacer);
spacer = EMPTY_STRING;
datatypeBuffer.append(namespace.toNamespace());
datatypeBuffer.append(namespace.toNamespaceString());
if (!hasName) {
int end = buffer.length();
datatypeBuffer.delete(end - 2, end); // strip off the last namespace characters
if (hasName) {
datatypeBuffer.append(NAMESPACE_SEPARATOR);
}
}
@@ -158,17 +159,14 @@ public class DemangledVariable extends DemangledObject {
if (datatype instanceof DemangledFunctionPointer) {
DemangledFunctionPointer funcPtr = (DemangledFunctionPointer) datatype;
//return funcPtr.toSignature(buffer.toString());
return buffer.append(funcPtr.toSignature(datatypeBuffer.toString())).toString();
}
else if (datatype instanceof DemangledFunctionReference) {
DemangledFunctionReference funcRef = (DemangledFunctionReference) datatype;
//return funcRef.toSignature(buffer.toString());
return buffer.append(funcRef.toSignature(datatypeBuffer.toString())).toString();
}
else if (datatype instanceof DemangledFunctionIndirect) {
DemangledFunctionIndirect funcDef = (DemangledFunctionIndirect) datatype;
//return funcDef.toSignature(buffer.toString());
return buffer.append(funcDef.toSignature(datatypeBuffer.toString())).toString();
}
@@ -177,6 +175,20 @@ public class DemangledVariable extends DemangledObject {
return buffer.toString();
}
@Override
public String toNamespaceName() {
String n = getDemangledName();
if (!StringUtils.isBlank(n)) {
return n;
}
if (datatype != null) {
return datatype.toSignature();
}
return "<no name>"; // shouldn't happen
}
@Override
protected boolean isAlreadyDemangled(Program program, Address address) {
Data data = program.getListing().getDefinedDataAt(address);
@@ -146,13 +146,4 @@ public class DemanglerUtil {
matcher.appendTail(buffy);
return buffy.toString();
}
public static void setNamespace(DemangledType dt, DemangledType namespace) {
if (dt.getNamespace() == null) {
dt.setNamespace(namespace);
}
else {
setNamespace(dt.getNamespace(), namespace);
}
}
}
@@ -123,14 +123,14 @@ public class GnuDemangler implements Demangler {
demangledObject.setSignature(demangled);
}
demangledObject.setOriginalMangled(originalMangled);
demangledObject.setMangledString(originalMangled);
if (isDwarf) {
DemangledAddressTable dat = new DemangledAddressTable((String) null, 1);
DemangledAddressTable dat = new DemangledAddressTable((String) null, false);
dat.setSpecialPrefix("DWARF Debug ");
dat.setName(demangledObject.getName());
dat.setNamespace(demangledObject.getNamespace());
dat.setOriginalMangled(originalMangled);
dat.setMangledString(originalMangled);
return dat;
}
@@ -72,14 +72,6 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
System.out.println("Elapsed Time: " + (System.currentTimeMillis() - start));
}
private void demangle(String mangled) throws IOException {
String demangled = process.demangle(mangled);
assertNotNull(demangled);
assertNotEquals(mangled, demangled);
//System.out.println(parser.parse(mangled, demangled));
assertNotNull(parser.parse(mangled, demangled));
}
@Test
public void testOverloadedShiftOperatorParsingBug() {
parser = new GnuDemanglerParser(null);
@@ -101,7 +93,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
parse = parser.parse(null, "typeinfo name for Magick::Blob");
assertTrue(parse instanceof DemangledString);
assertEquals("Magick::Blob", ((DemangledString) parse).getString());
assertName(parse, "typeinfo_name", "Magick", "Blob");
assertName(parse, "typeinfo-name", "Magick", "Blob");
parse = parser.parse(null, "Bob::operator_new[](float, double, Bob::Fred &)");
assertTrue(parse instanceof DemangledMethod);
@@ -161,33 +153,6 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"covariant return thunk [nv:0] [nv:16] to KHotKeys::WindowTrigger::copy(KHotKeys::ActionData*) const");
assertTrue(parse instanceof DemangledThunk);
assertName(parse, "copy", "KHotKeys", "WindowTrigger");
try {
parse = parser.parse(
"_ZZN12GrGLFunctionIFPKhjEEC1IZN13skia_bindings28CreateGLES2InterfaceBindingsEPN3gpu5gles214GLES2InterfaceEPNS6_14ContextSupportEE3$_0EET_ENUlPKvjE_8__invokeESF_j",
"GrGLFunction<unsigned char const* (unsigned int)>::GrGLFunction<skia_bindings::CreateGLES2InterfaceBindings(gpu::gles2::GLES2Interface*, gpu::ContextSupport*)::$_0>(skia_bindings::CreateGLES2InterfaceBindings(gpu::gles2::GLES2Interface*, gpu::ContextSupport*)::$_0)::{lambda(void const*, unsigned int)#1}::__invoke(void const*, unsigned int)");
assertNull("Shouldn't have parsed", parser);
}
catch (Exception exc) {
// should get an exception
}
}
private void assertName(DemangledObject demangledObj, String name, String... namespaces) {
// String label = demangledObj.getName();
// if (demangledObj instanceof DemangledString) {
// label = ((DemangledString) demangledObj).getString();
// }
assertEquals("Unexpected demangled name", name, demangledObj.getName());
DemangledType namespace = demangledObj.getNamespace();
for (int i = namespaces.length - 1; i >= 0; i--) {
String n = namespaces[i];
assertNotNull("Namespace mismatch", namespace);
assertEquals(n, namespace.getName());
namespace = namespace.getNamespace();
}
assertNull("Namespace mismatch", namespace);
}
@Test
@@ -420,7 +385,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledVariable variable = (DemangledVariable) object;
assertEquals("__gthread_active_ptr", variable.getName());
assertEquals("__gthread_active_p()", variable.getNamespace().getName());
assertEquals("__gthread_active_p()", variable.getNamespace().toNamespaceName());
assertNull(variable.getDataType()); // no type information provided
}
@@ -473,15 +438,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// The below demangles to DDDSaveOptionsCB(_WidgetRec*, void*, void*)::dialog [#1]
//
// from program ddd
//
String mangled = "_ZZ16DDDSaveOptionsCBP10_WidgetRecPvS1_E6dialog_0";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertTrue(object instanceof DemangledVariable);
assertName(object, "dialog", "DDDSaveOptionsCB(_WidgetRec*,void*,void*)");
assertName(object, "dialog", "DDDSaveOptionsCB(_WidgetRec *,void *,void *)");
assertEquals("DDDSaveOptionsCB(_WidgetRec *,void *,void *)::dialog",
object.getSignature(false));
@@ -737,6 +700,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Format: operator std::string() const { return "bob"; }
//
//
//
//
// Mangled: _ZNK6Magick5ColorcvSsEv
//
// Demangled: Magick::Color::operator std::basic_string<char, std::char_traits<char>, std::allocator<char> >() const
//
String mangled = "_ZNK6Magick5ColorcvSsEv";
@@ -955,7 +924,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
List<DemangledDataType> parameters = df.getParameters();
assertEquals("Number of parameters", 1, parameters.size());
assertEquals("Name of type parsed", "F", parameters.get(0).getName());
assertEquals("Param Type Name parsed", "WTF::",
assertEquals("Param Type Name parsed", "WTF",
parameters.get(0).getNamespace().toString());
assertEquals("Param Template was parsed",
"<WTF::F<void (Core::FileClient &)> (Core::File &)>",
@@ -991,7 +960,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledDataType demangParamDT = parameters.get(0);
assertEquals("Name of type parsed", "function", demangParamDT.getName());
assertEquals("Param Type Name parsed", "boost::", demangParamDT.getNamespace().toString());
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
assertEquals("Param Template parsed", "<void ()>", demangParamDT.getTemplate().toString());
assertTrue("Is referent", demangParamDT.isReference());
@@ -1023,7 +992,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledDataType demangParamDT = parameters.get(0);
assertEquals("Name of type parsed", "function", demangParamDT.getName());
assertEquals("Param Type Name parsed", "boost::", demangParamDT.getNamespace().toString());
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
assertEquals("Param Template parsed", "<void (ares_options *,int *)>",
demangParamDT.getTemplate().toString());
assertTrue("Is referent", demangParamDT.isReference());
@@ -1061,7 +1030,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Mangled: _ZTCN6Crypto10HmacSha256E0_NS_3MacE
//
// Demangled:
// Demangled: construction vtable for Crypto::Mac-in-Crypto::HmacSha256
//
String mangled = "_ZTCN6Crypto10HmacSha256E0_NS_3MacE";
@@ -1081,6 +1051,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Mangled: _Z11testVarArgsiz
//
// Demangled: testVarArgs(int, ...)
//
String mangled = "_Z11testVarArgsiz";
@@ -1134,13 +1105,110 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertNull(res);
}
// @Test TODO upcoming fix for GT-3545
@Test
public void testStructureConstructorWithinTemplatedFunction() throws Exception {
//
// Mangled: _ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev
//
// Demangled: __gnu_cxx
// ::
// __stoa<long, int, char, int>(long (*)(char const*, char**, int), char const*, char const*, unsigned long*, int)
// ::
// _Save_errno
// ::
// _Save_errno()
//
// This is _Save_errno struct's constructor inside of the stoa templated function, in the
// __gnu_cxx namespace.
//
String mangled =
"_ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertTrue("Expected a Demangled Function: " + object, object instanceof DemangledFunction);
String signature = object.getSignature(false);
assertEquals(
"undefined __gnu_cxx" +
"::" +
"__stoa<long,int,char,int>(long(*)(char_const*,char**,int),char_const*,char_const*,unsigned_long*,int)" +
"::" +
"_Save_errno::_Save_errno(void)",
signature);
}
@Test
public void testOperatorTODO() throws Exception {
//
// Mangled: _ZNK2cc14ScrollSnapTypeneERKS0_
//
// Demangled: cc::ScrollSnapType::operator!=(cc::ScrollSnapType const&) const
//
String mangled = "_ZNK2cc14ScrollSnapTypeneERKS0_";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertTrue(object instanceof DemangledFunction);
String signature = object.getSignature(false);
assertEquals("undefined cc::ScrollSnapType::operator!=(cc::ScrollSnapType const &)",
signature);
}
@Test
public void testFunctionInLambdaNamespace() throws Exception {
//
// Mangled: _ZZN12GrGLFunctionIFPKhjEEC1IZN13skia_bindings28CreateGLES2InterfaceBindingsEPN3gpu5gles214GLES2InterfaceEPNS6_14ContextSupportEE3$_0EET_ENUlPKvjE_8__invokeESF_j
//
// Demangled: GrGLFunction<unsigned char const* (unsigned int)>
// ::
// GrGLFunction<skia_bindings::CreateGLES2InterfaceBindings(gpu::gles2::GLES2Interface*, gpu::ContextSupport*)::$_0>(skia_bindings::CreateGLES2InterfaceBindings(gpu::gles2::GLES2Interface*, gpu::ContextSupport*)::$_0)
// ::
// {lambda(void const*, unsigned int)#1}
// ::
// __invoke(void const*, unsigned int)
//
DemangledObject object = parser.parse(
"_ZZN12GrGLFunctionIFPKhjEEC1IZN13skia_bindings28CreateGLES2InterfaceBindingsEPN3gpu5gles214GLES2InterfaceEPNS6_14ContextSupportEE3$_0EET_ENUlPKvjE_8__invokeESF_j",
"GrGLFunction<unsigned char const* (unsigned int)>::GrGLFunction<skia_bindings::CreateGLES2InterfaceBindings(gpu::gles2::GLES2Interface*, gpu::ContextSupport*)::$_0>(skia_bindings::CreateGLES2InterfaceBindings(gpu::gles2::GLES2Interface*, gpu::ContextSupport*)::$_0)::{lambda(void const*, unsigned int)#1}::__invoke(void const*, unsigned int)");
assertNotNull(object);
assertTrue(object instanceof DemangledFunction);
assertName(object, "__invoke",
"GrGLFunction<unsigned_char_const*(unsigned_int)>",
"GrGLFunction<skia_bindings--CreateGLES2InterfaceBindings(gpu--gles2--GLES2Interface*,gpu--ContextSupport*)--$_0>(skia_bindings--CreateGLES2InterfaceBindings(gpu--gles2--GLES2Interface*,gpu--ContextSupport*)--$_0)",
"{lambda(void_const*,unsigned_int)#1}");
String signature = object.getSignature(false);
assertEquals(
"undefined GrGLFunction<unsigned_char_const*(unsigned_int)>::GrGLFunction<skia_bindings--CreateGLES2InterfaceBindings(gpu--gles2--GLES2Interface*,gpu--ContextSupport*)--$_0>(skia_bindings--CreateGLES2InterfaceBindings(gpu--gles2--GLES2Interface*,gpu--ContextSupport*)--$_0)::{lambda(void_const*,unsigned_int)#1}::__invoke(void const *,unsigned int)",
signature);
}
@Test
public void testFunctionWithLambda_WrappingAnotherFunctionCall() throws Exception {
//
// Mangled: _Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_
//
// Demangled: (wrap_360({parm#1}, (float)[42c80000])) wrap_360_cd<int>(int)
// Demangled: decltype (wrap_360({parm#1}, (float)[42c80000])) wrap_360_cd<int>(int)
//
// 'wrap_360_cd<int>(int)' is a function that takes an int and then passes that int along
// with a constant value to 'wrap_360<int>' by using a lambda function. It looks like
// this:
// auto wrap_360_cd<int>(int a) -> decltype(wrap_360(angle, 100.f))
//
// where the function is declared with this syntax:
// auto identifier ( argument-declarations... ) -> return_type
//
String mangled = "_Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_";
@@ -1150,8 +1218,30 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertNotNull(object);
assertTrue(object instanceof DemangledFunction);
// TODO
// TODO maybe put full output in setUtilDemangled()
String signature = object.getSignature(false);
assertEquals("undefined wrap_360_cd<int>(int)", signature);
}
private void assertName(DemangledObject demangledObj, String name, String... namespaces) {
assertEquals("Unexpected demangled name", name, demangledObj.getName());
Demangled namespace = demangledObj.getNamespace();
for (int i = namespaces.length - 1; i >= 0; i--) {
String n = namespaces[i];
assertNotNull("Namespace mismatch", namespace);
assertEquals(n, namespace.toNamespaceName());
namespace = namespace.getNamespace();
}
assertNull("Namespace mismatch", namespace);
}
private void demangle(String mangled) throws IOException {
String demangled = process.demangle(mangled);
assertNotNull(demangled);
assertNotEquals(mangled, demangled);
assertNotNull(parser.parse(mangled, demangled));
}
}
@@ -63,7 +63,7 @@ public class MDMangGhidra extends MDMang {
qual = it.next();
DemangledType newType = new DemangledType(qual.toString());
if (qual.isNested()) {
newType.setOriginalMangled(qual.getNested().getMangled());
newType.setMangledString(qual.getNested().getMangled());
}
parentType.setNamespace(newType);
parentType = newType;
@@ -86,7 +86,7 @@ public class MDMangGhidra extends MDMang {
MDParsableItem returnedItem = super.demangle(mangledArg, true);
objectResult = processItem();
if (objectResult != null) {
objectResult.setOriginalMangled(mangledArg);
objectResult.setMangledString(mangledArg);
// Make our version of the demangled string available (could be large).
objectResult.setUtilDemangled(item.toString());
}
@@ -805,4 +805,3 @@ public class MDMangGhidra extends MDMang {
/******************************************************************************/
/******************************************************************************/
@@ -15,7 +15,7 @@
*/
package mdemangler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import org.junit.Test;
@@ -46,7 +46,7 @@ public class MDMangExtraTests extends AbstractGenericTest {
String demangled = item.toString();
assertEquals(wholeTruth, demangled);
DemangledObject obj = demangler.getObject();
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getOriginalMangled();
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getMangledString();
assertEquals(functionNamespaceMangledTruth, mangledFunctionNamespace);
item = demangler.demangle(mangledFunctionNamespace, true);