From 062b6769f81567a3d132fd9b7fad4beb3b1ad207 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 21 Oct 2020 16:42:43 -0400 Subject: [PATCH] template stripping in FID --- .../ghidra_scripts/FidStatistics.java | 19 ++--- .../fid/service/MatchNameAnalysis.java | 78 +++++++++---------- .../feature/fid/service/NameVersions.java | 35 +++++++++ 3 files changed, 76 insertions(+), 56 deletions(-) diff --git a/Ghidra/Features/FunctionID/ghidra_scripts/FidStatistics.java b/Ghidra/Features/FunctionID/ghidra_scripts/FidStatistics.java index bde8d5e6b6..90310869f1 100644 --- a/Ghidra/Features/FunctionID/ghidra_scripts/FidStatistics.java +++ b/Ghidra/Features/FunctionID/ghidra_scripts/FidStatistics.java @@ -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 iter = matchAnalysis.getRawNameIterator(); while(iter.hasNext()) { @@ -450,14 +445,12 @@ 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)) { - exactNameMatch = true; - break; - } + if (nameVersions.demangledNoTemplate != null && + matchNames.demangledNoTemplate != null) { + if (checkNames(nameVersions.demangledNoTemplate, + matchNames.demangledNoTemplate)) { + exactNameMatch = true; + break; } } } diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/MatchNameAnalysis.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/MatchNameAnalysis.java index f36aef1e3c..7a8fcd9c05 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/MatchNameAnalysis.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/MatchNameAnalysis.java @@ -32,8 +32,10 @@ public class MatchNameAnalysis { private Set finalNameList = null; private TreeSet rawNames = null; private TreeSet similarBaseNames = null; + private TreeSet demangledNameNoTemplate = null; private TreeSet exactDemangledBaseNames = null; private TreeSet 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 getRawNameIterator() { return rawNames.iterator(); } @@ -80,7 +86,9 @@ public class MatchNameAnalysis { rawNames = new TreeSet(); similarBaseNames = new TreeSet(); + demangledNameNoTemplate = new TreeSet(); exactDemangledBaseNames = new TreeSet(); + 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,35 +210,14 @@ 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) { - return null; + 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 } - 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 (demangledNameNoTemplate.size() == 1) { + return demangledNameNoTemplate.first(); } - if (nesting != 0) { - return null; - } - return name.substring(0, pos1 + 1) + name.substring(pos2); + return null; } 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 } 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; + return null; } } diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/NameVersions.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/NameVersions.java index 4a4225eaed..f6670d3d00 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/NameVersions.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/service/NameVersions.java @@ -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); }