mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch 'origin/GT-2956_caheckman_RetypeVariableAction'
This commit is contained in:
commit
8e78f72827
1 changed files with 82 additions and 41 deletions
|
@ -77,8 +77,9 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
}
|
}
|
||||||
if (tokenAtCursor instanceof ClangFieldToken) {
|
if (tokenAtCursor instanceof ClangFieldToken) {
|
||||||
DataType dt = RenameVariableAction.getStructDataType(tokenAtCursor);
|
DataType dt = RenameVariableAction.getStructDataType(tokenAtCursor);
|
||||||
if (dt == null)
|
if (dt == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
getPopupMenuData().setMenuItemName("Retype Field");
|
getPopupMenuData().setMenuItemName("Retype Field");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -92,11 +93,13 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
HighVariable variable = tokenAtCursor.getHighVariable();
|
HighVariable variable = tokenAtCursor.getHighVariable();
|
||||||
if (variable == null) {
|
if (variable == null) {
|
||||||
Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller);
|
Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller);
|
||||||
if (addr == null)
|
if (addr == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
variable = RenameVariableAction.forgeHighVariable(addr, controller);
|
variable = RenameVariableAction.forgeHighVariable(addr, controller);
|
||||||
if (variable == null)
|
if (variable == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (variable instanceof HighConstant) {
|
if (variable instanceof HighConstant) {
|
||||||
// getPopupMenuData().setMenuItemName("Retype Constant");
|
// getPopupMenuData().setMenuItemName("Retype Constant");
|
||||||
|
@ -146,10 +149,12 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
comp = struct.getComponentAt(offset);
|
comp = struct.getComponentAt(offset);
|
||||||
if (comp == null)
|
if (comp == null) {
|
||||||
dataType = chooseDataType(DataType.DEFAULT);
|
dataType = chooseDataType(DataType.DEFAULT);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
dataType = chooseDataType(comp.getDataType());
|
dataType = chooseDataType(comp.getDataType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (tokenAtCursor.Parent() instanceof ClangReturnType) {
|
else if (tokenAtCursor.Parent() instanceof ClangReturnType) {
|
||||||
ClangReturnType parent = (ClangReturnType) tokenAtCursor.Parent();
|
ClangReturnType parent = (ClangReturnType) tokenAtCursor.Parent();
|
||||||
|
@ -164,24 +169,30 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
variable = tokenAtCursor.getHighVariable();
|
variable = tokenAtCursor.getHighVariable();
|
||||||
if (variable == null) {
|
if (variable == null) {
|
||||||
Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller);
|
Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller);
|
||||||
if (addr == null)
|
if (addr == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
variable = RenameVariableAction.forgeHighVariable(addr, controller);
|
variable = RenameVariableAction.forgeHighVariable(addr, controller);
|
||||||
if (variable == null)
|
if (variable == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dataType = chooseDataType(variable.getDataType());
|
dataType = chooseDataType(variable.getDataType());
|
||||||
}
|
}
|
||||||
if (dataType == null)
|
if (dataType == null) {
|
||||||
return;
|
return;
|
||||||
if (struct != null)
|
}
|
||||||
|
if (struct != null) {
|
||||||
retypeStructVariable(struct, comp, dataType);
|
retypeStructVariable(struct, comp, dataType);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
retypeVariable(variable, tokenAtCursor.getVarnode(), dataType);
|
retypeVariable(variable, tokenAtCursor.getVarnode(), dataType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retypeReturnType(DataType dataType, ClangReturnType parent) {
|
private void retypeReturnType(DataType dataType, ClangReturnType parent) {
|
||||||
Program program = controller.getProgram();
|
Program program = controller.getProgram();
|
||||||
|
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||||
HighFunction hfunction = getHighFunctionFromReturnTypeToken(parent);
|
HighFunction hfunction = getHighFunctionFromReturnTypeToken(parent);
|
||||||
if (hfunction == null) {
|
if (hfunction == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -199,8 +210,12 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Function function = hfunction.getFunction();
|
Function function = hfunction.getFunction();
|
||||||
|
boolean successfulMod = false;
|
||||||
int transactionID = program.startTransaction("Retype return type");
|
int transactionID = program.startTransaction("Retype return type");
|
||||||
try {
|
try {
|
||||||
|
if (dataType.getDataTypeManager() != dataTypeManager) {
|
||||||
|
dataType = dataTypeManager.resolve(dataType, null);
|
||||||
|
}
|
||||||
if (commitRequired) {
|
if (commitRequired) {
|
||||||
try {
|
try {
|
||||||
HighFunctionDBUtil.commitParamsToDatabase(hfunction, true,
|
HighFunctionDBUtil.commitParamsToDatabase(hfunction, true,
|
||||||
|
@ -214,12 +229,13 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function.setReturnType(dataType, SourceType.USER_DEFINED);
|
function.setReturnType(dataType, SourceType.USER_DEFINED);
|
||||||
|
successfulMod = true;
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
|
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
|
||||||
"Failed to re-type return type '" + getName() + "': " + e.getMessage());
|
"Failed to re-type return type '" + getName() + "': " + e.getMessage());
|
||||||
}
|
}
|
||||||
program.endTransaction(transactionID, true);
|
program.endTransaction(transactionID, successfulMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HighFunction getHighFunctionFromReturnTypeToken(ClangReturnType returnType) {
|
private HighFunction getHighFunctionFromReturnTypeToken(ClangReturnType returnType) {
|
||||||
|
@ -278,8 +294,13 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Program program = controller.getProgram();
|
Program program = controller.getProgram();
|
||||||
|
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||||
|
boolean successfulMod = false;
|
||||||
int transaction = program.startTransaction("Retype Variable");
|
int transaction = program.startTransaction("Retype Variable");
|
||||||
try {
|
try {
|
||||||
|
if (dt.getDataTypeManager() != dataTypeManager) {
|
||||||
|
dt = dataTypeManager.resolve(dt, null);
|
||||||
|
}
|
||||||
if (commitRequired) {
|
if (commitRequired) {
|
||||||
try {
|
try {
|
||||||
HighFunctionDBUtil.commitParamsToDatabase(hfunction, true,
|
HighFunctionDBUtil.commitParamsToDatabase(hfunction, true,
|
||||||
|
@ -294,6 +315,7 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HighFunctionDBUtil.updateDBVariable(var, null, dt, SourceType.USER_DEFINED);
|
HighFunctionDBUtil.updateDBVariable(var, null, dt, SourceType.USER_DEFINED);
|
||||||
|
successfulMod = true;
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException e) {
|
catch (DuplicateNameException e) {
|
||||||
throw new AssertException("Unexpected exception", e);
|
throw new AssertException("Unexpected exception", e);
|
||||||
|
@ -303,7 +325,7 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
"Failed to re-type variable '" + var.getName() + "': " + e.getMessage());
|
"Failed to re-type variable '" + var.getName() + "': " + e.getMessage());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
program.endTransaction(transaction, true);
|
program.endTransaction(transaction, successfulMod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,17 +339,17 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
*/
|
*/
|
||||||
private int getEndComponentIndex(Structure struct, DataTypeComponent comp, DataType newtype) {
|
private int getEndComponentIndex(Structure struct, DataTypeComponent comp, DataType newtype) {
|
||||||
int newlen = newtype.getLength();
|
int newlen = newtype.getLength();
|
||||||
if (newlen <= 0)
|
if (newlen <= 0) {
|
||||||
return -1; // Don't support variable length types
|
return -1; // Don't support variable length types
|
||||||
|
}
|
||||||
DataType curtype = comp.getDataType();
|
DataType curtype = comp.getDataType();
|
||||||
newlen -= curtype.getLength();
|
newlen -= curtype.getLength();
|
||||||
if (newlen < 0)
|
|
||||||
return -1; // new size is smaller than original size
|
|
||||||
int index = comp.getOrdinal();
|
int index = comp.getOrdinal();
|
||||||
while (newlen > 0) {
|
while (newlen > 0) {
|
||||||
index += 1;
|
index += 1;
|
||||||
if (index >= struct.getNumComponents())
|
if (index >= struct.getNumComponents()) {
|
||||||
return -1; // Not enough space in the structure
|
return -1; // Not enough space in the structure
|
||||||
|
}
|
||||||
comp = struct.getComponent(index);
|
comp = struct.getComponent(index);
|
||||||
// String nm = comp.getFieldName();
|
// String nm = comp.getFieldName();
|
||||||
// if ((nm !=null)&&(nm.length()!=0))
|
// if ((nm !=null)&&(nm.length()!=0))
|
||||||
|
@ -335,17 +357,18 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
curtype = comp.getDataType();
|
curtype = comp.getDataType();
|
||||||
// if (!Undefined.isUndefined(curtype))
|
// if (!Undefined.isUndefined(curtype))
|
||||||
// return -1; // Overlaps non-undefined datatype
|
// return -1; // Overlaps non-undefined datatype
|
||||||
if (curtype != DataType.DEFAULT)
|
if (curtype != DataType.DEFAULT) {
|
||||||
return -1; // Only allow overwrite of placeholder components
|
return -1; // Only allow overwrite of placeholder components
|
||||||
|
}
|
||||||
newlen -= curtype.getLength();
|
newlen -= curtype.getLength();
|
||||||
}
|
}
|
||||||
if (newlen < 0)
|
|
||||||
return -1; // Partial field
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retypeStructVariable(Structure dt, DataTypeComponent comp, DataType newtype) {
|
private void retypeStructVariable(Structure dt, DataTypeComponent comp, DataType newtype) {
|
||||||
Program program = controller.getProgram();
|
Program program = controller.getProgram();
|
||||||
|
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||||
|
boolean successfulMod = false;
|
||||||
if (comp == null) {
|
if (comp == null) {
|
||||||
if (!dt.isNotYetDefined()) {
|
if (!dt.isNotYetDefined()) {
|
||||||
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
|
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
|
||||||
|
@ -355,72 +378,90 @@ public class RetypeVariableAction extends DockingAction {
|
||||||
// note if we reach here the offset must be zero, so assume we are inserting newtype
|
// note if we reach here the offset must be zero, so assume we are inserting newtype
|
||||||
int transaction = program.startTransaction("Retype Structure Field");
|
int transaction = program.startTransaction("Retype Structure Field");
|
||||||
try {
|
try {
|
||||||
|
// Make sure datatype is using the program's data organization before testing fit
|
||||||
|
if (newtype.getDataTypeManager() != dataTypeManager) {
|
||||||
|
newtype = dataTypeManager.resolve(newtype, null);
|
||||||
|
}
|
||||||
dt.insert(0, newtype);
|
dt.insert(0, newtype);
|
||||||
|
successfulMod = true;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
program.endTransaction(transaction, true);
|
program.endTransaction(transaction, successfulMod);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int startind = comp.getOrdinal();
|
|
||||||
int endind = getEndComponentIndex(dt, comp, newtype);
|
|
||||||
if (endind < 0) {
|
|
||||||
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
|
|
||||||
"Failed to re-type structure '" + dt.getName() + "': Datatype did not fit");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int transaction = program.startTransaction("Retype Structure Field");
|
int transaction = program.startTransaction("Retype Structure Field");
|
||||||
try {
|
try {
|
||||||
|
// Make sure datatype is using the program's data organization before testing fit
|
||||||
|
if (newtype.getDataTypeManager() != dataTypeManager) {
|
||||||
|
newtype = dataTypeManager.resolve(newtype, null);
|
||||||
|
}
|
||||||
|
int startind = comp.getOrdinal();
|
||||||
|
int endind = getEndComponentIndex(dt, comp, newtype);
|
||||||
|
if (endind < 0) {
|
||||||
|
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
|
||||||
|
"Failed to re-type structure '" + dt.getName() + "': Datatype did not fit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (int i = endind; i > startind; --i) { // Clear all but first field
|
for (int i = endind; i > startind; --i) { // Clear all but first field
|
||||||
dt.clearComponent(i);
|
dt.clearComponent(i);
|
||||||
}
|
}
|
||||||
dt.replaceAtOffset(comp.getOffset(), newtype, newtype.getLength(), comp.getFieldName(),
|
dt.replaceAtOffset(comp.getOffset(), newtype, newtype.getLength(), comp.getFieldName(),
|
||||||
comp.getComment());
|
comp.getComment());
|
||||||
|
successfulMod = true;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
program.endTransaction(transaction, true);
|
program.endTransaction(transaction, successfulMod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare a HighFunction's idea of what the signature is versus what the underlying Function thinks
|
* Compare the given HighFunction's idea of the prototype with the Function's idea.
|
||||||
* and returns true if there is a difference. If all the input parameters have the same storage and type,
|
* Return true if there is a difference. If a specific parameter is being changed,
|
||||||
* @param var
|
* it can be passed in indicating that slot can be skipped during the comparison.
|
||||||
* @param hfunction
|
* @param var (if not null) is a specific parameter to skip the check for
|
||||||
* @return true if a full commit is required
|
* @param hfunction is the given HighFunction
|
||||||
|
* @return true if there is a difference (and a full commit is required)
|
||||||
*/
|
*/
|
||||||
public static boolean checkFullCommit(HighVariable var, HighFunction hfunction) {
|
public static boolean checkFullCommit(HighVariable var, HighFunction hfunction) {
|
||||||
if ((var != null) && (!(var instanceof HighParam)))
|
if ((var != null) && (!(var instanceof HighParam))) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
Function function = hfunction.getFunction();
|
Function function = hfunction.getFunction();
|
||||||
Parameter[] parameters = function.getParameters();
|
Parameter[] parameters = function.getParameters();
|
||||||
LocalSymbolMap localSymbolMap = hfunction.getLocalSymbolMap();
|
LocalSymbolMap localSymbolMap = hfunction.getLocalSymbolMap();
|
||||||
int numParams = localSymbolMap.getNumParams();
|
int numParams = localSymbolMap.getNumParams();
|
||||||
if (numParams != parameters.length)
|
if (numParams != parameters.length) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int skipslot = -1;
|
int skipslot = -1;
|
||||||
if (var != null)
|
if (var != null) {
|
||||||
skipslot = ((HighParam) var).getSlot();
|
skipslot = ((HighParam) var).getSlot();
|
||||||
|
}
|
||||||
for (int i = 0; i < numParams; i++) {
|
for (int i = 0; i < numParams; i++) {
|
||||||
HighParam param = localSymbolMap.getParam(i);
|
HighParam param = localSymbolMap.getParam(i);
|
||||||
if (param.getSlot() != i) // Slot must match
|
if (param.getSlot() != i) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
VariableStorage storage = param.getStorage();
|
VariableStorage storage = param.getStorage();
|
||||||
if (!storage.equals(parameters[i].getVariableStorage())) // Storage must match
|
if (!storage.equals(parameters[i].getVariableStorage())) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (skipslot != i) { // Compare datatypes unless it is the specific -var- we are skipping
|
if (skipslot != i) { // Compare datatypes unless it is the specific -var- we are skipping
|
||||||
if (!param.getDataType().isEquivalent(parameters[i].getDataType()))
|
if (!param.getDataType().isEquivalent(parameters[i].getDataType())) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var != null) { // A null var indicates we are changing the returntype anyway, so we don't need to check it
|
if (var != null) { // A null var indicates we are changing the return type anyway, so we don't need to check it
|
||||||
DataType funcReturnType = function.getReturnType();
|
DataType funcReturnType = function.getReturnType();
|
||||||
if (funcReturnType != DataType.DEFAULT) {
|
if (funcReturnType != DataType.DEFAULT) {
|
||||||
DataType hfuncReturnType = hfunction.getFunctionPrototype().getReturnType();
|
DataType hfuncReturnType = hfunction.getFunctionPrototype().getReturnType();
|
||||||
if (!funcReturnType.equals(hfuncReturnType))
|
if (!funcReturnType.equals(hfuncReturnType)) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue