diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java index 6dd8a05718..b55588dfa4 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java @@ -70,6 +70,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter private DockingAction lockLocalAction; private DockingAction renameVarAction; private DockingAction retypeVarAction; + private DockingAction isolateVarAction; private DockingAction specifyCProtoAction; private DockingAction overrideSigAction; private DockingAction deleteSigAction; @@ -778,6 +779,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter retypeVarAction = new RetypeVariableAction(tool, controller); setGroupInfo(retypeVarAction, variableGroup, subGroupPosition++); + isolateVarAction = new IsolateVariableAction(tool, controller); + setGroupInfo(isolateVarAction, variableGroup, subGroupPosition++); + decompilerCreateStructureAction = new DecompilerStructureVariableAction(owner, tool, controller); setGroupInfo(decompilerCreateStructureAction, variableGroup, subGroupPosition++); @@ -907,6 +911,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter addLocalAction(removeSecondaryHighlightAction); addLocalAction(removeAllSecondadryHighlightsAction); addLocalAction(retypeVarAction); + addLocalAction(isolateVarAction); addLocalAction(decompilerCreateStructureAction); tool.addAction(listingCreateStructureAction); addLocalAction(editDataTypeAction); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/IsolateVariableAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/IsolateVariableAction.java new file mode 100644 index 0000000000..3a4964cee2 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/IsolateVariableAction.java @@ -0,0 +1,88 @@ +/* ### + * 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.decompiler.ClangToken; +import ghidra.app.decompiler.component.DecompilerController; +import ghidra.app.decompiler.component.DecompilerPanel; +import ghidra.app.plugin.core.decompile.DecompilerActionContext; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.listing.Function; +import ghidra.program.model.pcode.*; +import ghidra.util.UndefinedFunction; + +public class IsolateVariableAction extends RetypeVariableAction { + + public IsolateVariableAction(PluginTool tool, DecompilerController controller) { + super("New Isolated Variable", tool, controller); + setPopupMenuData(new MenuData(new String[] { "New Isolated Variable" }, "Decompile")); +// setKeyBindingData(new KeyBindingData(KeyEvent.VK_L, 0)); + } + + @Override + protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) { + Function function = controller.getFunction(); + if (function instanceof UndefinedFunction) { + return false; + } + + DecompilerPanel decompilerPanel = controller.getDecompilerPanel(); + ClangToken tokenAtCursor = decompilerPanel.getTokenAtCursor(); + if (tokenAtCursor == null) { + return false; + } + HighVariable variable = tokenAtCursor.getHighVariable(); + if (!(variable instanceof HighLocal)) { + return false; + } + HighSymbol highSymbol = variable.getSymbol(); + if (highSymbol == null) { + return false; + } + if (highSymbol.isIsolated()) { + return false; + } + + Varnode vn = tokenAtCursor.getVarnode(); + if (vn == null) { + return false; + } + short mergeGroup = vn.getMergeGroup(); + boolean mergeSplit = false; + for (Varnode var : variable.getInstances()) { + if (var.getMergeGroup() != mergeGroup) { + mergeSplit = true; + break; + } + } + if (!mergeSplit) { + return false; + } + return true; + } + + @Override + protected void decompilerActionPerformed(DecompilerActionContext context) { + DecompilerPanel decompilerPanel = controller.getDecompilerPanel(); + final ClangToken tokenAtCursor = decompilerPanel.getTokenAtCursor(); + HighVariable variable = tokenAtCursor.getHighVariable(); + HighSymbol highSymbol = variable.getSymbol(); + highSymbol.setTypeLock(true); + retypeSymbol(highSymbol, tokenAtCursor.getVarnode(), highSymbol.getDataType()); + } + +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RetypeVariableAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RetypeVariableAction.java index 3db754b19f..d999e52281 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RetypeVariableAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/RetypeVariableAction.java @@ -38,9 +38,15 @@ import ghidra.util.data.DataTypeParser.AllowedDataTypes; import ghidra.util.exception.*; public class RetypeVariableAction extends AbstractDecompilerAction { - private final DecompilerController controller; + protected final DecompilerController controller; private final PluginTool tool; + protected RetypeVariableAction(String name, PluginTool tool, DecompilerController controller) { + super(name); + this.tool = tool; + this.controller = controller; + } + public RetypeVariableAction(PluginTool tool, DecompilerController controller) { super("Retype Variable"); this.tool = tool; @@ -124,7 +130,7 @@ public class RetypeVariableAction extends AbstractDecompilerAction { return chooserDialog.getUserChosenDataType(); } - private void retypeSymbol(HighSymbol highSymbol, Varnode exactSpot, DataType dt) { + protected void retypeSymbol(HighSymbol highSymbol, Varnode exactSpot, DataType dt) { HighFunction hfunction = highSymbol.getHighFunction(); boolean commitRequired = checkFullCommit(highSymbol, hfunction); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java index 84191953f5..1a106184c1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java @@ -261,7 +261,17 @@ public class HighSymbol { public boolean isNameLocked() { return namelock; } - + + /** + * If this returns true, the decompiler will not speculatively merge this with + * other variables. + * Currently, being isolated is equivalent to being typelocked. + * @return true if this will not be merged with other variables + */ + public boolean isIsolated() { + return typelock; + } + /** * @return true if the symbol's value is considered read-only (by the decompiler) */ @@ -323,6 +333,9 @@ public class HighSymbol { if (isVolatile) { SpecXmlUtils.encodeBooleanAttribute(buf, "volatile", true); } + if (isIsolated()) { + SpecXmlUtils.encodeBooleanAttribute(buf, "merge", false); + } SpecXmlUtils.encodeSignedIntegerAttribute(buf, "cat", category); if (categoryIndex >= 0) { SpecXmlUtils.encodeSignedIntegerAttribute(buf, "index", categoryIndex); @@ -356,6 +369,12 @@ public class HighSymbol { if ((namelockstr != null) && (SpecXmlUtils.decodeBoolean(namelockstr))) { namelock = true; } +// isolate = false; +// String isolatestr = symel.getAttribute("merge"); +// if ((isolatestr != null) && !SpecXmlUtils.decodeBoolean(isolatestr)) { +// isolate = true; +// } + name = symel.getAttribute("name"); categoryIndex = -1; category = -1;