diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java index 9e1d2f19c9..6722672bfa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java @@ -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; } diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java index 416083804f..ba73d25e34 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java @@ -65,8 +65,8 @@ public class GnuDemanglerParser { * Pattern: name(([const] [params])) * * Parts: -optional spaces - * -optional (const) (non-capture group) - * -followed by '()' with optional 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: @@ -78,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]) @@ -452,7 +468,7 @@ public class GnuDemanglerParser { return; } - function.setReturnType(parseDataType(returnType)); + function.setReturnType(parseReturnType(returnType)); } private LambdaName getLambdaName(String name) { @@ -630,23 +646,40 @@ public class GnuDemanglerParser { List parameters = new ArrayList<>(); for (String parameter : parameterStrings) { - DemangledDataType ddt = parseDataType(parameter); + DemangledDataType ddt = parseParameter(parameter); parameters.add(ddt); } 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 ddt = parseDataType(inside); + ddt.setVarArgs(); + return ddt; + + } + return parseDataType(parameter); + } + + private DemangledDataType parseReturnType(String returnType) { + return parseDataType(returnType); + } + + private DemangledDataType parseDataType(String fullDatatype) { + DemangledDataType ddt = createTypeInNamespace(fullDatatype); String datatype = ddt.getDemangledName(); boolean finishedName = false; @@ -1028,7 +1061,7 @@ public class GnuDemanglerParser { List parameters = parseParameters(paramerterString); DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource); - DemangledDataType returnDataType = parseDataType(returnType); + DemangledDataType returnDataType = parseReturnType(returnType); dfp.setReturnType(returnDataType); for (DemangledDataType parameter : parameters) { dfp.addParameter(parameter); @@ -1364,7 +1397,7 @@ public class GnuDemanglerParser { DemangledFunction method = new DemangledFunction(mangledSource, demangledSource, (String) null); - DemangledDataType returnType = parseDataType(fullReturnType); + DemangledDataType returnType = parseReturnType(fullReturnType); if (isConst) { returnType.setConst(); } diff --git a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java index b3ee889a3a..81cda031b9 100644 --- a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java +++ b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java @@ -1502,6 +1502,40 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { 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::__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::Variant const&>::__type WTF::__visit_helper2<1l, 1ul>::__visit, WTF::Variant const&>(WTF::Visitor&, (WTF::__multi_visitor_return_type&&)...)"); + + assertNotNull(object); + assertType(object, DemangledFunction.class); + + String name = + "__visit,WTF::Variantconst&>"; + assertName(object, name, "WTF", "__visit_helper2<1l,1ul>"); + + String signature = object.getSignature(false); + assertEquals( + "WTF::__multi_visitor_return_type,WTF::Variantconst&>::__type WTF::__visit_helper2<1l,1ul>::__visit,WTF::Variantconst&>(WTF::Visitor &,WTF::__multi_visitor_return_type &&)", + signature); + } + @Test public void testOperator_Equals_ExcessivelyTemplated() throws Exception {