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

View file

@ -405,11 +405,6 @@ public class FidStatistics extends GhidraScript {
}
String funcName = chooseFunctionName(result);
NameVersions nameVersions = NameVersions.generate(funcName, program);
String strippedTemplateName = null;
if (nameVersions.demangledBaseName != null) {
strippedTemplateName =
MatchNameAnalysis.removeTemplateParams(nameVersions.demangledBaseName);
}
boolean exactNameMatch = false;
Iterator<String> iter = matchAnalysis.getRawNameIterator();
while(iter.hasNext()) {
@ -450,17 +445,15 @@ public class FidStatistics extends GhidraScript {
exactNameMatch = true;
break;
}
if (matchNames.demangledBaseName != null && strippedTemplateName != null) {
String strippedName =
MatchNameAnalysis.removeTemplateParams(matchNames.demangledBaseName);
if (strippedName != null) {
if (checkNames(strippedName, strippedTemplateName)) {
if (nameVersions.demangledNoTemplate != null &&
matchNames.demangledNoTemplate != null) {
if (checkNames(nameVersions.demangledNoTemplate,
matchNames.demangledNoTemplate)) {
exactNameMatch = true;
break;
}
}
}
}
if (exactNameMatch) {
record.nameMatched += 1;
}

View file

@ -32,8 +32,10 @@ public class MatchNameAnalysis {
private Set<String> finalNameList = null;
private TreeSet<String> rawNames = null;
private TreeSet<String> similarBaseNames = null;
private TreeSet<String> demangledNameNoTemplate = null;
private TreeSet<String> exactDemangledBaseNames = 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
// Once duplicates and similar base names are taken into account
@ -43,6 +45,10 @@ public class MatchNameAnalysis {
return finalNameList.size();
}
public boolean isDemangled() {
return demangleSelect;
}
public Iterator<String> getRawNameIterator() {
return rawNames.iterator();
}
@ -80,7 +86,9 @@ public class MatchNameAnalysis {
rawNames = new TreeSet<String>();
similarBaseNames = new TreeSet<String>();
demangledNameNoTemplate = new TreeSet<String>();
exactDemangledBaseNames = new TreeSet<String>();
int cannotDetemplate = 0;
int cannotDemangle = 0;
for (FidMatch match : matches) {
@ -93,6 +101,12 @@ public class MatchNameAnalysis {
if (nameVersions.rawName != null) {
rawNames.add(nameVersions.rawName); // Dedup the raw names
similarBaseNames.add(nameVersions.similarName); // Dedup names with underscores removed
if (nameVersions.demangledNoTemplate != null) {
demangledNameNoTemplate.add(nameVersions.demangledNoTemplate);
}
else {
cannotDetemplate += 1;
}
if (nameVersions.demangledBaseName != null) {
exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name
}
@ -111,8 +125,21 @@ public class MatchNameAnalysis {
else {
singleName = findCommonBaseName();
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) {
singleName = findCommonDemangledBaseName(cannotDemangle);
if (singleName != null) {
demangleSelect = true;
}
if (exactDemangledBaseNames.size() > 0 &&
exactDemangledBaseNames.size() < mostOptimisticCount) {
mostOptimisticCount = exactDemangledBaseNames.size();
@ -183,58 +210,23 @@ public class MatchNameAnalysis {
return null;
}
/**
* If there exists an initial set of template parameters bracketed by '<' and '>'
* in this name, strip them from the name.
* @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) {
private String findCommonNoTemplate(int cannotDetemplate) {
if (cannotDetemplate > 0) {
return null; // Couldn't remove a parameters from everything, so we can't have a common template
}
if (demangledNameNoTemplate.size() == 1) {
return demangledNameNoTemplate.first();
}
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 String findCommonDemangledBaseName(int cannotDemangle) {
if (cannotDemangle > 0) {
return null; // Couldn't demangle everything, so no way we can have a common base
}
if (exactDemangledBaseNames.size() == 1) {
return exactDemangledBaseNames.iterator().next();
return exactDemangledBaseNames.first();
}
// If we don't have a unique demangled name, try excising template parameters
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;
}
}

View file

@ -21,11 +21,13 @@ import ghidra.program.model.listing.Program;
public class NameVersions {
public String rawName; // Original name
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 NameVersions(String raw) {
rawName = raw;
similarName = null;
demangledNoTemplate = null;
demangledBaseName = null;
}
@ -55,6 +57,38 @@ public class NameVersions {
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) {
String origName = demangledObj.getName();
String name = origName.replaceFirst("_*", "");
@ -87,6 +121,7 @@ public class NameVersions {
if (rawName != null) {
DemangledObject demangledObj = demangle(program, rawName);
if (demangledObj != null) {
result.demangledNoTemplate = removeTemplateParams(demangledObj);
result.demangledBaseName = constructBaseName(demangledObj);
}