From a74b0c78717c2df9c3ea09e6d98234e85865701e Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 22 Jun 2021 18:02:27 -0400 Subject: [PATCH] GP-1051 - Demangler - fixed spaces inside of namespaces for demangled address tables --- .../util/demangler/DemangledAddressTable.java | 12 ++-- .../demangler/gnu/GnuDemanglerParser.java | 57 +++++++++++-------- .../demangler/GnuDemanglerParserTest.java | 31 ++++++++-- 3 files changed, 63 insertions(+), 37 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java index e129d26cbd..bb7c80efd3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java @@ -32,10 +32,10 @@ public class DemangledAddressTable extends DemangledObject { /** * Constructor * - * @param mangled the source mangled string + * @param mangled the source mangled string * @param originalDemangled the original demangled string * @param name the name of the address table - * @param calculateLength true if the length of this address table should be calculdated at + * @param calculateLength true if the length of this address table should be calculdated at * analysis time */ public DemangledAddressTable(String mangled, String originalDemangled, String name, @@ -56,7 +56,7 @@ public class DemangledAddressTable extends DemangledObject { @Override public String getSignature(boolean format) { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); if (specialPrefix != null) { buffer.append(specialPrefix); @@ -120,11 +120,11 @@ public class DemangledAddressTable extends DemangledObject { } /** - * Perform a best guess at the length of an address table assuming that + * Perform a best guess at the length of an address table assuming that * another label (or end of block) can be used to identify the end. * @param program the program * @param address start of address table - * @return maximum length of table or -1 if address does not reside + * @return maximum length of table or -1 if address does not reside * within an initialized memory block */ private static int guessTableLength(Program program, Address address) { @@ -191,7 +191,7 @@ public class DemangledAddressTable extends DemangledObject { if (!mem.contains(refAddr)) { // terminate table early if pointer reference address does not exist - // within memory (demangled address tables should only refer to entities + // within memory (demangled address tables should only refer to entities // contained within program memory). return; } 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 910607df30..3c0f99b940 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 @@ -245,7 +245,7 @@ public class GnuDemanglerParser { * -'for' or 'to' (capture group 3) | (capture group 1) * -a space -+ * -optional text (capture group 4) - * + * * Note: capture group 1 is the combination of groups 2 and 3 with trailing space * * Examples: @@ -313,7 +313,7 @@ public class GnuDemanglerParser { /** * Pattern to catch literal strings of the form: - * + * * -1l * 2l * 0u @@ -365,7 +365,7 @@ public class GnuDemanglerParser { return operatorHandler; } - // Note: this really is a 'special handler' check that used to be handled above. However, + // Note: this really is a 'special handler' check that used to be handled above. However, // some demangled operator strings begin with this text. If we do this check above, // then we will not correctly handle those operators. if (mangledSource.startsWith("_ZZ")) { @@ -490,14 +490,14 @@ public class GnuDemanglerParser { private LambdaName getLambdaName(String name) { if (!name.startsWith("{")) { - // the text must start with the lambda syntax; ignore lambdas that are internal to + // the text must start with the lambda syntax; ignore lambdas that are internal to // the given name return null; } // This replacement string will leave the initial 'lambda' text and replace all others // with a placeholder value. This allows us to use a simple regex pattern when pulling - // the lambda apart. This is required to handle the case where a lambda expression + // the lambda apart. This is required to handle the case where a lambda expression // contains a nested lambda expression. LambdaReplacedString replacedString = new LambdaReplacedString(name); String updatedName = replacedString.getModifiedText(); @@ -552,20 +552,8 @@ public class GnuDemanglerParser { String name = itemText.substring(pos + 2); DemangledObject item = parseFunctionOrVariable(name); - // - // Convert the parent type to a suitable namespace. The parent type may have spaces - // in its name, which is not allowed in an applied namespace. - // - // We may eventually want to move this logic into the DemangledObject's - // createNamespace() method. This would also apply to the convertToNamespaces() - // method in this class. - // - String namespaceName = parent.getNamespaceName(); - String escapedName = removeBadSpaces(namespaceName); - DemangledType type = new DemangledType(mangledSource, demangledSource, escapedName); - type.setNamespace(parent.getNamespace()); - - item.setNamespace(type); + DemangledType namespaceType = createNamespaceDemangledType(parent); + item.setNamespace(namespaceType); return item; } @@ -758,7 +746,7 @@ public class GnuDemanglerParser { } // note: we should only encounter literals as template arguments. Function parameters - // and return types should never be literals. + // and return types should never be literals. if (isLiteral(fullDatatype)) { return createLiteral(fullDatatype); } @@ -814,7 +802,7 @@ public class GnuDemanglerParser { // // Check for array case // - // remove the templates to allow us to use a simpler regex when checking for arrays + // remove the templates to allow us to use a simpler regex when checking for arrays DemangledDataType newDt = tryToParseArrayPointerOrReference(dt, datatype); if (newDt != null) { dt = newDt; @@ -834,7 +822,7 @@ public class GnuDemanglerParser { String fullText = lambdaName.getFullText(); dt.setName(fullText); int offset = fullText.indexOf('('); - // to to the end of the lambda, which is its length, minus our position + // to to the end of the lambda, which is its length, minus our position // inside the lambda int remaining = fullText.length() - offset; i = i + remaining; // end of lambda's closing '}' @@ -1583,11 +1571,30 @@ public class GnuDemanglerParser { DemangledObject doBuild(Demangled namespace) { DemangledAddressTable addressTable = new DemangledAddressTable(mangledSource, demangled, name, true); - addressTable.setNamespace(namespace); + DemangledType namespaceType = createNamespaceDemangledType(namespace); + addressTable.setNamespace(namespaceType); return addressTable; } } + // + // Convert the given demangled object into a suitable namespace. The given type may have spaces + // in its name, which is not allowed in an *applied* namespace. + // + // We may eventually want to move this logic into the DemangledObject's createNamespace() + // method. This would also apply to the convertToNamespaces() method in this class. The + // reasoning is that this parser should create namespaces just as they are given to the parser, + // while the code responsible for applying the namespace should be responsible for domain + // logic, such as removing spaces in the namespace name. + // + private DemangledType createNamespaceDemangledType(Demangled namespace) { + String namespaceName = namespace.getNamespaceName(); + String escapedName = removeBadSpaces(namespaceName); + DemangledType type = new DemangledType(mangledSource, demangledSource, escapedName); + type.setNamespace(namespace.getNamespace()); + return type; + } + private class OverloadOperatorHandler extends OperatorHandler { OverloadOperatorHandler(String demangled) { @@ -2088,8 +2095,8 @@ public class GnuDemanglerParser { /** * A class that allows us to pass around string content that has had some of its text - * replaced with temporary values. Clients can also use this class to get back the original - * text. + * replaced with temporary values. Clients can also use this class to get back the original + * text. */ private abstract class ReplacedString { 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 a67b90ef58..519b0008a4 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 @@ -540,6 +540,25 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { assertEquals("class_with_trailing_numbers1234::typeinfo", object.getSignature(false)); } + @Test + public void testTypeInfo_AddressTable_InFunctionNamespace() throws Exception { + + String mangled = + "_ZTIFR17ClimateAttributesPSt4pairISt17reference_wrapperI5BiomeES2_I24IWorldRegistriesProviderEEE"; + String demangled = process.demangle(mangled); + assertEquals( + "typeinfo for ClimateAttributes& (std::pair, std::reference_wrapper >*)", + demangled); + + DemangledObject object = parser.parse(mangled, demangled); + String namespaceString = + "ClimateAttributes&(std::pair,std::reference_wrapper>*)"; + assertType(object, DemangledAddressTable.class); + assertName(object, "typeinfo", namespaceString); + + assertEquals(namespaceString + "::typeinfo", object.getSignature(false)); + } + @Test public void testTypeInfo() throws Exception { String mangled = "_ZTIN4Arts28FileInputStream_impl_FactoryE"; @@ -1085,7 +1104,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { /* - Note: the empty template type: '<, std...' + Note: the empty template type: '<, std...' <, std::__cxx11::basic_string, std::allocator>> @@ -1147,7 +1166,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { lambda contents - lambdas in templates and as a parameter - bool (*** + bool (*** const* std:: __addressof< Bedrock:: @@ -1237,7 +1256,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { assertType(object, DemangledFunction.class); //@formatter:off - String expected = + String expected = "void (* " + "entt::" + "basic_registry::" + @@ -1848,16 +1867,16 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { // // Test to ensure proper handling of 'float AvoidBlockGoal::Definition::* const&' - // which is a const reference to a floating point member of the class + // which is a const reference to a floating point member of the class // AvoidBlockGoal::Definition - // + // /* Demangled: auto && JsonUtil:: - addMember>,AvoidBlockGoal::Definition,float> + addMember>,AvoidBlockGoal::Definition,float> ( std::shared_ptr>,