diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java index 6c0cbc781c..e51faa8f16 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java @@ -17,6 +17,7 @@ package ghidra.app.util.demangler; import java.util.Objects; +import generic.json.Json; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; @@ -77,4 +78,8 @@ public class MangledContext { return address; } + @Override + public String toString() { + return Json.toString(this); + } } diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java index 48c2397d72..14d7e934b4 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java @@ -120,12 +120,13 @@ public class GnuDemangler implements Demangler { DemangledObject demangledObject = parse(originalMangled, process, demangled, options); if (demangledObject == null) { - return demangledObject; + return null; } if (globalPrefix != null) { + String prefix = translateGlobalPrefix(globalPrefix); DemangledFunction dfunc = new DemangledFunction(originalMangled, demangled, - globalPrefix + demangledObject.getName()); + prefix + demangledObject.getName()); dfunc.setNamespace(demangledObject.getNamespace()); demangledObject = dfunc; } @@ -152,6 +153,17 @@ public class GnuDemangler implements Demangler { } } + private String translateGlobalPrefix(String globalPrefix) { + + return switch (globalPrefix) { + case "_GLOBAL__sub_I_" -> "global_init_constructor_"; + case "_GLOBAL__sub_D_" -> "global_destructor_"; + // case "_GLOBAL__N_" // anonymous namespace; only seen inside mangled text + // case "_GLOBAL__sub_G__" // debugging info; not seen in the wild + default -> globalPrefix; + }; + } + private GnuDemanglerOptions getGnuOptions(DemanglerOptions options) { if (options instanceof GnuDemanglerOptions) { diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java index 23fcbe4884..605727d187 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java @@ -15,6 +15,7 @@ */ package ghidra.app.util.demangler.gnu; +import generic.json.Json; import ghidra.app.util.demangler.DemanglerOptions; /** @@ -83,7 +84,7 @@ public class GnuDemanglerOptions extends DemanglerOptions { public GnuDemanglerOptions(GnuDemanglerFormat format, boolean isDeprecated) { this(format, isDeprecated, GnuDemanglerOptions.DEFAULT_TIMEOUT_SECONDS); } - + /** * Constructor to specify the format to use, whether to prefer the deprecated format when * both deprecated and modern are available, and the timeout @@ -219,16 +220,6 @@ public class GnuDemanglerOptions extends DemanglerOptions { @Override public String toString() { - //@formatter:off - return "{\n" + - "\tdoDisassembly: " + doDisassembly() + ",\n" + - "\tapplySignature: " + applySignature() + ",\n" + - "\tuseStandardReplacements: " + useStandardReplacements + ",\n" + - "\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" + - "\ttimeout (sec): " + timeout + ",\n" + - "\tdemanglerName: " + getDemanglerName() + ",\n" + - "\tdemanglerApplicationArguments: " + getDemanglerApplicationArguments() + ",\n" + - "}"; - //@formatter:on + return Json.toString(this); } } 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 312fd9854a..76283aacc4 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 @@ -1410,7 +1410,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { // // - // Mangled: _ZN12_GLOBAL__N_120decode_charset_iconvEPKc + // Mangled: _ZNK17GCC_IndicationPDUcvRK31GCC_ApplicationInvokeIndicationEv // // Demangled: GCC_IndicationPDU::operator GCC_ApplicationInvokeIndication const&() const // diff --git a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java index 87fe3939f2..a978719bc9 100644 --- a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java +++ b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java @@ -150,7 +150,9 @@ public class GnuDemanglerTest extends AbstractGenericTest { GnuDemanglerOptions options = new GnuDemanglerOptions(); options.setUseStandardReplacements(true); - DemangledFunction dobj = (DemangledFunction) demangler.demangle(mangled, options); + MangledContext context = new MangledContext(program, options, mangled, null); + + DemangledFunction dobj = (DemangledFunction) demangler.demangle(context); assertNotNull(dobj); String signature = dobj.getSignature(); @@ -172,7 +174,8 @@ public class GnuDemanglerTest extends AbstractGenericTest { // Now disable demangled string replacement // options.setUseStandardReplacements(false); - dobj = (DemangledFunction) demangler.demangle(mangled, options); + context = new MangledContext(program, options, mangled, null); + dobj = (DemangledFunction) demangler.demangle(context); assertNotNull(dobj); String fullSignature = dobj.getSignature(); @@ -233,6 +236,29 @@ public class GnuDemanglerTest extends AbstractGenericTest { assertTrue(d.isPointer()); } + @Test + public void testGlobalInitializationFunction() throws Exception { + + /* + Mangled: _GLOBAL__sub_I__ZN6ghidra8ATTRIB_AE + + We parse this as a DemangledVariable. We then us the '_GLOBAL__sub_I_' prefix as + a signal that the symbol represents a global initialization constructor. We then + convert the variable to a DemangledFunction. + + Signature: ghidra::global_init_constructor_ATTRIB_A(void) + + */ + + String mangled = "_GLOBAL__sub_I__ZN6ghidra8ATTRIB_AE"; + + GnuDemangler demangler = new GnuDemangler(); + DemangledFunction obj = (DemangledFunction) demangler.demangle(mangled); + + String signature = obj.getSignature(); + assertEquals("ghidra::global_init_constructor_ATTRIB_A(void)", signature); + } + @Test public void testDemangleTypeInfoName() throws Exception {