diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html index 6c57b766da..ec86c30414 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html +++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html @@ -628,12 +628,15 @@ Types
-

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 +

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 Apply Function Data Types 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 Apply All action does one of the + action attempts to match the function definition with symbol names in the + Program. When a match is found, the Apply Function Data Types action does one of the following:

@@ -667,8 +670,8 @@ within the selection will have their signatures captured. -

Once you have captured the function data types to an archive, you can use the Apply Function Data Types to apply the function definition data +

Once you have captured the function definitions to an archive, you can use the Apply Function Data Types action to apply the function definition data types to another program.

diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionDataTypesCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionDataTypesCmd.java index c6d5b54420..12d02d0266 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionDataTypesCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionDataTypesCmd.java @@ -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 managers; + private List sourceCategories; private AddressSetView addresses; private SourceType source; private boolean alwaysReplace; private boolean createBookmarksEnabled; - private Map 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 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 getRootCategories(List managers) { + List 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> 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> symbolMap) { - - for (DataTypeManager dataTypeManager : managers) { - Iterator 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> symbolMap) throws CancelledException { + Map 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 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> 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(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ApplyFunctionDataTypesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ApplyFunctionDataTypesAction.java index 5d466e5996..93ee14a6f3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ApplyFunctionDataTypesAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ApplyFunctionDataTypesAction.java @@ -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 managerList = new ArrayList(); - 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); } diff --git a/GhidraDocs/GhidraClass/Intermediate/Intermediate_Ghidra_Student_Guide.html b/GhidraDocs/GhidraClass/Intermediate/Intermediate_Ghidra_Student_Guide.html index 56a13e217d..182d4caccc 100644 --- a/GhidraDocs/GhidraClass/Intermediate/Intermediate_Ghidra_Student_Guide.html +++ b/GhidraDocs/GhidraClass/Intermediate/Intermediate_Ghidra_Student_Guide.html @@ -208,7 +208,8 @@
  • 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.
  • Users can create function definitions for their whole program by choosing Capture Function Data Types from the Data Type Manager right mouse menu.
  • -
  • In new program, apply function signature by right mousing on appropriate folder in Data Type Manager and choosing Apply Function Data Types
  • +
  • In new program, apply function signatures by right mouse-clicking on an appropriate category folder in the Data Type Manager and + choosing Apply Function Data Types from the popup menu.