Merge remote-tracking branch 'origin/patch'

This commit is contained in:
ghidra1 2020-11-16 16:16:39 -05:00
commit 29a3732adc
10 changed files with 721 additions and 174 deletions

View File

@ -450,8 +450,9 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
BigInteger value = context.getValue(isaModeSwitchRegister, false);
if (value != null && program.getListing().getInstructionAt(addr) == null) {
try {
program.getProgramContext().setValue(isaModeRegister, addr, addr,
value);
program.getProgramContext()
.setValue(isaModeRegister, addr, addr,
value);
}
catch (ContextChangeException e) {
// ignore
@ -641,7 +642,6 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
return null;
}
try {
Msg.debug(CreateFunctionCmd.class, "Creating external function symbol: " + s.getName());
ExternalManager extMgr = program.getExternalManager();
ExternalLocation extLoc =
extMgr.addExtFunction(Library.UNKNOWN, s.getName(), null, s.getSource());

View File

@ -80,7 +80,8 @@ public class DemanglerCmd extends BackgroundCommand {
return true; // no real error
}
setStatusMsg("Unable to demangle symbol: " + mangled + ". Message: " + e.getMessage());
setStatusMsg("Unable to demangle symbol: " + mangled + " at " + addr + ". Message: " +
e.getMessage());
return false; // error
// This produces too many messages for non-demangled symbols. If we could
@ -91,7 +92,8 @@ public class DemanglerCmd extends BackgroundCommand {
}
catch (Exception e) {
// Demangler IndexOutOfBoundsException that we're not sure how to fix
setStatusMsg("Unable to demangle symbol: " + mangled + ". Message: " + e.getMessage());
setStatusMsg("Unable to demangle symbol: " + mangled + " at " + addr + ". Message: " +
e.getMessage());
return false;
}
@ -111,7 +113,7 @@ public class DemanglerCmd extends BackgroundCommand {
}
setStatusMsg(
"Failed to apply mangled symbol at " + addr.toString() + "; name: " + mangled + " (" +
"Failed to apply mangled symbol at " + addr + "; name: " + mangled + " (" +
demangler.getClass().getName() + "/" + demangledObject.getClass().getName() + ")");
return false; // error
}

View File

@ -77,7 +77,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
Address address = symbol.getAddress();
String mangled = cleanSymbol(address, symbol.getName());
DemangledObject demangled = demangle(mangled, options, log);
DemangledObject demangled = demangle(mangled, address, options, log);
if (demangled != null) {
apply(program, address, demangled, options, log, monitor);
}
@ -172,11 +172,13 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
* handled.
*
* @param mangled the mangled string
* @param address the symbol address
* @param options the demangler options
* @param log the error log
* @return the demangled object; null if unsuccessful
*/
protected DemangledObject demangle(String mangled, DemanglerOptions options, MessageLog log) {
protected DemangledObject demangle(String mangled, Address address, DemanglerOptions options,
MessageLog log) {
DemangledObject demangled = null;
try {
@ -192,7 +194,8 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
}
log.appendMsg(getName(),
"Unable to demangle symbol: " + mangled + ". Message: " + e.getMessage());
"Unable to demangle symbol: " + mangled + " at " + address + ". Message: " +
e.getMessage());
return null;
}

View File

@ -90,6 +90,7 @@ public class DemangledDataType extends DemangledType {
private boolean isEnum;
private boolean isPointer64;
private boolean isReference;
private boolean isRValueReference;
private boolean isSigned;
private boolean isStruct;
private boolean isTemplate;
@ -445,6 +446,13 @@ public class DemangledDataType extends DemangledType {
isReference = true;
}
/**
* rvalue reference; C++11
*/
public void setRValueReference() {
isRValueReference = true;
}
public void setSigned() {
isSigned = true;
}
@ -671,6 +679,9 @@ public class DemangledDataType extends DemangledType {
if (isReference) {
buffer.append(SPACE + REF_NOTATION);
if (isRValueReference) {
buffer.append(REF_NOTATION); // &&
}
}
// the order of __ptr64 and __restrict can vary--with fuzzing...
@ -703,5 +714,4 @@ public class DemangledDataType extends DemangledType {
public String toString() {
return getSignature();
}
}

View File

@ -25,6 +25,7 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
import utility.function.Dummy;
public class DemangledThunk extends DemangledObject {
@ -176,8 +177,7 @@ public class DemangledThunk extends DemangledObject {
}
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
mangled, err -> Msg.warn(this, err));
mangled, Dummy.consumer());
if (s == null) {
Address thunkedAddr =
CreateThunkFunctionCmd.getThunkedAddr(program, thunkAddress, false);
@ -185,11 +185,13 @@ public class DemangledThunk extends DemangledObject {
s = program.getSymbolTable().getPrimarySymbol(thunkedAddr);
}
}
if (s == null || !block.contains(s.getAddress())) {
Msg.warn(this, "Unable to find or create thunk for " + mangled + " at " + thunkAddress);
return null;
}
Address addr = s.getAddress();
Address addr = s.getAddress();
DemanglerOptions subOptions = new DemanglerOptions(options);
subOptions.setApplySignature(true);

View File

@ -26,10 +26,11 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import generic.json.Json;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.SymbolPathParser;
import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.symbol.Namespace;
import ghidra.util.Msg;
import ghidra.util.StringUtilities;
public class GnuDemanglerParser {
@ -42,11 +43,16 @@ public class GnuDemanglerParser {
private static final String TYPEINFO_FOR = "typeinfo for ";
private static final String COVARIANT_RETURN_THUNK = "covariant return thunk";
private static final Set<String> ADDRESS_TABLE_PREFIXES =
Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR);
private static final Set<String> ADDRESS_TABLE_PREFIXES = Set.of(
CONSTRUCTION_VTABLE_FOR,
VTT_FOR,
VTABLE_FOR,
TYPEINFO_FN_FOR,
TYPEINFO_FOR);
private static final String OPERATOR = "operator";
private static final String LAMBDA = "lambda";
private static final String LAMBDA_START = "{lambda";
private static final String VAR_ARGS = "...";
private static final String THUNK = "thunk";
private static final String CONST = " const";
@ -59,8 +65,8 @@ public class GnuDemanglerParser {
* Pattern: name(([const] [params]))
*
* Parts: -optional spaces
* -optional (const) (non-capture group)
* -followed by '()' with optinal parameter text (capture group 1)
* -optional (const) (non-capture group)
* -followed by '()' with optional parameter text (capture group 1)
*
* Note: this pattern is used for matching the arguments string, in the above examples it
* would be:
@ -72,6 +78,22 @@ public class GnuDemanglerParser {
private static final Pattern UNNECESSARY_PARENS_PATTERN =
Pattern.compile("\\s*(?:const){0,1}\\((.*)\\)\\s*");
/**
* Captures the contents of a varargs parameter that is inside of parentheses.
*
* Sample: (NS1::type&&)...
*
* Pattern: (namespace::name[modifiers])...
*
* Parts: -open paren
* -contents (capture group 1)
* -close paren
* -varargs
*
*/
private static final Pattern VARARGS_IN_PARENS =
Pattern.compile("\\((.*)\\)" + Pattern.quote("..."));
/*
* Sample: bob(short (&)[7])
* bob(int const[8] (*) [12])
@ -191,16 +213,19 @@ public class GnuDemanglerParser {
* Pattern for newer C++ lambda syntax:
*
* Sample: {lambda(void const*, unsigned int)#1}
* {lambda(NS1::Class1 const&, int, int)#1} const&
* {lambda(auto:1&&)#1}<NS1::NS2>&&
*
* Pattern: [optional text] brace lambda([parameters])#digits brace
* Pattern: [optional text] brace lambda([parameters])#digits brace [trailing text]
*
* Parts:
* -full text without leading characters (capture group 1)
* -parameters of the lambda function (capture group 2)
* -trailing id (capture group 3)
* -trailing modifiers (e.g., const, &, templates) (capture group 4)
*/
private static final Pattern LAMBDA_PATTERN =
Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})");
Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})(.*)");
/*
* Sample: {unnamed type#1}
@ -279,6 +304,7 @@ public class GnuDemanglerParser {
String extra = userDefinedLiteral;
alternated += '|' + extra;
// note: this capture group seems to fail with excessive templating
String operatorTemplates = "(<.+>){0,1}";
String operatorPrefix =
".*(.*" + OPERATOR + "(" + alternated + ")\\s*" + operatorTemplates + ".*)\\s*";
@ -392,11 +418,17 @@ public class GnuDemanglerParser {
DemangledFunction function = new DemangledFunction(mangledSource, demangled, null);
String simpleName = signatureParts.getName();
LambdaName lambdaName = getLambdaName(demangled);
if (lambdaName != null) {
if (simpleName.endsWith(LAMBDA_START)) {
//
// For lambdas, the signature parser will set the name to '{lambda', with the parameters
// following that text in the original string. We want the name to be the full lambda
// text, without spaces.
//
LambdaName lambdaName = getLambdaName(demangled);
String uniqueName = lambdaName.getFullText();
String escapedLambda = removeBadSpaces(uniqueName);
simpleName = simpleName.replace("{lambda", escapedLambda);
simpleName = simpleName.replace(LAMBDA_START, escapedLambda);
function = new DemangledLambda(mangledSource, demangled, null);
function.setSignature(lambdaName.getFullText());
}
@ -436,10 +468,11 @@ public class GnuDemanglerParser {
return;
}
function.setReturnType(parseDataType(returnType));
function.setReturnType(parseReturnType(returnType));
}
private LambdaName getLambdaName(String name) {
Matcher matcher = LAMBDA_PATTERN.matcher(name);
if (!matcher.matches()) {
return null;
@ -448,7 +481,8 @@ public class GnuDemanglerParser {
String fullText = matcher.group(1);
String params = matcher.group(2);
String trailing = matcher.group(3);
return new LambdaName(fullText, params, trailing);
String modifiers = matcher.group(4);
return new LambdaName(fullText, params, trailing, modifiers);
}
private String stripOffTemplates(String string) {
@ -587,7 +621,18 @@ public class GnuDemanglerParser {
}
}
i = getFunctionPointerCloseParen(parameterString, i);
//
// we wish to move past two sets of parens for function pointers; however, sometimes
// we have code with only one set of parens; for example:
// unsigned long (*)(long const &)
// or
// iterator<boost::function<void ()>
//
int end = findBalancedEnd(parameterString, i, '(', ')');
if (end == -1) {
end = parameterString.length();
}
i = end;
}
}
if (startIndex < parameterString.length()) {
@ -597,40 +642,6 @@ public class GnuDemanglerParser {
return parameters;
}
private int getFunctionPointerCloseParen(String parameterString, int currentIndex) {
int firstCloseParen = parameterString.indexOf(')', currentIndex);
if (firstCloseParen == -1) {
throw new DemanglerParseException(
"Unable to find closing paren for parameter string: " + parameterString);
}
//
// we wish to move past two sets of parens for function pointers; however, sometimes
// we have code with only one set of parens; for example:
// unsigned long (*)(long const &)
// or
// iterator<boost::function<void ()>
//
boolean foundNextStart = false;
int length = parameterString.length();
for (int i = currentIndex; i < length; i++) {
char ch = parameterString.charAt(i);
if (ch == ')') {
return i;
}
else if (ch == '(') {
foundNextStart = true;
}
else if (ch == ',') {
if (!foundNextStart) {
return firstCloseParen;// no new set of parens found
}
}
}
return firstCloseParen;
}
/**
* This method converts each parameter string into
* actual DemangledDataType objects.
@ -639,25 +650,47 @@ public class GnuDemanglerParser {
List<DemangledDataType> parameters = new ArrayList<>();
for (String parameter : parameterStrings) {
DemangledDataType ddt = parseDataType(parameter);
parameters.add(ddt);
DemangledDataType dt = parseParameter(parameter);
parameters.add(dt);
}
return parameters;
}
private DemangledDataType parseDataType(String fullDatatype) {
private DemangledDataType parseParameter(String parameter) {
Matcher castMatcher = CAST_PATTERN.matcher(fullDatatype);
Matcher castMatcher = CAST_PATTERN.matcher(parameter);
if (castMatcher.matches()) {
// special case: template parameter with a cast (just make the datatype
// be the name of the template parameter, since it will just be a display
// attribute for the templated type)
return new DemangledDataType(mangledSource, demangledSource, fullDatatype);
return new DemangledDataType(mangledSource, demangledSource, parameter);
}
Matcher matcher = VARARGS_IN_PARENS.matcher(parameter);
if (matcher.matches()) {
String inside = matcher.group(1);
DemangledDataType dt = parseDataType(inside);
dt.setVarArgs();
return dt;
}
return parseDataType(parameter);
}
private DemangledDataType parseReturnType(String returnType) {
return parseDataType(returnType);
}
private DemangledDataType parseDataType(String fullDatatype) {
DemangledDataType dt = createTypeInNamespace(fullDatatype);
String datatype = dt.getDemangledName();
if ("*".equals(datatype)) {
return createMemberPointer(fullDatatype);
}
DemangledDataType ddt = createTypeInNamespace(fullDatatype);
String datatype = ddt.getDemangledName();
boolean finishedName = false;
for (int i = 0; i < datatype.length(); ++i) {
char ch = datatype.charAt(i);
@ -670,11 +703,11 @@ public class GnuDemanglerParser {
finishedName = true;
if (VAR_ARGS.equals(datatype)) {
ddt.setVarArgs();
dt.setVarArgs();
}
else {
String name = datatype.substring(0, i).trim();
ddt.setName(name);
dt.setName(name);
}
}
@ -690,7 +723,7 @@ public class GnuDemanglerParser {
String templateContent = datatype.substring(contentStart, templateEnd);
DemangledTemplate template = parseTemplate(templateContent);
ddt.setTemplate(template);
dt.setTemplate(template);
i = templateEnd;
}
else if (ch == '(') {// start of function pointer or array ref/pointer
@ -699,23 +732,35 @@ public class GnuDemanglerParser {
// e.g., unsigned long (*)(long const &)
// array pointer/refs
// e.g., short (&)[7]
//
// lambda function
// e.g., {lambda(NS1::Class1 const&, int, int)#1} const&
// {lambda(auto:1&&)#1}<NS1::NS2>>&&
//
LambdaName lambdaName = getLambdaName(datatype);
// check for array case
Matcher arrayMatcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(datatype);
if (arrayMatcher.matches()) {
Demangled namespace = ddt.getNamespace();
Demangled namespace = dt.getNamespace();
String name = arrayMatcher.group(1);// group 0 is the entire string
ddt = parseArrayPointerOrReference(datatype, name, arrayMatcher);
ddt.setNamespace(namespace);
dt = parseArrayPointerOrReference(datatype, name, arrayMatcher);
dt.setNamespace(namespace);
i = arrayMatcher.end();
}
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
}
else {
int startParenCount =
StringUtilities.countOccurrences(datatype.substring(i), '(');
boolean hasPointerParens = startParenCount == 2;
// e.g., unsigned long (*)(long const &)
boolean hasPointerParens = hasConsecutiveSetsOfParens(datatype.substring(i));
if (hasPointerParens) {
Demangled namespace = ddt.getNamespace();
Demangled namespace = dt.getNamespace();
DemangledFunctionPointer dfp = parseFunctionPointer(datatype);
int firstParenEnd = datatype.indexOf(')', i + 1);
int secondParenEnd = datatype.indexOf(')', firstParenEnd + 1);
@ -725,13 +770,13 @@ public class GnuDemanglerParser {
}
dfp.getReturnType().setNamespace(namespace);
ddt = dfp;
dt = dfp;
i = secondParenEnd + 1; // two sets of parens (normal case)
}
else {
// parse as a function pointer, but display as a function
Demangled namespace = ddt.getNamespace();
Demangled namespace = dt.getNamespace();
DemangledFunctionPointer dfp = parseFunction(datatype, i);
int firstParenEnd = datatype.indexOf(')', i + 1);
if (firstParenEnd == -1) {
@ -740,26 +785,26 @@ public class GnuDemanglerParser {
}
dfp.getReturnType().setNamespace(namespace);
ddt = dfp;
dt = dfp;
i = firstParenEnd + 1;// two sets of parens (normal case)
}
}
}
else if (ch == '*') {
ddt.incrementPointerLevels();
dt.incrementPointerLevels();
continue;
}
else if (ch == '&') {
if (!ddt.isReference()) {
ddt.setReference();
if (!dt.isReference()) {
dt.setReference();
}
else {
ddt.incrementPointerLevels();
dt.setRValueReference();
}
continue;
}
else if (ch == '[') {
ddt.setArray(ddt.getArrayDimensions() + 1);
dt.setArray(dt.getArrayDimensions() + 1);
i = datatype.indexOf(']', i + 1);
continue;
}
@ -767,53 +812,87 @@ public class GnuDemanglerParser {
String substr = datatype.substring(i);
if (substr.startsWith("const")) {
ddt.setConst();
dt.setConst();
i += 4;
}
else if (substr.startsWith("struct")) {
ddt.setStruct();
dt.setStruct();
i += 5;
}
else if (substr.startsWith("class")) {
ddt.setClass();
dt.setClass();
i += 4;
}
else if (substr.startsWith("enum")) {
ddt.setEnum();
dt.setEnum();
i += 3;
}
else if (ddt.getName().equals("long")) {
else if (dt.getName().equals("long")) {
if (substr.startsWith("long")) {
ddt.setName(DemangledDataType.LONG_LONG);
dt.setName(DemangledDataType.LONG_LONG);
i += 3;
}
else if (substr.startsWith("double")) {
ddt.setName(DemangledDataType.LONG_DOUBLE);
dt.setName(DemangledDataType.LONG_DOUBLE);
i += 5;
}
}
// unsigned can also mean unsigned long, int
else if (ddt.getName().equals("unsigned")) {
ddt.setUnsigned();
else if (dt.getName().equals("unsigned")) {
dt.setUnsigned();
if (substr.startsWith("long")) {
ddt.setName(DemangledDataType.LONG);
dt.setName(DemangledDataType.LONG);
i += 3;
}
else if (substr.startsWith("int")) {
ddt.setName(DemangledDataType.INT);
dt.setName(DemangledDataType.INT);
i += 2;
}
else if (substr.startsWith("short")) {
ddt.setName(DemangledDataType.SHORT);
dt.setName(DemangledDataType.SHORT);
i += 4;
}
else if (substr.startsWith("char")) {
ddt.setName(DemangledDataType.CHAR);
dt.setName(DemangledDataType.CHAR);
i += 3;
}
}
}
return ddt;
return dt;
}
private boolean hasConsecutiveSetsOfParens(String text) {
int end = findBalancedEnd(text, 0, '(', ')');
if (end < -1) {
return false;
}
String remaining = text.substring(end + 1).trim();
return remaining.startsWith("(");
}
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);
int space = typeWithoutPointer.indexOf(' ');
DemangledDataType dt;
if (space != -1) {
String type = typeWithoutPointer.substring(0, space);
dt = createTypeInNamespace(type);
String parentType = typeWithoutPointer.substring(space + 1);
DemangledDataType parentDt = createTypeInNamespace(parentType);
dt.setNamespace(parentDt);
}
else {
dt = createTypeInNamespace(typeWithoutPointer);
}
dt.incrementPointerLevels();
return dt;
}
private boolean isDataTypeNameCharacter(char ch) {
@ -837,26 +916,31 @@ public class GnuDemanglerParser {
}
/**
* Scans the given string from the given offset looking for a template and reporting the
* index of the closing template character '>' or -1 if no templates are found
* Scans the given string from the given offset looking for a balanced {@code close}
* character. This algorithm will not report a match for the end character until the
* {@code open} character has first been found. This allows clients to scan from anywhere
* in a string to find an open and start character combination, including at or before the
* desired opening character.
*
* @param string the input string
* @param start the start position within the string
* @return the template end index; -1 if no templates found
* @param open the open character (e.g, '(' or '<')
* @param close the close character (e.g, ')' or '>')
* @return the end index; -1 if no templates found
*/
private int findTemplateEnd(String string, int start) {
private int findBalancedEnd(String string, int start, char open, char close) {
boolean found = false;
int depth = 0;
for (int i = start; i < string.length(); i++) {
switch (string.charAt(i)) {
case '<':
depth++;
found = true;
break;
case '>':
depth--;
break;
char c = string.charAt(i);
if (c == open) {
depth++;
found = true;
}
else if (c == close) {
depth--;
}
if (found && depth == 0) {
@ -867,23 +951,119 @@ public class GnuDemanglerParser {
return -1;
}
// assumption: the given index is in a template
// Walk backwards to find the template start
private int findMatchingTemplateStart(String string, int templateEnd) {
/**
* Scans the given string from the given offset looking for a balanced {@code open}
* character. This algorithm will not report a match for the open character until the
* {@code end} character has first been found. This allows clients to scan from anywhere
* in a string to find an open and start character combination, including at or before the
* desired opening character.
*
* @param string the input string
* @param start the start position within the string
* @param open the open character (e.g, '(' or '<')
* @param close the close character (e.g, ')' or '>')
* @return the end index; -1 if no templates found
*/
private int findBalancedStart(String string, int start, char open, char close) {
int depth = 1;
for (int i = templateEnd - 1; i >= 0; i--) {
switch (string.charAt(i)) {
case '<':
depth--;
break;
case '>':
depth++;
break;
boolean found = false;
int depth = 0;
for (int i = start; i >= 0; i--) {
char c = string.charAt(i);
if (c == open) {
depth--;
}
else if (c == close) {
depth++;
found = true;
}
if (depth == 0) {
return i;// found our opening tag
if (found && depth == 0) {
return i;
}
}
return -1;
}
private int findTemplateEnd(String string, int start) {
return findBalancedEnd(string, start, '<', '>');
}
private int findTemplateStart(String string, int templateEnd) {
return findBalancedStart(string, templateEnd, '<', '>');
}
/**
* Walks backward from the given start position to find the next namespace separator. This
* allows clients to determine if a given position is inside of a namespace.
*
* @param text the text to search
* @param start the start position
* @param stop the stop position
* @return the start index of the namespace entry containing the current {@code start}
* index; -1 if no namespace start is found
*/
private int findNamespaceStart(String text, int start, int stop) {
if (!text.contains(Namespace.DELIMITER)) {
return -1;
}
int colonCount = 0;
int parenDepth = 0;
int templateDepth = 0;
int braceDepth = 0;
boolean isNested = false;
for (int i = start; i >= stop; i--) {
char c = text.charAt(i);
switch (c) {
case ':': {
colonCount++;
if (colonCount == 2) {
if (!isNested) {
return i + 2;
}
colonCount = 0;
}
break;
}
case ' ': {
if (!isNested) {
return -1; // a space implies a return type when not nested
}
break;
}
case '(': {
isNested = --parenDepth > 0 || templateDepth > 0 || braceDepth > 0;
break;
}
case ')': {
isNested = ++parenDepth > 0 || templateDepth > 0 || braceDepth > 0;
break;
}
case '<': {
isNested = parenDepth > 0 || --templateDepth > 0 || braceDepth > 0;
break;
}
case '>': {
isNested = parenDepth > 0 || ++templateDepth > 0 || braceDepth > 0;
break;
}
case '{': {
isNested = parenDepth > 0 || templateDepth > 0 || --braceDepth > 0;
break;
}
case '}': {
isNested = parenDepth > 0 || templateDepth > 0 || ++braceDepth > 0;
break;
}
default:
continue;
}
}
@ -891,25 +1071,21 @@ public class GnuDemanglerParser {
}
private DemangledDataType createTypeInNamespace(String name) {
SymbolPath path = new SymbolPath(name);
List<String> names = path.asList();
List<String> names = SymbolPathParser.parse(name, false);
DemangledType namespace = null;
if (names.size() > 1) {
namespace = convertToNamespaces(names.subList(0, names.size() - 1));
}
String datatypeName = names.get(names.size() - 1);
DemangledDataType ddt = new DemangledDataType(mangledSource, demangledSource, datatypeName);
ddt.setName(datatypeName);
ddt.setNamespace(namespace);
return ddt;
DemangledDataType dt = new DemangledDataType(mangledSource, demangledSource, datatypeName);
dt.setName(datatypeName);
dt.setNamespace(namespace);
return dt;
}
private void setNameAndNamespace(DemangledObject object, String name) {
SymbolPath path = new SymbolPath(name);
List<String> names = path.asList();
List<String> names = SymbolPathParser.parse(name, false);
DemangledType namespace = null;
if (names.size() > 1) {
namespace = convertToNamespaces(names.subList(0, names.size() - 1));
@ -923,8 +1099,7 @@ public class GnuDemanglerParser {
private void setNamespace(DemangledObject object, String name) {
SymbolPath path = new SymbolPath(name);
List<String> names = path.asList();
List<String> names = SymbolPathParser.parse(name, false);
object.setNamespace(convertToNamespaces(names));
}
@ -948,13 +1123,13 @@ public class GnuDemanglerParser {
// int (*)[8]
// char (&)[7]
DemangledDataType ddt = new DemangledDataType(mangledSource, demangledSource, name);
DemangledDataType dt = new DemangledDataType(mangledSource, demangledSource, name);
String type = matcher.group(2);
if (type.equals("*")) {
ddt.incrementPointerLevels();
dt.incrementPointerLevels();
}
else if (type.equals("&")) {
ddt.setReference();
dt.setReference();
}
else {
throw new DemanglerParseException("Unexpected charater inside of parens: " + type);
@ -962,9 +1137,9 @@ public class GnuDemanglerParser {
String arraySubscripts = matcher.group(3);
int n = StringUtilities.countOccurrences(arraySubscripts, '[');
ddt.setArray(n);
dt.setArray(n);
return ddt;
return dt;
}
private DemangledFunctionPointer parseFunctionPointer(String functionString) {
@ -985,7 +1160,8 @@ public class GnuDemanglerParser {
//unsigned long (long const &)
int parenStart = functionString.indexOf('(', offset);
int parenEnd = functionString.indexOf(')', parenStart + 1);
int parenEnd = findBalancedEnd(functionString, parenStart, '(', ')');
//int parenEnd = functionString.indexOf(')', parenStart + 1);
String returnType = functionString.substring(0, parenStart).trim();
@ -1003,7 +1179,8 @@ public class GnuDemanglerParser {
List<DemangledDataType> parameters = parseParameters(paramerterString);
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
dfp.setReturnType(parseDataType(returnType));
DemangledDataType returnDataType = parseReturnType(returnType);
dfp.setReturnType(returnDataType);
for (DemangledDataType parameter : parameters) {
dfp.addParameter(parameter);
}
@ -1231,7 +1408,17 @@ public class GnuDemanglerParser {
@Override
boolean matches(String text) {
matcher = OVERLOAD_OPERATOR_NAME_PATTERN.matcher(text);
return matcher.matches();
if (!matcher.matches()) {
return false;
}
int operatorStart = matcher.start(2);
int leafStart = findNamespaceStart(demangled, text.length() - 1, operatorStart);
if (leafStart > operatorStart) {
return false; // operator is inside of a non-leaf namespace entry
}
return true;
}
@Override
@ -1248,14 +1435,8 @@ public class GnuDemanglerParser {
// NS1::operator<(NS1::Coordinate const &,NS1::Coordinate const &)
//
String operatorChars = matcher.group(2);
String templates = matcher.group(3);
int start = matcher.start(2); // operator chars start
int end = matcher.end(3); // templates end
if (templates == null) {
templates = "";
end = matcher.end(2); // no templates; end of the operator chars
}
int end = matcher.end(2); // operator chars start
//
// The 'operator' functions have symbols that confuse our default function parsing.
@ -1263,11 +1444,16 @@ public class GnuDemanglerParser {
// template parsing to fail. To defeat the failure, we will install a temporary
// function name here and then restore it after parsing is finished.
//
String rawPrefix = OPERATOR + demangled.substring(start, end);
String placeholder = "TEMPNAMEPLACEHOLDERVALUE";
String tempName = demangled.replace(rawPrefix, placeholder);
DemangledFunction function = (DemangledFunction) parseFunctionOrVariable(tempName);
String templates = getTemplates(end);
end = end + templates.length();
// a string to replace operator chars; this value will be overwritten the name is set
String placeholder = "TEMPNAMEPLACEHOLDERVALUE";
String baseOperator = OPERATOR + demangled.substring(start, end);
String fixedFunction = demangled.replace(baseOperator, placeholder);
DemangledFunction function = (DemangledFunction) parseFunctionOrVariable(fixedFunction);
function.setOverloadedOperator(true);
String simpleName = OPERATOR + operatorChars;
@ -1283,6 +1469,30 @@ public class GnuDemanglerParser {
return function;
}
private String getTemplates(int start) {
String templates = "";
boolean hasTemplates = nextCharIs(demangled, start, '<');
if (hasTemplates) {
int templateStart = start;
int templateEnd = findTemplateEnd(demangled, templateStart);
if (templateEnd == -1) {
// should not happen
Msg.debug(this, "Unable to find template end for operator: " + demangled);
return templates;
}
templates = demangled.substring(templateStart, templateEnd + 1);
}
return templates;
}
}
private boolean nextCharIs(String text, int index, char c) {
char next = text.charAt(index);
while (next == ' ') {
next = text.charAt(++index);
}
return next == c;
}
private class ConversionOperatorHandler extends OperatorHandler {
@ -1315,7 +1525,7 @@ public class GnuDemanglerParser {
DemangledFunction method =
new DemangledFunction(mangledSource, demangledSource, (String) null);
DemangledDataType returnType = parseDataType(fullReturnType);
DemangledDataType returnType = parseReturnType(fullReturnType);
if (isConst) {
returnType.setConst();
}
@ -1331,8 +1541,8 @@ public class GnuDemanglerParser {
// shortReturnType: string
String templatelessReturnType = stripOffTemplates(fullReturnType);
SymbolPath path = new SymbolPath(templatelessReturnType);
String shortReturnTypeName = path.getName();
List<String> path = SymbolPathParser.parse(templatelessReturnType, false);
String shortReturnTypeName = path.get(path.size() - 1);
//
// The preferred name: 'operator basic_string()'
@ -1427,7 +1637,7 @@ public class GnuDemanglerParser {
int templateEnd = findTemplateEnd(text, 0);
int templateStart = -1;
if (templateEnd != -1) {
templateStart = findMatchingTemplateStart(text, templateEnd);
templateStart = findTemplateStart(text, templateEnd);
}
if (paramStart > templateStart && paramStart < templateEnd) {
// ignore parentheses inside of templates (they are cast operators)
@ -1481,16 +1691,19 @@ public class GnuDemanglerParser {
}
}
// {lambda(void const*, unsigned int)#1}
private class LambdaName {
private String fullText;
private String params;
private String id;
private String trailing;
LambdaName(String fullText, String params, String trailing) {
LambdaName(String fullText, String params, String id, String trailing) {
this.fullText = fullText;
this.params = params;
this.trailing = trailing;
this.id = id;
this.trailing = trailing == null ? "" : trailing;
}
String getFullText() {
@ -1502,6 +1715,7 @@ public class GnuDemanglerParser {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
return builder.append("fullText", fullText)
.append("params", params)
.append("id", id)
.append("trailing", trailing)
.toString();
}

View File

@ -842,6 +842,32 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals("Magick::Coordinate const &", parameters.get(1).getSignature());
}
@Test
public void testOperatorAsNamespace() throws Exception {
//
// Mangled: __ZN3WTF15__visitor_tableINS_7VisitorIZZN7WebCore12SubtleCrypto11generateKeyERN3JSC9ExecStateEONS_7VariantIJNS4_6StrongINS4_8JSObjectEEENS_6StringEEEEbONS_6VectorINS2_14CryptoKeyUsageELm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEEONS_3RefINS2_15DeferredPromiseENS_13DumbPtrTraitsISL_EEEEEN4$_10clEONS7_IJNS_6RefPtrINS2_9CryptoKeyENSM_ISS_EEEENS2_13CryptoKeyPairEEEEEUlRSU_E_JZZNS3_11generateKeyES6_SD_bSJ_SP_ENSQ_clESX_EUlRSV_E_EEEJSU_SV_EE12__trampolineE
//
// Demangled: WTF::__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >&)#1}, WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>, WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>::__trampoline
//
DemangledObject object = parser.parse(
"__ZN3WTF15__visitor_tableINS_7VisitorIZZN7WebCore12SubtleCrypto11generateKeyERN3JSC9ExecStateEONS_7VariantIJNS4_6StrongINS4_8JSObjectEEENS_6StringEEEEbONS_6VectorINS2_14CryptoKeyUsageELm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEEONS_3RefINS2_15DeferredPromiseENS_13DumbPtrTraitsISL_EEEEEN4$_10clEONS7_IJNS_6RefPtrINS2_9CryptoKeyENSM_ISS_EEEENS2_13CryptoKeyPairEEEEEUlRSU_E_JZZNS3_11generateKeyES6_SD_bSJ_SP_ENSQ_clESX_EUlRSV_E_EEEJSU_SV_EE12__trampolineE",
"WTF::__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >&)#1}, WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>, WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>::__trampoline");
assertNotNull(object);
assertType(object, DemangledVariable.class);
String name = "__trampoline";
assertName(object, name, "WTF",
"__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>&)#1},WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>,WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>");
String signature = object.getSignature(false);
assertEquals(
"WTF::__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>&)#1},WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>,WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>::__trampoline",
signature);
}
@Test
public void testOverloadedShiftOperatorTemplated_RightShift() {
parser = new GnuDemanglerParser();
@ -1166,6 +1192,25 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
object.getSignature(false));
}
@Test
public void testAnonymousNamespaceInParameter_FirstNamespace() throws Exception {
//
// Mangled: __ZL7pperrorPN12_GLOBAL__N_17ContextEPKc
//
// Demangled: pperror((anonymous namespace)::Context*, char const*)
//
String mangled = "_ZL7pperrorPN12_GLOBAL__N_17ContextEPKc";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertType(object, DemangledFunction.class);
assertName(object, "pperror");
assertEquals("undefined pperror((anonymous_namespace)::Context *,char const *)",
object.getSignature(false));
}
@Test
public void testTemplatedParametersWithCast() throws Exception {
//
@ -1233,7 +1278,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
parameters.get(0).getTemplate().toString());
assertEquals(
"undefined Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient &)> (Core::File &)> * &)",
"undefined Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient &)> (Core::File &)> &&)",
object.getSignature(false));
}
@ -1327,6 +1372,35 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
object.getSignature(false));
}
@Test
public void testTemplatesThatContainFunctionSignatures_Regression() throws Exception {
//
// Mangled: _ZN7WebCore27ContentFilterUnblockHandlerC2EN3WTF6StringENSt3__18functionIFvNS4_IFvbEEEEEE
//
// Demangled: WebCore::ContentFilterUnblockHandler::ContentFilterUnblockHandler(WTF::String, std::__1::function<void (std::__1::function<void (bool)>)>)
//
// Note: this parameter name caused an infinite loop
//
// function<void (std::__1::function<void (bool)>)>)
//
DemangledObject object = parser.parse(
"_ZN7WebCore27ContentFilterUnblockHandlerC2EN3WTF6StringENSt3__18functionIFvNS4_IFvbEEEEEE",
"WebCore::ContentFilterUnblockHandler::ContentFilterUnblockHandler(WTF::String, std::__1::function<void (std::__1::function<void (bool)>)>)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name = "ContentFilterUnblockHandler";
assertName(object, name, "WebCore", "ContentFilterUnblockHandler");
String signature = object.getSignature(false);
assertEquals(
"undefined WebCore::ContentFilterUnblockHandler::ContentFilterUnblockHandler(WTF::String,std::__1::function<void (std::__1::function<void (bool)>)>)",
signature);
}
@Test
public void testVtableParsingError_NoSpaceBeforeTrailingDigits() throws Exception {
//
@ -1460,6 +1534,208 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
signature);
}
@Test
public void testNamespaceElementWithMultipleFunctionParentheses() throws Exception {
// __ZN7brigand13for_each_argsIZN7WebCore11JSConverterINS1_8IDLUnionIJNS1_7IDLNullENS1_12IDLDOMStringENS1_21IDLUnrestrictedDoubleEEEEE7convertERN3JSC9ExecStateERNS1_17JSDOMGlobalObjectERKN3WTF7VariantIJDnNSE_6StringEdEEEEUlOT_E_JNS_5type_INSt3__117integral_constantIlLl0EEEEENSN_INSP_IlLl1EEEEENSN_INSP_IlLl2EEEEEEEESK_SK_DpOT0_
DemangledObject object = parser.parse(
"__ZN7brigand13for_each_argsIZN7WebCore11JSConverterINS1_8IDLUnionIJNS1_7IDLNullENS1_12IDLDOMStringENS1_21IDLUnrestrictedDoubleEEEEE7convertERN3JSC9ExecStateERNS1_17JSDOMGlobalObjectERKN3WTF7VariantIJDnNSE_6StringEdEEEEUlOT_E_JNS_5type_INSt3__117integral_constantIlLl0EEEEENSN_INSP_IlLl1EEEEENSN_INSP_IlLl2EEEEEEEESK_SK_DpOT0_",
"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> >&&)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name =
"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>>>";
assertName(object, name,
"brigand");
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>> &&)",
signature);
}
@Test
public void testFunctionParameterWithMemberPointer() throws Exception {
//
// Mangled: __ZN7WebCore22FontSelectionAlgorithm16filterCapabilityEPbMS0_KFNS0_14DistanceResultENS_25FontSelectionCapabilitiesEEMS3_NS_18FontSelectionRangeE
//
// Demangled: WebCore::FontSelectionAlgorithm::filterCapability(bool*, WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const, WebCore::FontSelectionRange WebCore::FontSelectionCapabilities::*)
//
//
// WebCore::FontSelectionAlgorithm::filterCapability
// (
// bool*,
// WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const,
// WebCore::FontSelectionRange WebCore::FontSelectionCapabilities::*
// )
//
// This demangled string introduces a new construct:
//
// FontSelectionRange FontSelectionCapabilities::*
//
// where the type is 'FontSelectionRange' which is a member of 'FontSelectionCapabilities'
//
DemangledObject object = parser.parse(
"__ZN7WebCore22FontSelectionAlgorithm16filterCapabilityEPbMS0_KFNS0_14DistanceResultENS_25FontSelectionCapabilitiesEEMS3_NS_18FontSelectionRangeE",
"WebCore::FontSelectionAlgorithm::filterCapability(bool*, WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const, WebCore::FontSelectionRange WebCore::FontSelectionCapabilities::*)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name = "filterCapability";
assertName(object, name, "WebCore", "FontSelectionAlgorithm");
String signature = object.getSignature(false);
assertEquals(
"undefined WebCore::FontSelectionAlgorithm::filterCapability(bool *,WebCore::FontSelectionAlgorithm::DistanceResult ()(WebCore::FontSelectionCapabilities) const,WebCore::FontSelectionCapabilities::FontSelectionRange *)",
signature);
}
@Test
public void testFunctionParameterWithMultipleParentheses() throws Exception {
//
// Mangled: __ZN7WebCore12TextCodecICU14registerCodecsEPFvPKcON3WTF8FunctionIFNSt3__110unique_ptrINS_9TextCodecENS5_14default_deleteIS7_EEEEvEEEE
//
// Demangled: undefined WebCore::TextCodecICU::registerCodecs(void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&))
//
// The regression tested here revolves around this parameter:
//
// void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&
//
// (note the trailing '()' chars)
//
DemangledObject object = parser.parse(
"__ZN7WebCore12TextCodecICU14registerCodecsEPFvPKcON3WTF8FunctionIFNSt3__110unique_ptrINS_9TextCodecENS5_14default_deleteIS7_EEEEvEEEE",
"undefined WebCore::TextCodecICU::registerCodecs(void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&))");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name = "registerCodecs";
assertName(object, name, "WebCore", "TextCodecICU");
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>> ()> &&))",
signature);
}
@Test
public void testFunctionWithVarargsRvalueParameter() throws Exception {
// __ZN3WTF15__visit_helper2ILl1ELm1EJEE7__visitINS_7VisitorIZNKS_17TextBreakIterator9followingEjEUlRKT_E_JEEEJRKNS_7VariantIJNS_20TextBreakIteratorICUENS_19TextBreakIteratorCFEEEEEEENS_27__multi_visitor_return_typeIS5_JDpT0_EE6__typeERS5_DpOSH_
//
//
// this demangled string introduces a new construct:
//
// (WTF::__multi_visitor_return_type&&)...
//
// where the above is a parameter to function, where the params look like:
// (
// WTF::Visitor<WTF::TextBreakIterator::following(unsigned int) const::{lambda(auto:1 const&)#1}>&,
// (WTF::__multi_visitor_return_type&&)...
// )
//
DemangledObject object = parser.parse(
"__ZN3WTF15__visit_helper2ILl1ELm1EJEE7__visitINS_7VisitorIZNKS_17TextBreakIterator9followingEjEUlRKT_E_JEEEJRKNS_7VariantIJNS_20TextBreakIteratorICUENS_19TextBreakIteratorCFEEEEEEENS_27__multi_visitor_return_typeIS5_JDpT0_EE6__typeERS5_DpOSH_",
"WTF::__multi_visitor_return_type<WTF::Visitor<WTF::TextBreakIterator::following(unsigned int) const::{lambda(auto:1 const&)#1}>, WTF::Variant<WTF::TextBreakIteratorICU, WTF::TextBreakIteratorCF> const&>::__type WTF::__visit_helper2<1l, 1ul>::__visit<WTF::Visitor<WTF::TextBreakIterator::following(unsigned int) const::{lambda(auto:1 const&)#1}>, WTF::Variant<WTF::TextBreakIteratorICU, WTF::TextBreakIteratorCF> const&>(WTF::Visitor<WTF::TextBreakIterator::following(unsigned int) const::{lambda(auto:1 const&)#1}>&, (WTF::__multi_visitor_return_type&&)...)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name =
"__visit<WTF::Visitor<WTF::TextBreakIterator::following(unsigned_int)const::{lambda(auto:1_const&)#1}>,WTF::Variant<WTF::TextBreakIteratorICU,WTF::TextBreakIteratorCF>const&>";
assertName(object, name, "WTF", "__visit_helper2<1l,1ul>");
String signature = object.getSignature(false);
assertEquals(
"WTF::__multi_visitor_return_type<WTF::Visitor<WTF::TextBreakIterator::following(unsigned_int)const::{lambda(auto:1_const&)#1}>,WTF::Variant<WTF::TextBreakIteratorICU,WTF::TextBreakIteratorCF>const&>::__type WTF::__visit_helper2<1l,1ul>::__visit<WTF::Visitor<WTF::TextBreakIterator::following(unsigned_int)const::{lambda(auto:1_const&)#1}>,WTF::Variant<WTF::TextBreakIteratorICU,WTF::TextBreakIteratorCF>const&>(WTF::Visitor<WTF::TextBreakIterator::following(unsigned_int) const::{lambda(auto:1 const&)#1}> &,WTF::__multi_visitor_return_type &&)",
signature);
}
@Test
public void testOperator_Equals_ExcessivelyTemplated() throws Exception {
DemangledObject object = parser.parse(
"__ZN3WTF8FunctionIFvvEEaSIZN7WebCore9IDBClient24TransactionOperationImplIJRKNS4_18IDBObjectStoreInfoEEEC1ERNS4_14IDBTransactionEMSB_FvRKNS4_13IDBResultDataEEMSB_FvRNS5_20TransactionOperationES9_ES9_EUlvE_vEERS2_OT_",
"WTF::Function<void ()>& WTF::Function<void ()>::operator=<WebCore::IDBClient::TransactionOperationImpl<WebCore::IDBObjectStoreInfo const&>::TransactionOperationImpl(WebCore::IDBTransaction&, void (WebCore::IDBTransaction::*)(WebCore::IDBResultData const&), void (WebCore::IDBTransaction::*)(WebCore::IDBClient::TransactionOperation&, WebCore::IDBObjectStoreInfo const&), WebCore::IDBObjectStoreInfo const&)::{lambda()#1}, void>(WebCore::IDBClient::TransactionOperationImpl<WebCore::IDBObjectStoreInfo const&>::TransactionOperationImpl(WebCore::IDBTransaction&, void (WebCore::IDBTransaction::*)(WebCore::IDBResultData const&), void (WebCore::IDBTransaction::*)(WebCore::IDBClient::TransactionOperation&, WebCore::IDBObjectStoreInfo const&), WebCore::IDBObjectStoreInfo const&)::{lambda()#1}&&)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name =
"operator=";
assertName(object, name, "WTF", "Function<void()>");
String signature = object.getSignature(false);
assertEquals(
"WTF::Function<void ()> & WTF::Function<void()>::operator=<WebCore::IDBClient::TransactionOperationImpl<WebCore::IDBObjectStoreInfo_const&>::TransactionOperationImpl(WebCore::IDBTransaction&,void(WebCore::IDBTransaction::*)(WebCore::IDBResultData_const&),void(WebCore::IDBTransaction::*)(WebCore::IDBClient::TransactionOperation&,WebCore::IDBObjectStoreInfo_const&),WebCore::IDBObjectStoreInfo_const&)::{lambda()#1},void>(WebCore::IDBClient::TransactionOperationImpl<WebCore::IDBObjectStoreInfo_const&>::TransactionOperationImpl(WebCore::IDBTransaction&,void(WebCore::IDBTransaction::*)(WebCore::IDBResultData_const&),void(WebCore::IDBTransaction::*)(WebCore::IDBClient::TransactionOperation&,WebCore::IDBObjectStoreInfo_const&),WebCore::IDBObjectStoreInfo_const&)::{lambda()#1} &&)",
signature);
}
@Test
public void testLambdaWithTemplates() throws Exception {
// {lambda(auto:1&&)#1}<NS1::NS2>>&&
DemangledObject object = parser.parse(
"_ZN3WTF6VectorINS_9RetainPtrI29AVAssetResourceLoadingRequestEELm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEE17removeAllMatchingIZNS6_9removeAllIPS2_EEjRKT_EUlRKS3_E_EEjSC_m",
"WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString, WebCore::IDLInterface<WebCore::CanvasGradient>, WebCore::IDLInterface<WebCore::CanvasPattern> > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1} brigand::for_each_args<WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString, WebCore::IDLInterface<WebCore::CanvasGradient>, WebCore::IDLInterface<WebCore::CanvasPattern> > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1}, brigand::type_<WebCore::IDLInterface<WebCore::CanvasGradient> >, WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString, WebCore::IDLInterface<WebCore::CanvasGradient>, WebCore::IDLInterface<WebCore::CanvasPattern> > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1}<WebCore::IDLInterface<WebCore::CanvasPattern> > >(WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString, WebCore::IDLInterface<WebCore::CanvasGradient>, WebCore::IDLInterface<WebCore::CanvasPattern> > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1}, brigand::type_<WebCore::IDLInterface<WebCore::CanvasGradient> >&&, WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString, WebCore::IDLInterface<WebCore::CanvasGradient>, WebCore::IDLInterface<WebCore::CanvasPattern> > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1}<WebCore::IDLInterface<WebCore::CanvasPattern> >&&)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name =
"for_each_args<WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1},brigand::type_<WebCore::IDLInterface<WebCore::CanvasGradient>>,WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1}<WebCore::IDLInterface<WebCore::CanvasPattern>>>";
assertName(object, name, "brigand");
String signature = object.getSignature(false);
assertEquals(
"WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1} brigand::for_each_args<WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1},brigand::type_<WebCore::IDLInterface<WebCore::CanvasGradient>>,WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1}<WebCore::IDLInterface<WebCore::CanvasPattern>>>(WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1},brigand::type_<WebCore::IDLInterface<WebCore::CanvasGradient>> &&,WebCore::Converter<WebCore::IDLUnion<WebCore::IDLDOMString,WebCore::IDLInterface<WebCore::CanvasGradient>,WebCore::IDLInterface<WebCore::CanvasPattern>>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1}<WebCore::IDLInterface<WebCore::CanvasPattern>> &&)",
signature);
}
@Test
public void testFunctionWithLambdaParameter() throws Exception {
//
// Mangled: _ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_
//
// Demangled: int
// JSC::Structure::add<
// (JSC::Structure::ShouldPin)1,
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1}
// >(
// JSC::VM&, JSC::PropertyName,
// unsigned int,
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const&
// )
//
//
DemangledObject object = parser.parse(
"_ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_",
"int JSC::Structure::add<(JSC::Structure::ShouldPin)1, JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1}>(JSC::VM&, JSC::PropertyName, unsigned int, JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const&)");
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name =
"add<(JSC::Structure::ShouldPin)1,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker_const&,int,int)#1}>";
assertName(object, name, "JSC", "Structure");
String signature = object.getSignature(false);
assertEquals(
"int JSC::Structure::add<(JSC::Structure::ShouldPin)1,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker_const&,int,int)#1}>(JSC::VM &,JSC::PropertyName,unsigned int,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const &)",
signature);
}
@Test
public void testFunctionInLambdaNamespace() throws Exception {

View File

@ -65,7 +65,7 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
combo.setSelectedIndex(0);
restrictionsCombo.setEnabled(!useMsDiaParser);
combo.addActionListener(e -> {
useMsDiaParser = (combo.getSelectedIndex() == 0);
useMsDiaParser = (combo.getSelectedIndex() == 1);
restrictionsCombo.setEnabled(!useMsDiaParser);
if (useMsDiaParser) {
restrictionsCombo.setSelectedItem(PdbApplicatorRestrictions.NONE);

View File

@ -32,8 +32,6 @@ import ghidra.program.model.symbol.Namespace;
*/
public class SymbolPathParser {
private static String ANONYMOUS_NAMESPACE = "(anonymous_namespace)";
/**
* Parses a String pathname into its constituent namespace and name components.
* The list does not contain the global namespace, which is implied, but then
@ -43,12 +41,26 @@ public class SymbolPathParser {
* @return {@literal List<String>} containing the sequence of namespaces and trailing name.
*/
public static List<String> parse(String name) {
return parse(name, true);
}
/**
* Parses a String pathname into its constituent namespace and name components.
* The list does not contain the global namespace, which is implied, but then
* has each more deeply nested namespace contained in order in the list, followed
* by the trailing name.
* @param name The input String to be parsed.
* @param ignoreLeaderParens true signals to ignore any string that starts with a '(' char.
* This is useful to work around some problem characters.
* @return {@literal List<String>} containing the sequence of namespaces and trailing name.
*/
public static List<String> parse(String name, boolean ignoreLeaderParens) {
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException(
"Symbol list must contain at least one symbol name!");
}
if (skipParsing(name)) {
if (skipParsing(name, ignoreLeaderParens)) {
List<String> list = new ArrayList<>();
list.add(name);
return list;
@ -56,17 +68,14 @@ public class SymbolPathParser {
return naiveParse(name);
}
private static boolean skipParsing(String name) {
private static boolean skipParsing(String name, boolean ignoreLeaderParens) {
// if (name.indexOf(Namespace.DELIMITER) == -1) {
// following is temporary kludge due to struct (blah). TODO: figure/fix
// This particular test for starting with the open parenthesis is to work around a type
// seen in "Rust."
if (name.startsWith("(")) {
// anonymous namespace is a gnu c++ construct. We do not have any way of modeling
// this yet, but still wish not to lose this information, so we do not strip it out of
// the name when parsing gnu demangled symbols.
return !name.startsWith(ANONYMOUS_NAMESPACE);
if (ignoreLeaderParens && name.startsWith("(")) {
return true;
}
return !name.contains(Namespace.DELIMITER);

View File

@ -101,6 +101,37 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
assertNotNull(cmd.getDemangledObject());
}
@Test
public void testParsingFunctionWithLambdaParameter() throws Exception {
//
// This shows a bug when applying a function that has as one of its parameters a lambda function
//
String mangled =
"_ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_";
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this performs initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler();
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals(
"int JSC::Structure::add<(JSC::Structure::ShouldPin)1,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker_const&,int,int)#1}>(JSC::VM &,JSC::PropertyName,unsigned int,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const &)",
result.getSignature(false));
DemanglerCmd cmd = new DemanglerCmd(addr("01001000"), mangled, options);
// this used to trigger an exception
boolean success = applyCmd(program, cmd);
assertTrue("Demangler command failed: " + cmd.getStatusMsg(), success);
assertNotNull(cmd.getDemangledObject());
}
private Address addr(String address) {
return program.getAddressFactory().getAddress(address);
}