diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt b/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt index c9fc62be06..e05664840b 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt @@ -37,6 +37,13 @@ method from cxxfilt.c and placed it, along with supporting methods, into cplus-d allows us to perform a simple build of the stand alone demangler, with less source files required. +Update January 2026 + +Fixed a bug seen in older mangled symbols that use an 'F' character for functions. We added a +function to handle this case, isQualifiersAndFunc(). This function called from inside the +demangle_signature() function. + + cp-demangle.c * This file contains a small, two-line change to send a newline character ('\n') along with diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/cplus-dem.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/cplus-dem.c index 0b7c5f1fbe..d3f335174f 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/cplus-dem.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/cplus-dem.c @@ -819,6 +819,33 @@ cplus_demangle_name_to_style (const char *name) return unknown_demangling; } + +/* Scans to see if mangled is a set of optional qualifiers and a function. */ +static int /* bool */ +isQualifiersAndFunc(const char *mangled) +{ + + int i = 0; + while (1) + { + + switch (mangled[i++]) + { + case 'C': + case 'V': + case 'u': + /*qualifier*/ + break; + case 'F': + /* function */ + return 1; + default: + /* anything else is not a qualifier or function */ + return 0; + } + } +} + /* char *cplus_demangle (const char *mangled, int options) If MANGLED is a mangled function name produced by GNU C++, then @@ -1485,8 +1512,10 @@ demangle_signature (struct work_stuff *work, { /* EDG and others will have the "F", so we let the loop cycle if we are looking at one. */ - if (**mangled != 'F') + // if (**mangled != 'F') + if (!isQualifiersAndFunc(*mangled)) { expect_func = 1; + } } oldmangled = NULL; break; 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 72bfea57df..3e60105978 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 @@ -181,6 +181,23 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { assertEquals("float", parameters.get(3).getType().getSignature()); } + @Test + public void testLegacy_DemangledFunctionCharacter() throws Exception { + + // This is only supported in the older v24 demangler. The 'F' character was not being + // correctly demangled. The native demangler was updated to fix this. + String mangled = "foo__03FooCFUcT1"; + process = GnuDemanglerNativeProcess + .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24); + String demangled = process.demangle(mangled); + assertEquals("Foo::foo(unsigned char, unsigned char) const", demangled); + + DemangledObject object = parser.parse(mangled, demangled); + assertType(object, DemangledFunction.class); + assertName(object, "foo", "Foo"); + assertEquals("undefined Foo::foo(unsigned char,unsigned char)", object.getSignature()); + } + @Test public void testTemplates_TemplatedType() throws Exception { String mangled =