mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
GP-272 - Gnu Demangler - fixed demangler failure related to parameter
namespaces that start with the anonymous namespace
This commit is contained in:
parent
ef013a0286
commit
c630625524
3 changed files with 49 additions and 22 deletions
|
@ -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<String> ADDRESS_TABLE_PREFIXES =
|
||||
Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR);
|
||||
private static final Set<String> 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<String> names = path.asList();
|
||||
|
||||
List<String> 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<String> names = path.asList();
|
||||
|
||||
List<String> 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<String> names = path.asList();
|
||||
List<String> 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<String> path = SymbolPathParser.parse(templatelessReturnType, false);
|
||||
String shortReturnTypeName = path.get(path.size() - 1);
|
||||
|
||||
//
|
||||
// The preferred name: 'operator basic_string()'
|
||||
|
|
|
@ -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 {
|
||||
//
|
||||
|
|
|
@ -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<String>} containing the sequence of namespaces and trailing 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)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Symbol list must contain at least one symbol name!");
|
||||
}
|
||||
|
||||
if (skipParsing(name)) {
|
||||
if (skipParsing(name, ignoreLeaderParens)) {
|
||||
List<String> 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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue