Merge remote-tracking branch 'origin/Ghidra_9.2'

This commit is contained in:
ghidra1 2020-11-05 15:04:07 -05:00
commit 7d2155ce71
17 changed files with 316 additions and 172 deletions

View file

@ -152,6 +152,7 @@
<li><I>Decompiler</I>. Addressed various situations where the Decompiler unexpectedly removes active instructions as dead code after renaming or retyping a stack location. If the location was really an array element or structure field, renaming forced the Decompiler to treat the location as a distinct variable. Subsequently, the Decompiler thought that indirect references based before the location could not alias any following stack locations, which could then by considered dead. As of the 9.2 release, the Decompiler's renaming action no longer switches an annotation to <code>forcing</code> if it wasn't already. A retyping action, although it is <code>forcing</code>, won't trigger alias blocking for atomic data-types (this is configurable). (GP-248, Issue #524, #873)</li> <li><I>Decompiler</I>. Addressed various situations where the Decompiler unexpectedly removes active instructions as dead code after renaming or retyping a stack location. If the location was really an array element or structure field, renaming forced the Decompiler to treat the location as a distinct variable. Subsequently, the Decompiler thought that indirect references based before the location could not alias any following stack locations, which could then by considered dead. As of the 9.2 release, the Decompiler's renaming action no longer switches an annotation to <code>forcing</code> if it wasn't already. A retyping action, although it is <code>forcing</code>, won't trigger alias blocking for atomic data-types (this is configurable). (GP-248, Issue #524, #873)</li>
<li><I>Decompiler</I>. Fixed decompiler memory issues reported by a community security researcher. (GP-267)</li> <li><I>Decompiler</I>. Fixed decompiler memory issues reported by a community security researcher. (GP-267)</li>
<li><I>Decompiler</I>. Fix for Decompiler error: <code>Pcode: XML comms: Missing symref attribute in &lt;high&gt; tag</code>. (GP-352, Issue #2360)</li> <li><I>Decompiler</I>. Fix for Decompiler error: <code>Pcode: XML comms: Missing symref attribute in &lt;high&gt; tag</code>. (GP-352, Issue #2360)</li>
<li><I>Decompiler</I>. Fixed bug preventing the decompiler from seeing Equates attached to "compare" instructions. (GP-369, Issue #2386)</li>
<li><I>Demangler</I>. Fixed the GnuDemangler to parse the full namespace for <code>operator</code> symbols. (GT-3474, Issue #1441, #1448)</li> <li><I>Demangler</I>. Fixed the GnuDemangler to parse the full namespace for <code>operator</code> symbols. (GT-3474, Issue #1441, #1448)</li>
<li><I>Demangler</I>. Fixed numerous GNU Demangler parsing issues. Most notable is the added support for C++ Lambda functions. (GT-3545, Issue #1457, #1569)</li> <li><I>Demangler</I>. Fixed numerous GNU Demangler parsing issues. Most notable is the added support for C++ Lambda functions. (GT-3545, Issue #1457, #1569)</li>
<li><I>Demangler</I>. Updated the GNU Demangler to correctly parse and apply C++ strings using the <code>unnamed type</code> syntax. (GT-3645)</li> <li><I>Demangler</I>. Updated the GNU Demangler to correctly parse and apply C++ strings using the <code>unnamed type</code> syntax. (GT-3645)</li>

View file

@ -5509,6 +5509,7 @@ int4 RuleEqual2Zero::applyOp(PcodeOp *op,Funcdata &data)
if (vn2->isConstant()) { if (vn2->isConstant()) {
Address val(vn2->getSpace(),uintb_negate(vn2->getOffset()-1,vn2->getSize())); Address val(vn2->getSpace(),uintb_negate(vn2->getOffset()-1,vn2->getSize()));
unnegvn = data.newVarnode(vn2->getSize(),val); unnegvn = data.newVarnode(vn2->getSize(),val);
unnegvn->copySymbolIfValid(vn2); // Propagate any markup
posvn = vn; posvn = vn;
} }
else { else {

View file

@ -23,6 +23,7 @@ import org.junit.Test;
import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldLocation;
import ghidra.app.cmd.equate.SetEquateCmd;
import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.cmd.function.DeleteFunctionCmd; import ghidra.app.cmd.function.DeleteFunctionCmd;
import ghidra.app.cmd.label.RenameLabelCmd; import ghidra.app.cmd.label.RenameLabelCmd;
@ -134,6 +135,13 @@ public class HighSymbolTest extends AbstractDecompilerTest {
waitForDecompiler(); waitForDecompiler();
} }
private void applyEquate(String equateName, Address addr, long equateValue) {
modifyProgram(p -> {
SetEquateCmd cmd = new SetEquateCmd(equateName, addr, 0, equateValue);
cmd.applyTo(program);
});
}
private void renameExisting(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) { private void renameExisting(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
SymbolEntry oldEntry = highSymbol.getFirstWholeMap(); SymbolEntry oldEntry = highSymbol.getFirstWholeMap();
long oldId = highSymbol.getId(); long oldId = highSymbol.getId();
@ -401,4 +409,62 @@ public class HighSymbolTest extends AbstractDecompilerTest {
assertTrue(highSymbol.isNameLocked()); assertTrue(highSymbol.isNameLocked());
assertTrue(highSymbol.isTypeLocked()); assertTrue(highSymbol.isTypeLocked());
} }
@Test
public void testHighSymbol_convert() {
Address subAddr = addr(0x10015ac);
String equateName = "00000000000000000000000001010011b";
int equateValue = 0x53;
applyEquate(equateName, subAddr, equateValue);
decompile("10015ac");
ClangTextField line = getLineContaining("if (param");
FieldLocation loc = loc(line.getLineNumber(), 20);
ClangToken token = line.getToken(loc);
assertTrue(token.getText().equals("0b01010011"));
HighVariable variable = token.getHighVariable();
assertTrue(variable instanceof HighConstant);
HighSymbol highSymbol = variable.getSymbol();
assertTrue(highSymbol instanceof EquateSymbol);
EquateSymbol eqSymbol = (EquateSymbol) highSymbol;
assertEquals(eqSymbol.getConvert(), EquateSymbol.FORMAT_BIN);
assertEquals(eqSymbol.getValue(), equateValue);
}
@Test
public void testHighSymbol_dualequates() {
// Two equates on the same value at different locations
// One a convert, and one a label
Address convAddr = addr(0x100165a);
String convName = "141";
int convValue = 0x8d;
applyEquate(convName, convAddr, convValue);
Address eqAddr = addr(0x10015f1);
String eqName = "BIGEQUATE";
int eqValue = 0x8d;
applyEquate(eqName, eqAddr, eqValue);
decompile("10015ac");
ClangTextField line = getLineContaining(",DAT_010056a8");
FieldLocation loc = loc(line.getLineNumber(), 23);
ClangToken token = line.getToken(loc);
assertTrue(token.getText().equals("141"));
HighVariable variable = token.getHighVariable();
assertTrue(variable instanceof HighConstant);
HighSymbol highSymbol = variable.getSymbol();
assertTrue(highSymbol instanceof EquateSymbol);
EquateSymbol eqSymbol = (EquateSymbol) highSymbol;
assertEquals(eqSymbol.getConvert(), EquateSymbol.FORMAT_DEC);
assertEquals(eqSymbol.getValue(), convValue);
line = getLineContaining("DAT_010056a8 = ");
loc = loc(line.getLineNumber(), 39);
token = line.getToken(loc);
assertTrue(token.getText().equals(eqName));
variable = token.getHighVariable();
assertTrue(variable instanceof HighConstant);
highSymbol = variable.getSymbol();
assertTrue(highSymbol instanceof EquateSymbol);
eqSymbol = (EquateSymbol) highSymbol;
assertEquals(eqSymbol.getConvert(), 0);
assertEquals(eqSymbol.getValue(), eqValue);
}
} }

View file

@ -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,17 +445,15 @@ 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;
} }
} }
} }
}
if (exactNameMatch) { if (exactNameMatch) {
record.nameMatched += 1; record.nameMatched += 1;
} }

View file

@ -41,7 +41,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
private MatchNameAnalysis nameAnalysis = new MatchNameAnalysis(); private MatchNameAnalysis nameAnalysis = new MatchNameAnalysis();
private AddressSet affectedLocations = new AddressSet(); private AddressSet affectedLocations = new AddressSet();
private TreeMap<String, Address> multiMatchNames = new TreeMap<String, Address>(); private TreeMap<String, List<Address>> multiMatchNames = new TreeMap<String, List<Address>>();
private LinkedList<Address> conflictFunctions = new LinkedList<Address>(); private LinkedList<Address> conflictFunctions = new LinkedList<Address>();
private boolean alwaysApplyFidLabels; private boolean alwaysApplyFidLabels;
private float scoreThreshold; private float scoreThreshold;
@ -128,18 +128,16 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
nameAnalysis.analyzeLibraries(result.matches, MAGIC_MULTIPLE_LIBRARY_LIMIT, monitor); nameAnalysis.analyzeLibraries(result.matches, MAGIC_MULTIPLE_LIBRARY_LIMIT, monitor);
String newFunctionName = null; String newFunctionName = null;
if (nameAnalysis.numNames() == 1) { if (nameAnalysis.numNames() == 1) { // If all names are the same, up to a difference in '_' prefix
newFunctionName = nameAnalysis.getNameIterator().next();
}
if (nameAnalysis.numSimilarNames() == 1) { // If all names are the same, up to a difference in '_' prefix
bookmarkContents = "Library Function - Single Match, "; bookmarkContents = "Library Function - Single Match, ";
plateCommentContents = "Library Function - Single Match"; plateCommentContents = "Library Function - Single Match";
newFunctionName = nameAnalysis.getNameIterator().next();
} }
else { // If names are different in some way else { // If names are different in some way
bookmarkContents = "Library Function - Multiple Matches, "; bookmarkContents = "Library Function - Multiple Matches, ";
plateCommentContents = "Library Function - Multiple Matches"; plateCommentContents = "Library Function - Multiple Matches";
if (nameAnalysis.numNames() == 1) { if (nameAnalysis.getMostOptimisticCount() == 1) {
newFunctionName = nameAnalysis.getMostOptimisticName();
plateCommentContents = plateCommentContents + " With Same Base Name"; plateCommentContents = plateCommentContents + " With Same Base Name";
bookmarkContents = bookmarkContents + "Same "; bookmarkContents = bookmarkContents + "Same ";
} }
@ -157,16 +155,26 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
monitor); monitor);
} }
/**
* Construct list of names as they should appear in the comment for the function.
* @param monitor is the task monitor
* @return the list of names as a formatted String
* @throws CancelledException if the user cancels the task
*/
private String listNames(TaskMonitor monitor) throws CancelledException { private String listNames(TaskMonitor monitor) throws CancelledException {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
int counter = 0; int counter = 0;
Iterator<String> iterator = nameAnalysis.getNameIterator(); Iterator<String> iterator = nameAnalysis.getNameIterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
monitor.checkCanceled(); monitor.checkCanceled();
String display = iterator.next();
NameVersions versions = nameAnalysis.getVersions(display);
if (versions != null && versions.demangledFull != null) {
display = versions.demangledFull;
}
buffer.append(' '); buffer.append(' ');
buffer.append(iterator.next()); buffer.append(display);
buffer.append('\n'); buffer.append('\n');
counter++; counter++;
if (counter > 3) { if (counter > 3) {
@ -332,11 +340,12 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
// Also checks those locations to see if there is only one label left and if so, removes the "FID conflict" bookmark. // Also checks those locations to see if there is only one label left and if so, removes the "FID conflict" bookmark.
private void removeConflictSymbols(Function function, String matchName, TaskMonitor monitor) { private void removeConflictSymbols(Function function, String matchName, TaskMonitor monitor) {
Address addr = multiMatchNames.get(matchName); List<Address> list = multiMatchNames.get(matchName);
if (addr == null) { if (list == null) {
return; return;
} }
Program program = function.getProgram(); Program program = function.getProgram();
for (Address addr : list) {
int numSymbols = deleteSymbol(matchName, addr, program); int numSymbols = deleteSymbol(matchName, addr, program);
if (numSymbols <= 1) { if (numSymbols <= 1) {
// Only one symbol left, delete the "FID conflict" bookmark // Only one symbol left, delete the "FID conflict" bookmark
@ -348,16 +357,13 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
} }
} }
} }
}
private int addFunctionLabelMultipleMatches(Function function, TaskMonitor monitor) private void addFunctionLabelMultipleMatches(Function function, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
Program program = function.getProgram(); Program program = function.getProgram();
if (nameAnalysis.numNames() >= MAGIC_MULTIPLE_MATCH_LIMIT) {
return nameAnalysis.numNames();
}
Symbol symbol = function.getSymbol(); Symbol symbol = function.getSymbol();
boolean preexistingSymbol = (symbol != null && symbol.getSource() != SourceType.DEFAULT); boolean preexistingSymbol = (symbol != null && symbol.getSource() != SourceType.DEFAULT);
@ -368,7 +374,12 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
for (String functionName : unusedNames) { for (String functionName : unusedNames) {
monitor.checkCanceled(); monitor.checkCanceled();
addSymbolToFunction(function, functionName); addSymbolToFunction(function, functionName);
multiMatchNames.put(functionName, addr); List<Address> list = multiMatchNames.get(functionName);
if (list == null) {
list = new LinkedList<Address>();
multiMatchNames.put(functionName, list);
}
list.add(addr);
} }
if (unusedNames.size() > 1) { if (unusedNames.size() > 1) {
@ -382,7 +393,6 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
"Multiple likely matching functions"); "Multiple likely matching functions");
} }
} }
return unusedNames.size();
} }
/** /**
@ -432,7 +442,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
* Takes a set of FID matching names and returns a subset that includes only names that don't exist * Takes a set of FID matching names and returns a subset that includes only names that don't exist
* somewhere else in the program. * somewhere else in the program.
*/ */
private static Set<String> getFIDNamesThatDontExistSomewhereElse(Program program, private Set<String> getFIDNamesThatDontExistSomewhereElse(Program program,
Iterator<String> iter) { Iterator<String> iter) {
Set<String> unusedNames = new HashSet<String>(); Set<String> unusedNames = new HashSet<String>();
@ -441,27 +451,42 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
String name = iter.next(); String name = iter.next();
if (!nameExistsSomewhereElse(symbolTable, name)) { if (!nameExistsSomewhereElse(symbolTable, name)) {
unusedNames.add(name); unusedNames.add(name);
if (unusedNames.size() > MAGIC_MULTIPLE_MATCH_LIMIT) {
break;
}
} }
} }
return unusedNames; return unusedNames;
} }
private static boolean containsPrimarySymbol(SymbolTable symTab, String name) {
List<Symbol> syms = symTab.getSymbols(name, null);
for (Symbol symbol : syms) {
SymbolType type = symbol.getSymbolType();
if (type != SymbolType.FUNCTION && type != SymbolType.LABEL) {
continue;
}
if (symbol.isPrimary()) {
return true;
}
}
return false;
}
//Check to see if other functions exist with the same baseName or _baseName or __baseName //Check to see if other functions exist with the same baseName or _baseName or __baseName
private static boolean nameExistsSomewhereElse(SymbolTable symTab, String baseName) { private boolean nameExistsSomewhereElse(SymbolTable symTab, String baseName) {
if (multiMatchNames.containsKey(baseName)) {
// If this name is part of a multimatch, don't treat as a definitive label
return false;
}
//I did it this way because doing it with an iterator and wildcard was really really slow //I did it this way because doing it with an iterator and wildcard was really really slow
List<Symbol> globalSymbols = symTab.getLabelOrFunctionSymbols(baseName, null); if (containsPrimarySymbol(symTab, baseName)) {
if (!globalSymbols.isEmpty()) {
return true; return true;
} }
if (containsPrimarySymbol(symTab, "_" + baseName)) {
globalSymbols = symTab.getLabelOrFunctionSymbols("_" + baseName, null);
if (!globalSymbols.isEmpty()) {
return true; return true;
} }
if (containsPrimarySymbol(symTab, "__" + baseName)) {
globalSymbols = symTab.getLabelOrFunctionSymbols("__" + baseName, null);
if (!globalSymbols.isEmpty()) {
return true; return true;
} }

View file

@ -30,58 +30,131 @@ import ghidra.util.task.TaskMonitor;
*/ */
public class MatchNameAnalysis { public class MatchNameAnalysis {
private Set<String> finalNameList = null; private Set<String> finalNameList = null;
private TreeMap<String, NameVersions> versionMap = 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 int mostOptimisticCount; // What is most optimistic (smallest) number of matches
// Once duplicates and similar base names are taken into account
private float overallScore = 0.0f; private float overallScore = 0.0f;
/**
* @return the number of deduped symbol names
*/
public int numNames() { public int numNames() {
return finalNameList.size(); return finalNameList.size();
} }
/**
* @return an iterator to the deduped list of raw names (similar names are not collapsed)
*/
public Iterator<String> getRawNameIterator() { public Iterator<String> getRawNameIterator() {
return rawNames.iterator(); return rawNames.iterator();
} }
/**
* Check if the given name is contained in the list of matches
* @param name is the given name
* @return true if the name is in the list
*/
public boolean containsRawName(String name) { public boolean containsRawName(String name) {
return rawNames.contains(name); return rawNames.contains(name);
} }
/**
* @return an iterator to the final list of deduped symbol names
*/
public Iterator<String> getNameIterator() { public Iterator<String> getNameIterator() {
return finalNameList.iterator(); return finalNameList.iterator();
} }
public int numSimilarNames() { /**
return similarBaseNames.size(); * @return the number of symbols in the deduped list of matching libraries
} */
public int numLibraries() { public int numLibraries() {
return libraries.size(); return libraries.size();
} }
/**
* @return an iterator to the deduped list of matching libraries
*/
public Iterator<String> getLibraryIterator() { public Iterator<String> getLibraryIterator() {
return libraries.iterator(); return libraries.iterator();
} }
/**
* Get an object with all the given versions of the given raw name
* @param raw is the raw name
* @return the corresponding NameVersions object
*/
public NameVersions getVersions(String raw) {
return versionMap.get(raw);
}
/**
* Run through all deduping strategies and return the number of unique symbols given
* by the best strategy.
* @return number of unique symbols given by the optimal deduping strategy
*/
public int getMostOptimisticCount() { public int getMostOptimisticCount() {
return mostOptimisticCount; int count = rawNames.size();
if (similarBaseNames.size() < count) {
count = similarBaseNames.size();
}
if (demangledNameNoTemplate != null && demangledNameNoTemplate.size() < count) {
count = demangledNameNoTemplate.size();
}
if (exactDemangledBaseNames != null && exactDemangledBaseNames.size() < count) {
count = exactDemangledBaseNames.size();
}
return count;
}
/**
* Run through ALL deduping strategies and if one results in a single label, return that label.
* Otherwise return null.
* @return a unique name describing all matches or null
*/
public String getMostOptimisticName() {
if (rawNames.size() == 1) {
return rawNames.first();
}
if (similarBaseNames.size() == 1) {
return similarBaseNames.first();
}
if (demangledNameNoTemplate != null && demangledNameNoTemplate.size() == 1) {
return demangledNameNoTemplate.first();
}
if (exactDemangledBaseNames != null && exactDemangledBaseNames.size() == 1) {
return exactDemangledBaseNames.first();
}
return null;
} }
public float getOverallScore() { public float getOverallScore() {
return overallScore; return overallScore;
} }
/**
* Analyze a list of FID matches from a single address, deciding on the final list of symbols
* that will be associated with the address by deduping and omitting similar names.
* The final list is in finalNameList.
* Demangling and template stripping can produce an even shorter list than finalNameList.
* This is optionally available through getMostOptimisticName().
* @param matches is the set of FID matches to analyze
* @param program is the Program
* @param monitor is the monitor
* @throws CancelledException if the user cancels the task
*/
public void analyzeNames(List<FidMatch> matches, Program program, TaskMonitor monitor) public void analyzeNames(List<FidMatch> matches, Program program, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
versionMap = new TreeMap<String, NameVersions>();
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 cannotDemangle = 0;
for (FidMatch match : matches) { for (FidMatch match : matches) {
monitor.checkCanceled(); monitor.checkCanceled();
@ -91,36 +164,27 @@ public class MatchNameAnalysis {
NameVersions nameVersions = NameVersions.generate(function.getName(), program); NameVersions nameVersions = NameVersions.generate(function.getName(), program);
// Put exact base names in a HashSet // Put exact base names in a HashSet
if (nameVersions.rawName != null) { if (nameVersions.rawName != null) {
versionMap.put(nameVersions.rawName, nameVersions);
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.demangledBaseName != null) { if (nameVersions.demangledNoTemplate != null && demangledNameNoTemplate != null) {
demangledNameNoTemplate.add(nameVersions.demangledNoTemplate);
}
else {
demangledNameNoTemplate = null; // Get rid of container if we can't strip everything
}
if (nameVersions.demangledBaseName != null && exactDemangledBaseNames != null) {
exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name
} }
else { else {
cannotDemangle += 1; exactDemangledBaseNames = null; // Get rid of container if we can't demangle everything
} }
} }
} }
String singleName = null;
mostOptimisticCount = rawNames.size();
finalNameList = rawNames; finalNameList = rawNames;
if (rawNames.size() == 1) { String singleName = findCommonBaseName();
singleName = rawNames.first();
}
else {
singleName = findCommonBaseName();
mostOptimisticCount = similarBaseNames.size();
if (singleName == null) {
singleName = findCommonDemangledBaseName(cannotDemangle);
if (exactDemangledBaseNames.size() > 0 &&
exactDemangledBaseNames.size() < mostOptimisticCount) {
mostOptimisticCount = exactDemangledBaseNames.size();
}
}
}
if (singleName != null) { if (singleName != null) {
mostOptimisticCount = 1;
finalNameList = Collections.singleton(singleName); finalNameList = Collections.singleton(singleName);
} }
else if (rawNames.size() > similarBaseNames.size()) { else if (rawNames.size() > similarBaseNames.size()) {
@ -134,6 +198,15 @@ public class MatchNameAnalysis {
} }
} }
/**
* Collect strings describing the library descriptor of a set of FID matches.
* Dedup the list trying to get the size down below a specified limit, stripping
* version and family information from the library string if necessary.
* @param matches is the set of FID matches
* @param libraryLimit is the specified size limit
* @param monitor is a task monitor
* @throws CancelledException if the user cancels the task
*/
public void analyzeLibraries(Collection<FidMatch> matches,int libraryLimit,TaskMonitor monitor) public void analyzeLibraries(Collection<FidMatch> matches,int libraryLimit,TaskMonitor monitor)
throws CancelledException { throws CancelledException {
libraries = new TreeSet<String>(); libraries = new TreeSet<String>();
@ -176,65 +249,15 @@ public class MatchNameAnalysis {
} }
} }
private String findCommonBaseName() {
if (similarBaseNames.size() == 1) {
return rawNames.iterator().next();
}
return null;
}
/** /**
* If there exists an initial set of template parameters bracketed by '<' and '>' * Make a final decision based on the deduping strategies if there is a single
* in this name, strip them from the name. * matching name that describes all matches.
* @param name is the function name to strip * @return the single matching name or null
* @return the stripped name or null if no parameters present
*/ */
public static String removeTemplateParams(String name) { private String findCommonBaseName() {
int pos1 = name.indexOf('<'); if (rawNames.size() == 1 || similarBaseNames.size() == 1) {
if (pos1 < 0) { return rawNames.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();
}
// 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 null;
} }
} }
return finalName;
}
}

View file

@ -21,11 +21,14 @@ 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 String demangledFull; // The full demangled signature
public NameVersions(String raw) { public NameVersions(String raw) {
rawName = raw; rawName = raw;
similarName = null; similarName = null;
demangledNoTemplate = null;
demangledBaseName = null; demangledBaseName = null;
} }
@ -55,6 +58,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 +122,8 @@ 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.demangledFull = demangledObj.getOriginalDemangled();
result.demangledNoTemplate = removeTemplateParams(demangledObj);
result.demangledBaseName = constructBaseName(demangledObj); result.demangledBaseName = constructBaseName(demangledObj);
} }

View file

@ -5,6 +5,7 @@
##MODULE IP: LGPL 2.1 ##MODULE IP: LGPL 2.1
##MODULE IP: MIT ##MODULE IP: MIT
##MODULE IP: Oxygen Icons - LGPL 3.0 ##MODULE IP: Oxygen Icons - LGPL 3.0
##MODULE IP: Tango Icons - Public Domain
Module.manifest||GHIDRA||||END| Module.manifest||GHIDRA||||END|
build.gradle||GHIDRA||||END| build.gradle||GHIDRA||||END|
src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END|
@ -17,7 +18,9 @@ src/main/help/help/topics/GraphServices/images/DefaultGraphDisplay.png||GHIDRA||
src/main/help/help/topics/GraphServices/images/ExportDialog.png||GHIDRA||||END| src/main/help/help/topics/GraphServices/images/ExportDialog.png||GHIDRA||||END|
src/main/resources/images/Lasso.png||GHIDRA||||END| src/main/resources/images/Lasso.png||GHIDRA||||END|
src/main/resources/images/magnifier.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/magnifier.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/project-open.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/redspheregraph.png||GHIDRA||||END| src/main/resources/images/redspheregraph.png||GHIDRA||||END|
src/main/resources/images/sat2.png||GHIDRA||||END| src/main/resources/images/sat2.png||GHIDRA||||END|
src/main/resources/images/tree.png||GHIDRA||||END| src/main/resources/images/tree.png||GHIDRA||||END|
src/main/resources/images/view-fullscreen.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/jungrapht.properties||GHIDRA||||END| src/main/resources/jungrapht.properties||GHIDRA||||END|

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before After
Before After

View file

@ -27,10 +27,12 @@ final class DefaultDisplayGraphIcons {
private DefaultDisplayGraphIcons() { private DefaultDisplayGraphIcons() {
} }
public static final Icon SATELLITE_VIEW_ICON = Icons.get("images/network-wireless-16.png"); public static final Icon SATELLITE_VIEW_ICON = Icons.get("images/project-open.png");
public static final Icon VIEW_MAGNIFIER_ICON = Icons.get("images/magnifier.png"); public static final Icon VIEW_MAGNIFIER_ICON = Icons.get("images/magnifier.png");
public static final Icon PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.png"); public static final Icon PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.png");
public static final Icon LAYOUT_ALGORITHM_ICON = Icons.get("images/katomic.png"); public static final Icon LAYOUT_ALGORITHM_ICON = Icons.get("images/katomic.png");
public static final Icon LASSO_ICON = Icons.get("images/Lasso.png"); public static final Icon LASSO_ICON = Icons.get("images/Lasso.png");
public static final Icon FILTER_ICON = Icons.CONFIGURE_FILTER_ICON; public static final Icon FILTER_ICON = Icons.CONFIGURE_FILTER_ICON;
public static final Icon FIT_TO_WINDOW = Icons.get("images/view-fullscreen.png");
} }

View file

@ -304,8 +304,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
// create an icon button to reset the view transformations to identity (scaled to layout) // create an icon button to reset the view transformations to identity (scaled to layout)
new ActionBuilder("Reset View", ACTION_OWNER) new ActionBuilder("Reset View", ACTION_OWNER)
.description("Reset all view transforms to center graph in display") .description("Fit Graph to Window")
.toolBarIcon(Icons.REFRESH_ICON) .toolBarIcon(DefaultDisplayGraphIcons.FIT_TO_WINDOW)
.onAction(context -> viewer.scaleToLayout()) .onAction(context -> viewer.scaleToLayout())
.buildAndInstallLocal(componentProvider); .buildAndInstallLocal(componentProvider);

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

View file

@ -59,6 +59,10 @@ public class EquateSymbol extends HighSymbol {
public long getValue() { return value; } public long getValue() { return value; }
public int getConvert() {
return convert;
}
@Override @Override
public void restoreXML(XmlPullParser parser) throws PcodeXMLException { public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement symel = parser.start("equatesymbol"); XmlElement symel = parser.start("equatesymbol");

View file

@ -476,12 +476,9 @@ public class LocalSymbolMap {
symbolMap.put(uniqueId, sym); symbolMap.put(uniqueId, sym);
} }
private void newEquateSymbol(long uniqueId, String nm, long val, long hash, Address addr, private EquateSymbol newEquateSymbol(long uniqueId, String nm, long val, long hash,
TreeMap<String, HighSymbol> constantSymbolMap) { Address addr) {
HighSymbol eqSymbol = constantSymbolMap.get(nm); EquateSymbol eqSymbol;
if (eqSymbol != null) {
return; // New reference to same symbol
}
if (uniqueId == 0) { if (uniqueId == 0) {
uniqueId = getNextId(); uniqueId = getNextId();
} }
@ -494,7 +491,7 @@ public class LocalSymbolMap {
eqSymbol = new EquateSymbol(uniqueId, conv, val, func, addr, hash); eqSymbol = new EquateSymbol(uniqueId, conv, val, func, addr, hash);
} }
//Do NOT setTypeLock //Do NOT setTypeLock
constantSymbolMap.put(nm, eqSymbol); return eqSymbol;
} }
/** /**
@ -502,7 +499,6 @@ public class LocalSymbolMap {
* @param dbFunction is the function to pull equates for * @param dbFunction is the function to pull equates for
*/ */
private void grabEquates(Function dbFunction) { private void grabEquates(Function dbFunction) {
TreeMap<String, HighSymbol> constantSymbolMap = null;
// Find named constants via Equates // Find named constants via Equates
Program program = dbFunction.getProgram(); Program program = dbFunction.getProgram();
EquateTable equateTable = program.getEquateTable(); EquateTable equateTable = program.getEquateTable();
@ -516,34 +512,21 @@ public class LocalSymbolMap {
continue; continue;
} }
long hash[] = DynamicHash.calcConstantHash(instr, eq.getValue()); long hash[] = DynamicHash.calcConstantHash(instr, eq.getValue());
for (long element : hash) { if (hash.length == 0) {
if (constantSymbolMap == null) { continue;
constantSymbolMap = new TreeMap<String, HighSymbol>();
}
newEquateSymbol(0, eq.getDisplayName(), eq.getValue(), element, defAddr,
constantSymbolMap);
}
}
} }
Arrays.sort(hash); // Sort in preparation for deduping
String displayName = eq.getDisplayName();
long eqValue = eq.getValue();
// TODO: Find typed constants via DataTypeReferences EquateSymbol eqSymbol;
// -- for each datatype reference within the scope of the function for (int i = 0; i < hash.length; ++i) {
// MappedVarKey key = new MappedVarKey(AddressSpace.HASH_SPACE.getAddress(hash),defAddr); if (i != 0 && hash[i - 1] == hash[i]) {
// DynamicSymbol sym = constantSymbolMap.get(key); continue; // Found a duplicate, skip it
// String name = sym != null ? sym.getName() : null; }
// sym = new DynamicSymbol(name, dt, dt.getLength(), hash, defAddr, func, 0); // format?? eqSymbol = newEquateSymbol(0, displayName, eqValue, hash[i], defAddr);
// if (name != null) { symbolMap.put(eqSymbol.getId(), eqSymbol);
// sym.setTypeLock(true); }
// }
// sym.setTypeLock(true);
// sym.setReadOnly(true);
//
// Add constant dynamic symbols to map
if (constantSymbolMap != null) {
for (HighSymbol sym : constantSymbolMap.values()) {
long id = getNextId();
symbolMap.put(id, sym);
} }
} }
} }

View file

@ -349,7 +349,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
BigInteger val = context.getValue(reg, false); BigInteger val = context.getValue(reg, false);
if (val != null) { if (val != null) {
long lval = val.longValue(); long lval = val.longValue();
Address refAddr = instr.getMinAddress().getNewAddress(lval); Address refAddr = null;
try {
refAddr = instr.getMinAddress().getNewAddress(lval);
} catch (AddressOutOfBoundsException e) {
// invalid reference
return;
}
if ((lval > 4096 || lval < 0) && lval != 0xffff && if ((lval > 4096 || lval < 0) && lval != 0xffff &&
program.getMemory().contains(refAddr)) { program.getMemory().contains(refAddr)) {