GP-272 - Gnu Demangler - fixed demangler failure related to parameter

namespaces that start with the anonymous namespace
This commit is contained in:
dragonmacher 2020-11-09 18:58:44 -05:00
parent ef013a0286
commit c630625524
3 changed files with 49 additions and 22 deletions

View file

@ -26,7 +26,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import generic.json.Json; import generic.json.Json;
import ghidra.app.util.SymbolPath; import ghidra.app.util.SymbolPathParser;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.symbol.Namespace; 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 TYPEINFO_FOR = "typeinfo for ";
private static final String COVARIANT_RETURN_THUNK = "covariant return thunk"; private static final String COVARIANT_RETURN_THUNK = "covariant return thunk";
private static final Set<String> ADDRESS_TABLE_PREFIXES = private static final Set<String> ADDRESS_TABLE_PREFIXES = Set.of(
Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR); CONSTRUCTION_VTABLE_FOR,
VTT_FOR,
VTABLE_FOR,
TYPEINFO_FN_FOR,
TYPEINFO_FOR);
private static final String OPERATOR = "operator"; private static final String OPERATOR = "operator";
private static final String LAMBDA = "lambda"; private static final String LAMBDA = "lambda";
@ -918,9 +922,7 @@ public class GnuDemanglerParser {
} }
private DemangledDataType createTypeInNamespace(String name) { private DemangledDataType createTypeInNamespace(String name) {
SymbolPath path = new SymbolPath(name); List<String> names = SymbolPathParser.parse(name, false);
List<String> names = path.asList();
DemangledType namespace = null; DemangledType namespace = null;
if (names.size() > 1) { if (names.size() > 1) {
namespace = convertToNamespaces(names.subList(0, 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) { private void setNameAndNamespace(DemangledObject object, String name) {
SymbolPath path = new SymbolPath(name); List<String> names = SymbolPathParser.parse(name, false);
List<String> names = path.asList();
DemangledType namespace = null; DemangledType namespace = null;
if (names.size() > 1) { if (names.size() > 1) {
namespace = convertToNamespaces(names.subList(0, 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) { private void setNamespace(DemangledObject object, String name) {
SymbolPath path = new SymbolPath(name); List<String> names = SymbolPathParser.parse(name, false);
List<String> names = path.asList();
object.setNamespace(convertToNamespaces(names)); object.setNamespace(convertToNamespaces(names));
} }
@ -1382,8 +1381,8 @@ public class GnuDemanglerParser {
// shortReturnType: string // shortReturnType: string
String templatelessReturnType = stripOffTemplates(fullReturnType); String templatelessReturnType = stripOffTemplates(fullReturnType);
SymbolPath path = new SymbolPath(templatelessReturnType); List<String> path = SymbolPathParser.parse(templatelessReturnType, false);
String shortReturnTypeName = path.getName(); String shortReturnTypeName = path.get(path.size() - 1);
// //
// The preferred name: 'operator basic_string()' // The preferred name: 'operator basic_string()'

View file

@ -1166,6 +1166,25 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
object.getSignature(false)); 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 @Test
public void testTemplatedParametersWithCast() throws Exception { public void testTemplatedParametersWithCast() throws Exception {
// //

View file

@ -32,8 +32,6 @@ import ghidra.program.model.symbol.Namespace;
*/ */
public class SymbolPathParser { public class SymbolPathParser {
private static String ANONYMOUS_NAMESPACE = "(anonymous_namespace)";
/** /**
* Parses a String pathname into its constituent namespace and name components. * Parses a String pathname into its constituent namespace and name components.
* The list does not contain the global namespace, which is implied, but then * The list does not contain the global namespace, which is implied, but then
@ -43,12 +41,26 @@ public class SymbolPathParser {
* @return {@literal List<String>} containing the sequence of namespaces and trailing name. * @return {@literal List<String>} containing the sequence of namespaces and trailing name.
*/ */
public static List<String> parse(String name) { public static List<String> 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<String>} containing the sequence of namespaces and trailing name.
*/
public static List<String> parse(String name, boolean ignoreLeaderParens) {
if (StringUtils.isBlank(name)) { if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Symbol list must contain at least one symbol name!"); "Symbol list must contain at least one symbol name!");
} }
if (skipParsing(name)) { if (skipParsing(name, ignoreLeaderParens)) {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
list.add(name); list.add(name);
return list; return list;
@ -56,17 +68,14 @@ public class SymbolPathParser {
return naiveParse(name); return naiveParse(name);
} }
private static boolean skipParsing(String name) { private static boolean skipParsing(String name, boolean ignoreLeaderParens) {
// if (name.indexOf(Namespace.DELIMITER) == -1) { // if (name.indexOf(Namespace.DELIMITER) == -1) {
// following is temporary kludge due to struct (blah). TODO: figure/fix // 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 // This particular test for starting with the open parenthesis is to work around a type
// seen in "Rust." // seen in "Rust."
if (name.startsWith("(")) { if (ignoreLeaderParens && name.startsWith("(")) {
// anonymous namespace is a gnu c++ construct. We do not have any way of modeling return true;
// 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);
} }
return !name.contains(Namespace.DELIMITER); return !name.contains(Namespace.DELIMITER);