mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/Ghidra_9.2'
This commit is contained in:
commit
7d2155ce71
17 changed files with 316 additions and 172 deletions
|
@ -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>. 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 <high> 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 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>
|
||||
|
|
|
@ -5509,6 +5509,7 @@ int4 RuleEqual2Zero::applyOp(PcodeOp *op,Funcdata &data)
|
|||
if (vn2->isConstant()) {
|
||||
Address val(vn2->getSpace(),uintb_negate(vn2->getOffset()-1,vn2->getSize()));
|
||||
unnegvn = data.newVarnode(vn2->getSize(),val);
|
||||
unnegvn->copySymbolIfValid(vn2); // Propagate any markup
|
||||
posvn = vn;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.Test;
|
|||
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.cmd.equate.SetEquateCmd;
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.app.cmd.function.DeleteFunctionCmd;
|
||||
import ghidra.app.cmd.label.RenameLabelCmd;
|
||||
|
@ -134,6 +135,13 @@ public class HighSymbolTest extends AbstractDecompilerTest {
|
|||
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) {
|
||||
SymbolEntry oldEntry = highSymbol.getFirstWholeMap();
|
||||
long oldId = highSymbol.getId();
|
||||
|
@ -401,4 +409,62 @@ public class HighSymbolTest extends AbstractDecompilerTest {
|
|||
assertTrue(highSymbol.isNameLocked());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
|
|||
|
||||
private MatchNameAnalysis nameAnalysis = new MatchNameAnalysis();
|
||||
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 boolean alwaysApplyFidLabels;
|
||||
private float scoreThreshold;
|
||||
|
@ -128,18 +128,16 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
|
|||
nameAnalysis.analyzeLibraries(result.matches, MAGIC_MULTIPLE_LIBRARY_LIMIT, monitor);
|
||||
|
||||
String newFunctionName = null;
|
||||
if (nameAnalysis.numNames() == 1) {
|
||||
newFunctionName = nameAnalysis.getNameIterator().next();
|
||||
}
|
||||
|
||||
if (nameAnalysis.numSimilarNames() == 1) { // If all names are the same, up to a difference in '_' prefix
|
||||
if (nameAnalysis.numNames() == 1) { // If all names are the same, up to a difference in '_' prefix
|
||||
bookmarkContents = "Library Function - Single Match, ";
|
||||
plateCommentContents = "Library Function - Single Match";
|
||||
newFunctionName = nameAnalysis.getNameIterator().next();
|
||||
}
|
||||
else { // If names are different in some way
|
||||
bookmarkContents = "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";
|
||||
bookmarkContents = bookmarkContents + "Same ";
|
||||
}
|
||||
|
@ -157,16 +155,26 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
|
|||
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 {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
int counter = 0;
|
||||
|
||||
Iterator<String> iterator = nameAnalysis.getNameIterator();
|
||||
while (iterator.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
String display = iterator.next();
|
||||
NameVersions versions = nameAnalysis.getVersions(display);
|
||||
if (versions != null && versions.demangledFull != null) {
|
||||
display = versions.demangledFull;
|
||||
}
|
||||
buffer.append(' ');
|
||||
buffer.append(iterator.next());
|
||||
buffer.append(display);
|
||||
buffer.append('\n');
|
||||
counter++;
|
||||
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.
|
||||
private void removeConflictSymbols(Function function, String matchName, TaskMonitor monitor) {
|
||||
|
||||
Address addr = multiMatchNames.get(matchName);
|
||||
if (addr == null) {
|
||||
List<Address> list = multiMatchNames.get(matchName);
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
Program program = function.getProgram();
|
||||
for (Address addr : list) {
|
||||
int numSymbols = deleteSymbol(matchName, addr, program);
|
||||
if (numSymbols <= 1) {
|
||||
// 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 {
|
||||
|
||||
Program program = function.getProgram();
|
||||
|
||||
if (nameAnalysis.numNames() >= MAGIC_MULTIPLE_MATCH_LIMIT) {
|
||||
return nameAnalysis.numNames();
|
||||
}
|
||||
|
||||
Symbol symbol = function.getSymbol();
|
||||
boolean preexistingSymbol = (symbol != null && symbol.getSource() != SourceType.DEFAULT);
|
||||
|
||||
|
@ -368,7 +374,12 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
|
|||
for (String functionName : unusedNames) {
|
||||
monitor.checkCanceled();
|
||||
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) {
|
||||
|
@ -382,7 +393,6 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
|
|||
"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
|
||||
* somewhere else in the program.
|
||||
*/
|
||||
private static Set<String> getFIDNamesThatDontExistSomewhereElse(Program program,
|
||||
private Set<String> getFIDNamesThatDontExistSomewhereElse(Program program,
|
||||
Iterator<String> iter) {
|
||||
|
||||
Set<String> unusedNames = new HashSet<String>();
|
||||
|
@ -441,27 +451,42 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
|
|||
String name = iter.next();
|
||||
if (!nameExistsSomewhereElse(symbolTable, name)) {
|
||||
unusedNames.add(name);
|
||||
if (unusedNames.size() > MAGIC_MULTIPLE_MATCH_LIMIT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
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
|
||||
List<Symbol> globalSymbols = symTab.getLabelOrFunctionSymbols(baseName, null);
|
||||
if (!globalSymbols.isEmpty()) {
|
||||
if (containsPrimarySymbol(symTab, baseName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
globalSymbols = symTab.getLabelOrFunctionSymbols("_" + baseName, null);
|
||||
if (!globalSymbols.isEmpty()) {
|
||||
if (containsPrimarySymbol(symTab, "_" + baseName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
globalSymbols = symTab.getLabelOrFunctionSymbols("__" + baseName, null);
|
||||
if (!globalSymbols.isEmpty()) {
|
||||
if (containsPrimarySymbol(symTab, "__" + baseName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,58 +30,131 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class MatchNameAnalysis {
|
||||
private Set<String> finalNameList = null;
|
||||
private TreeMap<String, NameVersions> versionMap = 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 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;
|
||||
|
||||
/**
|
||||
* @return the number of deduped symbol names
|
||||
*/
|
||||
public int numNames() {
|
||||
return finalNameList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an iterator to the deduped list of raw names (similar names are not collapsed)
|
||||
*/
|
||||
public Iterator<String> getRawNameIterator() {
|
||||
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) {
|
||||
return rawNames.contains(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an iterator to the final list of deduped symbol names
|
||||
*/
|
||||
public Iterator<String> getNameIterator() {
|
||||
return finalNameList.iterator();
|
||||
}
|
||||
|
||||
public int numSimilarNames() {
|
||||
return similarBaseNames.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of symbols in the deduped list of matching libraries
|
||||
*/
|
||||
public int numLibraries() {
|
||||
return libraries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an iterator to the deduped list of matching libraries
|
||||
*/
|
||||
public Iterator<String> getLibraryIterator() {
|
||||
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() {
|
||||
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() {
|
||||
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)
|
||||
throws CancelledException {
|
||||
|
||||
versionMap = new TreeMap<String, NameVersions>();
|
||||
rawNames = new TreeSet<String>();
|
||||
similarBaseNames = new TreeSet<String>();
|
||||
demangledNameNoTemplate = new TreeSet<String>();
|
||||
exactDemangledBaseNames = new TreeSet<String>();
|
||||
int cannotDemangle = 0;
|
||||
|
||||
for (FidMatch match : matches) {
|
||||
monitor.checkCanceled();
|
||||
|
@ -91,36 +164,27 @@ public class MatchNameAnalysis {
|
|||
NameVersions nameVersions = NameVersions.generate(function.getName(), program);
|
||||
// Put exact base names in a HashSet
|
||||
if (nameVersions.rawName != null) {
|
||||
versionMap.put(nameVersions.rawName, nameVersions);
|
||||
rawNames.add(nameVersions.rawName); // Dedup the raw names
|
||||
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
|
||||
}
|
||||
else {
|
||||
cannotDemangle += 1;
|
||||
exactDemangledBaseNames = null; // Get rid of container if we can't demangle everything
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String singleName = null;
|
||||
mostOptimisticCount = rawNames.size();
|
||||
finalNameList = rawNames;
|
||||
if (rawNames.size() == 1) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
String singleName = findCommonBaseName();
|
||||
if (singleName != null) {
|
||||
mostOptimisticCount = 1;
|
||||
finalNameList = Collections.singleton(singleName);
|
||||
}
|
||||
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)
|
||||
throws CancelledException {
|
||||
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 '>'
|
||||
* 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
|
||||
* Make a final decision based on the deduping strategies if there is a single
|
||||
* matching name that describes all matches.
|
||||
* @return the single matching name or null
|
||||
*/
|
||||
public static String removeTemplateParams(String name) {
|
||||
int pos1 = name.indexOf('<');
|
||||
if (pos1 < 0) {
|
||||
return null;
|
||||
private String findCommonBaseName() {
|
||||
if (rawNames.size() == 1 || similarBaseNames.size() == 1) {
|
||||
return rawNames.first();
|
||||
}
|
||||
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 finalName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,14 @@ 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 String demangledFull; // The full demangled signature
|
||||
|
||||
public NameVersions(String raw) {
|
||||
rawName = raw;
|
||||
similarName = null;
|
||||
demangledNoTemplate = null;
|
||||
demangledBaseName = null;
|
||||
}
|
||||
|
||||
|
@ -55,6 +58,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 +122,8 @@ public class NameVersions {
|
|||
if (rawName != null) {
|
||||
DemangledObject demangledObj = demangle(program, rawName);
|
||||
if (demangledObj != null) {
|
||||
result.demangledFull = demangledObj.getOriginalDemangled();
|
||||
result.demangledNoTemplate = removeTemplateParams(demangledObj);
|
||||
result.demangledBaseName = constructBaseName(demangledObj);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
##MODULE IP: LGPL 2.1
|
||||
##MODULE IP: MIT
|
||||
##MODULE IP: Oxygen Icons - LGPL 3.0
|
||||
##MODULE IP: Tango Icons - Public Domain
|
||||
Module.manifest||GHIDRA||||END|
|
||||
build.gradle||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/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/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/sat2.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|
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -27,10 +27,12 @@ final class 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 PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.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 FILTER_ICON = Icons.CONFIGURE_FILTER_ICON;
|
||||
public static final Icon FIT_TO_WINDOW = Icons.get("images/view-fullscreen.png");
|
||||
|
||||
}
|
||||
|
|
|
@ -304,8 +304,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
|
||||
// create an icon button to reset the view transformations to identity (scaled to layout)
|
||||
new ActionBuilder("Reset View", ACTION_OWNER)
|
||||
.description("Reset all view transforms to center graph in display")
|
||||
.toolBarIcon(Icons.REFRESH_ICON)
|
||||
.description("Fit Graph to Window")
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.FIT_TO_WINDOW)
|
||||
.onAction(context -> viewer.scaleToLayout())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 742 B |
Binary file not shown.
After Width: | Height: | Size: 650 B |
|
@ -59,6 +59,10 @@ public class EquateSymbol extends HighSymbol {
|
|||
|
||||
public long getValue() { return value; }
|
||||
|
||||
public int getConvert() {
|
||||
return convert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement symel = parser.start("equatesymbol");
|
||||
|
|
|
@ -476,12 +476,9 @@ public class LocalSymbolMap {
|
|||
symbolMap.put(uniqueId, sym);
|
||||
}
|
||||
|
||||
private void newEquateSymbol(long uniqueId, String nm, long val, long hash, Address addr,
|
||||
TreeMap<String, HighSymbol> constantSymbolMap) {
|
||||
HighSymbol eqSymbol = constantSymbolMap.get(nm);
|
||||
if (eqSymbol != null) {
|
||||
return; // New reference to same symbol
|
||||
}
|
||||
private EquateSymbol newEquateSymbol(long uniqueId, String nm, long val, long hash,
|
||||
Address addr) {
|
||||
EquateSymbol eqSymbol;
|
||||
if (uniqueId == 0) {
|
||||
uniqueId = getNextId();
|
||||
}
|
||||
|
@ -494,7 +491,7 @@ public class LocalSymbolMap {
|
|||
eqSymbol = new EquateSymbol(uniqueId, conv, val, func, addr, hash);
|
||||
}
|
||||
//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
|
||||
*/
|
||||
private void grabEquates(Function dbFunction) {
|
||||
TreeMap<String, HighSymbol> constantSymbolMap = null;
|
||||
// Find named constants via Equates
|
||||
Program program = dbFunction.getProgram();
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
|
@ -516,34 +512,21 @@ public class LocalSymbolMap {
|
|||
continue;
|
||||
}
|
||||
long hash[] = DynamicHash.calcConstantHash(instr, eq.getValue());
|
||||
for (long element : hash) {
|
||||
if (constantSymbolMap == null) {
|
||||
constantSymbolMap = new TreeMap<String, HighSymbol>();
|
||||
}
|
||||
newEquateSymbol(0, eq.getDisplayName(), eq.getValue(), element, defAddr,
|
||||
constantSymbolMap);
|
||||
}
|
||||
}
|
||||
if (hash.length == 0) {
|
||||
continue;
|
||||
}
|
||||
Arrays.sort(hash); // Sort in preparation for deduping
|
||||
String displayName = eq.getDisplayName();
|
||||
long eqValue = eq.getValue();
|
||||
|
||||
// TODO: Find typed constants via DataTypeReferences
|
||||
// -- for each datatype reference within the scope of the function
|
||||
// MappedVarKey key = new MappedVarKey(AddressSpace.HASH_SPACE.getAddress(hash),defAddr);
|
||||
// DynamicSymbol sym = constantSymbolMap.get(key);
|
||||
// String name = sym != null ? sym.getName() : null;
|
||||
// sym = new DynamicSymbol(name, dt, dt.getLength(), hash, defAddr, func, 0); // format??
|
||||
// if (name != null) {
|
||||
// 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);
|
||||
EquateSymbol eqSymbol;
|
||||
for (int i = 0; i < hash.length; ++i) {
|
||||
if (i != 0 && hash[i - 1] == hash[i]) {
|
||||
continue; // Found a duplicate, skip it
|
||||
}
|
||||
eqSymbol = newEquateSymbol(0, displayName, eqValue, hash[i], defAddr);
|
||||
symbolMap.put(eqSymbol.getId(), eqSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -349,7 +349,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||
BigInteger val = context.getValue(reg, false);
|
||||
if (val != null) {
|
||||
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 &&
|
||||
program.getMemory().contains(refAddr)) {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue