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] 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 { //