GP-3919 Decompiler analysis toggle buttons

This commit is contained in:
Ghidra78 2023-11-30 13:55:23 +00:00
parent 0cdbf1ef41
commit 907dc96d16
15 changed files with 628 additions and 9 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

View file

@ -389,7 +389,6 @@ src/main/help/help/topics/MemoryMapPlugin/images/MoveMemory.png||GHIDRA||||END|
src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png||GHIDRA||||END|
src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png||GHIDRA||||END|
src/main/help/help/topics/Misc/Appendix.htm||GHIDRA||||END|
src/main/help/help/topics/Misc/Tips.htm||NONE||||END|
src/main/help/help/topics/Misc/Welcome_to_Ghidra_Help.htm||GHIDRA||||END|
src/main/help/help/topics/Navigation/Navigation.htm||GHIDRA||||END|
src/main/help/help/topics/Navigation/images/GoToDialog.png||GHIDRA||||END|
@ -886,6 +885,7 @@ src/main/resources/images/searchm_obj.gif||GHIDRA||||END|
src/main/resources/images/searchm_pink.gif||GHIDRA||||END|
src/main/resources/images/settings16.gif||GHIDRA||||END|
src/main/resources/images/sitemap_color.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/slash.png||GHIDRA||||END|
src/main/resources/images/smallLeftArrow.png||GHIDRA||||END|
src/main/resources/images/smallRightArrow.png||GHIDRA||||END|
src/main/resources/images/small_minus.png||GHIDRA||||END|

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

View file

@ -96,3 +96,5 @@ src/main/help/help/topics/DecompilePlugin/images/EditFunctionSignature.png||GHID
src/main/help/help/topics/DecompilePlugin/images/ForwardSlice.png||GHIDRA||||END|
src/main/help/help/topics/DecompilePlugin/images/Undefined.png||GHIDRA||||END|
src/main/resources/images/decompileFunction.gif||GHIDRA||reviewed||END|
src/main/resources/images/eliminateUnreachable.png||GHIDRA||||END|
src/main/resources/images/readOnly.png||GHIDRA||||END|

View file

@ -34,7 +34,10 @@ color.bg.decompiler.pcode.dfg.edge.within.block = color.palette.black
color.bg.decompiler.pcode.dfg.edge.between.blocks = color.palette.red
icon.decompiler.action.provider = decompileFunction.gif
icon.decompiler.action.slash = slash.png
icon.decompiler.action.provider.clone = icon.provider.clone
icon.decompiler.action.provider.unreachable = eliminateUnreachable.png
icon.decompiler.action.provider.readonly = readOnly.png
icon.decompiler.action.export = page_edit.png
font.decompiler = font.monospaced

View file

@ -4114,6 +4114,40 @@
</tip>
</sect2>
<sect2 id="ToolBarEliminateUnreachableCode">
<title>Eliminate Unreachable Code</title>
<para>
<guiicon>
<inlinemediaobject>
<imageobject>
<imagedata condition="noscaling" fileref="icon.decompiler.action.provider.unreachable" contentwidth="16px" contentdepth="16px"/>
<imagedata condition="withscaling" fileref="icon.decompiler.action.provider.unreachable" contentwidth="0.15in" contentdepth="0.15in"/>
</imageobject>
</inlinemediaobject>
</guiicon>&nbsp;- toggle button
</para>
<para>
Quickly turn off the <xref linkend="AnalysisUnreachable"/> decompiler setting.
</para>
</sect2>
<sect2 id="ToolBarRespectReadOnly">
<title>Respect Read-only Flags</title>
<para>
<guiicon>
<inlinemediaobject>
<imageobject>
<imagedata condition="noscaling" fileref="icon.decompiler.action.provider.readonly" contentwidth="16px" contentdepth="16px"/>
<imagedata condition="withscaling" fileref="icon.decompiler.action.provider.readonly" contentwidth="0.15in" contentdepth="0.15in"/>
</imageobject>
</inlinemediaobject>
</guiicon>&nbsp;- toggle button
</para>
<para>
Quickly turn off the <xref linkend="AnalysisReadOnly"/> decompiler setting.
</para>
</sect2>
<sect2 id="ToolBarCopy">
<title>Copy</title>
<para>

View file

@ -4,7 +4,7 @@
<title>Program Annotations Affecting the Decompiler</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerConcepts.html" title="Decompiler Concepts">

View file

@ -4,7 +4,7 @@
<title>Decompiler Concepts</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerIntro.html" title="Decompiler">

View file

@ -4,7 +4,7 @@
<title>Decompiler</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="Decompiler.html" title="Decompiler">
@ -43,7 +43,7 @@
a Code Browser by selecting the
</p>
<div class="informalexample">
<span class="bold"><strong>File -&gt; Configure</strong></span>
<span class="bold"><strong>File -&gt; Configure...</strong></span>
</div>
<p>
menu option, then clicking on the <span class="emphasis"><em>Configure</em></span> link under the

View file

@ -4,7 +4,7 @@
<title>Decompiler Window</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerOptions.html" title="Decompiler Options">
@ -303,6 +303,34 @@
</table></div>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ToolBarEliminateUnreachableCode"></a>Eliminate Unreachable Code</h3></div></div></div>
<p>
<span class="guiicon">
<span class="inlinemediaobject"><img src="icon.decompiler.action.provider.unreachable" width="16" height="16"></span>
</span> - toggle button
</p>
<p>
Quickly turn off the <a class="xref" href="DecompilerOptions.html#AnalysisUnreachable"><span class="bold"><strong>Eliminate unreachable code</strong></span></a> decompiler setting.
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ToolBarRespectReadOnly"></a>Respect Read-only Flags</h3></div></div></div>
<p>
<span class="guiicon">
<span class="inlinemediaobject"><img src="icon.decompiler.action.provider.readonly" width="16" height="16"></span>
</span> - toggle button
</p>
<p>
Quickly turn off the <a class="xref" href="DecompilerOptions.html#AnalysisReadOnly"><span class="bold"><strong>Respect read-only flags</strong></span></a> decompiler setting.
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ToolBarCopy"></a>Copy</h3></div></div></div>

View file

@ -1117,6 +1117,21 @@ public class DecompileOptions {
this.eliminateUnreachable = eliminateUnreachable;
}
/**
* @return true if the decompiler currently respects read-only flags
*/
public boolean isRespectReadOnly() {
return readOnly;
}
/**
* Set whether the decompiler should respect read-only flags as part of its analysis.
* @param readOnly is true if read-only flags are respected
*/
public void setRespectReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
/**
* If the decompiler currently applies transformation rules that identify and
* simplify double precision arithmetic operations, true is returned.

View file

@ -53,6 +53,7 @@ import ghidra.util.Swing;
import ghidra.util.bean.field.AnnotatedTextFieldElement;
import ghidra.util.task.SwingUpdateManager;
import resources.Icons;
import resources.MultiIconBuilder;
import utility.function.Callback;
public class DecompilerProvider extends NavigatableComponentProviderAdapter
@ -64,9 +65,26 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
private static final Icon REFRESH_ICON = Icons.REFRESH_ICON;
private static final Icon C_SOURCE_ICON = new GIcon("icon.decompiler.action.provider");
private static final Icon SLASH_ICON = new GIcon("icon.decompiler.action.slash");
private static final Icon TOGGLE_UNREACHABLE_CODE_ICON =
new GIcon("icon.decompiler.action.provider.unreachable");
private static final Icon TOGGLE_UNREACHABLE_CODE_DISABLED_ICON =
new MultiIconBuilder(TOGGLE_UNREACHABLE_CODE_ICON).addCenteredIcon(SLASH_ICON).build();
private static final Icon TOGGLE_READ_ONLY_ICON =
new GIcon("icon.decompiler.action.provider.readonly");
private static final Icon TOGGLE_READ_ONLY_DISABLED_ICON =
new MultiIconBuilder(TOGGLE_READ_ONLY_ICON).addCenteredIcon(SLASH_ICON).build();
private DockingAction pcodeGraphAction;
private DockingAction astGraphAction;
private ToggleDockingAction displayUnreachableCodeToggle;
private ToggleDockingAction respectReadOnlyFlags;
private final DecompilePlugin plugin;
private ClipboardService clipboardService;
private DecompilerClipboardProvider clipboardProvider;
@ -142,7 +160,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "DecompilerIntro"));
addToTool();
redecompileUpdater = new SwingUpdateManager(500, 5000, () -> doRefresh());
redecompileUpdater = new SwingUpdateManager(500, 5000, () -> doRefresh(false));
followUpWorkUpdater = new SwingUpdateManager(() -> doFollowUpWork());
plugin.getTool().addServiceListener(serviceListener);
@ -180,6 +198,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
decompilerOptions.grabFromToolAndProgram(fieldOptions, opt, program);
controller.setOptions(decompilerOptions);
refreshToggleButtons();
controller.display(program, currentLocation, null);
}
}
@ -320,16 +341,39 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
}
}
private void doRefresh() {
private void doRefresh(boolean optionsChanged) {
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
// Current values of toggle buttons
boolean decompilerEliminatesUnreachable = decompilerOptions.isEliminateUnreachable();
boolean decompilerRespectsReadOnlyFlags = decompilerOptions.isRespectReadOnly();
decompilerOptions.grabFromToolAndProgram(fieldOptions, opt, program);
// If the tool options were not changed
if (!optionsChanged) {
// Keep these analysis options the same
decompilerOptions.setEliminateUnreachable(decompilerEliminatesUnreachable);
decompilerOptions.setRespectReadOnly(decompilerRespectsReadOnlyFlags);
}
else {
// Otherwise, keep the new analysis options and update the state of the toggle buttons
refreshToggleButtons();
}
controller.setOptions(decompilerOptions);
if (currentLocation != null) {
controller.refreshDisplay(program, currentLocation, null);
}
}
private void refreshToggleButtons() {
displayUnreachableCodeToggle.setSelected(!decompilerOptions.isEliminateUnreachable());
respectReadOnlyFlags.setSelected(!decompilerOptions.isRespectReadOnly());
}
private void doFollowUpWork() {
if (isBusy()) {
// try again later
@ -357,7 +401,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
if (options.getName().equals(OPTIONS_TITLE) ||
options.getName().equals(GhidraOptions.CATEGORY_BROWSER_FIELDS)) {
doRefresh();
doRefresh(true);
}
}
@ -465,6 +509,15 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
controller.refreshDisplay(program, currentLocation, null);
}
/**
* Update the options from decompilerOptions
*/
void updateOptionsAndRefresh() {
controller.setOptions(decompilerOptions);
refresh();
}
@Override
public ProgramSelection getSelection() {
return currentSelection;
@ -771,6 +824,87 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
refreshAction
.setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ToolBarRedecompile")); // just use the default
displayUnreachableCodeToggle = new ToggleDockingAction("Toggle Unreachable Code", owner) {
@Override
public void actionPerformed(ActionContext context) {
boolean isSelected = this.isSelected();
// Set the option based on the button state
decompilerOptions.setEliminateUnreachable(!isSelected);
updateOptionsAndRefresh();
}
@Override
public void setSelected(boolean isSelected) {
super.setSelected(isSelected);
// Update the icon to have a slash or not
if (!isSelected) {
displayUnreachableCodeToggle
.setToolBarData(new ToolBarData(TOGGLE_UNREACHABLE_CODE_ICON, "A"));
}
else {
displayUnreachableCodeToggle.setToolBarData(
new ToolBarData(TOGGLE_UNREACHABLE_CODE_DISABLED_ICON, "A"));
}
}
@Override
public boolean isEnabledForContext(ActionContext context) {
DecompileData decompileData = controller.getDecompileData();
if (decompileData == null) {
return false;
}
return decompileData.hasDecompileResults();
}
};
displayUnreachableCodeToggle.setDescription("Toggle off to eliminate unreachable code");
displayUnreachableCodeToggle.setHelpLocation(
new HelpLocation(HelpTopics.DECOMPILER, "ToolBarEliminateUnreachableCode"));
respectReadOnlyFlags = new ToggleDockingAction("Toggle Respecting Read-only Flags", owner) {
@Override
public void actionPerformed(ActionContext context) {
boolean isSelected = this.isSelected();
// Set the option based on the button state
decompilerOptions.setRespectReadOnly(!isSelected);
updateOptionsAndRefresh();
}
@Override
public void setSelected(boolean isSelected) {
super.setSelected(isSelected);
// Update the icon to have a slash or not
if (!isSelected) {
respectReadOnlyFlags
.setToolBarData(new ToolBarData(TOGGLE_READ_ONLY_ICON, "A"));
}
else {
respectReadOnlyFlags
.setToolBarData(new ToolBarData(TOGGLE_READ_ONLY_DISABLED_ICON, "A"));
}
}
@Override
public boolean isEnabledForContext(ActionContext context) {
DecompileData decompileData = controller.getDecompileData();
if (decompileData == null) {
return false;
}
return decompileData.hasDecompileResults();
}
};
respectReadOnlyFlags.setDescription("Toggle off to respect readonly flags set on memory");
respectReadOnlyFlags
.setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ToolBarRespectReadOnly"));
// Set the selected state and icon for the above two toggle icons
refreshToggleButtons();
//
// Below are actions along with their groups and subgroup information. The comments
// for each section indicates the logical group for the actions that follow.
@ -999,6 +1133,8 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
GoToPreviousBraceAction goToPreviousBraceAction = new GoToPreviousBraceAction();
addLocalAction(refreshAction);
addLocalAction(displayUnreachableCodeToggle);
addLocalAction(respectReadOnlyFlags);
addLocalAction(selectAllAction);
addLocalAction(defUseHighlightAction);
addLocalAction(forwardSliceAction);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

View file

@ -0,0 +1,401 @@
/* ###
* 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;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import docking.action.ToggleDockingActionIf;
import ghidra.GhidraOptions;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.component.DecompilerController;
import ghidra.framework.options.ToolOptions;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
public class DecompilerToggleButtonTest extends AbstractDecompilerTest {
private Program prog;
@Override
@After
public void tearDown() throws Exception {
super.tearDown();
}
@Override
protected Program getProgram() throws Exception {
return buildProgram();
}
private Program buildProgram() throws Exception {
/*
int b = 1;
int readB(){
return b;
}
int main()
{
int a = 5;
a++;
if (a > 4)
{
a = 0;
}
else
{
a = readB();
}
return a;
}
*/
ProgramBuilder builder =
new ProgramBuilder("TestDecompilerToggleButtons", ProgramBuilder._X64);
// Create the global "b" variable
MemoryBlock bVarBlock = builder.createMemory("bVarBl", "0x104010", 4);
builder.setWrite(bVarBlock, false);
builder.createLabel("0x104010", "b");
builder.setBytes("0x104010", "01 00 00 00");
// Create the "readB" function
MemoryBlock readBFunctionBlock = builder.createMemory("readBFunction", "0x101129", 16);
builder.setWrite(readBFunctionBlock, false);
builder.setBytes("0x101129", "f3 0f 1e fa 55 48 89 e5 8b 05 d9 2e 00 00 5d c3");
builder.createFunction("0x101129");
builder.createLabel("0x101129", "readB");
// Create the "main" function
MemoryBlock mainFunctionBlock = builder.createMemory("mainFunction", "0x101139", 56);
builder.setWrite(mainFunctionBlock, false);
builder.setBytes("0x101139",
"f3 0f 1e fa 55 48 89 e5 48 83 ec 10 c7 45 fc 05 00 00 00 83 45 fc 01 83 7d fc 04 7e " +
"09 c7 45 fc 00 00 00 00 eb 0d b8 00 00 00 00 e8 c0 ff ff ff 89 45 fc 8b 45 fc c9 c3");
builder.createFunction("0x101139");
builder.createLabel("0x101129", "main");
builder.analyze();
prog = builder.getProgram();
return prog;
}
@Test
public void testUnreachableCodeToggle() {
DecompilerController controller = provider.getController();
// Point the decompiler at the "main" function
decompile("0x101139");
waitForSwing();
// Get the decompiled program as a C code string
String resultingC = getResultingCCode(controller);
// Check that the resulting decompilation does NOT contain unreachable code
assertNotNull(resultingC);
assertNotEquals("", resultingC);
assertTrue(resultingC.contains("WARNING: Removing unreachable block"));
ToggleDockingActionIf eliminateUnreachableToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Unreachable Code");
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
// Toggle unreachable code
performAction(eliminateUnreachableToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Get the decompiled program as a C code string
resultingC = getResultingCCode(controller);
// Check that the resulting decompilation now contains unreachable code
assertNotNull(resultingC);
assertNotEquals("", resultingC);
assertFalse(resultingC.contains("WARNING: Removing unreachable block"));
// Check button state - should be pressed down (with slash)
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertTrue(eliminateUnreachableToggleAction.isSelected());
}
@Test
public void testReadOnlyCodeToggle() {
DecompilerController controller = provider.getController();
// Point the decompiler at the "readB" function
decompile("0x101129");
waitForSwing();
// Get the decompiled program as a C code string
String resultingC = getResultingCCode(controller);
// Check that the resulting decompilation does NOT respect read-only flags
assertNotNull(resultingC);
assertNotEquals("", resultingC);
assertTrue(resultingC.contains("return 1;"));
ToggleDockingActionIf respectReadonlyToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Respecting Read-only Flags");
// Check button state - should not be pressed down
assertTrue(respectReadonlyToggleAction.isEnabled());
assertFalse(respectReadonlyToggleAction.isSelected());
// Toggle read-only code visibility
performAction(respectReadonlyToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Get the decompiled program as a C code string
resultingC = getResultingCCode(controller);
// Check that the resulting decompilation now respects read-only flags
assertNotNull(resultingC);
assertNotEquals("", resultingC);
assertTrue(resultingC.contains("return b;"));
// Check button state - should be pressed down (with slash)
assertTrue(respectReadonlyToggleAction.isEnabled());
assertTrue(respectReadonlyToggleAction.isSelected());
}
@Test
public void unreachableCodeToggleDoesNotUpdateOptions() {
// Point the decompiler at the "main" function
decompile("0x101139");
waitForSwing();
ToggleDockingActionIf eliminateUnreachableToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Unreachable Code");
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
// Get the (currently default) options
DecompileOptions decompilerOptions = getOptions();
// Check default state to be eliminating unreachable code
assertTrue(decompilerOptions.isEliminateUnreachable());
// Toggle unreachable code
performAction(eliminateUnreachableToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Grab new options - should be the same as before
decompilerOptions = getOptions();
assertTrue(decompilerOptions.isEliminateUnreachable());
}
@Test
public void buttonsResetOnOptionChange() {
// Point the decompiler at the "main" function
decompile("0x101139");
waitForSwing();
ToggleDockingActionIf eliminateUnreachableToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Unreachable Code");
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
// Get the (currently default) options
DecompileOptions decompilerOptions = getOptions();
// Check default state to be eliminating unreachable code
assertTrue(decompilerOptions.isEliminateUnreachable());
// Set the option to be false (should update the toggle button)
setEliminateUnreachable(false);
// The button state and decompiler options should have updated automatically
decompilerOptions = getOptions();
assertFalse(decompilerOptions.isEliminateUnreachable());
// Check button state - should be pressed down (with slash)
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertTrue(eliminateUnreachableToggleAction.isSelected());
}
@Test
public void buttonStatesRemainOnFunctionSwitch() {
// Point the decompiler at the "main" function
decompile("0x101139");
waitForSwing();
ToggleDockingActionIf eliminateUnreachableToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Unreachable Code");
ToggleDockingActionIf respectReadonlyToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Respecting Read-only Flags");
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
assertTrue(respectReadonlyToggleAction.isEnabled());
assertFalse(respectReadonlyToggleAction.isSelected());
// Toggle unreachable code
performAction(eliminateUnreachableToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Toggle respecting read-only flags
performAction(respectReadonlyToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Check button state - should be pressed down (with slash)
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertTrue(eliminateUnreachableToggleAction.isSelected());
assertTrue(respectReadonlyToggleAction.isEnabled());
assertTrue(respectReadonlyToggleAction.isSelected());
// Switch functions
// Point the decompiler at the "readB" function
decompile("0x101129");
waitForSwing();
// Check button state - should be pressed down (with slash)
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertTrue(eliminateUnreachableToggleAction.isSelected());
assertTrue(respectReadonlyToggleAction.isEnabled());
assertTrue(respectReadonlyToggleAction.isSelected());
}
@Test
public void buttonStatesUpdateWhenHidden() {
// Point the decompiler at the "main" function
decompile("0x101139");
waitForSwing();
ToggleDockingActionIf eliminateUnreachableToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Unreachable Code");
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
// Hide the decompiler panel
tool.showComponentProvider(provider, false);
waitForSwing();
// Change the option to a non-default state
setEliminateUnreachable(false);
// Show the decompiler panel
tool.showComponentProvider(provider, true);
waitForSwing();
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertTrue(eliminateUnreachableToggleAction.isSelected());
}
@Test
public void buttonStatesResetOnReopen() {
// Point the decompiler at the "main" function
decompile("0x101139");
waitForSwing();
ToggleDockingActionIf eliminateUnreachableToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Unreachable Code");
ToggleDockingActionIf respectReadonlyToggleAction =
(ToggleDockingActionIf) getAction(decompiler, "Toggle Respecting Read-only Flags");
// Check button state - should not be pressed down
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
assertTrue(respectReadonlyToggleAction.isEnabled());
assertFalse(respectReadonlyToggleAction.isSelected());
// Toggle unreachable code
performAction(eliminateUnreachableToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Toggle respecting read-only flags
performAction(respectReadonlyToggleAction, provider.getActionContext(null), false);
waitForDecompiler();
// Check button state - should be pressed down (with slash)
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertTrue(eliminateUnreachableToggleAction.isSelected());
assertTrue(respectReadonlyToggleAction.isEnabled());
assertTrue(respectReadonlyToggleAction.isSelected());
// Hide the decompiler panel
tool.showComponentProvider(provider, false);
waitForSwing();
// Show the decompiler panel
tool.showComponentProvider(provider, true);
waitForSwing();
// Check button states - should have reset to tool option state
assertTrue(eliminateUnreachableToggleAction.isEnabled());
assertFalse(eliminateUnreachableToggleAction.isSelected());
assertTrue(respectReadonlyToggleAction.isEnabled());
assertFalse(respectReadonlyToggleAction.isSelected());
}
//==================================================================================================
// Private Methods
//==================================================================================================
private String getResultingCCode(DecompilerController controller) {
return controller.getDecompileData().getDecompileResults().getDecompiledFunction().getC();
}
private DecompileOptions getOptions() {
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
ToolOptions opt = tool.getOptions("Decompiler");
DecompileOptions decompilerOptions = new DecompileOptions();
decompilerOptions.registerOptions(fieldOptions, opt, program);
return decompilerOptions;
}
private void setEliminateUnreachable(boolean enabled) {
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
ToolOptions opt = tool.getOptions("Decompiler");
opt.getOptions("Analysis").setBoolean("Eliminate unreachable code", enabled);
DecompileOptions decompilerOptions = new DecompileOptions();
decompilerOptions.registerOptions(fieldOptions, opt, program);
}
}