From c6306255243b66eb1ee9dabf7b57ca34b0ed9bf7 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 9 Nov 2020 18:58:44 -0500 Subject: [PATCH] GP-272 - Gnu Demangler - fixed demangler failure related to parameter namespaces that start with the anonymous namespace --- .../demangler/gnu/GnuDemanglerParser.java | 25 +++++++++-------- .../demangler/GnuDemanglerParserTest.java | 19 +++++++++++++ .../ghidra/app/util/SymbolPathParser.java | 27 ++++++++++++------- 3 files changed, 49 insertions(+), 22 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 21abf19e22..7f475e471f 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 @@ -26,7 +26,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import generic.json.Json; -import ghidra.app.util.SymbolPath; +import ghidra.app.util.SymbolPathParser; import ghidra.app.util.demangler.*; import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.symbol.Namespace; @@ -43,8 +43,12 @@ public class GnuDemanglerParser { private static final String TYPEINFO_FOR = "typeinfo for "; private static final String COVARIANT_RETURN_THUNK = "covariant return thunk"; - private static final Set ADDRESS_TABLE_PREFIXES = - Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR); + private static final Set ADDRESS_TABLE_PREFIXES = Set.of( + CONSTRUCTION_VTABLE_FOR, + VTT_FOR, + VTABLE_FOR, + TYPEINFO_FN_FOR, + TYPEINFO_FOR); private static final String OPERATOR = "operator"; private static final String LAMBDA = "lambda"; @@ -918,9 +922,7 @@ public class GnuDemanglerParser { } private DemangledDataType createTypeInNamespace(String name) { - SymbolPath path = new SymbolPath(name); - List names = path.asList(); - + List names = SymbolPathParser.parse(name, false); DemangledType namespace = null; if (names.size() > 1) { namespace = convertToNamespaces(names.subList(0, names.size() - 1)); @@ -934,9 +936,7 @@ public class GnuDemanglerParser { } private void setNameAndNamespace(DemangledObject object, String name) { - SymbolPath path = new SymbolPath(name); - List names = path.asList(); - + List names = SymbolPathParser.parse(name, false); DemangledType namespace = null; if (names.size() > 1) { namespace = convertToNamespaces(names.subList(0, names.size() - 1)); @@ -950,8 +950,7 @@ public class GnuDemanglerParser { private void setNamespace(DemangledObject object, String name) { - SymbolPath path = new SymbolPath(name); - List names = path.asList(); + List names = SymbolPathParser.parse(name, false); object.setNamespace(convertToNamespaces(names)); } @@ -1382,8 +1381,8 @@ public class GnuDemanglerParser { // shortReturnType: string String templatelessReturnType = stripOffTemplates(fullReturnType); - SymbolPath path = new SymbolPath(templatelessReturnType); - String shortReturnTypeName = path.getName(); + List path = SymbolPathParser.parse(templatelessReturnType, false); + String shortReturnTypeName = path.get(path.size() - 1); // // The preferred name: 'operator basic_string()' 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 dd66dc10be..2214691b66 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 @@ -1166,6 +1166,25 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { object.getSignature(false)); } + @Test + public void testAnonymousNamespaceInParameter_FirstNamespace() throws Exception { + // + // Mangled: __ZL7pperrorPN12_GLOBAL__N_17ContextEPKc + // + // Demangled: pperror((anonymous namespace)::Context*, char const*) + // + String mangled = "_ZL7pperrorPN12_GLOBAL__N_17ContextEPKc"; + + String demangled = process.demangle(mangled); + + DemangledObject object = parser.parse(mangled, demangled); + assertType(object, DemangledFunction.class); + assertName(object, "pperror"); + + assertEquals("undefined pperror((anonymous_namespace)::Context *,char const *)", + object.getSignature(false)); + } + @Test public void testTemplatedParametersWithCast() throws Exception { // diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java index ede72c9508..412017fc96 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java @@ -32,8 +32,6 @@ import ghidra.program.model.symbol.Namespace; */ public class SymbolPathParser { - private static String ANONYMOUS_NAMESPACE = "(anonymous_namespace)"; - /** * Parses a String pathname into its constituent namespace and name components. * The list does not contain the global namespace, which is implied, but then @@ -43,12 +41,26 @@ public class SymbolPathParser { * @return {@literal List} containing the sequence of namespaces and trailing name. */ public static List parse(String name) { + return parse(name, true); + } + + /** + * Parses a String pathname into its constituent namespace and name components. + * The list does not contain the global namespace, which is implied, but then + * has each more deeply nested namespace contained in order in the list, followed + * by the trailing name. + * @param name The input String to be parsed. + * @param ignoreLeaderParens true signals to ignore any string that starts with a '(' char. + * This is useful to work around some problem characters. + * @return {@literal List} containing the sequence of namespaces and trailing name. + */ + public static List parse(String name, boolean ignoreLeaderParens) { if (StringUtils.isBlank(name)) { throw new IllegalArgumentException( "Symbol list must contain at least one symbol name!"); } - if (skipParsing(name)) { + if (skipParsing(name, ignoreLeaderParens)) { List list = new ArrayList<>(); list.add(name); return list; @@ -56,17 +68,14 @@ public class SymbolPathParser { return naiveParse(name); } - private static boolean skipParsing(String name) { + private static boolean skipParsing(String name, boolean ignoreLeaderParens) { // if (name.indexOf(Namespace.DELIMITER) == -1) { // following is temporary kludge due to struct (blah). TODO: figure/fix // This particular test for starting with the open parenthesis is to work around a type // seen in "Rust." - if (name.startsWith("(")) { - // anonymous namespace is a gnu c++ construct. We do not have any way of modeling - // this yet, but still wish not to lose this information, so we do not strip it out of - // the name when parsing gnu demangled symbols. - return !name.startsWith(ANONYMOUS_NAMESPACE); + if (ignoreLeaderParens && name.startsWith("(")) { + return true; } return !name.contains(Namespace.DELIMITER);