From ea851ffe7b3363a2de1223a40fcce730f1327883 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 5 Nov 2020 16:22:58 -0500 Subject: [PATCH 01/12] GP-272 - Gnu Demangler - updated to handle a lambda function as a function parameter --- .../demangler/gnu/GnuDemanglerParser.java | 36 ++++++++++++++----- .../demangler/GnuDemanglerParserTest.java | 34 ++++++++++++++++++ .../gnu/GnuDemanglerIntegrationTest.java | 31 ++++++++++++++++ 3 files changed, 93 insertions(+), 8 deletions(-) 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 416f77bfcc..130b834cd6 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 @@ -47,6 +47,7 @@ public class GnuDemanglerParser { 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"; @@ -60,7 +61,7 @@ public class GnuDemanglerParser { * * Parts: -optional spaces * -optional (const) (non-capture group) - * -followed by '()' with optinal parameter text (capture group 1) + * -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: @@ -191,16 +192,18 @@ public class GnuDemanglerParser { * Pattern for newer C++ lambda syntax: * * Sample: {lambda(void const*, unsigned int)#1} + * {lambda(NS1::Class1 const&, int, int)#1} const& * - * Pattern: [optional text] brace lambda([parameters])#digits brace + * Pattern: [optional text] brace lambda([parameters])#digits brace [optional modifiers] * * 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) */ private static final Pattern LAMBDA_PATTERN = - Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})"); + Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})(\\s*(?:const|\\*|\\&)*){0,1}"); /* * Sample: {unnamed type#1} @@ -396,7 +399,7 @@ public class GnuDemanglerParser { if (lambdaName != null) { 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()); } @@ -440,6 +443,7 @@ public class GnuDemanglerParser { } private LambdaName getLambdaName(String name) { + Matcher matcher = LAMBDA_PATTERN.matcher(name); if (!matcher.matches()) { return null; @@ -448,7 +452,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) { @@ -699,7 +704,11 @@ 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& + // + + LambdaName lambdaName = getLambdaName(datatype); // check for array case Matcher arrayMatcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(datatype); @@ -710,6 +719,13 @@ public class GnuDemanglerParser { ddt.setNamespace(namespace); i = arrayMatcher.end(); } + else if (lambdaName != null) { + String fullText = lambdaName.getFullText(); + ddt.setName(fullText); + int offset = fullText.indexOf('('); + int remaining = fullText.length() - offset; + i = i + remaining; + } else { int startParenCount = StringUtilities.countOccurrences(datatype.substring(i), '('); @@ -1003,7 +1019,8 @@ public class GnuDemanglerParser { List parameters = parseParameters(paramerterString); DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource); - dfp.setReturnType(parseDataType(returnType)); + DemangledDataType returnDataType = parseDataType(returnType); + dfp.setReturnType(returnDataType); for (DemangledDataType parameter : parameters) { dfp.addParameter(parameter); } @@ -1486,11 +1503,13 @@ public class GnuDemanglerParser { private String fullText; private String params; private String trailing; + private String modifiers; - LambdaName(String fullText, String params, String trailing) { + LambdaName(String fullText, String params, String trailing, String modifiers) { this.fullText = fullText; this.params = params; this.trailing = trailing; + this.modifiers = modifiers == null ? "" : modifiers; } String getFullText() { @@ -1503,6 +1522,7 @@ public class GnuDemanglerParser { return builder.append("fullText", fullText) .append("params", params) .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 af908cb4fc..4c87890528 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 @@ -1460,6 +1460,40 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { 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 { diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/gnu/GnuDemanglerIntegrationTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/gnu/GnuDemanglerIntegrationTest.java index 5de5575264..cee9fe64fa 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/gnu/GnuDemanglerIntegrationTest.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/gnu/GnuDemanglerIntegrationTest.java @@ -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); } 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 02/12] 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 { From ef013a028658778c37f4450b4cd292369ee57ccc Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:38:02 -0500 Subject: [PATCH 03/12] GP-272 - Gnu Demangler - updated to handle a overloaded operator with excessive templates --- .../ghidra/app/cmd/label/DemanglerCmd.java | 8 ++-- .../demangler/gnu/GnuDemanglerParser.java | 47 ++++++++++++++----- .../demangler/GnuDemanglerParserTest.java | 26 ++++++++-- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/DemanglerCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/DemanglerCmd.java index 612a6fcfa3..9be2c5a7d3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/DemanglerCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/label/DemanglerCmd.java @@ -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 } 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 57fb12c592..21abf19e22 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 @@ -30,6 +30,7 @@ import ghidra.app.util.SymbolPath; 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 { @@ -283,6 +284,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*"; @@ -1274,14 +1276,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. @@ -1289,11 +1285,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; @@ -1309,6 +1310,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 { 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 eddf5c4800..dd66dc10be 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 @@ -1460,15 +1460,31 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { 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& WTF::Function::operator=::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::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"); + + String signature = object.getSignature(false); + assertEquals( + "WTF::Function & WTF::Function::operator=::TransactionOperationImpl(WebCore::IDBTransaction&,void(WebCore::IDBTransaction::*)(WebCore::IDBResultData_const &,void ()(WebCore::IDBClient::TransactionOperation &,WebCore::IDBObjectStoreInfo_const &),WebCore::IDBObjectStoreInfo_const&)::{lambda()#1},void>(WebCore::IDBClient::TransactionOperationImpl::TransactionOperationImpl(WebCore::IDBTransaction&, void (WebCore::IDBTransaction::*)(WebCore::IDBResultData const &,void ()(WebCore::IDBClient::TransactionOperation &,WebCore::IDBObjectStoreInfo const &),WebCore::IDBObjectStoreInfo const&)::{lambda()#1} &&)", + 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} >&&)"); From c6306255243b66eb1ee9dabf7b57ca34b0ed9bf7 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 9 Nov 2020 18:58:44 -0500 Subject: [PATCH 04/12] GP-272 - Gnu Demangler - fixed demangler failure related to parameter namespaces that start with the anonymous namespace --- .../demangler/gnu/GnuDemanglerParser.java | 25 +++++++++-------- .../demangler/GnuDemanglerParserTest.java | 19 +++++++++++++ .../ghidra/app/util/SymbolPathParser.java | 27 ++++++++++++------- 3 files changed, 49 insertions(+), 22 deletions(-) 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 21abf19e22..7f475e471f 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 @@ -26,7 +26,7 @@ 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; @@ -43,8 +43,12 @@ 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 ADDRESS_TABLE_PREFIXES = - Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR); + private static final Set 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"; @@ -918,9 +922,7 @@ public class GnuDemanglerParser { } private DemangledDataType createTypeInNamespace(String name) { - SymbolPath path = new SymbolPath(name); - List names = path.asList(); - + List names = SymbolPathParser.parse(name, false); DemangledType namespace = null; if (names.size() > 1) { namespace = convertToNamespaces(names.subList(0, names.size() - 1)); @@ -934,9 +936,7 @@ public class GnuDemanglerParser { } private void setNameAndNamespace(DemangledObject object, String name) { - SymbolPath path = new SymbolPath(name); - List names = path.asList(); - + List names = SymbolPathParser.parse(name, false); DemangledType namespace = null; if (names.size() > 1) { namespace = convertToNamespaces(names.subList(0, names.size() - 1)); @@ -950,8 +950,7 @@ public class GnuDemanglerParser { private void setNamespace(DemangledObject object, String name) { - SymbolPath path = new SymbolPath(name); - List names = path.asList(); + List names = SymbolPathParser.parse(name, false); object.setNamespace(convertToNamespaces(names)); } @@ -1382,8 +1381,8 @@ public class GnuDemanglerParser { // shortReturnType: string String templatelessReturnType = stripOffTemplates(fullReturnType); - SymbolPath path = new SymbolPath(templatelessReturnType); - String shortReturnTypeName = path.getName(); + List path = SymbolPathParser.parse(templatelessReturnType, false); + String shortReturnTypeName = path.get(path.size() - 1); // // The preferred name: 'operator basic_string()' 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 dd66dc10be..2214691b66 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 @@ -1166,6 +1166,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 { // diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java index ede72c9508..412017fc96 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java @@ -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} containing the sequence of namespaces and trailing name. */ public static List 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} containing the sequence of namespaces and trailing name. + */ + public static List 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 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); From 0e6c7a685968a5407f85a6f8aee213a93886d245 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 10 Nov 2020 11:28:44 -0500 Subject: [PATCH 05/12] GP-272 - Gnu Demangler - fixed demangler failure related to namespace elements that have multiple function parenetheses --- .../cmd/function/CreateThunkFunctionCmd.java | 6 +- .../demangler/gnu/GnuDemanglerParser.java | 123 +++++++++--------- .../demangler/GnuDemanglerParserTest.java | 25 +++- 3 files changed, 88 insertions(+), 66 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java index 8737cd9da4..ef3430330a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java @@ -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()); 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 7f475e471f..416083804f 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 @@ -605,7 +605,14 @@ 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 + // + i = findBalancedEnd(parameterString, i, '(', ')'); } } if (startIndex < parameterString.length()) { @@ -615,40 +622,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 - // - 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. @@ -868,26 +841,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) { @@ -898,29 +876,50 @@ 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, '<', '>'); + } + private DemangledDataType createTypeInNamespace(String name) { List names = SymbolPathParser.parse(name, false); DemangledType namespace = null; @@ -1477,7 +1476,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) 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 2214691b66..b3ee889a3a 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 @@ -1479,6 +1479,29 @@ 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 >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1} brigand::for_each_args >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1}, brigand::type_ >, WebCore::JSConverter >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1} >, WebCore::JSConverter >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1} > >(WebCore::JSConverter >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1}, brigand::type_ >&&, WebCore::JSConverter >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1} >&&, WebCore::JSConverter >::convert(JSC::ExecState&, WebCore::JSDOMGlobalObject&, WTF::Variant const&)::{lambda(auto:1&&)#1} >&&)"); + + assertNotNull(object); + assertType(object, DemangledFunction.class); + + String name = + "for_each_args>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1},brigand::type_>,WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1}>,WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1}>>"; + assertName(object, name, + "brigand"); + + String signature = object.getSignature(false); + assertEquals( + "WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1} brigand::for_each_args>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1},brigand::type_>,WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1}>,WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1}>>(WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1},brigand::type_> &&,WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1}> &&,WebCore::JSConverter>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variantconst&)::{lambda(auto:1&&)#1}> &&)", + signature); + } + @Test public void testOperator_Equals_ExcessivelyTemplated() throws Exception { @@ -1495,7 +1518,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { String signature = object.getSignature(false); assertEquals( - "WTF::Function & WTF::Function::operator=::TransactionOperationImpl(WebCore::IDBTransaction&,void(WebCore::IDBTransaction::*)(WebCore::IDBResultData_const &,void ()(WebCore::IDBClient::TransactionOperation &,WebCore::IDBObjectStoreInfo_const &),WebCore::IDBObjectStoreInfo_const&)::{lambda()#1},void>(WebCore::IDBClient::TransactionOperationImpl::TransactionOperationImpl(WebCore::IDBTransaction&, void (WebCore::IDBTransaction::*)(WebCore::IDBResultData const &,void ()(WebCore::IDBClient::TransactionOperation &,WebCore::IDBObjectStoreInfo const &),WebCore::IDBObjectStoreInfo const&)::{lambda()#1} &&)", + "WTF::Function & WTF::Function::operator=::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::TransactionOperationImpl(WebCore::IDBTransaction&,void(WebCore::IDBTransaction::*)(WebCore::IDBResultData_const&),void(WebCore::IDBTransaction::*)(WebCore::IDBClient::TransactionOperation&,WebCore::IDBObjectStoreInfo_const&),WebCore::IDBObjectStoreInfo_const&)::{lambda()#1} &&)", signature); } From e664fd518ac3732f2096ea2b25290e304698fdac Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 10 Nov 2020 13:11:39 -0500 Subject: [PATCH 06/12] GP-272 - Gnu Demangler - fixed demangler failure related to function parameters with RValue varargs --- .../analysis/AbstractDemanglerAnalyzer.java | 9 ++-- .../demangler/gnu/GnuDemanglerParser.java | 51 +++++++++++++++---- .../demangler/GnuDemanglerParserTest.java | 34 +++++++++++++ 3 files changed, 82 insertions(+), 12 deletions(-) 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 { From 34535a85632b1c8c5fc6f1831ef7a12bc7e740cb Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 10 Nov 2020 17:10:28 -0500 Subject: [PATCH 07/12] GP-272 - Gnu Demangler - fixed demangler failure function parameter that is a member pointer --- .../demangler/gnu/GnuDemanglerParser.java | 29 ++++++++++++++ .../demangler/GnuDemanglerParserTest.java | 40 ++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) 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 ba73d25e34..c04666bf1c 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 @@ -682,6 +682,11 @@ public class GnuDemanglerParser { DemangledDataType ddt = createTypeInNamespace(fullDatatype); String datatype = ddt.getDemangledName(); + + if ("*".equals(datatype)) { + return createMemberPointer(fullDatatype); + } + boolean finishedName = false; for (int i = 0; i < datatype.length(); ++i) { char ch = datatype.charAt(i); @@ -853,6 +858,30 @@ public class GnuDemanglerParser { return ddt; } + private DemangledDataType createMemberPointer(String datatype) { + // this is temp code we expect to update as more samples arrive + + // example: NS1::Type1 NS1::ParenType::* + + String typeWithoutPointer = datatype.substring(0, datatype.length() - 3); + int space = typeWithoutPointer.indexOf(' '); + DemangledDataType ddt; + if (space != -1) { + String type = typeWithoutPointer.substring(0, space); + ddt = createTypeInNamespace(type); + + String parentType = typeWithoutPointer.substring(space + 1); + DemangledDataType parentDdt = createTypeInNamespace(parentType); + ddt.setNamespace(parentDdt); + } + else { + ddt = createTypeInNamespace(typeWithoutPointer); + } + + ddt.incrementPointerLevels(); + return ddt; + } + private boolean isDataTypeNameCharacter(char ch) { /* 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 81cda031b9..9ebc143f9f 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,11 +1502,49 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { 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 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: // From bf9245d54f05dc12c3eb290e5047374876ba6072 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 10 Nov 2020 17:23:11 -0500 Subject: [PATCH 08/12] GP-272 - Gnu Demangler - fixed demangler failure on function parameter that has more than 2 sets of parentheses --- .../demangler/gnu/GnuDemanglerParser.java | 2 +- .../demangler/GnuDemanglerParserTest.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) 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 c04666bf1c..6c44813195 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 @@ -755,7 +755,7 @@ public class GnuDemanglerParser { else { int startParenCount = StringUtilities.countOccurrences(datatype.substring(i), '('); - boolean hasPointerParens = startParenCount == 2; + boolean hasPointerParens = startParenCount >= 2; if (hasPointerParens) { Demangled namespace = ddt.getNamespace(); DemangledFunctionPointer dfp = parseFunctionPointer(datatype); 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 9ebc143f9f..81573e9211 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 @@ -1540,6 +1540,37 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { 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> ()> &&)) + // + // The regression tested here revolves around this parameter: + // + // void ()(char const *,WTF::Function> ()> && + // + // (note the trailing '()' chars) + // + + DemangledObject object = parser.parse( + "__ZN7WebCore12TextCodecICU14registerCodecsEPFvPKcON3WTF8FunctionIFNSt3__110unique_ptrINS_9TextCodecENS5_14default_deleteIS7_EEEEvEEEE", + "undefined WebCore::TextCodecICU::registerCodecs(void ()(char const *,WTF::Function> ()> &&))"); + + 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> ()> &&))", + signature); + } + @Test public void testFunctionWithVarargsRvalueParameter() throws Exception { From c75491d70a3103307a92882147d1e7fa02c29b6e Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 12 Nov 2020 17:35:56 -0500 Subject: [PATCH 09/12] GP-272 - Gnu Demangler - fixed demangler failure on template that contained function signature --- .../demangler/gnu/GnuDemanglerParser.java | 33 ++++++++++++++++--- .../demangler/GnuDemanglerParserTest.java | 29 ++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) 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 6c44813195..3b17ce4a7f 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 @@ -628,7 +628,11 @@ public class GnuDemanglerParser { // or // iterator // - i = findBalancedEnd(parameterString, i, '(', ')'); + int end = findBalancedEnd(parameterString, i, '(', ')'); + if (end == -1) { + end = parameterString.length(); + } + i = end; } } if (startIndex < parameterString.length()) { @@ -753,9 +757,8 @@ public class GnuDemanglerParser { 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(); DemangledFunctionPointer dfp = parseFunctionPointer(datatype); @@ -858,6 +861,25 @@ public class GnuDemanglerParser { return ddt; } + private boolean hasConsecutiveSetsOfParens(String text) { + int end = findBalancedEnd(text, 0, '(', ')'); + if (end < -1) { + return false; + } + + for (int i = end + 1; i < text.length(); i++) { + char c = text.charAt(i); + if (c == '(') { + return true; + } + if (c != ' ') { + return false; + } + } + + return false; + } + private DemangledDataType createMemberPointer(String datatype) { // this is temp code we expect to update as more samples arrive @@ -1072,7 +1094,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(); 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 81573e9211..751fb13a52 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 @@ -1346,6 +1346,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)>) + // + // Note: this parameter name caused an infinite loop + // + // function)>) + // + + DemangledObject object = parser.parse( + "_ZN7WebCore27ContentFilterUnblockHandlerC2EN3WTF6StringENSt3__18functionIFvNS4_IFvbEEEEEE", + "WebCore::ContentFilterUnblockHandler::ContentFilterUnblockHandler(WTF::String, std::__1::function)>)"); + + 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)>)", + signature); + } + @Test public void testVtableParsingError_NoSpaceBeforeTrailingDigits() throws Exception { // From 118372d3ce5b93b854b9c18fb462386c7fad9d3a Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 13 Nov 2020 12:51:33 -0500 Subject: [PATCH 10/12] GP-272 - Gnu Demangler - fixed demangler failure on variable name when the parent namespace is an operator function --- .../app/util/demangler/DemangledThunk.java | 8 +- .../demangler/gnu/GnuDemanglerParser.java | 87 ++++++++++++++++++- .../demangler/GnuDemanglerParserTest.java | 26 ++++++ 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledThunk.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledThunk.java index 3497838956..94c1917b5d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledThunk.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledThunk.java @@ -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); 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 3b17ce4a7f..5d2a8e8571 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 @@ -1004,6 +1004,81 @@ public class GnuDemanglerParser { 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 nsCount = 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 ':': { + nsCount++; + if (nsCount == 2) { + if (!isNested) { + return i + 2; + } + nsCount = 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; + } + } + + return -1; + } + private DemangledDataType createTypeInNamespace(String name) { List names = SymbolPathParser.parse(name, false); DemangledType namespace = null; @@ -1342,7 +1417,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 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 751fb13a52..50b908baff 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 @@ -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::String>&&, bool, WTF::Vector&&, WTF::Ref >&&)::$_10::operator()(WTF::Variant >, WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr >&)#1}, WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant, WTF::String>&&, bool, WTF::Vector&&, WTF::Ref >&&)::$_10::operator()(WTF::Variant >, WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>, WTF::RefPtr >, 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::String>&&, bool, WTF::Vector&&, WTF::Ref >&&)::$_10::operator()(WTF::Variant >, WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr >&)#1}, WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant, WTF::String>&&, bool, WTF::Vector&&, WTF::Ref >&&)::$_10::operator()(WTF::Variant >, WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>, WTF::RefPtr >, WebCore::CryptoKeyPair>::__trampoline"); + + assertNotNull(object); + assertType(object, DemangledVariable.class); + + String name = "__trampoline"; + assertName(object, name, "WTF", + "__visitor_table,WTF::String>&&,bool,WTF::Vector&&,WTF::Ref>&&)::$_10::operator()(WTF::Variant>,WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr>&)#1},WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant,WTF::String>&&,bool,WTF::Vector&&,WTF::Ref>&&)::$_10::operator()(WTF::Variant>,WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>,WTF::RefPtr>,WebCore::CryptoKeyPair>"); + + String signature = object.getSignature(false); + assertEquals( + "WTF::__visitor_table,WTF::String>&&,bool,WTF::Vector&&,WTF::Ref>&&)::$_10::operator()(WTF::Variant>,WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr>&)#1},WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant,WTF::String>&&,bool,WTF::Vector&&,WTF::Ref>&&)::$_10::operator()(WTF::Variant>,WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>,WTF::RefPtr>,WebCore::CryptoKeyPair>::__trampoline", + signature); + } + @Test public void testOverloadedShiftOperatorTemplated_RightShift() { parser = new GnuDemanglerParser(); From 355a934dc6890430476de1c3d4df3337d2adc390 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:20:40 -0500 Subject: [PATCH 11/12] GP-272 - Gnu Demangler - review fixes --- .../demangler/gnu/GnuDemanglerParser.java | 131 ++++++++---------- 1 file changed, 61 insertions(+), 70 deletions(-) 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 5d2a8e8571..0a8e286903 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 @@ -650,8 +650,8 @@ public class GnuDemanglerParser { List parameters = new ArrayList<>(); for (String parameter : parameterStrings) { - DemangledDataType ddt = parseParameter(parameter); - parameters.add(ddt); + DemangledDataType dt = parseParameter(parameter); + parameters.add(dt); } return parameters; @@ -670,9 +670,9 @@ public class GnuDemanglerParser { Matcher matcher = VARARGS_IN_PARENS.matcher(parameter); if (matcher.matches()) { String inside = matcher.group(1); - DemangledDataType ddt = parseDataType(inside); - ddt.setVarArgs(); - return ddt; + DemangledDataType dt = parseDataType(inside); + dt.setVarArgs(); + return dt; } return parseDataType(parameter); @@ -684,8 +684,8 @@ public class GnuDemanglerParser { private DemangledDataType parseDataType(String fullDatatype) { - DemangledDataType ddt = createTypeInNamespace(fullDatatype); - String datatype = ddt.getDemangledName(); + DemangledDataType dt = createTypeInNamespace(fullDatatype); + String datatype = dt.getDemangledName(); if ("*".equals(datatype)) { return createMemberPointer(fullDatatype); @@ -703,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); } } @@ -723,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 @@ -742,15 +742,15 @@ public class GnuDemanglerParser { // 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(); - ddt.setName(fullText); + dt.setName(fullText); int offset = fullText.indexOf('('); int remaining = fullText.length() - offset; i = i + remaining; // end of lambda's closing '}' @@ -760,7 +760,7 @@ public class GnuDemanglerParser { // 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); @@ -770,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) { @@ -785,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.setRValueReference(); + dt.setRValueReference(); } continue; } else if (ch == '[') { - ddt.setArray(ddt.getArrayDimensions() + 1); + dt.setArray(dt.getArrayDimensions() + 1); i = datatype.indexOf(']', i + 1); continue; } @@ -812,53 +812,53 @@ 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) { @@ -867,41 +867,32 @@ public class GnuDemanglerParser { return false; } - for (int i = end + 1; i < text.length(); i++) { - char c = text.charAt(i); - if (c == '(') { - return true; - } - if (c != ' ') { - return false; - } - } - - 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::* - - String typeWithoutPointer = datatype.substring(0, datatype.length() - 3); + int trimLength = 3; // '::*' + String typeWithoutPointer = datatype.substring(0, datatype.length() - trimLength); int space = typeWithoutPointer.indexOf(' '); - DemangledDataType ddt; + DemangledDataType dt; if (space != -1) { String type = typeWithoutPointer.substring(0, space); - ddt = createTypeInNamespace(type); + dt = createTypeInNamespace(type); String parentType = typeWithoutPointer.substring(space + 1); - DemangledDataType parentDdt = createTypeInNamespace(parentType); - ddt.setNamespace(parentDdt); + DemangledDataType parentDt = createTypeInNamespace(parentType); + dt.setNamespace(parentDt); } else { - ddt = createTypeInNamespace(typeWithoutPointer); + dt = createTypeInNamespace(typeWithoutPointer); } - ddt.incrementPointerLevels(); - return ddt; + dt.incrementPointerLevels(); + return dt; } private boolean isDataTypeNameCharacter(char ch) { @@ -1020,7 +1011,7 @@ public class GnuDemanglerParser { return -1; } - int nsCount = 0; + int colonCount = 0; int parenDepth = 0; int templateDepth = 0; int braceDepth = 0; @@ -1031,12 +1022,12 @@ public class GnuDemanglerParser { char c = text.charAt(i); switch (c) { case ':': { - nsCount++; - if (nsCount == 2) { + colonCount++; + if (colonCount == 2) { if (!isNested) { return i + 2; } - nsCount = 0; + colonCount = 0; } break; } @@ -1087,10 +1078,10 @@ public class GnuDemanglerParser { } 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) { @@ -1132,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); @@ -1146,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) { From 612f4dcc9f8b3c4005b815c36739792901ba7e89 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 16 Nov 2020 16:13:28 -0500 Subject: [PATCH 12/12] GP-390 Corrected PDB Parser choice for load/download on Windows --- Ghidra/Features/PDB/src/main/java/pdb/AskPdbOptionsDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ghidra/Features/PDB/src/main/java/pdb/AskPdbOptionsDialog.java b/Ghidra/Features/PDB/src/main/java/pdb/AskPdbOptionsDialog.java index 02ee462e1b..a422254ad7 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/AskPdbOptionsDialog.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/AskPdbOptionsDialog.java @@ -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);