From 5dd4b43b13007c463b57118551538f144eb29e57 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:10:10 -0500 Subject: [PATCH] GP-6394 - Gnu Demangler - Added legacy support for the static qualifier --- .../src/demangler_gnu_v2_24/README.txt | 4 +- .../src/demangler_gnu_v2_24/c/cplus-dem.c | 48 ++++++++++++------- .../demangler/GnuDemanglerParserTest.java | 40 ++++++++++++++++ 3 files changed, 75 insertions(+), 17 deletions(-) diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt b/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt index e05664840b..6795e27a98 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_24/README.txt @@ -41,7 +41,9 @@ 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. +demangle_signature() function. The output also makes use of the added TYPE_QUAL_STATIC define. + + cp-demangle.c * 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 d3f335174f..e6ebe5901d 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 @@ -463,6 +463,7 @@ static int snarf_numeric_literal (const char **, string *); #define TYPE_QUAL_CONST 0x1 #define TYPE_QUAL_VOLATILE 0x2 #define TYPE_QUAL_RESTRICT 0x4 +#define TYPE_QUAL_STATIC 0x8 static int code_for_qualifier (int); @@ -573,6 +574,9 @@ code_for_qualifier (int c) case 'C': return TYPE_QUAL_CONST; + case 'S': + return TYPE_QUAL_STATIC; + case 'V': return TYPE_QUAL_VOLATILE; @@ -601,22 +605,34 @@ qualifier_string (int type_quals) case TYPE_QUAL_CONST: return "const"; + case TYPE_QUAL_STATIC: + return "static"; + case TYPE_QUAL_VOLATILE: return "volatile"; case TYPE_QUAL_RESTRICT: return "__restrict"; + case TYPE_QUAL_CONST | TYPE_QUAL_STATIC: + return "const static"; + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: return "const volatile"; case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: return "const __restrict"; + + case TYPE_QUAL_STATIC | TYPE_QUAL_VOLATILE: + return "static volatile"; case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: return "volatile __restrict"; - case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + case TYPE_QUAL_CONST | TYPE_QUAL_STATIC | TYPE_QUAL_VOLATILE: + return "static const volatile"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: return "const volatile __restrict"; default: @@ -819,33 +835,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; + case 'C': + case 'S': + 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 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 3e60105978..ab4e1f80b6 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 @@ -198,6 +198,46 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { assertEquals("undefined Foo::foo(unsigned char,unsigned char)", object.getSignature()); } + @Test + public void testLegacy_DemangedFunctionCharacter_Qualifiers() throws Exception { + + // This is only supported in the older v24 demangler. The 'F' character was not being + // correctly demangled along with some qualifier characters. The native demangler was + // updated to fix this. + process = GnuDemanglerNativeProcess + .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24); + + //@formatter:off + assertLegacyDemangled("foo__03FooCF", + "Foo::foo(void) const", + "undefined Foo::foo(void)"); + + assertLegacyDemangled("foo__03FooSF", + "Foo::foo(void) static", + "undefined Foo::foo(void)"); + + assertLegacyDemangled("foo__03FooSFUcT1", + "Foo::foo(unsigned char, unsigned char) static", + "undefined Foo::foo(unsigned char,unsigned char)"); + + assertLegacyDemangled("foo__03FooSCFUcT1", + "Foo::foo(unsigned char, unsigned char) static const", + "undefined Foo::foo(unsigned char,unsigned char)"); + + //@formatter:on + } + + private void assertLegacyDemangled(String mangled, String demangledExpected, + String signatureExpected) throws Exception { + + String demangledActual = process.demangle(mangled); + assertEquals(demangledExpected, demangledActual); + + DemangledObject object = parser.parse(mangled, demangledExpected); + assertType(object, DemangledFunction.class); + assertEquals(signatureExpected, object.getSignature()); + } + @Test public void testTemplates_TemplatedType() throws Exception { String mangled =