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 d1930ff6e0..31ead2181f 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 @@ -213,7 +213,7 @@ public class GnuDemanglerParser { * {lambda(NS1::Class1 const&, int, int)#1} const& * {lambda(auto:1&&)#1}&& * - * Pattern: [optional text] brace lambda([parameters])#digits brace [trailing text] + * Pattern: [optional text] { lambda([parameters])#digits } [trailing text] * * Parts: * -full text without leading characters (capture group 1) @@ -227,13 +227,24 @@ public class GnuDemanglerParser { /* * Sample: {unnamed type#1} * - * Pattern: [optional text] brace unnamed type#digits brace + * Pattern: [optional text] { unnamed type#digits } * * Parts: * -full text without leading characters (capture group 1) */ private static final Pattern UNNAMED_TYPE_PATTERN = Pattern.compile("(\\{unnamed type#\\d+})"); + /** + * Sample: template parameter object for namespace::StringLiteral<38ul>{char [38]{(char)69, (char)101, ... }} + * + * Pattern: (text) { (array type) [size] { array contents } } + * + * Parts: + * -non-array definition prefix, which is the type (capture group 1) + */ + private static final Pattern ARRAY_DATA_PATTERN = + Pattern.compile("(.+)\\{(.+)\\[\\d*\\]\\{.*\\}\\}"); + /* * Sample: covariant return thunk to Foo::Bar::copy(Foo::CoolStructure*) const * @@ -412,6 +423,11 @@ public class GnuDemanglerParser { return new TypeInfoNameHandler(demangled, TYPEINFO_NAME_FOR); } + Matcher arrayMatcher = ARRAY_DATA_PATTERN.matcher(type); + if (arrayMatcher.matches()) { + return new ArrayHandler(demangled, prefix, type); + } + return new ItemInNamespaceHandler(demangled, prefix, type); } @@ -754,6 +770,14 @@ public class GnuDemanglerParser { for (int i = 0; i < datatype.length(); ++i) { char ch = datatype.charAt(i); + // + // Hack: Not sure what this is, but we have seen template parameter values that start + // with an '&' + // + if (ch == '&' && i == 0) { + continue; // for now, let the '&' through to be part of the name + } + if (!finishedName && isDataTypeNameCharacter(ch)) { continue; } @@ -1492,6 +1516,52 @@ public class GnuDemanglerParser { } } + private class ArrayHandler extends SpecialPrefixHandler { + + private String arrayType; + + ArrayHandler(String demangled, String prefix, String item) { + super(demangled); + this.demangled = demangled; + this.prefix = prefix; + this.type = item; + + // + // Handle array data definitions here for now. If we see this in non-specialized prefix + // cases, then we can extract this code. + // + Matcher arrayMatcher = ARRAY_DATA_PATTERN.matcher(type); + if (arrayMatcher.matches()) { + // keep only the type information, dropping the array definition + type = arrayMatcher.group(1); + arrayType = arrayMatcher.group(2).trim(); + } + + } + + @Override + DemangledObject doBuild(Demangled namespace) { + DemangledObject demangledObject = parseItemInNamespace(type); + if (demangledObject instanceof DemangledVariable variable) { + + // + // Creating a DemangledString here will correctly create the string data when this + // demangled type is applied. + // + if ("char".equals(arrayType) && type.contains("StringLiteral")) { + // treat a char[] as a string + DemangledString ds = + new DemangledString(variable.getMangledString(), demangled, type, type, + -1 /*unknown length*/, false); + ds.setSpecialPrefix(prefix); + return ds; + } + + } + return demangledObject; + } + } + private class ThunkHandler extends SpecialPrefixHandler { ThunkHandler(String demangled, String prefix, String item) { 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 1922a5c323..a0ce7e2b09 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 @@ -2140,8 +2140,63 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { new DemangledDataType("fake", "fake", DemangledDataType.LONG_LONG).getDataType(null)); } + @Test + public void testTemplateParameterObectWithArrayDefinition() throws Exception { + + // + // mangled: _ZTAXtlN9envHelper13StringLiteralILm38EEEtlA38_cLc67ELc111ELc114ELc101ELc65ELc117ELc100ELc105ELc111ELc95ELc67ELc97ELc112ELc116ELc117ELc114ELc101ELc67ELc111ELc110ELc118ELc101ELc114ELc116ELc101ELc114ELc67ELc104ELc97ELc105ELc110ELc95ELc73ELc110ELc112ELc117ELc116EEEE + // + // demangled: template parameter object for envHelper::StringLiteral<38ul>{char [38]{(char)67, (char)111, (char)114, (char)101, (char)65, (char)117, (char)100, (char)105, (char)111, (char)95, (char)67, (char)97, (char)112, (char)116, (char)117, (char)114, (char)101, (char)67, (char)111, (char)110, (char)118, (char)101, (char)114, (char)116, (char)101, (char)114, (char)67, (char)104, (char)97, (char)105, (char)110, (char)95, (char)73, (char)110, (char)112, (char)117, (char)116}} + // + // Note: this object ends in a char array definition: + // + // ...{char [38]{(char)67, .... }} + // + + String mangled = + "_ZTAXtlN9envHelper13StringLiteralILm38EEEtlA38_cLc67ELc111ELc114ELc101ELc65ELc117ELc100ELc105ELc111ELc95ELc67ELc97ELc112ELc116ELc117ELc114ELc101ELc67ELc111ELc110ELc118ELc101ELc114ELc116ELc101ELc114ELc67ELc104ELc97ELc105ELc110ELc95ELc73ELc110ELc112ELc117ELc116EEEE"; + String demangled = process.demangle(mangled); + + DemangledObject object = parser.parse(mangled, demangled); + assertNotNull(object); + assertType(object, DemangledString.class); + + String signature = object.getSignature(false); + assertEquals("template parameter object for envHelper::StringLiteral<38ul>", signature); + } + + @Test + public void testAllocatorTraits_AlocateAtLeast() throws Exception { + + // + // mangled: _ZNSt3__119__allocate_at_leastB7v160006INS_9allocatorINS_10unique_ptrIvN10applesauce4raii2v16detail23opaque_deletion_functorIPvXadL_Z27VPTimeFreqConverter_DisposeEEEEEEEEEENS_19__allocation_resultINS_16allocator_traitsIT_E7pointerEEERSE_m + // + // demangled: std::__1::__allocation_result > > >::pointer> std::__1::__allocate_at_least[abi:v160006] > > >(std::__1::allocator > >&, unsigned long) + // + // Note: __allocate_at_least is a C++23 feature + // + + String mangled = + "_ZNSt3__119__allocate_at_leastB7v160006INS_9allocatorINS_10unique_ptrIvN10applesauce4raii2v16detail23opaque_deletion_functorIPvXadL_Z27VPTimeFreqConverter_DisposeEEEEEEEEEENS_19__allocation_resultINS_16allocator_traitsIT_E7pointerEEERSE_m"; + String demangled = process.demangle(mangled); + + DemangledObject object = parser.parse(mangled, demangled); + assertNotNull(object); + assertType(object, DemangledFunction.class); + + assertName(object, + "__allocate_at_least[abi:v160006]>>>", + "std", + "__1"); + + String signature = object.getSignature(false); + assertEquals( + "std::__1::__allocation_result>>>::pointer> std::__1::__allocate_at_least[abi:v160006]>>>(std::__1::allocator>> &,unsigned long)", + signature); + } + private void assertType(Demangled o, Class c) { - assertTrue("Wrong demangled type. " + "\nExpected " + c + "; " + "\nfound " + o.getClass(), + assertTrue("Wrong demangled type. \nExpected " + c + "; \nfound " + o.getClass(), c.isInstance(o)); }