template stripping in FID

This commit is contained in:
caheckman
2020-10-21 16:42:43 -04:00
parent 956e8ef342
commit 062b6769f8
3 changed files with 76 additions and 56 deletions
@@ -405,11 +405,6 @@ public class FidStatistics extends GhidraScript {
} }
String funcName = chooseFunctionName(result); String funcName = chooseFunctionName(result);
NameVersions nameVersions = NameVersions.generate(funcName, program); NameVersions nameVersions = NameVersions.generate(funcName, program);
String strippedTemplateName = null;
if (nameVersions.demangledBaseName != null) {
strippedTemplateName =
MatchNameAnalysis.removeTemplateParams(nameVersions.demangledBaseName);
}
boolean exactNameMatch = false; boolean exactNameMatch = false;
Iterator<String> iter = matchAnalysis.getRawNameIterator(); Iterator<String> iter = matchAnalysis.getRawNameIterator();
while(iter.hasNext()) { while(iter.hasNext()) {
@@ -450,14 +445,12 @@ public class FidStatistics extends GhidraScript {
exactNameMatch = true; exactNameMatch = true;
break; break;
} }
if (matchNames.demangledBaseName != null && strippedTemplateName != null) { if (nameVersions.demangledNoTemplate != null &&
String strippedName = matchNames.demangledNoTemplate != null) {
MatchNameAnalysis.removeTemplateParams(matchNames.demangledBaseName); if (checkNames(nameVersions.demangledNoTemplate,
if (strippedName != null) { matchNames.demangledNoTemplate)) {
if (checkNames(strippedName, strippedTemplateName)) { exactNameMatch = true;
exactNameMatch = true; break;
break;
}
} }
} }
} }
@@ -32,8 +32,10 @@ public class MatchNameAnalysis {
private Set<String> finalNameList = null; private Set<String> finalNameList = null;
private TreeSet<String> rawNames = null; private TreeSet<String> rawNames = null;
private TreeSet<String> similarBaseNames = null; private TreeSet<String> similarBaseNames = null;
private TreeSet<String> demangledNameNoTemplate = null;
private TreeSet<String> exactDemangledBaseNames = null; private TreeSet<String> exactDemangledBaseNames = null;
private TreeSet<String> libraries = null; private TreeSet<String> libraries = null;
private boolean demangleSelect = false; // True if either deamngledNameNoTemplate or exactDemangledBaseNames is unique
private int mostOptimisticCount; // What is most optimistic (smallest) number of matches private int mostOptimisticCount; // What is most optimistic (smallest) number of matches
// Once duplicates and similar base names are taken into account // Once duplicates and similar base names are taken into account
@@ -43,6 +45,10 @@ public class MatchNameAnalysis {
return finalNameList.size(); return finalNameList.size();
} }
public boolean isDemangled() {
return demangleSelect;
}
public Iterator<String> getRawNameIterator() { public Iterator<String> getRawNameIterator() {
return rawNames.iterator(); return rawNames.iterator();
} }
@@ -80,7 +86,9 @@ public class MatchNameAnalysis {
rawNames = new TreeSet<String>(); rawNames = new TreeSet<String>();
similarBaseNames = new TreeSet<String>(); similarBaseNames = new TreeSet<String>();
demangledNameNoTemplate = new TreeSet<String>();
exactDemangledBaseNames = new TreeSet<String>(); exactDemangledBaseNames = new TreeSet<String>();
int cannotDetemplate = 0;
int cannotDemangle = 0; int cannotDemangle = 0;
for (FidMatch match : matches) { for (FidMatch match : matches) {
@@ -93,6 +101,12 @@ public class MatchNameAnalysis {
if (nameVersions.rawName != null) { if (nameVersions.rawName != null) {
rawNames.add(nameVersions.rawName); // Dedup the raw names rawNames.add(nameVersions.rawName); // Dedup the raw names
similarBaseNames.add(nameVersions.similarName); // Dedup names with underscores removed similarBaseNames.add(nameVersions.similarName); // Dedup names with underscores removed
if (nameVersions.demangledNoTemplate != null) {
demangledNameNoTemplate.add(nameVersions.demangledNoTemplate);
}
else {
cannotDetemplate += 1;
}
if (nameVersions.demangledBaseName != null) { if (nameVersions.demangledBaseName != null) {
exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name
} }
@@ -111,8 +125,21 @@ public class MatchNameAnalysis {
else { else {
singleName = findCommonBaseName(); singleName = findCommonBaseName();
mostOptimisticCount = similarBaseNames.size(); mostOptimisticCount = similarBaseNames.size();
if (singleName == null) {
singleName = findCommonNoTemplate(cannotDetemplate);
if (singleName != null) {
demangleSelect = true;
}
if (demangledNameNoTemplate.size() > 0 &&
demangledNameNoTemplate.size() < mostOptimisticCount) {
mostOptimisticCount = demangledNameNoTemplate.size();
}
}
if (singleName == null) { if (singleName == null) {
singleName = findCommonDemangledBaseName(cannotDemangle); singleName = findCommonDemangledBaseName(cannotDemangle);
if (singleName != null) {
demangleSelect = true;
}
if (exactDemangledBaseNames.size() > 0 && if (exactDemangledBaseNames.size() > 0 &&
exactDemangledBaseNames.size() < mostOptimisticCount) { exactDemangledBaseNames.size() < mostOptimisticCount) {
mostOptimisticCount = exactDemangledBaseNames.size(); mostOptimisticCount = exactDemangledBaseNames.size();
@@ -183,35 +210,14 @@ public class MatchNameAnalysis {
return null; return null;
} }
/** private String findCommonNoTemplate(int cannotDetemplate) {
* If there exists an initial set of template parameters bracketed by '<' and '>' if (cannotDetemplate > 0) {
* in this name, strip them from the name. return null; // Couldn't remove a parameters from everything, so we can't have a common template
* @param name is the function name to strip
* @return the stripped name or null if no parameters present
*/
public static String removeTemplateParams(String name) {
int pos1 = name.indexOf('<');
if (pos1 < 0) {
return null;
} }
int nesting = 1; if (demangledNameNoTemplate.size() == 1) {
int pos2; return demangledNameNoTemplate.first();
for (pos2 = pos1 + 1; pos2 < name.length(); ++pos2) {
char c = name.charAt(pos2);
if (c == '<') {
nesting += 1;
}
else if (c == '>') {
nesting -= 1;
if (nesting == 0) {
break;
}
}
} }
if (nesting != 0) { return null;
return null;
}
return name.substring(0, pos1 + 1) + name.substring(pos2);
} }
private String findCommonDemangledBaseName(int cannotDemangle) { private String findCommonDemangledBaseName(int cannotDemangle) {
@@ -219,22 +225,8 @@ public class MatchNameAnalysis {
return null; // Couldn't demangle everything, so no way we can have a common base return null; // Couldn't demangle everything, so no way we can have a common base
} }
if (exactDemangledBaseNames.size() == 1) { if (exactDemangledBaseNames.size() == 1) {
return exactDemangledBaseNames.iterator().next(); return exactDemangledBaseNames.first();
} }
// If we don't have a unique demangled name, try excising template parameters return null;
String finalName = null;
for (String name : exactDemangledBaseNames) {
String templateFree = removeTemplateParams(name);
if (templateFree == null) {
return null; // At least one name has no template parameters
}
if (finalName == null) {
finalName = templateFree;
}
else if (!finalName.equals(templateFree)) {
return null;
}
}
return finalName;
} }
} }
@@ -21,11 +21,13 @@ import ghidra.program.model.listing.Program;
public class NameVersions { public class NameVersions {
public String rawName; // Original name public String rawName; // Original name
public String similarName; // Name with underscores removed public String similarName; // Name with underscores removed
public String demangledNoTemplate; // Demangled string with (first) template removed
public String demangledBaseName; // Base name of the demangled string public String demangledBaseName; // Base name of the demangled string
public NameVersions(String raw) { public NameVersions(String raw) {
rawName = raw; rawName = raw;
similarName = null; similarName = null;
demangledNoTemplate = null;
demangledBaseName = null; demangledBaseName = null;
} }
@@ -55,6 +57,38 @@ public class NameVersions {
return name; return name;
} }
/**
* If there exists an initial set of template parameters bracketed by '<' and '>'
* in the given demangled name, strip them.
* @param demangledObj is the object holding the demangled name
* @return the stripped name or null if no parameters present
*/
private static String removeTemplateParams(DemangledObject demangledObj) {
String name = demangledObj.getDemangledName();
int pos1 = name.indexOf('<');
if (pos1 < 0) {
return null;
}
int nesting = 1;
int pos2;
for (pos2 = pos1 + 1; pos2 < name.length(); ++pos2) {
char c = name.charAt(pos2);
if (c == '<') {
nesting += 1;
}
else if (c == '>') {
nesting -= 1;
if (nesting == 0) {
break;
}
}
}
if (nesting != 0) {
return null;
}
return name.substring(0, pos1 + 1) + name.substring(pos2);
}
private static String constructBaseName(DemangledObject demangledObj) { private static String constructBaseName(DemangledObject demangledObj) {
String origName = demangledObj.getName(); String origName = demangledObj.getName();
String name = origName.replaceFirst("_*", ""); String name = origName.replaceFirst("_*", "");
@@ -87,6 +121,7 @@ public class NameVersions {
if (rawName != null) { if (rawName != null) {
DemangledObject demangledObj = demangle(program, rawName); DemangledObject demangledObj = demangle(program, rawName);
if (demangledObj != null) { if (demangledObj != null) {
result.demangledNoTemplate = removeTemplateParams(demangledObj);
result.demangledBaseName = constructBaseName(demangledObj); result.demangledBaseName = constructBaseName(demangledObj);
} }