mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-09-13 21:56:19 +00:00
GP-3919 Decompiler analysis toggle buttons
This commit is contained in:
parent
0cdbf1ef41
commit
907dc96d16
Binary file not shown.
Before Width: | Height: | Size: 733 B |
|
@ -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|
|
||||
|
|
BIN
Ghidra/Features/Base/src/main/resources/images/slash.png
Normal file
BIN
Ghidra/Features/Base/src/main/resources/images/slash.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
|
@ -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|
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> - 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> - toggle button
|
||||
</para>
|
||||
<para>
|
||||
Quickly turn off the <xref linkend="AnalysisReadOnly"/> decompiler setting.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ToolBarCopy">
|
||||
<title>Copy</title>
|
||||
<para>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 -> Configure</strong></span>
|
||||
<span class="bold"><strong>File -> Configure...</strong></span>
|
||||
</div>
|
||||
<p>
|
||||
menu option, then clicking on the <span class="emphasis"><em>Configure</em></span> link under the
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 |
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue