mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-4263 added Edit Signature Override action to decompiler (Help still needed)
This commit is contained in:
parent
ad7694a7a9
commit
a4f7bb24b9
8 changed files with 243 additions and 93 deletions
|
@ -905,6 +905,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
OverridePrototypeAction overrideSigAction = new OverridePrototypeAction();
|
OverridePrototypeAction overrideSigAction = new OverridePrototypeAction();
|
||||||
setGroupInfo(overrideSigAction, functionGroup, subGroupPosition++);
|
setGroupInfo(overrideSigAction, functionGroup, subGroupPosition++);
|
||||||
|
|
||||||
|
EditPrototypeOverrideAction editOverrideSigAction = new EditPrototypeOverrideAction();
|
||||||
|
setGroupInfo(editOverrideSigAction, functionGroup, subGroupPosition++);
|
||||||
|
|
||||||
DeletePrototypeOverrideAction deleteSigAction = new DeletePrototypeOverrideAction();
|
DeletePrototypeOverrideAction deleteSigAction = new DeletePrototypeOverrideAction();
|
||||||
setGroupInfo(deleteSigAction, functionGroup, subGroupPosition++);
|
setGroupInfo(deleteSigAction, functionGroup, subGroupPosition++);
|
||||||
|
|
||||||
|
@ -1144,6 +1147,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
addLocalAction(editDataTypeAction);
|
addLocalAction(editDataTypeAction);
|
||||||
addLocalAction(specifyCProtoAction);
|
addLocalAction(specifyCProtoAction);
|
||||||
addLocalAction(overrideSigAction);
|
addLocalAction(overrideSigAction);
|
||||||
|
addLocalAction(editOverrideSigAction);
|
||||||
addLocalAction(deleteSigAction);
|
addLocalAction(deleteSigAction);
|
||||||
addLocalAction(renameFunctionAction);
|
addLocalAction(renameFunctionAction);
|
||||||
addLocalAction(renameLabelAction);
|
addLocalAction(renameLabelAction);
|
||||||
|
|
|
@ -159,7 +159,7 @@ public abstract class AbstractDecompilerAction extends DockingAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the function corresponding to the specified decompiler context.
|
* Get the function corresponding to the specified decompiler context token.
|
||||||
*
|
*
|
||||||
* @param context decompiler action context
|
* @param context decompiler action context
|
||||||
* @return the function associated with the current context token or null if none identified.
|
* @return the function associated with the current context token or null if none identified.
|
||||||
|
|
|
@ -16,16 +16,13 @@
|
||||||
package ghidra.app.plugin.core.decompile.actions;
|
package ghidra.app.plugin.core.decompile.actions;
|
||||||
|
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
import ghidra.app.decompiler.ClangToken;
|
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.program.database.symbol.CodeSymbol;
|
|
||||||
import ghidra.program.model.data.ProgramBasedDataTypeManager;
|
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.pcode.HighFunction;
|
import ghidra.program.model.pcode.DataTypeSymbol;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
import ghidra.program.model.pcode.HighFunctionDBUtil;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.UndefinedFunction;
|
import ghidra.util.UndefinedFunction;
|
||||||
|
|
||||||
|
@ -37,38 +34,6 @@ public class DeletePrototypeOverrideAction extends AbstractDecompilerAction {
|
||||||
setPopupMenuData(new MenuData(new String[] { "Remove Signature Override" }, "Decompile"));
|
setPopupMenuData(new MenuData(new String[] { "Remove Signature Override" }, "Decompile"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CodeSymbol getSymbol(Function func, ClangToken tokenAtCursor) {
|
|
||||||
if (tokenAtCursor == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Namespace overspace = HighFunction.findOverrideSpace(func);
|
|
||||||
if (overspace == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
PcodeOp op = OverridePrototypeAction.getCallOp(func.getProgram(), tokenAtCursor);
|
|
||||||
if (op == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
SymbolTable symtab = func.getProgram().getSymbolTable();
|
|
||||||
SymbolIterator iter = symtab.getSymbolsAsIterator(op.getSeqnum().getTarget());
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Symbol sym = iter.next();
|
|
||||||
if (!sym.getName().startsWith("prt")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!(sym instanceof CodeSymbol)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!sym.getParentNamespace().equals(overspace)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return (CodeSymbol) sym;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
|
|
||||||
|
@ -77,22 +42,26 @@ public class DeletePrototypeOverrideAction extends AbstractDecompilerAction {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSymbol(function, context.getTokenAtCursor()) != null;
|
return OverridePrototypeAction.getSymbol(function, context.getTokenAtCursor()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
||||||
Function func = context.getFunction();
|
Function func = context.getFunction();
|
||||||
CodeSymbol sym = getSymbol(func, context.getTokenAtCursor());
|
Symbol sym = OverridePrototypeAction.getSymbol(func, context.getTokenAtCursor());
|
||||||
|
if (sym == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Program program = func.getProgram();
|
Program program = func.getProgram();
|
||||||
SymbolTable symtab = program.getSymbolTable();
|
|
||||||
ProgramBasedDataTypeManager dtm = program.getDataTypeManager();
|
|
||||||
int txId = program.startTransaction("Remove Override Signature");
|
int txId = program.startTransaction("Remove Override Signature");
|
||||||
try {
|
try {
|
||||||
symtab.removeSymbolSpecial(sym);
|
DataTypeSymbol dts = HighFunctionDBUtil.readOverride(sym);
|
||||||
|
sym.delete();
|
||||||
|
dts.cleanupUnusedOverride();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
program.endTransaction(txId, true);
|
program.endTransaction(txId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.decompile.actions;
|
||||||
|
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
|
import ghidra.app.util.HelpTopics;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.FunctionDefinition;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.pcode.*;
|
||||||
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
import ghidra.util.*;
|
||||||
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
|
public class EditPrototypeOverrideAction extends AbstractDecompilerAction {
|
||||||
|
|
||||||
|
public EditPrototypeOverrideAction() {
|
||||||
|
super("Edit Signature Override");
|
||||||
|
setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionEditOverride"));
|
||||||
|
setPopupMenuData(new MenuData(new String[] { "Edit Signature Override" }, "Decompile"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
|
Function function = context.getFunction();
|
||||||
|
if (function == null || function instanceof UndefinedFunction) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol sym = OverridePrototypeAction.getSymbol(function, context.getTokenAtCursor());
|
||||||
|
if (sym == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HighFunctionDBUtil.readOverride(sym) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
||||||
|
Function function = context.getFunction();
|
||||||
|
Symbol sym = OverridePrototypeAction.getSymbol(function, context.getTokenAtCursor());
|
||||||
|
if (sym == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DataTypeSymbol dts = HighFunctionDBUtil.readOverride(sym);
|
||||||
|
if (dts == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Function func = context.getFunction();
|
||||||
|
Program program = func.getProgram();
|
||||||
|
PcodeOp op = OverridePrototypeAction.getCallOp(program, context.getTokenAtCursor());
|
||||||
|
Function calledFunc = null;
|
||||||
|
if (op != null) {
|
||||||
|
calledFunc = OverridePrototypeAction.getCalledFunction(program, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionDefinition updatedFuncDef = null;
|
||||||
|
try {
|
||||||
|
// Copy is used for edit so we can adjust name
|
||||||
|
FunctionDefinition funcDef =
|
||||||
|
(FunctionDefinition) dts.getDataType().copy(program.getDataTypeManager());
|
||||||
|
funcDef.setName(calledFunc != null ? calledFunc.getName() : "func");
|
||||||
|
updatedFuncDef = OverridePrototypeAction.editSignature(context, calledFunc,
|
||||||
|
funcDef.getPrototypeString());
|
||||||
|
if (updatedFuncDef == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: should use comparison to see if funcDef was changed.
|
||||||
|
// Should be able to use equals method after fixing category and name, however
|
||||||
|
// it does not check param names.
|
||||||
|
}
|
||||||
|
catch (InvalidNameException | DuplicateNameException e) {
|
||||||
|
Msg.error(this, "Unexpected error", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
int transaction = program.startTransaction("Override Signature");
|
||||||
|
try {
|
||||||
|
Address addr = sym.getAddress();
|
||||||
|
sym.delete(); // delete old marker symbol
|
||||||
|
HighFunctionDBUtil.writeOverride(func, addr, updatedFuncDef);
|
||||||
|
dts.cleanupUnusedOverride();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Msg.showError(getClass(), context.getDecompilerPanel(), "Override Signature Failed",
|
||||||
|
"Error overriding signature: " + e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.endTransaction(transaction, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,8 +28,7 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
@ -48,7 +47,7 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
* @param tokenAtCursor is the point in the window the user has selected
|
* @param tokenAtCursor is the point in the window the user has selected
|
||||||
* @return the PcodeOp or null
|
* @return the PcodeOp or null
|
||||||
*/
|
*/
|
||||||
public static PcodeOp getCallOp(Program program, ClangToken tokenAtCursor) {
|
static PcodeOp getCallOp(Program program, ClangToken tokenAtCursor) {
|
||||||
if (tokenAtCursor == null) {
|
if (tokenAtCursor == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +75,38 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Symbol getSymbol(Function func, ClangToken tokenAtCursor) {
|
||||||
|
if (tokenAtCursor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Namespace overspace = HighFunction.findOverrideSpace(func);
|
||||||
|
if (overspace == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PcodeOp op = getCallOp(func.getProgram(), tokenAtCursor);
|
||||||
|
if (op == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SymbolTable symtab = func.getProgram().getSymbolTable();
|
||||||
|
SymbolIterator iter = symtab.getSymbolsAsIterator(op.getSeqnum().getTarget());
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Symbol sym = iter.next();
|
||||||
|
if (sym.getSymbolType() != SymbolType.LABEL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!sym.getParentNamespace().equals(overspace)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!sym.getName().startsWith("prt")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static PcodeOp getOpForAddress(Program program, Address addr, ClangToken token) {
|
private static PcodeOp getOpForAddress(Program program, Address addr, ClangToken token) {
|
||||||
|
|
||||||
ClangFunction cfunc = token.getClangFunction();
|
ClangFunction cfunc = token.getClangFunction();
|
||||||
|
@ -114,7 +145,7 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
return opCode == PcodeOp.CALL || opCode == PcodeOp.CALLIND;
|
return opCode == PcodeOp.CALL || opCode == PcodeOp.CALLIND;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function getCalledFunction(Program program, PcodeOp op) {
|
static Function getCalledFunction(Program program, PcodeOp op) {
|
||||||
if (op.getOpcode() != PcodeOp.CALL) {
|
if (op.getOpcode() != PcodeOp.CALL) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -226,8 +257,7 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't enable if override already in place
|
// don't enable if override already in place
|
||||||
return DeletePrototypeOverrideAction.getSymbol(context.getFunction(),
|
return getSymbol(context.getFunction(), context.getTokenAtCursor()) == null;
|
||||||
context.getTokenAtCursor()) == null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -235,10 +265,10 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
Function func = context.getFunction();
|
Function func = context.getFunction();
|
||||||
Program program = func.getProgram();
|
Program program = func.getProgram();
|
||||||
PcodeOp op = getCallOp(program, context.getTokenAtCursor());
|
PcodeOp op = getCallOp(program, context.getTokenAtCursor());
|
||||||
Function calledfunc = getCalledFunction(program, op);
|
Function calledFunc = getCalledFunction(program, op);
|
||||||
boolean varargs = false;
|
boolean varargs = false;
|
||||||
if (calledfunc != null) {
|
if (calledFunc != null) {
|
||||||
varargs = calledfunc.hasVarArgs();
|
varargs = calledFunc.hasVarArgs();
|
||||||
}
|
}
|
||||||
if ((op.getOpcode() == PcodeOp.CALL) && !varargs) {
|
if ((op.getOpcode() == PcodeOp.CALL) && !varargs) {
|
||||||
if (OptionDialog.showOptionDialog(context.getDecompilerPanel(),
|
if (OptionDialog.showOptionDialog(context.getDecompilerPanel(),
|
||||||
|
@ -250,26 +280,21 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Address addr = op.getSeqnum().getTarget();
|
|
||||||
String name = "func"; // Default if we don't have a real name
|
|
||||||
String conv = program.getCompilerSpec().getDefaultCallingConvention().getName();
|
|
||||||
if (calledfunc != null) {
|
|
||||||
name = calledfunc.getName();
|
|
||||||
conv = calledfunc.getCallingConventionName();
|
|
||||||
}
|
|
||||||
|
|
||||||
String signature = generateSignature(op, name, calledfunc);
|
String name = "func"; // Default if we don't have a real name
|
||||||
PluginTool tool = context.getTool();
|
if (calledFunc != null) {
|
||||||
ProtoOverrideDialog dialog =
|
name = calledFunc.getName();
|
||||||
new ProtoOverrideDialog(tool, calledfunc != null ? calledfunc : func, signature, conv);
|
}
|
||||||
tool.showDialog(dialog);
|
String signature = generateSignature(op, name, calledFunc);
|
||||||
FunctionDefinition fdef = dialog.getFunctionDefinition();
|
|
||||||
|
FunctionDefinition fdef = editSignature(context, calledFunc, signature);
|
||||||
if (fdef == null) {
|
if (fdef == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int transaction = program.startTransaction("Override Signature");
|
int transaction = program.startTransaction("Override Signature");
|
||||||
boolean commit = false;
|
boolean commit = false;
|
||||||
try {
|
try {
|
||||||
|
Address addr = op.getSeqnum().getTarget();
|
||||||
HighFunctionDBUtil.writeOverride(func, addr, fdef);
|
HighFunctionDBUtil.writeOverride(func, addr, fdef);
|
||||||
commit = true;
|
commit = true;
|
||||||
}
|
}
|
||||||
|
@ -282,13 +307,30 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FunctionDefinition editSignature(DecompilerActionContext context, Function calledFunc,
|
||||||
|
String signature) {
|
||||||
|
Function func = context.getFunction();
|
||||||
|
Program program = func.getProgram();
|
||||||
|
PluginTool tool = context.getTool();
|
||||||
|
|
||||||
|
String conv = program.getCompilerSpec().getDefaultCallingConvention().getName();
|
||||||
|
if (calledFunc != null) {
|
||||||
|
conv = calledFunc.getCallingConventionName();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoOverrideDialog dialog =
|
||||||
|
new ProtoOverrideDialog(tool, calledFunc != null ? calledFunc : func, signature, conv);
|
||||||
|
tool.showDialog(dialog);
|
||||||
|
return dialog.getFunctionDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>ProtoOverrideDialog</code> provides the ability to edit the
|
* <code>ProtoOverrideDialog</code> provides the ability to edit the
|
||||||
* function signature associated with a specific function definition override
|
* function signature associated with a specific function definition override
|
||||||
* at a sub-function callsite.
|
* at a sub-function callsite.
|
||||||
* Use of this editor requires the presence of the tool-based datatype manager service.
|
* Use of this editor requires the presence of the tool-based datatype manager service.
|
||||||
*/
|
*/
|
||||||
private class ProtoOverrideDialog extends EditFunctionSignatureDialog {
|
private static class ProtoOverrideDialog extends EditFunctionSignatureDialog {
|
||||||
private FunctionDefinition functionDefinition;
|
private FunctionDefinition functionDefinition;
|
||||||
private final String initialSignature;
|
private final String initialSignature;
|
||||||
private final String initialConvention;
|
private final String initialConvention;
|
||||||
|
|
|
@ -139,34 +139,23 @@ public class SpecifyCPrototypeAction extends AbstractDecompilerAction {
|
||||||
return fsig;
|
return fsig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get function affected by specified action context
|
|
||||||
*
|
|
||||||
* @param function is the current decompiled function which will be the default if no other
|
|
||||||
* function identified by context token.
|
|
||||||
* @param context decompiler action context
|
|
||||||
* @return the function associated with the current context token. If no function corresponds
|
|
||||||
* to context token the decompiled function will be returned.
|
|
||||||
*/
|
|
||||||
private Function getFunction(Function function, DecompilerActionContext context) {
|
|
||||||
// try to look up the function that is at the current cursor location
|
|
||||||
// If there isn't one, just use the function we are in.
|
|
||||||
Function tokenFunction = getFunction(context);
|
|
||||||
return tokenFunction != null ? tokenFunction : function;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
Function function = context.getFunction();
|
Function decompiledFunction = context.getFunction();
|
||||||
if (function instanceof UndefinedFunction) {
|
Function func = getFunction(context);
|
||||||
|
if (func == null || (func instanceof UndefinedFunction)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return getFunction(function, context) != null;
|
if (func != decompiledFunction && OverridePrototypeAction.getSymbol(decompiledFunction,
|
||||||
|
context.getTokenAtCursor()) != null) {
|
||||||
|
return false; // disable action for sub-function call w/ override
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
||||||
Function function = getFunction(context.getFunction(), context);
|
Function function = getFunction(context);
|
||||||
PluginTool tool = context.getTool();
|
PluginTool tool = context.getTool();
|
||||||
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
|
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,12 @@ import generic.hash.SimpleCRC32;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.FunctionSignature;
|
import ghidra.program.model.listing.FunctionSignature;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class DataTypeSymbol {
|
public class DataTypeSymbol {
|
||||||
private Symbol sym; // Traditional symbol object
|
private Symbol sym; // Traditional symbol object
|
||||||
|
@ -105,14 +107,12 @@ public class DataTypeSymbol {
|
||||||
public static void deleteSymbols(String nmroot, Address addr, SymbolTable symtab,
|
public static void deleteSymbols(String nmroot, Address addr, SymbolTable symtab,
|
||||||
Namespace space) throws InvalidInputException {
|
Namespace space) throws InvalidInputException {
|
||||||
ArrayList<Symbol> dellist = new ArrayList<Symbol>();
|
ArrayList<Symbol> dellist = new ArrayList<Symbol>();
|
||||||
SymbolIterator iter = symtab.getSymbols(space);
|
for (Symbol sym : symtab.getSymbols(addr)) {
|
||||||
while (iter.hasNext()) {
|
|
||||||
Symbol sym = iter.next();
|
|
||||||
if (!sym.getName().startsWith(nmroot))
|
if (!sym.getName().startsWith(nmroot))
|
||||||
continue;
|
continue;
|
||||||
if (sym.getSymbolType() != SymbolType.LABEL)
|
if (sym.getSymbolType() != SymbolType.LABEL)
|
||||||
continue;
|
continue;
|
||||||
if (!addr.equals(sym.getAddress()))
|
if (space.equals(sym.getParentNamespace()))
|
||||||
continue;
|
continue;
|
||||||
if (sym.hasReferences())
|
if (sym.hasReferences())
|
||||||
throw new InvalidInputException("DataTypeSymbol has a reference");
|
throw new InvalidInputException("DataTypeSymbol has a reference");
|
||||||
|
@ -123,6 +123,34 @@ public class DataTypeSymbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void cleanupUnusedOverride() {
|
||||||
|
if (sym == null) {
|
||||||
|
throw new RuntimeException("not instantiated with readSymbol method");
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Although the symbol may have just been deleted its name will still be
|
||||||
|
// be accesible within its retained DB record.
|
||||||
|
String overrideName = sym.getName(); // override marker symbol
|
||||||
|
|
||||||
|
Program program = sym.getProgram();
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
String prefix = nmroot + "_";
|
||||||
|
String hashSuffix = "_" + extractHash(overrideName);
|
||||||
|
for (Symbol s : symbolTable.scanSymbolsByName(prefix)) {
|
||||||
|
String n = s.getName();
|
||||||
|
if (!n.startsWith(prefix)) {
|
||||||
|
break; // stop scan
|
||||||
|
}
|
||||||
|
if (s.getSymbolType() == SymbolType.LABEL && n.endsWith(hashSuffix) &&
|
||||||
|
HighFunction.isOverrideNamespace(s.getParentNamespace())) {
|
||||||
|
return; // do nothing if any symbol found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove unused override signature
|
||||||
|
program.getDataTypeManager().remove(getDataType(), TaskMonitor.DUMMY);
|
||||||
|
}
|
||||||
|
|
||||||
public static DataTypeSymbol readSymbol(String cat, Symbol s) {
|
public static DataTypeSymbol readSymbol(String cat, Symbol s) {
|
||||||
if (s.getSymbolType() != SymbolType.LABEL) {
|
if (s.getSymbolType() != SymbolType.LABEL) {
|
||||||
throw new IllegalArgumentException("Expected CODE symbol");
|
throw new IllegalArgumentException("Expected CODE symbol");
|
||||||
|
|
|
@ -40,6 +40,8 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
*/
|
*/
|
||||||
public class HighFunction extends PcodeSyntaxTree {
|
public class HighFunction extends PcodeSyntaxTree {
|
||||||
public final static String DECOMPILER_TAG_MAP = "decompiler_tags";
|
public final static String DECOMPILER_TAG_MAP = "decompiler_tags";
|
||||||
|
public final static String OVERRIDE_NAMESPACE_NAME = "override";
|
||||||
|
|
||||||
private Function func; // The traditional function object
|
private Function func; // The traditional function object
|
||||||
private Language language;
|
private Language language;
|
||||||
private CompilerSpec compilerSpec;
|
private CompilerSpec compilerSpec;
|
||||||
|
@ -485,14 +487,22 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isOverrideNamespace(Namespace namespace) {
|
||||||
|
if (!OVERRIDE_NAMESPACE_NAME.equals(namespace.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Namespace parent = namespace.getParentNamespace();
|
||||||
|
return (parent instanceof Function);
|
||||||
|
}
|
||||||
|
|
||||||
public static Namespace findOverrideSpace(Function func) {
|
public static Namespace findOverrideSpace(Function func) {
|
||||||
SymbolTable symtab = func.getProgram().getSymbolTable();
|
SymbolTable symtab = func.getProgram().getSymbolTable();
|
||||||
return findNamespace(symtab, func, "override");
|
return findNamespace(symtab, func, OVERRIDE_NAMESPACE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Namespace findCreateOverrideSpace(Function func) {
|
public static Namespace findCreateOverrideSpace(Function func) {
|
||||||
SymbolTable symtab = func.getProgram().getSymbolTable();
|
SymbolTable symtab = func.getProgram().getSymbolTable();
|
||||||
return findCreateNamespace(symtab, func, "override");
|
return findCreateNamespace(symtab, func, OVERRIDE_NAMESPACE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Namespace findNamespace(SymbolTable symtab, Namespace parent, String name) {
|
public static Namespace findNamespace(SymbolTable symtab, Namespace parent, String name) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue