GP-4825 - Gnu Demangler - Update parser for some special global constructor/destructor symbols

This commit is contained in:
dragonmacher 2024-08-07 18:59:49 -04:00
parent 95573ed834
commit 518860f0d6
3 changed files with 143 additions and 28 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -45,38 +45,38 @@ public abstract class DemangledObject implements Demangled {
The following names probably need to be refactored. Until then, this is how the following The following names probably need to be refactored. Until then, this is how the following
fields are used. fields are used.
mangled - mangled -
Source: The original mangled string as seen in the program Source: The original mangled string as seen in the program
Usage: Can be used to see if a program symbol has already been demangled Usage: Can be used to see if a program symbol has already been demangled
originalDemangled - originalDemangled -
Source: The raw demangled string returned from the demangler Source: The raw demangled string returned from the demangler
Usage: for display Usage: for display
demangledName - demangledName -
Source: The name as created by the parser which may transform or even replace the Source: The name as created by the parser which may transform or even replace the
string returned from the demangler string returned from the demangler
Usage: for display Usage: for display
name - name -
Source: This is derived from the 'demangledName' This is updated to be suitable Source: This is derived from the 'demangledName' This is updated to be suitable
for use as a symbol name. This may be null while building, but is for use as a symbol name. This may be null while building, but is
expected to be non-null when applyTo() is called expected to be non-null when applyTo() is called
Usage: The name that will be applied when applyTo() is called. Usage: The name that will be applied when applyTo() is called.
Future: These variables should be refactored and renamed to be clearer and more cohesive, Future: These variables should be refactored and renamed to be clearer and more cohesive,
something like: something like:
mangled mangled
rawDemangled rawDemangled
escapedDemangled escapedDemangled
symbolName symbolName
*/ */
protected final String mangled; // original mangled string protected final String mangled; // original mangled string
protected final String originalDemangled; // raw demangled string protected String originalDemangled; // raw demangled string
private String demangledName; // updated demangled string private String demangledName; // updated demangled string
private String name; // version of demangled name suitable for symbols private String name; // version of demangled name suitable for symbols
@ -240,6 +240,17 @@ public abstract class DemangledObject implements Demangled {
return originalDemangled; return originalDemangled;
} }
/**
* Sets the original demangled string. This is useful for clients that reuse constructed
* demangled objects for special case constructs.
* <p>
* Note: this method is not on the interface
* @param originalDemangled the new original demangled string
*/
public void setOriginalDemangled(String originalDemangled) {
this.originalDemangled = originalDemangled;
}
@Override @Override
public Demangled getNamespace() { public Demangled getNamespace() {
return namespace; return namespace;
@ -364,7 +375,7 @@ public abstract class DemangledObject implements Demangled {
} }
/** /**
* Apply this demangled object detail to the specified program. * Apply this demangled object detail to the specified program.
* <br> * <br>
* NOTE: An open Program transaction must be established prior to invoking this method. * NOTE: An open Program transaction must be established prior to invoking this method.
* *

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -271,6 +271,19 @@ public class GnuDemanglerParser {
private static final Pattern DESCRIPTIVE_PREFIX_PATTERN = private static final Pattern DESCRIPTIVE_PREFIX_PATTERN =
Pattern.compile("((.+ )(for|to) )(.+)"); Pattern.compile("((.+ )(for|to) )(.+)");
/*
* Sample: global constructors keyed to cyg_libc_stdio_altout
*
* Pattern: global (constructors|destructors) keyed to text
*
* Parts:
* -global (constructors|destructors) keyed to (group 1)
* -text (group 3)
*
*/
private static final Pattern GLOBAL_CTOR_DTOR_FOR_PATTERN =
Pattern.compile("(global (constructors|destructors) keyed to )(.+)");
/** /**
* The c 'decltype' keyword pattern * The c 'decltype' keyword pattern
*/ */
@ -446,6 +459,13 @@ public class GnuDemanglerParser {
return new ArrayHandler(demangled, prefix, type); return new ArrayHandler(demangled, prefix, type);
} }
Matcher globalCtorMatcher = GLOBAL_CTOR_DTOR_FOR_PATTERN.matcher(demangled);
if (globalCtorMatcher.matches()) {
prefix = globalCtorMatcher.group(1);
type = globalCtorMatcher.group(3);
return new GlobalCtorDtorHandler(demangled, prefix, type);
}
return new ItemInNamespaceHandler(demangled, prefix, type); return new ItemInNamespaceHandler(demangled, prefix, type);
} }
@ -1524,13 +1544,11 @@ public class GnuDemanglerParser {
ItemInNamespaceHandler(String demangled) { ItemInNamespaceHandler(String demangled) {
super(demangled); super(demangled);
this.demangled = demangled;
this.type = demangled; this.type = demangled;
} }
ItemInNamespaceHandler(String demangled, String prefix, String item) { ItemInNamespaceHandler(String demangled, String prefix, String item) {
super(demangled); super(demangled);
this.demangled = demangled;
this.prefix = prefix; this.prefix = prefix;
this.type = item; this.type = item;
} }
@ -1542,6 +1560,40 @@ public class GnuDemanglerParser {
} }
} }
private class GlobalCtorDtorHandler extends SpecialPrefixHandler {
GlobalCtorDtorHandler(String demangled, String prefix, String item) {
super(demangled);
this.prefix = prefix;
this.type = item;
}
@Override
DemangledObject doBuild(Demangled namespace) {
//
// Since we are for constructors/destructors, assume each item is function
//
String functionName = type;
if (!functionName.contains("(")) {
// add parens so the type will be parsed as a function
functionName += "()";
}
DemangledObject demangledFunction = parseFunctionOrVariable(functionName);
demangledFunction.setOriginalDemangled(demangled);
// e.g., global.constructors.keyed.to.functionName
String parsedFunctionName = demangledFunction.getName();
String prefixNoSpaces = prefix.replaceAll("\s", "\\.");
String fullName = prefixNoSpaces + parsedFunctionName;
demangledFunction.setName(fullName);
demangledFunction.setBackupPlateComment(demangled);
return demangledFunction;
}
}
private class ArrayHandler extends SpecialPrefixHandler { private class ArrayHandler extends SpecialPrefixHandler {
private String arrayType; private String arrayType;
@ -1576,9 +1628,8 @@ public class GnuDemanglerParser {
// //
if ("char".equals(arrayType) && type.contains("StringLiteral")) { if ("char".equals(arrayType) && type.contains("StringLiteral")) {
// treat a char[] as a string // treat a char[] as a string
DemangledString ds = DemangledString ds = new DemangledString(variable.getMangledString(), demangled,
new DemangledString(variable.getMangledString(), demangled, type, type, type, type, -1 /*unknown length*/, false);
-1 /*unknown length*/, false);
ds.setSpecialPrefix(prefix); ds.setSpecialPrefix(prefix);
return ds; return ds;
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -1025,7 +1025,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
/* /*
typeinfo for typeinfo for
std::__ndk1::__function::__func< std::__ndk1::__function::__func<
dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1}, dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1},
std::__ndk1::allocator<dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1}>, std::__ndk1::allocator<dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1}>,
@ -2216,8 +2216,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertName(object, assertName(object,
"__allocate_at_least[abi:v160006]<std::__1::allocator<std::__1::unique_ptr<void,applesauce::raii::v1::detail::opaque_deletion_functor<void*,&VPTimeFreqConverter_Dispose>>>>", "__allocate_at_least[abi:v160006]<std::__1::allocator<std::__1::unique_ptr<void,applesauce::raii::v1::detail::opaque_deletion_functor<void*,&VPTimeFreqConverter_Dispose>>>>",
"std", "std", "__1");
"__1");
String signature = object.getSignature(false); String signature = object.getSignature(false);
assertEquals( assertEquals(
@ -2225,6 +2224,60 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
signature); signature);
} }
@Test
public void testGlobalConstructor() throws Exception {
//
// mangled: _GLOBAL__I_cyg_libc_stdio_altout
//
// demangled: global constructors keyed to cyg_libc_stdio_altout
//
// updated name: global.constructors.keyed.to.cyg_libc_stdio_altout
//
String mangled = "_GLOBAL__I_cyg_libc_stdio_altout";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertType(object, DemangledFunction.class);
assertEquals("global constructors keyed to cyg_libc_stdio_altout",
object.getOriginalDemangled());
assertName(object, "global.constructors.keyed.to.cyg_libc_stdio_altout");
String signature = object.getSignature(false);
assertEquals("undefined global.constructors.keyed.to.cyg_libc_stdio_altout(void)",
signature);
}
@Test
public void testGlobalDestructor() throws Exception {
//
// mangled: _GLOBAL__D_cyg_libc_stdio_altout
//
// demangled: global destructors keyed to cyg_libc_stdio_altout
//
// updated name: global.destructors.keyed.to.cyg_libc_stdio_altout
//
String mangled = "_GLOBAL__D_cyg_libc_stdio_altout";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertType(object, DemangledFunction.class);
assertEquals("global destructors keyed to cyg_libc_stdio_altout",
object.getOriginalDemangled());
assertName(object, "global.destructors.keyed.to.cyg_libc_stdio_altout");
String signature = object.getSignature(false);
assertEquals("undefined global.destructors.keyed.to.cyg_libc_stdio_altout(void)",
signature);
}
private void assertType(Demangled o, Class<?> c) { 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)); c.isInstance(o));