mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-25 15:49:55 +08:00
Merge remote-tracking branch
'origin/GP-3747_ghidra007_PR-5644_saruman9_fix_apply_class_function_signature_updates' (Closes #5644)
This commit is contained in:
+133
-30
@@ -16,7 +16,17 @@
|
||||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||
package classrecovery;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
|
||||
@@ -30,21 +40,78 @@ import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.flatapi.FlatProgramAPI;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.AddressRangeIterator;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.address.GlobalNamespace;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.Category;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.DataTypeConflictHandler;
|
||||
import ghidra.program.model.data.DataTypeDependencyException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FunctionDefinition;
|
||||
import ghidra.program.model.data.FunctionDefinitionDataType;
|
||||
import ghidra.program.model.data.NoisyStructureBuilder;
|
||||
import ghidra.program.model.data.ParameterDefinition;
|
||||
import ghidra.program.model.data.Pointer;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.Undefined1DataType;
|
||||
import ghidra.program.model.data.Undefined4DataType;
|
||||
import ghidra.program.model.data.Undefined8DataType;
|
||||
import ghidra.program.model.data.VoidDataType;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Bookmark;
|
||||
import ghidra.program.model.listing.BookmarkManager;
|
||||
import ghidra.program.model.listing.BookmarkType;
|
||||
import ghidra.program.model.listing.CircularDependencyException;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.FlowOverride;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||
import ghidra.program.model.listing.FunctionManager;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.listing.InstructionIterator;
|
||||
import ghidra.program.model.listing.Listing;
|
||||
import ghidra.program.model.listing.Parameter;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.ReturnParameterImpl;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.pcode.HighFunction;
|
||||
import ghidra.program.model.pcode.HighVariable;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.PcodeOpAST;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceIterator;
|
||||
import ghidra.program.model.symbol.ReferenceManager;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolIterator;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramMemoryUtil;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.bytesearch.*;
|
||||
import ghidra.util.bytesearch.GenericByteSequencePattern;
|
||||
import ghidra.util.bytesearch.GenericMatchAction;
|
||||
import ghidra.util.bytesearch.Match;
|
||||
import ghidra.util.bytesearch.MemoryBytePatternSearcher;
|
||||
import ghidra.util.datastruct.ListAccumulator;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class RecoveredClassHelper {
|
||||
@@ -7644,11 +7711,13 @@ public class RecoveredClassHelper {
|
||||
|
||||
Address[] functionThunkAddresses = function.getFunctionThunkAddresses(true);
|
||||
|
||||
// add any thunk addresses to the list
|
||||
List<Address> functionAddresses =
|
||||
new ArrayList<Address>(Arrays.asList(functionThunkAddresses));
|
||||
List<Address> functionAddresses = new ArrayList<>();
|
||||
// add the function itself to the list
|
||||
functionAddresses.add(function.getEntryPoint());
|
||||
if (functionThunkAddresses != null) {
|
||||
// add any thunk addresses to the list
|
||||
functionAddresses.addAll(Arrays.asList(functionThunkAddresses));
|
||||
}
|
||||
|
||||
for (Address address : functionAddresses) {
|
||||
monitor.checkCancelled();
|
||||
@@ -7673,7 +7742,7 @@ public class RecoveredClassHelper {
|
||||
Address vftableAddress = dataContaining.getAddress();
|
||||
|
||||
Symbol vftableSymbol = api.getSymbolAt(vftableAddress);
|
||||
if (!vftableSymbol.getName().contains("vftable")) {
|
||||
if (vftableSymbol == null || !vftableSymbol.getName().contains("vftable")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7826,25 +7895,21 @@ public class RecoveredClassHelper {
|
||||
ParameterDefinition[] currentArgs = functionDefinition.getArguments();
|
||||
ParameterDefinition[] changedArgs = newFunctionDefinition.getArguments();
|
||||
|
||||
// only update if there are differences and the func sigs have same length
|
||||
// if they don't have same length then something was possibly overridden in a child and
|
||||
// it needs to stay the same as it was except the name
|
||||
if (!currentArgs.equals(changedArgs) && (currentArgs.length == changedArgs.length)) {
|
||||
ParameterDefinition[] newArgs = new ParameterDefinition[currentArgs.length];
|
||||
for (int i = 0; i < currentArgs.length; i++) {
|
||||
if (currentArgs[i].getName().equals("this") ||
|
||||
currentArgs[i].equals(changedArgs[i])) {
|
||||
newArgs[i] = currentArgs[i];
|
||||
}
|
||||
else {
|
||||
newArgs[i] = changedArgs[i];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
functionDefinition.setArguments(newArgs);
|
||||
}
|
||||
// only update if same number of params and there are differences
|
||||
// if different number then user must decide whether to update the definition
|
||||
if (currentArgs.length > 0 && currentArgs.length == changedArgs.length) {
|
||||
|
||||
// keep the original function definition's this param if there is one hard coded
|
||||
// if only the this is different then don't update changed flag
|
||||
if (currentArgs[0].getName().equals("this")) {
|
||||
changedArgs[0] = currentArgs[0];
|
||||
}
|
||||
// if other than hard-coded this is different then change
|
||||
// to use to changedArgs
|
||||
if (!areEqualFunctionArgs(currentArgs, changedArgs)) {
|
||||
functionDefinition.setArguments(changedArgs);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!functionDefinition.getReturnType().equals(newFunctionDefinition.getReturnType())) {
|
||||
@@ -7858,6 +7923,44 @@ public class RecoveredClassHelper {
|
||||
|
||||
}
|
||||
|
||||
private boolean areEqualFunctionArgs(ParameterDefinition[] currentArgs,
|
||||
ParameterDefinition[] changedArgs) {
|
||||
|
||||
// not equals if diff num or arguments
|
||||
if (currentArgs.length != changedArgs.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// equals if both have no args
|
||||
if (currentArgs.length == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// not equals if any args are not equal
|
||||
for (int i = 0; i < currentArgs.length; i++) {
|
||||
if (!areEqualArgs(currentArgs[i], changedArgs[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// equals if all args are equal
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean areEqualArgs(ParameterDefinition def1, ParameterDefinition def2) {
|
||||
|
||||
if (!def1.isEquivalent(def2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!def1.getName().equals(def2.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public List<Structure> getClassStructures() throws CancelledException {
|
||||
|
||||
Category category = program.getDataTypeManager().getCategory(classDataTypesCategoryPath);
|
||||
|
||||
Reference in New Issue
Block a user