From 839f9eeac27c1fa2e0307978c50abbe1803925f3 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 6 Nov 2020 11:01:42 -0500 Subject: [PATCH] GP-272 - Gnu Demangler - updated to handle a lambda function parameter with templates --- .../app/util/demangler/DemangledDataType.java | 12 ++++++- .../demangler/gnu/GnuDemanglerParser.java | 34 ++++++++++++------- .../demangler/GnuDemanglerParserTest.java | 28 ++++++++++++++- 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java index 86cd6c4f9c..59cdfceeb9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java @@ -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(); } - } 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 130b834cd6..57fb12c592 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 @@ -193,17 +193,18 @@ public class GnuDemanglerParser { * * Sample: {lambda(void const*, unsigned int)#1} * {lambda(NS1::Class1 const&, int, int)#1} const& + * {lambda(auto:1&&)#1}&& * - * Pattern: [optional text] brace lambda([parameters])#digits brace [optional modifiers] + * 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, &) (capture group 4) + * -trailing modifiers (e.g., const, &, templates) (capture group 4) */ private static final Pattern LAMBDA_PATTERN = - Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})(\\s*(?:const|\\*|\\&)*){0,1}"); + Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})(.*)"); /* * Sample: {unnamed type#1} @@ -395,8 +396,14 @@ 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_START, escapedLambda); @@ -706,6 +713,7 @@ public class GnuDemanglerParser { // e.g., short (&)[7] // lambda function // e.g., {lambda(NS1::Class1 const&, int, int)#1} const& + // {lambda(auto:1&&)#1}>&& // LambdaName lambdaName = getLambdaName(datatype); @@ -724,7 +732,8 @@ public class GnuDemanglerParser { ddt.setName(fullText); int offset = fullText.indexOf('('); int remaining = fullText.length() - offset; - i = i + remaining; + 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 = @@ -770,7 +779,7 @@ public class GnuDemanglerParser { ddt.setReference(); } else { - ddt.incrementPointerLevels(); + ddt.setRValueReference(); } continue; } @@ -1498,18 +1507,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; - private String modifiers; - LambdaName(String fullText, String params, String trailing, String modifiers) { + LambdaName(String fullText, String params, String id, String trailing) { this.fullText = fullText; this.params = params; - this.trailing = trailing; - this.modifiers = modifiers == null ? "" : modifiers; + this.id = id; + this.trailing = trailing == null ? "" : trailing; } String getFullText() { @@ -1521,8 +1531,8 @@ 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) - .append("modifiers", modifiers) .toString(); } } 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 4c87890528..eddf5c4800 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 @@ -1233,7 +1233,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { parameters.get(0).getTemplate().toString()); assertEquals( - "undefined Core::AsyncFile::perform(WTF::F (Core::File &)> * &)", + "undefined Core::AsyncFile::perform(WTF::F (Core::File &)> &&)", object.getSignature(false)); } @@ -1460,6 +1460,32 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { signature); } + @Test + public void testLambdaWithTemplates() throws Exception { + + // _ZN7brigand13for_each_argsIZN7WebCore9ConverterINS1_8IDLUnionIJNS1_12IDLDOMStringENS1_12IDLInterfaceINS1_14CanvasGradientEEENS5_INS1_13CanvasPatternEEEEEEE7convertERN3JSC9ExecStateENSC_7JSValueEEUlOT_E_JNS_5type_IS7_EENSJ_IS9_EEEEESG_SG_DpOT0_ + + // {lambda(auto:1&&)#1} + + // {lambda(auto:1&&)#1}>&& + + DemangledObject object = parser.parse( + "_ZN3WTF6VectorINS_9RetainPtrI29AVAssetResourceLoadingRequestEELm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEE17removeAllMatchingIZNS6_9removeAllIPS2_EEjRKT_EUlRKS3_E_EEjSC_m", + "WebCore::Converter, WebCore::IDLInterface > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1} brigand::for_each_args, WebCore::IDLInterface > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1}, brigand::type_ >, WebCore::Converter, WebCore::IDLInterface > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1} > >(WebCore::Converter, WebCore::IDLInterface > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1}, brigand::type_ >&&, WebCore::Converter, WebCore::IDLInterface > >::convert(JSC::ExecState&, JSC::JSValue)::{lambda(auto:1&&)#1} >&&)"); + + assertNotNull(object); + assertType(object, DemangledFunction.class); + + String name = + "for_each_args,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1},brigand::type_>,WebCore::Converter,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1}>>"; + assertName(object, name, "brigand"); + + String signature = object.getSignature(false); + assertEquals( + "WebCore::Converter,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1} brigand::for_each_args,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1},brigand::type_>,WebCore::Converter,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1}>>(WebCore::Converter,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1},brigand::type_> &&,WebCore::Converter,WebCore::IDLInterface>>::convert(JSC::ExecState&,JSC::JSValue)::{lambda(auto:1&&)#1}> &&)", + signature); + } + @Test public void testFunctionWithLambdaParameter() throws Exception {