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} >&&)");