GP-199 allow function definitions to be applied from selected category

This commit is contained in:
ghidra1 2023-01-05 10:58:00 -05:00
parent 7f9de4251d
commit 3fc5e55d7a
4 changed files with 107 additions and 51 deletions

View File

@ -628,12 +628,15 @@
Types</H3>
<BLOCKQUOTE>
<P>You can apply all function signature data types from an archive to the currently
open Program. Function signature definitions can also be applied from the currently
open program's defined data types. Applying data types from the program is useful when
<P>You can apply all function definition data types from an archive or selected category to the currently
open Program. This can be done from the Data Type Manager tree
by selecting the <I><B>Apply Function Data Types</B></I> popup action
for a selected Archive or Category node.
Function definitions can also be applied from the currently open program's defined data types.
Applying data types from the program is useful when
source header files have been parsed into the program instead of an archive. This
action attempts to match the function definition with user defined symbol names in the
Program. When a match is found, the <I><B>Apply All</B></I> action does one of the
action attempts to match the function definition with symbol names in the
Program. When a match is found, the <I><B>Apply Function Data Types</B></I> action does one of the
following:<BR>
</P>
@ -667,8 +670,8 @@
within the selection will have their signatures captured.</LI>
</UL>
<P>Once you have captured the function data types to an archive, you can use the <A
href="#Apply_All">Apply Function Data Types</A> to apply the function definition data
<P>Once you have captured the function definitions to an archive, you can use the <A
href="#Apply_Function_Data_Types">Apply Function Data Types</A> action to apply the function definition data
types to another program.</P>
</BLOCKQUOTE>

View File

@ -21,12 +21,14 @@ import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.util.PseudoDisassembler;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
@ -37,12 +39,11 @@ import ghidra.util.task.TaskMonitor;
public class ApplyFunctionDataTypesCmd extends BackgroundCommand {
private Program program;
private BookmarkManager bookmarkMgr;
private List<DataTypeManager> managers;
private List<Category> sourceCategories;
private AddressSetView addresses;
private SourceType source;
private boolean alwaysReplace;
private boolean createBookmarksEnabled;
private Map<String, FunctionDefinition> functionNameMap = new HashMap<>();
/**
* Constructs a new command to apply all function signature data types
@ -61,13 +62,45 @@ public class ApplyFunctionDataTypesCmd extends BackgroundCommand {
public ApplyFunctionDataTypesCmd(List<DataTypeManager> managers, AddressSetView set,
SourceType source, boolean alwaysReplace, boolean createBookmarksEnabled) {
super("Apply Function Data Types", true, false, false);
this.managers = managers;
this.sourceCategories = getRootCategories(managers);
this.addresses = set;
this.source = source;
this.alwaysReplace = alwaysReplace;
this.createBookmarksEnabled = createBookmarksEnabled;
}
/**
* Constructs a new command to apply all function signature data types
* in the given data type category (includes all subcategories).
*
* @param sourceCategory datatype category containing the function signature data types
* @param set set of addresses containing labels to match against function names.
* The addresses must not already be included in the body of any existing function.
* If null, all symbols will be processed
* @param source the source of this command.
* @param alwaysReplace true to always replace the existing function signature with the
* function signature data type.
* @param createBookmarksEnabled true to create a bookmark when a function signature
* has been applied.
*/
public ApplyFunctionDataTypesCmd(Category sourceCategory, AddressSetView set,
SourceType source, boolean alwaysReplace, boolean createBookmarksEnabled) {
super("Apply Function Data Types", true, false, false);
this.sourceCategories = List.of(sourceCategory);
this.addresses = set;
this.source = source;
this.alwaysReplace = alwaysReplace;
this.createBookmarksEnabled = createBookmarksEnabled;
}
private static List<Category> getRootCategories(List<DataTypeManager> managers) {
List<Category> roots = new ArrayList<>();
for (DataTypeManager dtm : managers) {
roots.add(dtm.getRootCategory());
}
return roots;
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
program = (Program) obj;
@ -77,7 +110,12 @@ public class ApplyFunctionDataTypesCmd extends BackgroundCommand {
Map<String, List<Symbol>> symbolMap = createSymMap();
applyDataTypes(monitor, symbolMap);
try {
applyFunctionDefinitions(monitor, symbolMap);
}
catch (CancelledException e) {
// ignore and return
}
return true;
}
@ -136,39 +174,23 @@ public class ApplyFunctionDataTypesCmd extends BackgroundCommand {
}
/**
* Apply all descendants starting at node.
* Apply all descendants starting at each category node.
* @param monitor task monitor
* @param symbolMap symbol map where possible function definitions may be applied
* @throws CancelledException if task cancelled
*/
private void applyDataTypes(TaskMonitor monitor, Map<String, List<Symbol>> symbolMap) {
for (DataTypeManager dataTypeManager : managers) {
Iterator<DataType> iter = dataTypeManager.getAllDataTypes();
while (iter.hasNext()) {
if (monitor.isCancelled()) {
return;
}
DataType dt = iter.next();
if (!(dt instanceof FunctionDefinition)) {
continue;
}
FunctionDefinition fdef = (FunctionDefinition) dt;
String name = fdef.getName();
if (functionNameMap.containsKey(name)) {
FunctionDefinition dupeFdef = functionNameMap.get(name);
if (!fdef.isEquivalent(dupeFdef)) {
// set the functionDef to null to mark dupes
functionNameMap.put(name, null);
}
}
else {
functionNameMap.put(name, fdef);
}
}
private void applyFunctionDefinitions(TaskMonitor monitor,
Map<String, List<Symbol>> symbolMap) throws CancelledException {
Map<String, FunctionDefinition> functionNameMap = new HashMap<>();
for (Category cat : sourceCategories) {
collectFunctionDefinitions(cat, monitor, functionNameMap);
}
monitor.initialize(functionNameMap.size());
for (String functionName : functionNameMap.keySet()) {
monitor.checkCanceled();
FunctionDefinition fdef = functionNameMap.get(functionName);
checkForSymbol(monitor, functionName, fdef, symbolMap, null);
@ -180,6 +202,36 @@ public class ApplyFunctionDataTypesCmd extends BackgroundCommand {
}
private void collectFunctionDefinitions(Category cat, TaskMonitor monitor,
Map<String, FunctionDefinition> functionNameMap) throws CancelledException {
monitor.checkCanceled();
for (DataType dt : cat.getDataTypes()) {
monitor.checkCanceled();
if (!(dt instanceof FunctionDefinition)) {
continue;
}
FunctionDefinition fdef = (FunctionDefinition) dt;
String name = fdef.getName();
if (functionNameMap.containsKey(name)) {
FunctionDefinition dupeFdef = functionNameMap.get(name);
if (!fdef.isEquivalent(dupeFdef)) {
// set the functionDef to null to mark dupes
functionNameMap.put(name, null);
}
}
else {
functionNameMap.put(name, fdef);
}
}
for (Category subcat : cat.getCategories()) {
collectFunctionDefinitions(subcat, monitor, functionNameMap);
}
}
private void checkForSymbol(TaskMonitor monitor, String functionName, FunctionDefinition fdef,
Map<String, List<Symbol>> symbolMap, String prefix) {
@ -330,7 +382,7 @@ public class ApplyFunctionDataTypesCmd extends BackgroundCommand {
}
private SourceType getMostTrustedParameterSource(Function func) {
SourceType highestSource = SourceType.DEFAULT;
SourceType highestSource = func.getSignatureSource();
Parameter[] parameters = func.getParameters();
for (Parameter parameter : parameters) {
SourceType paramSource = parameter.getSource();

View File

@ -15,9 +15,6 @@
*/
package ghidra.app.plugin.core.datamgr.actions;
import java.util.ArrayList;
import java.util.List;
import javax.swing.tree.TreePath;
import docking.ActionContext;
@ -30,7 +27,6 @@ import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
import ghidra.app.plugin.core.datamgr.tree.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
@ -66,6 +62,12 @@ public class ApplyFunctionDataTypesAction extends DockingAction {
}
GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
if (node instanceof CategoryNode) {
CategoryNode catNode = (CategoryNode) node;
node = catNode.getArchiveNode();
}
return (node instanceof FileArchiveNode) || (node instanceof ProjectArchiveNode) ||
(node instanceof ProgramArchiveNode);
}
@ -74,14 +76,12 @@ public class ApplyFunctionDataTypesAction extends DockingAction {
public void actionPerformed(ActionContext context) {
GTree gTree = (GTree) context.getContextObject();
TreePath selectionPath = gTree.getSelectionPath();
ArchiveNode node = (ArchiveNode) selectionPath.getLastPathComponent();
CategoryNode node = (CategoryNode) selectionPath.getLastPathComponent();
Program program = plugin.getProgram();
DataTypeManager manager = node.getArchive().getDataTypeManager();
List<DataTypeManager> managerList = new ArrayList<DataTypeManager>();
managerList.add(manager);
ApplyFunctionDataTypesCmd cmd =
new ApplyFunctionDataTypesCmd(managerList, null, SourceType.USER_DEFINED, true, true);
new ApplyFunctionDataTypesCmd(node.getCategory(), null, SourceType.USER_DEFINED, true,
true);
PluginTool tool = plugin.getTool();
tool.executeBackgroundCommand(cmd, program);
}

View File

@ -208,7 +208,8 @@
<ul>
<li>Users can create a function definition data type for function signatures they might want apply again in a new program for a particular named function. To do this, click on a function signature and choose Function->Create Function Definition from the Listing right mouse menu.</li>
<li>Users can create function definitions for their whole program by choosing Capture Function Data Types from the Data Type Manager right mouse menu.</li>
<li>In new program, apply function signature by right mousing on appropriate folder in Data Type Manager and choosing Apply Function Data Types</li>
<li>In new program, apply function signatures by right mouse-clicking on an appropriate category folder in the Data Type Manager and
choosing <b>Apply Function Data Types</b> from the popup menu.</li>
</ul>
</ul>