Merge branch 'GP-213-dragonmacher-call-tree-duplicates' into Ghidra_9.2

This commit is contained in:
dragonmacher
2020-09-29 14:47:33 -04:00
2 changed files with 106 additions and 18 deletions
@@ -141,4 +141,28 @@ public abstract class CallNode extends GTreeSlowLoadingNode {
}
return false;
}
// overridden since we may have multiple children with the same function name, but in
// different namespaces
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
CallNode other = (CallNode) obj;
return getSourceAddress().equals(other.getSourceAddress());
}
@Override
public int hashCode() {
return getSourceAddress().hashCode();
}
}
@@ -42,6 +42,7 @@ import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.gotoquery.GoToServicePlugin;
import ghidra.app.services.GoToService;
import ghidra.app.services.ProgramManager;
import ghidra.app.util.NamespaceUtils;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
@@ -158,6 +159,10 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
}
}
private Function function(int addr) throws Exception {
return ensureFunction(addr);
}
private void function(int from, int to) throws Exception {
ensureFunction(from);
ensureFunction(to);
@@ -168,16 +173,39 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
}
}
private void ensureFunction(long from) throws Exception {
private Function function(String namespace, String name, int addr) throws Exception {
Function f = ensureFunction(addr);
tx(program, () -> {
f.setName(name, SourceType.ANALYSIS);
Namespace ns = NamespaceUtils.createNamespaceHierarchy(namespace, null, program,
SourceType.ANALYSIS);
f.setParentNamespace(ns);
});
return f;
}
private void function(Function from, Function to) {
// a bit of space so the function call is not at the entry point
int offset = (int) from.getEntryPoint().getOffset() + 5;
int toOffset = (int) to.getEntryPoint().getOffset();
while (!createReference(offset, toOffset)) {
offset++;
}
}
private Function ensureFunction(long from) throws Exception {
ProgramDB p = builder.getProgram();
FunctionManager fm = p.getFunctionManager();
Function f = fm.getFunctionAt(addr(from));
if (f != null) {
return;
return f;
}
String a = Long.toHexString(from);
builder.createEmptyFunction("Function_" + a, "0x" + a, 50, DataType.DEFAULT);
return builder.createEmptyFunction("Function_" + a, "0x" + a, 50, DataType.DEFAULT);
}
private boolean createReference(long from, long to) {
@@ -580,12 +608,10 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
setProviderFunction("0x5000");
final ToggleDockingAction filterDuplicatesAction =
ToggleDockingAction filterDuplicatesAction =
(ToggleDockingAction) getAction("Filter Duplicates");
if (!filterDuplicatesAction.isSelected()) {
performAction(filterDuplicatesAction, true);
}
setToggleActionSelected(filterDuplicatesAction, new ActionContext(), true);
waitForTree(outgoingTree);
GTreeNode rootNode = getRootNode(outgoingTree);
@@ -597,8 +623,7 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
// copy the names of the children into a map so that we can verify that there are
// no duplicates
boolean shouldHaveDuplicates = false;
Map<String, Integer> nameCountMap = createNameCountMap(rootNode);
System.out.println("nameCountMap: before: = " + nameCountMap);
Map<GTreeNode, Integer> nameCountMap = createNameCountMap(rootNode);
assertDuplicateChildStatus(nameCountMap, shouldHaveDuplicates);
performAction(filterDuplicatesAction, true);// deselect
@@ -608,7 +633,47 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
rootNode = getRootNode(outgoingTree);
nameCountMap = createNameCountMap(rootNode);
shouldHaveDuplicates = true;
System.out.println("nameCountMap: after: = " + nameCountMap);
assertDuplicateChildStatus(nameCountMap, shouldHaveDuplicates);
}
@Test
public void testFilterIncomingDuplicates_SameFunctionNameInDifferentNamespaces()
throws Exception {
/*
Create a function call tree that looks like:
NS1::Foo
root
NS2::Foo
root
*/
Function f1 = function("NS1", "Foo", 0x11000);
Function f2 = function("NS2", "Foo", 0x12000);
Function root = function(0x0000);
function(f1, root);
function(f2, root);
setProviderFunction("0x0000");
ToggleDockingAction filterDuplicatesAction =
(ToggleDockingAction) getAction("Filter Duplicates");
setToggleActionSelected(filterDuplicatesAction, new ActionContext(), true);
waitForTree(incomingTree);
GTreeNode rootNode = getRootNode(incomingTree);
List<GTreeNode> children = rootNode.getChildren();
assertTrue(
"Outgoing tree does not have callers as expected for function: " + getListingFunction(),
children.size() > 0);
// copy the names of the children into a map so that we can verify that there are
// no duplicates
boolean shouldHaveDuplicates = false;
Map<GTreeNode, Integer> nameCountMap = createNameCountMap(rootNode);
assertDuplicateChildStatus(nameCountMap, shouldHaveDuplicates);
}
@@ -1071,27 +1136,26 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
return codeBrowserPlugin.getCurrentAddress();
}
private Map<String, Integer> createNameCountMap(GTreeNode node) {
Map<String, Integer> map = new HashMap<>();
private Map<GTreeNode, Integer> createNameCountMap(GTreeNode node) {
Map<GTreeNode, Integer> map = new HashMap<>();
List<GTreeNode> children = node.getChildren();
for (GTreeNode child : children) {
String name = child.getName();
Integer integer = map.get(name);
Integer integer = map.get(child);
if (integer == null) {
integer = 0;
}
int asInt = integer;
asInt++;
map.put(name, asInt);
map.put(child, asInt);
}
return map;
}
private void assertDuplicateChildStatus(Map<String, Integer> childCountMap,
private void assertDuplicateChildStatus(Map<GTreeNode, Integer> childCountMap,
boolean shouldHaveDuplicates) {
boolean foundDuplicates = false;
Set<Entry<String, Integer>> entrySet = childCountMap.entrySet();
for (Entry<String, Integer> entry : entrySet) {
Set<Entry<GTreeNode, Integer>> entrySet = childCountMap.entrySet();
for (Entry<GTreeNode, Integer> entry : entrySet) {
int value = entry.getValue();
if (value != 1) {
foundDuplicates = true;