mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-810 - Gnu Demangler - Fixed some failures when parsing function member pointers and array pointers/references; Fixed the parser not handling cast operators for function pointers
This commit is contained in:
parent
6a8788acbc
commit
071eb82103
14 changed files with 898 additions and 159 deletions
|
@ -129,7 +129,7 @@ public class DemanglerCmd extends BackgroundCommand {
|
|||
". Message: " + message);
|
||||
}
|
||||
|
||||
Msg.error(this, getStatusMsg());
|
||||
Msg.error(this, getStatusMsg(), e);
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.app.util.demangler;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
|
@ -40,9 +42,6 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
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());
|
||||
}
|
||||
|
@ -134,10 +133,6 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
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
|
||||
|
@ -158,13 +153,8 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
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);
|
||||
}
|
||||
|
||||
addFunctionPointerParens(buffer1, s);
|
||||
|
||||
buffer1.append('(');
|
||||
for (int i = 0; i < parameters.size(); ++i) {
|
||||
|
@ -234,26 +224,28 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(callingConvention == null ? EMPTY_STRING : callingConvention);
|
||||
|
||||
StringBuilder typeBuffer = new StringBuilder();
|
||||
int pointerLevels = getPointerLevels();
|
||||
if (pointerLevels > 0) {
|
||||
if (callingConvention != null) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
|
||||
addParentName(buffer);
|
||||
addParentName(typeBuffer);
|
||||
|
||||
for (int i = 0; i < pointerLevels; ++i) {
|
||||
buffer.append(getTypeString());
|
||||
typeBuffer.append(getTypeString());
|
||||
}
|
||||
}
|
||||
|
||||
if ((modifier != null) && (modifier.length() != 0)) {
|
||||
if (buffer.length() > 2) {
|
||||
if (!StringUtils.isBlank(typeBuffer)) {
|
||||
|
||||
if (!StringUtils.isBlank(callingConvention)) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(modifier);
|
||||
|
||||
buffer.append(typeBuffer);
|
||||
}
|
||||
|
||||
addModifier(buffer);
|
||||
|
||||
if (isConstPointer) {
|
||||
buffer.append(CONST);
|
||||
}
|
||||
|
@ -266,7 +258,7 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
}
|
||||
|
||||
if (name != null) {
|
||||
if ((buffer.length() > 2) && (buffer.charAt(buffer.length() - 1) != SPACE)) {
|
||||
if ((buffer.length() > 0) && (buffer.charAt(buffer.length() - 1) != SPACE)) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(name);
|
||||
|
@ -275,11 +267,29 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
protected void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
if (!displayFunctionPointerParens) {
|
||||
private void addModifier(StringBuilder buffer) {
|
||||
if (StringUtils.isBlank(modifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Guilty knowledge: in many cases the 'modifier' is the same as the type string. Further,
|
||||
// when we print signatures, we will print the type string if there are pointer levels. To
|
||||
// prevent duplication, do not print the modifier when it matches the type string and we
|
||||
// will be printing the type string (which is printed when there are pointer levels).
|
||||
//
|
||||
if (modifier.equals(getTypeString()) &&
|
||||
getPointerLevels() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.length() > 2) {
|
||||
buffer.append(SPACE);
|
||||
}
|
||||
buffer.append(modifier);
|
||||
}
|
||||
|
||||
protected void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
buffer.append('(').append(s).append(')');
|
||||
}
|
||||
|
||||
|
@ -310,15 +320,7 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
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);
|
||||
}
|
||||
setParameters(fddt, dataTypeManager);
|
||||
|
||||
DataType dt = DemangledDataType.findDataType(dataTypeManager, namespace, getName());
|
||||
if (dt == null || !(dt instanceof FunctionDefinitionDataType)) {
|
||||
|
@ -327,4 +329,27 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
|||
|
||||
return new PointerDataType(dt, dataTypeManager);
|
||||
}
|
||||
|
||||
private void setParameters(FunctionDefinitionDataType fddt, DataTypeManager dataTypeManager) {
|
||||
if (hasSingleVoidParameter(dataTypeManager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private boolean hasSingleVoidParameter(DataTypeManager dataTypeManager) {
|
||||
if (parameters.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DemangledDataType parameter = parameters.get(0);
|
||||
DataType dt = parameter.getDataType(dataTypeManager);
|
||||
return dt instanceof VoidDataType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import java.util.List;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
|
@ -404,6 +406,9 @@ public class DemangledDataType extends DemangledType {
|
|||
}
|
||||
|
||||
static Structure createPlaceHolderStructure(String dtName, Demangled namespace) {
|
||||
if (StringUtils.isBlank(dtName)) {
|
||||
throw new IllegalArgumentException("Name cannot be blank");
|
||||
}
|
||||
StructureDataType structDT = new StructureDataType(dtName, 0);
|
||||
structDT.setDescription("PlaceHolder Structure");
|
||||
structDT.setCategoryPath(getDemanglerCategoryPath(dtName, namespace));
|
||||
|
|
|
@ -229,25 +229,8 @@ public class DemangledFunction extends DemangledObject {
|
|||
buffer.append('<').append(templatedConstructorType).append('>');
|
||||
}
|
||||
|
||||
Iterator<DemangledDataType> paramIterator = parameters.iterator();
|
||||
buffer.append('(');
|
||||
String pad = format ? pad(buffer.length()) : "";
|
||||
if (!paramIterator.hasNext()) {
|
||||
buffer.append("void");
|
||||
}
|
||||
addParameters(buffer, format);
|
||||
|
||||
while (paramIterator.hasNext()) {
|
||||
buffer.append(paramIterator.next().getSignature());
|
||||
if (paramIterator.hasNext()) {
|
||||
buffer.append(',');
|
||||
if (format) {
|
||||
buffer.append('\n');
|
||||
}
|
||||
buffer.append(pad);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append(')');
|
||||
buffer.append(storageClass == null ? "" : " " + storageClass);
|
||||
|
||||
if (returnType instanceof DemangledFunctionPointer) {
|
||||
|
@ -303,6 +286,29 @@ public class DemangledFunction extends DemangledObject {
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
protected void addParameters(StringBuilder buffer, boolean format) {
|
||||
Iterator<DemangledDataType> paramIterator = parameters.iterator();
|
||||
buffer.append('(');
|
||||
int padLength = format ? buffer.length() : 0;
|
||||
String pad = StringUtils.rightPad("", padLength);
|
||||
if (!paramIterator.hasNext()) {
|
||||
buffer.append("void");
|
||||
}
|
||||
|
||||
while (paramIterator.hasNext()) {
|
||||
buffer.append(paramIterator.next().getSignature());
|
||||
if (paramIterator.hasNext()) {
|
||||
buffer.append(',');
|
||||
if (format) {
|
||||
buffer.append('\n');
|
||||
}
|
||||
buffer.append(pad);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append(')');
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespaceName() {
|
||||
return getName() + getParameterString();
|
||||
|
|
|
@ -32,4 +32,10 @@ public class DemangledFunctionIndirect extends AbstractDemangledFunctionDefiniti
|
|||
protected String getTypeString() {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
// do not display pointer parens
|
||||
buffer.append(s);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,34 @@ package ghidra.app.util.demangler;
|
|||
*/
|
||||
public class DemangledFunctionPointer extends AbstractDemangledFunctionDefinitionDataType {
|
||||
|
||||
/** display parens in front of parameter list */
|
||||
private boolean displayFunctionPointerSyntax = true;
|
||||
|
||||
public DemangledFunctionPointer(String mangled, String originalDemangled) {
|
||||
super(mangled, originalDemangled);
|
||||
incrementPointerLevels(); // a function pointer is 1 level by default
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTypeString() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals whether to display function pointer syntax when there is no function name, which
|
||||
* is '{@code (*)}', such as found in this example '{@code void (*)()}'. the default is true
|
||||
* @param b true to display nameless function pointer syntax; false to not display
|
||||
*/
|
||||
public void setDisplayDefaultFunctionPointerSyntax(boolean b) {
|
||||
this.displayFunctionPointerSyntax = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addFunctionPointerParens(StringBuilder buffer, String s) {
|
||||
if (!displayFunctionPointerSyntax) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append('(').append(s).append(')');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,4 +34,9 @@ public class DemangledLambda extends DemangledFunction {
|
|||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameters(StringBuilder buffer, boolean format) {
|
||||
// no parameter display for lambdas; the name currently shows the parameters
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public abstract class DemangledObject implements Demangled {
|
|||
protected String basedName;
|
||||
protected String memberScope;
|
||||
|
||||
private String signature;
|
||||
private String plateComment;
|
||||
|
||||
DemangledObject(String mangled, String originalDemangled) {
|
||||
this.mangled = mangled;
|
||||
|
@ -248,15 +248,6 @@ public abstract class DemangledObject implements Demangled {
|
|||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
@ -332,19 +323,29 @@ public abstract class DemangledObject implements Demangled {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the plate comment to be used if the {@link #getOriginalDemangled()} string is not
|
||||
* available
|
||||
*
|
||||
* @param plateComment the plate comment text
|
||||
*/
|
||||
public void setBackupPlateComment(String plateComment) {
|
||||
this.plateComment = plateComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates descriptive text that is intended to be used as documentation. The text defaults
|
||||
* to the original demangled text. If that is not available, then any text set by
|
||||
* {@link #setBackupPlateComment(String)} will be used. The last choice for this text is
|
||||
* the signature generated by {@link #getSignature(boolean)}.
|
||||
*
|
||||
* @return the text
|
||||
*/
|
||||
protected String generatePlateComment() {
|
||||
if (originalDemangled != null) {
|
||||
return originalDemangled;
|
||||
}
|
||||
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();
|
||||
return (plateComment == null) ? getSignature(true) : plateComment;
|
||||
}
|
||||
|
||||
protected Symbol applyDemangledName(Address addr, boolean setPrimary,
|
||||
|
@ -461,8 +462,7 @@ public abstract class DemangledObject implements Demangled {
|
|||
break;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(DemangledObject.class,
|
||||
"Failed to create namespace: " + e.getMessage());
|
||||
Msg.error(DemangledObject.class, "Failed to create namespace: " + e.getMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -479,7 +479,6 @@ public abstract class DemangledObject implements Demangled {
|
|||
NamespaceUtils.getNamespaceQualifiedName(namespace, namespaceName, false));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return namespace;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.app.util.demangler;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
|
@ -53,6 +55,10 @@ public class DemangledType implements Demangled {
|
|||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
if (StringUtils.isBlank(name)) {
|
||||
throw new IllegalArgumentException("Name cannot be blank");
|
||||
}
|
||||
|
||||
demangledName = name;
|
||||
this.name = name;
|
||||
if (name != null) {
|
||||
|
|
|
@ -117,9 +117,6 @@ public class GnuDemangler implements Demangler {
|
|||
dfunc.setNamespace(demangledObject.getNamespace());
|
||||
demangledObject = dfunc;
|
||||
}
|
||||
else {
|
||||
demangledObject.setSignature(demangled);
|
||||
}
|
||||
|
||||
if (isDwarf) {
|
||||
DemangledAddressTable dat =
|
||||
|
|
|
@ -93,16 +93,17 @@ public class GnuDemanglerParser {
|
|||
/*
|
||||
* Sample: bob(short (&)[7])
|
||||
* bob(int const[8] (*) [12])
|
||||
* _S_ref(array<float, 3ul> const (&) [64])
|
||||
* _S_ptr(Foo<Bar> const* const (&) [3])
|
||||
* {lambda(long&, unsigned int)#1} const (&) [4]
|
||||
*
|
||||
* Pattern: name[optional '*']<space>(*|&)[optional spaces][optional value]
|
||||
*
|
||||
* Pattern: <space>[optional const with optional '[',']', number, '*', '&' <space>]
|
||||
* (*|&)[optional spaces]brackets with optional characters inside
|
||||
*
|
||||
* Parts:
|
||||
* -a word (capture group 1)
|
||||
* -followed by an optional pointer '*'
|
||||
* -followed by a space
|
||||
* -*optional: any other text (e.g., const[8]) (non-capture group)
|
||||
* -followed by '()' that contain a '&' or a '*' (capture group 2)
|
||||
* -followed by one or more '[]' with optional interior text (capture group 3)
|
||||
* -optional const text (e.g., const[8]) (non-capture group)
|
||||
* -followed by '()' that contain a '&' or a '*' (capture group 1)
|
||||
* -followed by one or more '[]' with optional interior text (capture group 2)
|
||||
*
|
||||
* Group Samples:
|
||||
* short (&)[7]
|
||||
|
@ -117,7 +118,8 @@ public class GnuDemanglerParser {
|
|||
*
|
||||
*/
|
||||
private static final Pattern ARRAY_POINTER_REFERENCE_PATTERN =
|
||||
Pattern.compile("([\\w:]+)\\*?\\s(?:.*)\\(([&*])\\)\\s*((?:\\[.*?\\])+)");
|
||||
Pattern.compile(
|
||||
"\\s(?:const[\\[\\]\\d\\*&]{0,4}\\s)*\\(([&*])\\)\\s*((?:\\[.*?\\])+)");
|
||||
|
||||
/*
|
||||
* Sample: bob(short (&)[7])
|
||||
|
@ -309,6 +311,16 @@ public class GnuDemanglerParser {
|
|||
return Pattern.compile(operatorPrefix + parameters + trailing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pattern to catch literal strings of the form:
|
||||
*
|
||||
* -1l
|
||||
* 2l
|
||||
* 0u
|
||||
* 4294967295u
|
||||
*/
|
||||
private static final Pattern LITERAL_NUMBER_PATTERN = Pattern.compile("-*\\d+[ul]{0,1}");
|
||||
|
||||
private String mangledSource;
|
||||
private String demangledSource;
|
||||
|
||||
|
@ -353,6 +365,13 @@ public class GnuDemanglerParser {
|
|||
return operatorHandler;
|
||||
}
|
||||
|
||||
// Note: this really is a 'special handler' check that used to be handled above. However,
|
||||
// some demangled operator strings begin with this text. If we do this check above,
|
||||
// then we will not correctly handle those operators.
|
||||
if (mangledSource.startsWith("_ZZ")) {
|
||||
return new ItemInNamespaceHandler(demangled);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -397,9 +416,6 @@ public class GnuDemanglerParser {
|
|||
return new ItemInNamespaceHandler(demangled, prefix, type);
|
||||
}
|
||||
|
||||
if (mangled.startsWith("_ZZ")) {
|
||||
return new ItemInNamespaceHandler(demangled);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -420,12 +436,15 @@ public class GnuDemanglerParser {
|
|||
// following that text in the original string. We want the name to be the full lambda
|
||||
// text, without spaces.
|
||||
//
|
||||
LambdaName lambdaName = getLambdaName(demangled);
|
||||
String prefix = signatureParts.getRawParameterPrefix();
|
||||
int lambdaStart = prefix.length() - LAMBDA_START.length(); // strip off '{lambda'
|
||||
String lambdaText = demangled.substring(lambdaStart);
|
||||
LambdaName lambdaName = getLambdaName(lambdaText);
|
||||
String uniqueName = lambdaName.getFullText();
|
||||
String escapedLambda = removeBadSpaces(uniqueName);
|
||||
simpleName = simpleName.replace(LAMBDA_START, escapedLambda);
|
||||
function = new DemangledLambda(mangledSource, demangled, null);
|
||||
function.setSignature(lambdaName.getFullText());
|
||||
function.setBackupPlateComment(lambdaName.getFullText());
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -437,16 +456,8 @@ public class GnuDemanglerParser {
|
|||
function.addParameter(parameter);
|
||||
}
|
||||
|
||||
// For GNU, we cannot leave the return type as null, because the DemangleCmd will fill in
|
||||
// pointer to the class to accommodate windows demangling
|
||||
DemangledDataType defaultReturnType =
|
||||
new DemangledDataType(mangledSource, demangled, "undefined");
|
||||
function.setReturnType(defaultReturnType);
|
||||
|
||||
String returnType = signatureParts.getReturnType();
|
||||
if (returnType != null) {
|
||||
setReturnType(function, returnType);
|
||||
}
|
||||
setReturnType(demangled, function, returnType);
|
||||
|
||||
if (demangled.endsWith(CONST)) {
|
||||
function.setConst(true);
|
||||
|
@ -455,27 +466,54 @@ public class GnuDemanglerParser {
|
|||
return function;
|
||||
}
|
||||
|
||||
private void setReturnType(DemangledFunction function, String returnType) {
|
||||
private void setReturnType(String demangled, DemangledFunction function, String returnType) {
|
||||
|
||||
if (DECLTYPE_RETURN_TYPE_PATTERN.matcher(returnType).matches()) {
|
||||
String updatedReturnType = returnType;
|
||||
if (returnType != null && DECLTYPE_RETURN_TYPE_PATTERN.matcher(returnType).matches()) {
|
||||
// Not sure yet if there is any information we wish to recover from this pattern.
|
||||
// Sample: decltype (functionName({parm#1}, (float)[42c80000]))
|
||||
updatedReturnType = null;
|
||||
}
|
||||
|
||||
if (updatedReturnType != null) {
|
||||
function.setReturnType(parseReturnType(updatedReturnType));
|
||||
return;
|
||||
}
|
||||
|
||||
function.setReturnType(parseReturnType(returnType));
|
||||
// For GNU, we cannot leave the return type as null, because the DemangleCmd will fill in
|
||||
// pointer to the class to accommodate windows demangling
|
||||
DemangledDataType defaultReturnType =
|
||||
new DemangledDataType(mangledSource, demangled, "undefined");
|
||||
function.setReturnType(defaultReturnType);
|
||||
}
|
||||
|
||||
private LambdaName getLambdaName(String name) {
|
||||
|
||||
Matcher matcher = LAMBDA_PATTERN.matcher(name);
|
||||
if (!name.startsWith("{")) {
|
||||
// the text must start with the lambda syntax; ignore lambdas that are internal to
|
||||
// the given name
|
||||
return null;
|
||||
}
|
||||
|
||||
// This replacement string will leave the initial 'lambda' text and replace all others
|
||||
// with a placeholder value. This allows us to use a simple regex pattern when pulling
|
||||
// the lambda apart. This is required to handle the case where a lambda expression
|
||||
// contains a nested lambda expression.
|
||||
LambdaReplacedString replacedString = new LambdaReplacedString(name);
|
||||
String updatedName = replacedString.getModifiedText();
|
||||
|
||||
Matcher matcher = LAMBDA_PATTERN.matcher(updatedName);
|
||||
if (!matcher.matches()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// restore the placeholder values to get back the original lambda text
|
||||
String fullText = matcher.group(1);
|
||||
fullText = replacedString.restoreReplacedText(fullText);
|
||||
String params = matcher.group(2);
|
||||
params = replacedString.restoreReplacedText(params);
|
||||
String trailing = matcher.group(3);
|
||||
trailing = replacedString.restoreReplacedText(trailing);
|
||||
String modifiers = matcher.group(4);
|
||||
return new LambdaName(fullText, params, trailing, modifiers);
|
||||
}
|
||||
|
@ -513,7 +551,21 @@ public class GnuDemanglerParser {
|
|||
DemangledObject parent = parseFunctionOrVariable(parentText);
|
||||
String name = itemText.substring(pos + 2);
|
||||
DemangledObject item = parseFunctionOrVariable(name);
|
||||
item.setNamespace(parent);
|
||||
|
||||
//
|
||||
// Convert the parent type to a suitable namespace. The parent type may have spaces
|
||||
// in its name, which is not allowed in an applied namespace.
|
||||
//
|
||||
// We may eventually want to move this logic into the DemangledObject's
|
||||
// createNamespace() method. This would also apply to the convertToNamespaces()
|
||||
// method in this class.
|
||||
//
|
||||
String namespaceName = parent.getNamespaceName();
|
||||
String escapedName = removeBadSpaces(namespaceName);
|
||||
DemangledType type = new DemangledType(mangledSource, demangledSource, escapedName);
|
||||
type.setNamespace(parent.getNamespace());
|
||||
|
||||
item.setNamespace(type);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -530,6 +582,19 @@ public class GnuDemanglerParser {
|
|||
return condensedString.getCondensedText();
|
||||
}
|
||||
|
||||
private String removeTrailingDereferenceCharacters(String text) {
|
||||
|
||||
int i = text.length() - 1;
|
||||
for (; i >= 0; i--) {
|
||||
char c = text.charAt(i);
|
||||
if (c == '*' || c == '&') {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return text.substring(0, i + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method separates the parameters as strings.
|
||||
* This is more complicated then one might initially think.
|
||||
|
@ -670,6 +735,12 @@ public class GnuDemanglerParser {
|
|||
return dt;
|
||||
|
||||
}
|
||||
|
||||
// this handles the case where the demangled template has an empty argument
|
||||
if ("".equals(parameter.trim())) {
|
||||
return new DemangledDataType(mangledSource, demangledSource, "missing_argument");
|
||||
}
|
||||
|
||||
return parseDataType(parameter);
|
||||
}
|
||||
|
||||
|
@ -682,10 +753,16 @@ public class GnuDemanglerParser {
|
|||
DemangledDataType dt = createTypeInNamespace(fullDatatype);
|
||||
String datatype = dt.getDemangledName();
|
||||
|
||||
if ("*".equals(datatype)) {
|
||||
if (isMemberPointerOrReference(fullDatatype, datatype)) {
|
||||
return createMemberPointer(fullDatatype);
|
||||
}
|
||||
|
||||
// note: we should only encounter literals as template arguments. Function parameters
|
||||
// and return types should never be literals.
|
||||
if (isLiteral(fullDatatype)) {
|
||||
return createLiteral(fullDatatype);
|
||||
}
|
||||
|
||||
boolean finishedName = false;
|
||||
for (int i = 0; i < datatype.length(); ++i) {
|
||||
char ch = datatype.charAt(i);
|
||||
|
@ -734,23 +811,37 @@ public class GnuDemanglerParser {
|
|||
|
||||
LambdaName lambdaName = getLambdaName(datatype);
|
||||
|
||||
// check for array case
|
||||
Matcher arrayMatcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(datatype);
|
||||
if (arrayMatcher.matches()) {
|
||||
Demangled namespace = dt.getNamespace();
|
||||
String name = arrayMatcher.group(1);// group 0 is the entire string
|
||||
dt = parseArrayPointerOrReference(datatype, name, arrayMatcher);
|
||||
dt.setNamespace(namespace);
|
||||
i = arrayMatcher.end();
|
||||
//
|
||||
// Check for array case
|
||||
//
|
||||
// remove the templates to allow us to use a simpler regex when checking for arrays
|
||||
DemangledDataType newDt = tryToParseArrayPointerOrReference(dt, datatype);
|
||||
if (newDt != null) {
|
||||
dt = newDt;
|
||||
i = datatype.length();
|
||||
}
|
||||
// lambda case, maybe an array
|
||||
else if (lambdaName != null) {
|
||||
String fullText = lambdaName.getFullText();
|
||||
dt.setName(fullText);
|
||||
int offset = fullText.indexOf('(');
|
||||
int remaining = fullText.length() - offset;
|
||||
i = i + remaining; // end of lambda's closing '}'
|
||||
i = i - 1; // back up one space to catch optional templates on next loop pass
|
||||
|
||||
DemangledDataType lambdaArrayDt =
|
||||
tryToParseLambdaArrayPointerOrReference(lambdaName, dt, datatype);
|
||||
if (lambdaArrayDt != null) {
|
||||
dt = lambdaArrayDt;
|
||||
i = datatype.length();
|
||||
}
|
||||
else {
|
||||
// try a non-array lambda
|
||||
String fullText = lambdaName.getFullText();
|
||||
dt.setName(fullText);
|
||||
int offset = fullText.indexOf('(');
|
||||
// to to the end of the lambda, which is its length, minus our position
|
||||
// inside the lambda
|
||||
int remaining = fullText.length() - offset;
|
||||
i = i + remaining; // end of lambda's closing '}'
|
||||
i = i - 1; // back up one space to catch optional templates on next loop pass
|
||||
}
|
||||
}
|
||||
// function pointer case
|
||||
else {
|
||||
// e.g., unsigned long (*)(long const &)
|
||||
boolean hasPointerParens = hasConsecutiveSetsOfParens(datatype.substring(i));
|
||||
|
@ -856,6 +947,81 @@ public class GnuDemanglerParser {
|
|||
return dt;
|
||||
}
|
||||
|
||||
private DemangledDataType createLiteral(String datatype) {
|
||||
|
||||
// literal cases handled: -1, -1l, -1ul
|
||||
char lastChar = datatype.charAt(datatype.length() - 1);
|
||||
if (lastChar == 'l') {
|
||||
return new DemangledDataType(mangledSource, demangledSource, "long");
|
||||
}
|
||||
|
||||
return new DemangledDataType(mangledSource, demangledSource, "int");
|
||||
}
|
||||
|
||||
private boolean isLiteral(String fullDatatype) {
|
||||
Matcher m = LITERAL_NUMBER_PATTERN.matcher(fullDatatype);
|
||||
return m.matches();
|
||||
}
|
||||
|
||||
private DemangledDataType tryToParseLambdaArrayPointerOrReference(LambdaName lambdaName,
|
||||
DemangledDataType dt, String datatype) {
|
||||
|
||||
// remove the lambda text to allow us to use a simpler regex when checking for arrays
|
||||
String fullText = lambdaName.getFullText();
|
||||
ReplacedString lambdaString = new CustomReplacedString(datatype, fullText);
|
||||
String noLambdaString = lambdaString.getModifiedText();
|
||||
|
||||
Matcher matcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(noLambdaString);
|
||||
if (!matcher.find()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int start = matcher.start(0);
|
||||
String leading = noLambdaString.substring(0, start);
|
||||
leading = removeTrailingDereferenceCharacters(leading);
|
||||
|
||||
Demangled namespace = dt.getNamespace();
|
||||
String name = leading;
|
||||
DemangledDataType newDt = parseArrayPointerOrReference(datatype, name, lambdaString,
|
||||
matcher);
|
||||
newDt.setNamespace(namespace);
|
||||
return newDt;
|
||||
}
|
||||
|
||||
private DemangledDataType tryToParseArrayPointerOrReference(DemangledDataType dt,
|
||||
String datatype) {
|
||||
|
||||
ReplacedString templatedString = new TemplatedString(datatype);
|
||||
String untemplatedDatatype = templatedString.getModifiedText();
|
||||
|
||||
Matcher matcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(untemplatedDatatype);
|
||||
if (!matcher.find()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int start = matcher.start(0);
|
||||
String leading = untemplatedDatatype.substring(0, start);
|
||||
leading = removeTrailingDereferenceCharacters(leading);
|
||||
|
||||
Demangled namespace = dt.getNamespace();
|
||||
String name = leading;
|
||||
DemangledDataType newDt = parseArrayPointerOrReference(datatype, name, templatedString,
|
||||
matcher);
|
||||
newDt.setNamespace(namespace);
|
||||
return newDt;
|
||||
}
|
||||
|
||||
private boolean isMemberPointerOrReference(String fullDataType, String datatype) {
|
||||
|
||||
String test = datatype;
|
||||
test = test.replaceAll("const|\\*|&|\\s", "");
|
||||
if (!test.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fullDataType.endsWith(Namespace.DELIMITER + datatype);
|
||||
}
|
||||
|
||||
private boolean hasConsecutiveSetsOfParens(String text) {
|
||||
int end = findBalancedEnd(text, 0, '(', ')');
|
||||
if (end < -1) {
|
||||
|
@ -869,9 +1035,12 @@ public class GnuDemanglerParser {
|
|||
private DemangledDataType createMemberPointer(String datatype) {
|
||||
// this is temp code we expect to update as more samples arrive
|
||||
|
||||
// example: NS1::Type1 NS1::ParenType::*
|
||||
int trimLength = 3; // '::*'
|
||||
String typeWithoutPointer = datatype.substring(0, datatype.length() - trimLength);
|
||||
//
|
||||
// Examples:
|
||||
// Type NS1::Type1 NS1::ParenType::*
|
||||
// Type NS1::Type1 NS1::ParenType::* const&
|
||||
int namespaceEnd = datatype.lastIndexOf(Namespace.DELIMITER);
|
||||
String typeWithoutPointer = datatype.substring(0, namespaceEnd);
|
||||
int space = typeWithoutPointer.indexOf(' ');
|
||||
DemangledDataType dt;
|
||||
if (space != -1) {
|
||||
|
@ -906,6 +1075,7 @@ public class GnuDemanglerParser {
|
|||
Character.isDigit(ch) ||
|
||||
ch == ':' ||
|
||||
ch == '_' ||
|
||||
ch == '{' ||
|
||||
ch == '$';
|
||||
//@formatter:on
|
||||
}
|
||||
|
@ -1114,12 +1284,16 @@ public class GnuDemanglerParser {
|
|||
}
|
||||
|
||||
private DemangledDataType parseArrayPointerOrReference(String datatype, String name,
|
||||
Matcher matcher) {
|
||||
ReplacedString replacedString, Matcher matcher) {
|
||||
|
||||
// int (*)[8]
|
||||
// char (&)[7]
|
||||
// Foo<Bar> const* const (&) [3]
|
||||
|
||||
DemangledDataType dt = new DemangledDataType(mangledSource, demangledSource, name);
|
||||
String type = matcher.group(2);
|
||||
String realName = replacedString.restoreReplacedText(name);
|
||||
|
||||
DemangledDataType dt = new DemangledDataType(mangledSource, demangledSource, realName);
|
||||
String type = matcher.group(1);
|
||||
if (type.equals("*")) {
|
||||
dt.incrementPointerLevels();
|
||||
}
|
||||
|
@ -1130,9 +1304,29 @@ public class GnuDemanglerParser {
|
|||
throw new DemanglerParseException("Unexpected charater inside of parens: " + type);
|
||||
}
|
||||
|
||||
String arraySubscripts = matcher.group(3);
|
||||
int n = StringUtilities.countOccurrences(arraySubscripts, '[');
|
||||
dt.setArray(n);
|
||||
//
|
||||
// Grab the middle text, for example, inside:
|
||||
//
|
||||
// Foo<Bar> const* const (&) [3]
|
||||
//
|
||||
// we would like to grab 'const* const(&)' and similar text such as 'const* const*'
|
||||
//
|
||||
String safeDatatype = replacedString.getModifiedText();
|
||||
int midTextStart = safeDatatype.indexOf(name) + name.length();
|
||||
int midTextEnd = matcher.start(1) - 1; // -1 for opening '('
|
||||
String midText = safeDatatype.substring(midTextStart, midTextEnd);
|
||||
if (midText.contains(CONST)) {
|
||||
dt.setConst();
|
||||
}
|
||||
|
||||
int pointers = StringUtils.countMatches(midText, '*');
|
||||
for (int i = 0; i < pointers; i++) {
|
||||
dt.incrementPointerLevels();
|
||||
}
|
||||
|
||||
String arraySubscripts = matcher.group(2);
|
||||
int arrays = StringUtilities.countOccurrences(arraySubscripts, '[');
|
||||
dt.setArray(arrays);
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
@ -1141,14 +1335,14 @@ public class GnuDemanglerParser {
|
|||
//unsigned long (*)(long const &)
|
||||
|
||||
int parenStart = functionString.indexOf('(');
|
||||
int parenEnd = functionString.indexOf(')');
|
||||
|
||||
int parenEnd = findBalancedEnd(functionString, parenStart, '(', ')');
|
||||
String returnType = functionString.substring(0, parenStart).trim();
|
||||
|
||||
int paramStart = functionString.indexOf('(', parenEnd + 1);
|
||||
int paramEnd = functionString.lastIndexOf(')');
|
||||
String parameters = functionString.substring(paramStart + 1, paramEnd);
|
||||
return createFunctionPointer(parameters, returnType);
|
||||
DemangledFunctionPointer dfp = createFunctionPointer(parameters, returnType);
|
||||
return dfp;
|
||||
}
|
||||
|
||||
private DemangledFunctionPointer parseFunction(String functionString, int offset) {
|
||||
|
@ -1156,7 +1350,6 @@ public class GnuDemanglerParser {
|
|||
|
||||
int parenStart = functionString.indexOf('(', offset);
|
||||
int parenEnd = findBalancedEnd(functionString, parenStart, '(', ')');
|
||||
//int parenEnd = functionString.indexOf(')', parenStart + 1);
|
||||
|
||||
String returnType = functionString.substring(0, parenStart).trim();
|
||||
|
||||
|
@ -1164,7 +1357,9 @@ public class GnuDemanglerParser {
|
|||
int paramEnd = parenEnd;
|
||||
String parameters = functionString.substring(paramStart + 1, paramEnd);
|
||||
DemangledFunctionPointer dfp = createFunctionPointer(parameters, returnType);
|
||||
dfp.setDisplayFunctionPointerParens(false);
|
||||
|
||||
// disable the function pointer display so this type reads like a function
|
||||
dfp.setDisplayDefaultFunctionPointerSyntax(false);
|
||||
return dfp;
|
||||
}
|
||||
|
||||
|
@ -1324,7 +1519,6 @@ public class GnuDemanglerParser {
|
|||
DemangledObject doBuild(Demangled demangledObject) {
|
||||
|
||||
DemangledFunction function = (DemangledFunction) demangledObject;
|
||||
function.setSignature(type);
|
||||
function.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
|
||||
DemangledThunk thunk = new DemangledThunk(mangledSource, demangledSource, function);
|
||||
|
@ -1545,9 +1739,14 @@ public class GnuDemanglerParser {
|
|||
// Ghidra does not allow spaces in the name or extra parens. So, make a name that is
|
||||
// as clear as possible in describing the construct.
|
||||
//
|
||||
if (shortReturnTypeName.contains("(")) {
|
||||
// assume function pointer
|
||||
shortReturnTypeName = "function.pointer";
|
||||
}
|
||||
|
||||
method.setName("operator.cast.to." + shortReturnTypeName);
|
||||
|
||||
method.setSignature(fullName + " " + fullReturnType);
|
||||
method.setBackupPlateComment(fullName + " " + fullReturnType + "()");
|
||||
method.setOverloadedOperator(true);
|
||||
|
||||
return method;
|
||||
|
@ -1604,10 +1803,9 @@ public class GnuDemanglerParser {
|
|||
if (arrayBrackets != null) {
|
||||
name += "[]";
|
||||
}
|
||||
|
||||
function.setName("operator." + name);
|
||||
|
||||
function.setSignature(operatorText + " " + operatorName);
|
||||
|
||||
function.setBackupPlateComment(operatorText + " " + operatorName);
|
||||
return function;
|
||||
}
|
||||
}
|
||||
|
@ -1628,6 +1826,7 @@ public class GnuDemanglerParser {
|
|||
paramEnd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
paramStart = findParameterStart(text, paramEnd);
|
||||
int templateEnd = findTemplateEnd(text, 0);
|
||||
int templateStart = -1;
|
||||
|
@ -1727,6 +1926,7 @@ public class GnuDemanglerParser {
|
|||
|
||||
private String returnType;
|
||||
private String name;
|
||||
private String rawParameterPrefix;
|
||||
|
||||
private List<DemangledDataType> parameters;
|
||||
|
||||
|
@ -1746,9 +1946,9 @@ public class GnuDemanglerParser {
|
|||
|
||||
// 'prefix' is the text before the parameters
|
||||
int prefixEndPos = paramStart;
|
||||
String rawPrefix = signatureString.substring(0, prefixEndPos).trim();
|
||||
rawParameterPrefix = signatureString.substring(0, prefixEndPos).trim();
|
||||
|
||||
CondensedString prefixString = new CondensedString(rawPrefix);
|
||||
CondensedString prefixString = new CondensedString(rawParameterPrefix);
|
||||
String prefix = prefixString.getCondensedText();
|
||||
int nameStart = Math.max(0, prefix.lastIndexOf(' '));
|
||||
name = prefix.substring(nameStart, prefix.length()).trim();
|
||||
|
@ -1767,6 +1967,11 @@ public class GnuDemanglerParser {
|
|||
return name;
|
||||
}
|
||||
|
||||
// this is the original demangled text up to, but excluding, the parameters
|
||||
String getRawParameterPrefix() {
|
||||
return rawParameterPrefix;
|
||||
}
|
||||
|
||||
boolean isValidFunction() {
|
||||
return isFunction;
|
||||
}
|
||||
|
@ -1880,4 +2085,149 @@ public class GnuDemanglerParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that allows us to pass around string content that has had some of its text
|
||||
* replaced with temporary values. Clients can also use this class to get back the original
|
||||
* text.
|
||||
*/
|
||||
private abstract class ReplacedString {
|
||||
|
||||
static final String PLACEHOLDER = "REPLACEDSTRINGTEMPNAMEPLACEHOLDERVALUE";
|
||||
|
||||
@SuppressWarnings("unused") // used by toString()
|
||||
private String sourceText;
|
||||
|
||||
ReplacedString(String sourceText) {
|
||||
this.sourceText = sourceText;
|
||||
}
|
||||
|
||||
abstract String restoreReplacedText(String modifiedText);
|
||||
|
||||
abstract String getModifiedText();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Json.toString(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A string that clients can use to replace specific text patterns
|
||||
*/
|
||||
private class CustomReplacedString extends ReplacedString {
|
||||
|
||||
private String placeholderText = getClass().getSimpleName().toUpperCase() + PLACEHOLDER;
|
||||
private String replacedText;
|
||||
private String modifiedText;
|
||||
|
||||
CustomReplacedString(String input, String textToReplace) {
|
||||
super(input);
|
||||
this.replacedText = textToReplace;
|
||||
this.modifiedText = input.replace(textToReplace, placeholderText);
|
||||
}
|
||||
|
||||
@Override
|
||||
String restoreReplacedText(String mutatedText) {
|
||||
return mutatedText.replace(placeholderText, replacedText);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getModifiedText() {
|
||||
return modifiedText;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class to replace templates with a temporary placeholder value
|
||||
*/
|
||||
private class TemplatedString extends ReplacedString {
|
||||
|
||||
private String placeholderText = getClass().getSimpleName().toUpperCase() + PLACEHOLDER;
|
||||
|
||||
private String replacedText;
|
||||
private String modifiedText;
|
||||
|
||||
TemplatedString(String input) {
|
||||
super(input);
|
||||
replaceTemplates(input);
|
||||
}
|
||||
|
||||
private void replaceTemplates(String string) {
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
StringBuilder templateBuffer = new StringBuilder();
|
||||
int depth = 0;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
char c = string.charAt(i);
|
||||
if (c == '<') {
|
||||
if (depth == 0) {
|
||||
buffy.append(placeholderText);
|
||||
}
|
||||
|
||||
templateBuffer.append(c);
|
||||
depth++;
|
||||
continue;
|
||||
}
|
||||
else if (c == '>') {
|
||||
templateBuffer.append(c);
|
||||
depth--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == 0) {
|
||||
buffy.append(c);
|
||||
}
|
||||
else {
|
||||
templateBuffer.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
modifiedText = buffy.toString();
|
||||
replacedText = templateBuffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
String restoreReplacedText(String s) {
|
||||
return s.replace(placeholderText, replacedText);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getModifiedText() {
|
||||
return modifiedText;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class to replace the text 'lambda' with a temporary placeholder value
|
||||
*/
|
||||
private class LambdaReplacedString extends ReplacedString {
|
||||
|
||||
private String placeholderText = getClass().getSimpleName().toUpperCase() + PLACEHOLDER;
|
||||
private String modifiedText;
|
||||
|
||||
LambdaReplacedString(String input) {
|
||||
super(input);
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
Pattern p = Pattern.compile(LAMBDA);
|
||||
Matcher matcher = p.matcher(input);
|
||||
matcher.find(); // keep the first match
|
||||
while (matcher.find()) {
|
||||
matcher.appendReplacement(buffer, placeholderText);
|
||||
}
|
||||
matcher.appendTail(buffer);
|
||||
modifiedText = buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
String restoreReplacedText(String s) {
|
||||
return s.replaceAll(placeholderText, LAMBDA);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getModifiedText() {
|
||||
return modifiedText;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
// bob(int const[8] (*) [12])
|
||||
|
||||
//
|
||||
// Note: it is not clear whether the this demangled string is valid modern demangler output.
|
||||
// We are creating a constant array pointer from this construct, but is this what
|
||||
// we should be creating?
|
||||
//
|
||||
|
||||
String demangled = "bob(int const[8] (*) [12])";
|
||||
DemangledObject object = parser.parse("fake", demangled);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
@ -52,7 +58,27 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
assertEquals(1, parameters.size());
|
||||
DemangledDataType p1 = parameters.get(0);
|
||||
assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled());
|
||||
assertEquals("undefined bob(int *[])", object.getSignature(false));
|
||||
assertEquals("undefined bob(int const *[])", object.getSignature(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse_ArrayPointerReferencePattern_ConstPointerToArrayReference()
|
||||
throws Exception {
|
||||
|
||||
// _S_ptr(entt::sparse_set<EntityId> const * &[])
|
||||
|
||||
String mangled =
|
||||
"_ZNSt14__array_traitsIPKN4entt10sparse_setI8EntityIdEELm3EE6_S_ptrERA3_KS5_";
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"undefined std::__array_traits<entt::sparse_set<EntityId>const*,3ul>::_S_ptr(entt::sparse_set<EntityId> const * &[])",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -122,14 +148,14 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
assertEquals(
|
||||
"undefined XpsMap<long,CORBA_TypeCode*>::XpsMap(" +
|
||||
"unsigned long ()(long const &),unsigned long,unsigned long,float)",
|
||||
"unsigned long (*)(long const &),unsigned long,unsigned long,float)",
|
||||
object.getSignature(false));
|
||||
|
||||
DemangledFunction method = (DemangledFunction) object;
|
||||
|
||||
List<DemangledDataType> parameters = method.getParameters();
|
||||
assertEquals(4, parameters.size());
|
||||
assertEquals("unsigned long ()(long const &)", parameters.get(0).getSignature());
|
||||
assertEquals("unsigned long (*)(long const &)", parameters.get(0).getSignature());
|
||||
assertEquals("unsigned long", parameters.get(1).getSignature());
|
||||
assertEquals("unsigned long", parameters.get(2).getSignature());
|
||||
assertEquals("float", parameters.get(3).getSignature());
|
||||
|
@ -182,7 +208,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
"__gnu_cxx::__normal_iterator<std::pair<unsigned long,PcodeOp *> *,std::vector<std::pair<unsigned long,PcodeOp *>,std::allocator<std::pair<unsigned long,PcodeOp *>>>>",
|
||||
parameters.get(1).toString());
|
||||
assertEquals(
|
||||
"bool ()(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)",
|
||||
"bool (*)(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)",
|
||||
parameters.get(2).toString());
|
||||
|
||||
assertType(parameters.get(2), DemangledFunctionPointer.class);
|
||||
|
@ -334,6 +360,64 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
object.getSignature(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse_DefaultArg() throws Exception {
|
||||
|
||||
//
|
||||
// The demangled string contains this string: {default arg#1}
|
||||
//
|
||||
String mangled =
|
||||
"_ZZN12PackManifest18CapabilityRegistry18registerCapabilityEN3gsl17basic_string_spanIKcLln1EEEbSt8functionIFbRS_R10PackReportbEEEd_NKUlS6_S8_bE_clES6_S8_b";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"PackManifest::CapabilityRegistry::registerCapability(gsl::basic_string_span<char_const,-1l>,bool,std::function<bool(PackManifest&,PackReport&,bool)>)::{default arg#1}::{lambda(PackManifest&,PackReport&,bool)#1}::operator()(PackManifest &,PackReport &,bool)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse_UnnamedType() throws Exception {
|
||||
|
||||
//
|
||||
// The demangled string contains this string: {unnamed_type#1}
|
||||
//
|
||||
String mangled =
|
||||
"_ZN14GoalDefinitionUt_aSERKS0_";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"undefined GoalDefinition::{unnamed_type#1}::operator=({unnamed const &)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse_DecltypeAuto() throws Exception {
|
||||
|
||||
String mangled =
|
||||
"_Z9enum_castIN17FurnaceBlockActorUt_EEDcT_";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals("decltype (auto)", signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethod() throws Exception {
|
||||
String mangled = "_ZN3Foo7getBoolEf";
|
||||
|
@ -416,9 +500,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertType(object, DemangledVariable.class);
|
||||
assertName(object, "dotdot", "KSimpleFileFilter", "passesFilter(KFileItem const *)");
|
||||
assertName(object, "dotdot", "KSimpleFileFilter", "passesFilter(KFileItem_const*)");
|
||||
|
||||
assertEquals("KSimpleFileFilter::passesFilter(KFileItem const *)::dotdot",
|
||||
assertEquals("KSimpleFileFilter::passesFilter(KFileItem_const*)::dotdot",
|
||||
object.getSignature(false));
|
||||
}
|
||||
|
||||
|
@ -612,9 +696,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertType(object, DemangledVariable.class);
|
||||
assertName(object, "dialog", "DDDSaveOptionsCB(_WidgetRec *,void *,void *)");
|
||||
assertName(object, "dialog", "DDDSaveOptionsCB(_WidgetRec*,void*,void*)");
|
||||
|
||||
assertEquals("DDDSaveOptionsCB(_WidgetRec *,void *,void *)::dialog",
|
||||
assertEquals("DDDSaveOptionsCB(_WidgetRec*,void*,void*)::dialog",
|
||||
object.getSignature(false));
|
||||
}
|
||||
|
||||
|
@ -682,8 +766,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
assertType(object, DemangledFunction.class);
|
||||
assertName(object, "graphNew", "Layout");
|
||||
|
||||
// note: the two pointers were condensed to one (I think this is correct, but not sure)
|
||||
assertEquals("undefined Layout::graphNew(_GRAPH *[],char *)", object.getSignature(false));
|
||||
assertEquals("undefined Layout::graphNew(_GRAPH * *[],char *)", object.getSignature(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -913,7 +996,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
assertEquals("operator<<", name);
|
||||
assertName(object, "operator<<", "std", "basic_ostream<char,std::char_traits<char>>");
|
||||
assertEquals("undefined std::basic_ostream<char,std::char_traits<char>>" + "::operator<<(" +
|
||||
"std::basic_ostream<char,std::char_traits<char>> & ()(std::basic_ostream<char,std::char_traits<char>> &))",
|
||||
"std::basic_ostream<char,std::char_traits<char>> & (*)(std::basic_ostream<char,std::char_traits<char>> &))",
|
||||
object.getSignature());
|
||||
}
|
||||
|
||||
|
@ -979,6 +1062,128 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
assertEquals("Magick::Image &", parameters.get(0).getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerToArray_WithLambda() throws Exception {
|
||||
|
||||
String mangled =
|
||||
"_ZNSt14__array_traitsIN12LayerDetails15RandomProviderTIZNKS0_9LayerBase10initRandomEllEUlRljE_EELm4EE6_S_refERA4_KS5_m";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"undefined std::__array_traits<LayerDetails::RandomProviderT<LayerDetails::LayerBase::initRandom(long,long)const::{lambda(long&,unsigned_int)#1}>,4ul>::_S_ref(LayerDetails::LayerBase::initRandom(long,long) const::{lambda(long&, unsigned int)#1} const &[],unsigned long)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperator_WithTemplatesMissingATemplateArgument() throws Exception {
|
||||
|
||||
/*
|
||||
|
||||
Note: the empty template type: '<, std...'
|
||||
<, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>
|
||||
|
||||
|
||||
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::_Bind<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > (EduAppConfigs::*(EduAppConfigs const*))() const>::operator()<, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >()
|
||||
|
||||
*/
|
||||
String mangled =
|
||||
"_ZNSt5_BindIFM13EduAppConfigsKFNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvEPKS0_EEclIJES6_EET0_DpOT_";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> std::_Bind<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>(EduAppConfigs::*(EduAppConfigs_const*))()const>::operator()<missing_argument,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>(void)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamegterWithTemplateValue_DataTypeLiteral_int() throws Exception {
|
||||
|
||||
String mangled = "_Z13reverse_rangeIjLin1EE5RangeIiXT0_EET_";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals("Range<int,int> reverse_range<unsigned_int,-1>(unsigned int)", signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamegterWithTemplateValue_DataTypeLiteral_long() throws Exception {
|
||||
|
||||
String mangled =
|
||||
"_ZN3gsl9to_stringIKcLln1EEENSt7__cxx1112basic_stringINSt12remove_constIT_E4typeESt11char_traitsIS7_ESaIS7_EEENS_17basic_string_spanIS5_XT0_EEE";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"std::__cxx11::basic_string<std::remove_const<char_const>::type,std::char_traits<std::remove_const<char_const>::type>,std::allocator<std::remove_const<char_const>::type>> gsl::to_string<char_const,-1l>(gsl::basic_string_span<char const,long>)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLambdaWithLambdaParameters() throws Exception {
|
||||
|
||||
/*
|
||||
|
||||
lambda contents - lambdas in templates and as a parameter
|
||||
|
||||
bool (***
|
||||
const* std::
|
||||
__addressof<
|
||||
Bedrock::
|
||||
Threading::
|
||||
TLSDetail::
|
||||
DefaultConstructor<bool (**)(AssertHandlerContext const&), void>::
|
||||
create()::
|
||||
{lambda(bool (*** const)(AssertHandlerContext const&))#1}
|
||||
>
|
||||
(
|
||||
Bedrock::
|
||||
Threading::
|
||||
TLSDetail::
|
||||
DefaultConstructor<bool (**)(AssertHandlerContext const&), void>::
|
||||
create()::
|
||||
{lambda(bool (*** const&)(AssertHandlerContext const&))#1}
|
||||
)
|
||||
)(AssertHandlerContext const&)
|
||||
|
||||
*/
|
||||
|
||||
String mangled =
|
||||
"_ZSt11__addressofIKZN7Bedrock9Threading9TLSDetail18DefaultConstructorIPPFbRK20AssertHandlerContextEvE6createEvEUlPS9_E_EPT_RSE_";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"undefined Bedrock::Threading::TLSDetail::DefaultConstructor<bool(**)(AssertHandlerContext_const&),void>::create()::{lambda(bool(***const*std::__addressof<Bedrock::Threading::TLSDetail::DefaultConstructor<bool(**)(AssertHandlerContext_const&),void>::create()::{lambda(bool(***const)(AssertHandlerContext_const&))#1}>(Bedrock::Threading::TLSDetail::DefaultConstructor<bool(**)(AssertHandlerContext_const&),void>::create()::{lambda(bool(***const&)(AssertHandlerContext_const&))#1}))(AssertHandlerContext_const&))#1}",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperatorCastTo() throws Exception {
|
||||
//
|
||||
|
@ -998,6 +1203,53 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
assertEquals("bool std::integral_constant::operator.cast.to.bool(void)", signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperatorCastTo_FunctionPointer() throws Exception {
|
||||
|
||||
String mangled =
|
||||
"_ZZNK4entt14basic_registryI8EntityIdE6assureI32FilteredTransformationAttributesI26PreHillsEdgeTransformationEEERKNS2_12pool_handlerIT_EEvENKUlRNS_10sparse_setIS1_EERS2_S1_E_cvPFvSE_SF_S1_EEv";
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
/*
|
||||
|
||||
Full demangled:
|
||||
|
||||
Operator Text
|
||||
|
||||
entt::
|
||||
basic_registry<EntityId>::
|
||||
assure<FilteredTransformationAttributes<PreHillsEdgeTransformation> >() const::
|
||||
{lambda(entt::sparse_set<EntityId>&, entt::basic_registry<EntityId>&, EntityId)#1}::
|
||||
operator void (*)(entt::sparse_set<EntityId>&, entt::basic_registry<EntityId>&, EntityId)() const
|
||||
|
||||
Operartor Without Namespace
|
||||
|
||||
operator void (*)(entt::sparse_set<EntityId>&, entt::basic_registry<EntityId>&, EntityId)()
|
||||
|
||||
Simplified Cast Operator Construct
|
||||
|
||||
operator void (*)(A,B,C)()
|
||||
|
||||
*/
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
//@formatter:off
|
||||
String expected =
|
||||
"void (* " +
|
||||
"entt::" +
|
||||
"basic_registry::" +
|
||||
"assure() const::" +
|
||||
"{lambda(entt::sparse_set&,entt::basic_registry&,EntityId)#1}::" +
|
||||
"operator.cast.to.function.pointer(void)" +
|
||||
")(entt::sparse_set<EntityId> &,entt::basic_registry<EntityId> &,EntityId)";
|
||||
//@formatter:on
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(expected, signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConversionOperator() throws Exception {
|
||||
|
||||
|
@ -1226,7 +1478,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
assertName(object, "FTransferGvmlData", "Dr", "ClipboardHelper");
|
||||
|
||||
assertEquals(
|
||||
"undefined Dr::ClipboardHelper::FTransferGvmlData(Art::Transaction &,Ofc::TReferringPtr<Dr::DrawingE2o> const &,bool,Ofc::TCntPtr<IDataObject>,Dr::IClientDataCreator &,Ofc::TVector<Ofc::TWeakPtr<Dr::DrawingElement>,0u,4294967295u> &,Art::Rect64 &)",
|
||||
"undefined Dr::ClipboardHelper::FTransferGvmlData(Art::Transaction &,Ofc::TReferringPtr<Dr::DrawingE2o> const &,bool,Ofc::TCntPtr<IDataObject>,Dr::IClientDataCreator &,Ofc::TVector<Ofc::TWeakPtr<Dr::DrawingElement>,int,int> &,Art::Rect64 &)",
|
||||
object.getSignature(false));
|
||||
}
|
||||
|
||||
|
@ -1549,7 +1801,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1} brigand::for_each_args<WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1},brigand::type_<std::__1::integral_constant<long,0l>>,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,1l>>,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,2l>>>(WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1},brigand::type_<std::__1::integral_constant<long,0l>> &&,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,1l>> &&,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,2l>> &&)",
|
||||
"WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1} brigand::for_each_args<WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1},brigand::type_<std::__1::integral_constant<long,0l>>,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,1l>>,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,2l>>>(WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1},brigand::type_<std::__1::integral_constant<long,long>> &&,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,long>> &&,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,long>> &&)",
|
||||
signature);
|
||||
}
|
||||
|
||||
|
@ -1587,7 +1839,46 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"undefined WebCore::FontSelectionAlgorithm::filterCapability(bool *,WebCore::FontSelectionAlgorithm::DistanceResult ()(WebCore::FontSelectionCapabilities) const,WebCore::FontSelectionCapabilities::FontSelectionRange *)",
|
||||
"undefined WebCore::FontSelectionAlgorithm::filterCapability(bool *,WebCore::FontSelectionAlgorithm::DistanceResult (*)(WebCore::FontSelectionCapabilities) const,WebCore::FontSelectionCapabilities::FontSelectionRange *)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionParameterWithMemberPointer_ToFloat() throws Exception {
|
||||
|
||||
//
|
||||
// Test to ensure proper handling of 'float AvoidBlockGoal::Definition::* const&'
|
||||
// which is a const reference to a floating point member of the class
|
||||
// AvoidBlockGoal::Definition
|
||||
//
|
||||
|
||||
/*
|
||||
|
||||
Demangled:
|
||||
|
||||
auto && JsonUtil::
|
||||
addMember<std::shared_ptr<JsonUtil::JsonSchemaObjectNode<JsonUtil::EmptyClass,AvoidBlockGoal::Definition>>,AvoidBlockGoal::Definition,float>
|
||||
(
|
||||
|
||||
std::shared_ptr<JsonUtil::JsonSchemaObjectNode<JsonUtil::EmptyClass,AvoidBlockGoal::Definition>>,
|
||||
float AvoidBlockGoal::Definition::*,
|
||||
char const *,
|
||||
float AvoidBlockGoal::Definition::* const&
|
||||
|
||||
)
|
||||
|
||||
*/
|
||||
String mangled =
|
||||
"_ZN8JsonUtil9addMemberISt10shared_ptrINS_20JsonSchemaObjectNodeINS_10EmptyClassEN14AvoidBlockGoal10DefinitionEEEES5_fEEODaT_MT0_T1_PKcRKSC_";
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"auto && JsonUtil::addMember<std::shared_ptr<JsonUtil::JsonSchemaObjectNode<JsonUtil::EmptyClass,AvoidBlockGoal::Definition>>,AvoidBlockGoal::Definition,float>(std::shared_ptr<JsonUtil::JsonSchemaObjectNode<JsonUtil::EmptyClass,AvoidBlockGoal::Definition>>,AvoidBlockGoal::Definition::float *,char const *,AvoidBlockGoal::Definition::float *)",
|
||||
signature);
|
||||
}
|
||||
|
||||
|
@ -1618,7 +1909,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"undefined WebCore::TextCodecICU::registerCodecs(void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&))",
|
||||
"undefined WebCore::TextCodecICU::registerCodecs(void (*)(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&))",
|
||||
signature);
|
||||
}
|
||||
|
||||
|
@ -1676,6 +1967,23 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperator_ArrayReference() throws Exception {
|
||||
String mangled =
|
||||
"_ZN12LayerDetails15RandomProviderTIZNKS_9LayerBase10initRandomEllEUlRljE_EclIiLm2EEET_RAT0__KS6_";
|
||||
|
||||
String demangled = process.demangle(mangled);
|
||||
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"int LayerDetails::RandomProviderT<LayerDetails::LayerBase::initRandom(long,long)const::{lambda(long&,unsigned_int)#1}>::operator()<int,2ul>(LayerDetails::RandomProviderT<LayerDetails::LayerBase::initRandom(long,long)const::{lambda(long&,unsigned_int)#1}>::operator() const &[])",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLambdaWithTemplates() throws Exception {
|
||||
|
||||
|
|
|
@ -476,6 +476,15 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
|||
demangleAndTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionPointer_NamedFunctionPointerWithAnonymousFunctionPointerParameter()
|
||||
throws Exception {
|
||||
mangled = "?fun@@3P6KXP6KXH@Z@ZA";
|
||||
msTruth = "void (* fun)(void (*)(int))";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionPointer_EMod_invalid() throws Exception {
|
||||
mangled = "?fn@@3PE6AHH@ZA";
|
||||
|
|
|
@ -2312,7 +2312,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
SourceType originalSource = namespaceSymbol.getSource();
|
||||
|
||||
// no duplicate check, since this class name will be set to that of the existing namespace
|
||||
String tempName = name + System.nanoTime();
|
||||
String tempName = "_temp_" + System.nanoTime();
|
||||
SymbolDB classSymbol =
|
||||
doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(),
|
||||
SymbolType.CLASS, -1, -1, null, originalSource, false /*check for duplicate */);
|
||||
|
@ -2334,7 +2334,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
return classNamespace;
|
||||
}
|
||||
catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) {
|
||||
throw new AssertException("Unexpected exception creating class from namespace", e);
|
||||
throw new AssertException("Unexpected exception creating class from namespace: " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue