Candidate release of source code.

This commit is contained in:
Dan 2019-03-26 13:45:32 -04:00
parent db81e6b3b0
commit 79d8f164f8
12449 changed files with 2800756 additions and 16 deletions

View file

@ -0,0 +1,40 @@
/* ###
* 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 help.screenshot;
import java.util.Map;
import org.junit.Test;
import ghidra.app.plugin.core.help.AboutDomainObjectUtils;
public class AboutScreenShots extends GhidraScreenShotGenerator {
public AboutScreenShots() {
super();
}
@Test
public void testAbout_Program() {
Map<String, String> metaData = program.getMetadata();
metaData.put("Executable Location", "/Users/bob/WinHelloCPP.exe");
AboutDomainObjectUtils.displayInformation(tool, program.getDomainFile(), metaData,
"About WinHelloCPP.exe", null, null);
captureDialog(800, 500);
}
}

View file

@ -0,0 +1,40 @@
/* ###
* 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 help.screenshot;
import java.awt.Color;
import javax.swing.JFrame;
/*package*/ abstract class AbstractSearchScreenShots extends GhidraScreenShotGenerator {
protected static final Color YELLOW_ORANGE = new Color(155, 150, 50);
protected static final Color BLUE_GREEN = new Color(0, 128, 64);
protected static final Color DARK_BLUE = new Color(0, 0, 128);
protected static final Color DARK_GREEN = new Color(0, 128, 0);
@Override
protected String getHelpTopicName() {
return "Search";
}
protected void moveTool(final int x, final int y) {
runSwing(() -> {
JFrame toolFrame = tool.getToolFrame();
toolFrame.setLocation(x, y);
});
}
}

View file

@ -0,0 +1,78 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.comments.CommentsDialog;
import ghidra.app.util.viewer.field.EolCommentFieldFactory;
public class AnnotationsScreenShots extends GhidraScreenShotGenerator {
public AnnotationsScreenShots() {
super();
}
@Test
public void testCommentDialogURLExample() {
goToListing(0x00407716, "Address", true);
showCommentDialog(
"The link below is an example of a URL annotation:\n{@url http://www.google.com}");
captureDialog();
}
@Test
public void testInvalidAnnotationsDialogExample() {
goToListing(0x00407716, "Address", true);
showCommentDialog("Bad annotations:\n{@unknown smile}\n{@sym }");
captureDialog();
}
@Test
public void testRenderedInvalidAnnotation() throws Exception {
String fieldName = EolCommentFieldFactory.FIELD_NAME;
setListingFieldWidth(fieldName, 400);
setCommentFieldText("Bad annotations:\n{@unknown smile}\n{@sym }");
captureListingField(0x00407716, fieldName, 100);
}
@Test
public void testRenderedURLExample() throws Exception {
String fieldName = EolCommentFieldFactory.FIELD_NAME;
setListingFieldWidth(fieldName, 400);
setCommentFieldText(
"The link below is an example of a URL annotation:\n{@url http://www.google.com}");
captureListingField(0x00407716, fieldName, 100);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void setCommentFieldText(String text) {
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
plugin.goToField(addr(0x00407716), "Address", 0, 0);
performAction("Set EOL Comment", "CommentsPlugin", false);
CommentsDialog dialog = (CommentsDialog) getDialog();
prepareCommentsDialog(dialog, text);
pressButtonByText(dialog, "OK");
}
}

View file

@ -0,0 +1,70 @@
/* ###
* 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 help.screenshot;
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.util.List;
import org.junit.Test;
import docking.action.DockingActionIf;
import ghidra.app.plugin.core.assembler.AssembleDockingAction;
import ghidra.app.plugin.core.assembler.AssemblerPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.framework.plugintool.util.PluginException;
public class AssemblerPluginScreenShots extends GhidraScreenShotGenerator {
@Test
public void testCaptureAssembler() throws PluginException, AWTException, InterruptedException {
setToolSize(1000, 800);
positionListingTop(0x00405120);
positionCursor(0x0040512e);
tool.addPlugin(AssemblerPlugin.class.getName());
String fullActionName = "Assemble (AssemblerPlugin)";
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
AssembleDockingAction action = (AssembleDockingAction) actions.get(0);
performAction(action, true);
Robot rob = new Robot();
rob.keyPress(KeyEvent.VK_RIGHT);
rob.keyRelease(KeyEvent.VK_RIGHT);
// TODO: Will this work on Mac? control vs command
rob.keyPress(KeyEvent.VK_CONTROL);
rob.keyPress(KeyEvent.VK_SPACE);
rob.keyRelease(KeyEvent.VK_SPACE);
rob.keyRelease(KeyEvent.VK_CONTROL);
Thread.sleep(100);
rob.keyPress(KeyEvent.VK_ESCAPE);
rob.keyRelease(KeyEvent.VK_ESCAPE);
Thread.sleep(100);
rob.keyPress(KeyEvent.VK_CONTROL);
rob.keyPress(KeyEvent.VK_SPACE);
rob.keyRelease(KeyEvent.VK_SPACE);
rob.keyRelease(KeyEvent.VK_CONTROL);
captureProvider(CodeViewerProvider.class);
}
}

View file

@ -0,0 +1,143 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.concurrent.CountDownLatch;
import org.junit.Test;
import docking.DialogComponentProvider;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.util.task.TaskMonitor;
public class AutoAnalysisPluginScreenShots extends GhidraScreenShotGenerator {
public AutoAnalysisPluginScreenShots() {
super();
}
@Override
public void loadDefaultTool() {
// not tool for this test
}
@Test
public void testAutoAnalysis() {
Color darkGreen = new Color(20, 154, 65);
Color darkBlue = new Color(10, 62, 149);
image = new BufferedImage(700, 400, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 700, 400);
drawText("(1) User Disassembles Code", Color.BLACK, new Point(160, 30), 24);
drawArrow(darkBlue, new Point(325, 35), new Point(325, 70));
drawText("(new code)", darkGreen, new Point(270, 90), 24);
drawText("(2) Function Analyzer", Color.BLACK, new Point(0, 150), 24);
drawArrow(darkBlue, new Point(265, 82), new Point(180, 120));
drawText("(new function)", darkGreen, new Point(100, 190), 24);
drawText("(3) Stack Analyzer", Color.BLACK, new Point(10, 230), 24);
drawArrow(darkBlue, new Point(50, 155), new Point(50, 205));
drawText("(4) Operand Analyzer", Color.BLACK, new Point(180, 290), 24);
drawArrow(darkBlue, new Point(300, 94), new Point(300, 260));
drawText("(5) Data Reference Analyzer", Color.BLACK, new Point(280, 350), 24);
drawArrow(darkBlue, new Point(350, 94), new Point(490, 325));
Point p1 = new Point(447, 355);
Point p2 = new Point(447, 395);
Point p3 = new Point(690, 395);
drawLine(darkBlue, 3, p1, p2);
drawLine(darkBlue, 3, p2, p3);
drawArrow(darkBlue, p3, new Point(404, 88));
}
@Test
public void testCaptureAutoAnalysisOptions() {
showAnalysisOptions("Data Reference");
captureDialog(800, 400);
}
@Test
public void testCaptureBackgroundAnalysisTasks() throws InterruptedException {
CountDownLatch start = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(1);
TestBackgroundCommand cmd = new TestBackgroundCommand(start, end);
tool.executeBackgroundCommand(cmd, program);
start.await();
waitForPostedSwingRunnables();
captureWindow();
end.countDown();
int width = image.getWidth(null);
int height = image.getHeight(null);
crop(new Rectangle(width - 400, height - 120, 400, 120));
}
@Test
public void testCaptureProgramOptions() {
showProgramOptions("Analyzers");
DialogComponentProvider dialog = getDialog();
Component comp = findComponentByName(dialog.getComponent(), "Analysis Panel");
setSelectedAnayzer(comp, "Reference");
captureDialog(1000, 600);
}
//==================================================================================================
// Inner Classes
//==================================================================================================
class TestBackgroundCommand extends BackgroundCommand {
private CountDownLatch start;
private CountDownLatch end;
TestBackgroundCommand(CountDownLatch start, CountDownLatch end) {
super("Test", true, true, false);
this.start = start;
this.end = end;
setStatusMsg("Applying Function Signatures");
}
@Override
public boolean applyTo(DomainObject obj, final TaskMonitor monitor) {
monitor.initialize(100);
monitor.setProgress(65);
monitor.setMessage("Applying Function Signatures");
runSwing(new Runnable() {
@Override
public void run() {
invokeInstanceMethod("update", monitor);
}
});
start.countDown();
try {
end.await();
}
catch (InterruptedException e) {
// so what?
}
return true;
}
}
}

View file

@ -0,0 +1,208 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import ghidra.GhidraOptions;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.colorizer.ColorizingService;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
import ghidra.app.util.viewer.field.*;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.format.FormatManager;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.MarginProvider;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.util.OptionsService;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.block.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitorAdapter;
public class BlockModelScreenShots extends GhidraScreenShotGenerator {
public BlockModelScreenShots() {
super();
}
@Test
public void testBasicBlockCode() throws Exception {
closeProvider(DataTypesProvider.class);
closeProvider(ViewManagerComponentProvider.class);
disableFlowArrows();
createMinimalFormat();
enlargeFont();
AddressSet addressSet = new AddressSet();
addressSet.addRange(addr(0x004074c6), addr(0x004074fa).subtract(1));
restrictView(addressSet);
highlightCodeBlocks(addressSet);
//crop just the needed fields and pad the image
goToListing(0x0401de0);
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
ListingPanel lp = cb.getListingPanel();
Dimension size = lp.getPreferredSize();
final Window window = windowForComponent(lp);
runSwing(() -> {
Point p = window.getLocation();
p.y = 50;
window.setLocation(p);
});
setWindowSize(window, size.width, 970);
captureComponent(lp);
}
private void restrictView(final AddressSet addressSet) {
runSwing(() -> {
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
ListingPanel lp = cb.getListingPanel();
lp.setView(addressSet);
lp.setNeverSroll();
});
}
private void highlightCodeBlocks(final AddressSet addressSet) {
int tx = program.startTransaction("Test");
runSwing(() -> {
ColorizingService colorizer = tool.getService(ColorizingService.class);
Color c1 = new Color(0xE8F2FE);
Color c2 = new Color(170, 204, 245);
Color color = c1;
BasicBlockModel basicBlockModel = new BasicBlockModel(program);
CodeBlockIterator iterator;
try {
iterator = basicBlockModel.getCodeBlocksContaining(addressSet,
TaskMonitorAdapter.DUMMY_MONITOR);
while (iterator.hasNext()) {
CodeBlock block = iterator.next();
Address min = block.getMinAddress();
Address max = block.getMaxAddress();
colorizer.setBackgroundColor(min, max, color);
color = (color == c1) ? c2 : c1;
}
}
catch (CancelledException e) {
// can't happen--dummy monitor
}
});
program.endTransaction(tx, true);
waitForSwing();
}
private void enlargeFont() {
runSwing(() -> {
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
Font font = options.getFont(GhidraOptions.OPTION_BASE_FONT, null);
options.setFont(GhidraOptions.OPTION_BASE_FONT, font.deriveFont(18f));
});
}
private void disableFlowArrows() {
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
final ListingPanel lp = cb.getListingPanel();
@SuppressWarnings("unchecked")
final List<MarginProvider> list =
new ArrayList<>((List<MarginProvider>) getInstanceField("marginProviders", lp));
runSwing(() -> {
invokeInstanceMethod("buildPanels", lp);
for (MarginProvider marginProvider : list) {
lp.removeMarginProvider(marginProvider);
}
});
}
private ListingPanel createMinimalFormat() {
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
final ListingPanel lp = cb.getListingPanel();
runSwing(() -> {
FormatManager newFormat = createFormat();
lp.setFormatManager(newFormat);
});
return lp;
}
private FormatManager createFormat() {
OptionsService options = tool.getService(OptionsService.class);
ToolOptions displayOptions = options.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
ToolOptions fieldOptions = options.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
FormatManager manager = new FormatManager(displayOptions, fieldOptions);
for (int i = 0; i < manager.getNumModels(); i++) {
FieldFormatModel formatModel = manager.getModel(i);
int numRows = formatModel.getNumRows();
for (int row = 0; row < numRows; row++) {
FieldFactory[] allRowFactories = formatModel.getFactorys(row);
for (int col = allRowFactories.length - 1; col >= 0; col--) {
FieldFactory fieldFactory = allRowFactories[col];
// Msg.debug(this, "checking factory: " + fieldFactory.getFieldName());
if (fieldFactory.getFieldName().indexOf("XRef") != -1) {
formatModel.removeFactory(row, col);
}
else if (fieldFactory.getFieldName().equals(
EolCommentFieldFactory.FIELD_NAME)) {
formatModel.removeFactory(row, col);
}
else if (fieldFactory.getFieldName().equals(AddressFieldFactory.FIELD_NAME)) {
fieldFactory.setWidth(fieldFactory.getWidth() + 25);
formatModel.updateRow(row);
}
else if (fieldFactory.getFieldName().equals(OperandFieldFactory.FIELD_NAME)) {
fieldFactory.setWidth(fieldFactory.getWidth() + 25);
formatModel.updateRow(row);
}
}
}
}
for (int i = 0; i < manager.getNumModels(); i++) {
FieldFormatModel codeUnitFormat = manager.getModel(i);
int numRows = codeUnitFormat.getNumRows();
for (int j = numRows - 1; j >= 0; j--) {
FieldFactory[] allRowFactories = codeUnitFormat.getFactorys(j);
if (allRowFactories.length == 0) {
codeUnitFormat.removeRow(j);
}
}
}
return manager;
}
}

View file

@ -0,0 +1,92 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import docking.DialogComponentProvider;
import ghidra.app.plugin.core.bookmark.BookmarkProvider;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
public class BookmarkPluginScreenShots extends GhidraScreenShotGenerator {
@Test
public void testAddBookmarkDialog() {
performAction("Add Bookmark", "BookmarkPlugin", false);
captureDialog();
}
@Test
public void testBefore() {
removeFlowArrows();
positionListingTop(0x40f66a);
addSelection(0x40f66c, 0x40f66f);
addSelection(0x40f672, 0x40f672);
addSelection(0x40f676, 0x40f676);
captureIsolatedProvider(CodeViewerProvider.class, 500, 350);
}
@Test
public void testAfter() {
removeFlowArrows();
createBookmarks();
captureIsolatedProvider(CodeViewerProvider.class, 500, 350);
}
@Test
public void testBookmarks() {
removeFlowArrows();
createBookmarks();
performAction("Show Bookmarks", "BookmarkPlugin", true);
captureIsolatedProvider(BookmarkProvider.class, 900, 300);
}
@Test
public void testBookmarksFilter() {
performAction("Show Bookmarks", "BookmarkPlugin", true);
performAction("Filter Bookmarks", "BookmarkPlugin", false);
waitForSwing();
DialogComponentProvider dialog = waitForDialogComponent("Bookmark Filter");
captureDialog(dialog);
close(dialog);
waitForSwing();
}
@Test
public void testMarkerForBookmark() {
removeFlowArrows();
closeProvider(DataTypesProvider.class);
positionListingTop(0x4058ed);
createBookmark(0x4058fc);
program.flushEvents();
captureToolWindow(810, 500);
}
private void createBookmarks() {
positionListingTop(0x40f66a);
addSelection(0x40f66c, 0x40f66f);
addSelection(0x40f672, 0x40f672);
addSelection(0x40f676, 0x40f676);
performAction("Add Bookmark", "BookmarkPlugin", false);
pressOkOnDialog();
}
}

View file

@ -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 help.screenshot;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import ghidra.app.plugin.core.clear.ClearCmd;
import ghidra.app.util.AddressInput;
import ghidra.program.model.address.AddressSet;
public class ByteViewerPluginScreenShots extends GhidraScreenShotGenerator {
public ByteViewerPluginScreenShots() {
super();
}
@Test
public void testByteViewer() {
ComponentProvider provider = getProvider("Bytes");
showProvider(provider.getClass());
goToListing(0x400000);
captureIsolatedProvider(provider.getClass(), 500, 400);
}
@Test
public void testByteViewerOptionsDialog() {
performAction("Byte Viewer Options", "ByteViewerPlugin", false);
captureDialog();
}
@Test
public void testByteViewerExample() {
AddressSet set = new AddressSet(addr(0x40b000));
ClearCmd cmd = new ClearCmd(set);
tool.execute(cmd, program);
ComponentProvider provider = getProvider("Bytes");
showProvider(provider.getClass());
goToListing(0x41cc08);
goToListing(0x40b003);
captureIsolatedProvider(provider.getClass(), 500, 400);
}
@Test
public void testByteViewerResults() {
AddressSet set = new AddressSet(addr(0x40b000));
ClearCmd cmd = new ClearCmd(set);
tool.execute(cmd, program);
ComponentProvider provider = getProvider("Bytes");
showProvider(provider.getClass());
performAction("Byte Viewer Options", "ByteViewerPlugin", false);
goToListing(0x41cc08);
goToListing(0x40b003);
final DialogComponentProvider dialog = getDialog();
runSwing(new Runnable() {
@Override
public void run() {
AddressInput addressInput =
(AddressInput) getInstanceField("addressInputField", dialog);
addressInput.setAddress(addr(0x40b003));
}
});
pressOkOnDialog();
goToListing(0x41cc08);
goToListing(0x40b000);
goToListing(0x40b003);
captureIsolatedProvider(provider.getClass(), 500, 400);
}
}

View file

@ -0,0 +1,71 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.widgets.OptionDialog;
import ghidra.app.plugin.core.cparser.CParserPlugin;
import ghidra.util.Msg;
public class CParserPluginScreenShots extends GhidraScreenShotGenerator {
@Override
public void setUp() throws Exception {
super.setUp();
loadPlugin(CParserPlugin.class);
}
@Test
public void testParseCSource() {
performAction("Import C DataTypes", "CParserPlugin", false);
captureDialog();
closeAllWindowsAndFrames();
}
@Test
public void testParseError() {
Msg.showInfo(getClass(), null, "Parse Errors",
"C Parser: Encountered errors during parse.\n" +
" in C:\\tmp\\samp.h near line 12\n " +
" near token: \"This function or variable may be unsafe. Consider using \" \n" +
" Last Valid Dataype: PCUWSTR");
captureDialog();
closeAllWindowsAndFrames();
}
@Test
public void testUseOpenArchives() {
performAction("Import C DataTypes", "CParserPlugin", false);
DialogComponentProvider parseDialog = getDialog();
pressButtonByText(parseDialog, "Parse to Program", false);
OptionDialog confirmDialog =
waitForDialogComponent(null, OptionDialog.class, DEFAULT_WINDOW_TIMEOUT);
pressButtonByText(confirmDialog, "Continue");
OptionDialog useOpenArchivesDialog = waitForDialogComponent(null, OptionDialog.class, 5000);
captureDialog(useOpenArchivesDialog);
closeAllWindowsAndFrames();
}
}

View file

@ -0,0 +1,48 @@
/* ###
* 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 help.screenshot;
import javax.swing.JSplitPane;
import org.junit.Test;
import docking.ComponentProvider;
import ghidra.app.plugin.core.calltree.CallTreeProvider;
public class CallTreePluginScreenShots extends GhidraScreenShotGenerator {
public CallTreePluginScreenShots() {
super();
}
@Test
public void testCallTreeWindow() {
positionListingTop(0x4014e0);
performAction("Show Function Call Trees", "CallTreePlugin", true);
runSwing(new Runnable() {
@Override
public void run() {
ComponentProvider provider = getProvider(CallTreeProvider.class);
JSplitPane splitPane = (JSplitPane) getInstanceField("splitPane", provider);
splitPane.setResizeWeight(0.5);
}
});
captureIsolatedProvider(CallTreeProvider.class, 700, 500);
}
}

View file

@ -0,0 +1,40 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
public class ClearPluginScreenShots extends GhidraScreenShotGenerator {
public ClearPluginScreenShots() {
super();
}
@Test
public void testClearFlow() {
positionListingTop(0x401000);
performAction("Clear Flow and Repair", "ClearPlugin", false);
captureDialog();
}
@Test
public void testClearWithOptions() {
positionListingTop(0x401000);
performAction("Clear With Options", "ClearPlugin", false);
captureDialog();
}
}

View file

@ -0,0 +1,190 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import javax.swing.*;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.widgets.fieldpanel.FieldPanel;
import ghidra.app.plugin.core.clipboard.CopyPasteSpecialDialog;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.util.viewer.field.MnemonicFieldFactory;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
public class ClipboardPluginScreenShots extends GhidraScreenShotGenerator {
public ClipboardPluginScreenShots() {
super();
}
@Test
public void testCaptureCopySpecial() {
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
ProgramSelection sel = cb.getCurrentSelection();
Msg.debug(this, "selection: " + sel);
makeSelection(0x401000, 0x401000);
sel = cb.getCurrentSelection();
Msg.debug(this, "selection: " + sel);
showCopySpecialDialog();
captureDialog();
}
@Test
public void testCaptureCopySpecialAgain() {
long start = 0x406604;
long end = 0x40660d;
makeSelection(start, end);
copySpecialLabelsAndComments();
waitForSwing();
showCopyMenu();
captureMenu();
cropCopyMenu();
Image menuImage = image;
captureListingCallMnemonic(start, end);
placeImagesSideBySide(image, menuImage);
drawBorder(Color.BLACK);
}
private void cropCopyMenu() {
JPopupMenu popupMenu = getPopupMenu();
MenuElement[] elements = popupMenu.getSubElements();
//
// we expect the following menu items in order:
// -Copy
// -Copy Special
// -Copy "Labels and Comments"
// -Paste
//
int index = -1;
int n = elements.length;
for (int i = 0; i < n; i++) {
JMenuItem item = (JMenuItem) elements[i];
String text = item.getText();
if ("Copy".equals(text)) {
// found it!
index = i;
break;
}
}
if (index == -1) {
throw new AssertException("Couldn't find copy menu item");
}
Rectangle copySectionBounds = new Rectangle();
int height = 0;
JMenuItem item = (JMenuItem) elements[index];
Rectangle itemBounds = item.getBounds();
copySectionBounds.x = itemBounds.x;
copySectionBounds.y = itemBounds.y;
copySectionBounds.width = itemBounds.width;
height += itemBounds.height;
item = (JMenuItem) elements[index + 1];
itemBounds = item.getBounds();
height += itemBounds.height;
item = (JMenuItem) elements[index + 2];
itemBounds = item.getBounds();
height += itemBounds.height;
item = (JMenuItem) elements[index + 3];
itemBounds = item.getBounds();
height += itemBounds.height;
copySectionBounds.height = height;
crop(copySectionBounds);
}
private void showCopyMenu() {
long addr = 0x406606;
positionListingCenter(addr);
positionCursor(addr, MnemonicFieldFactory.FIELD_NAME);
rightClickCursor();
}
private void copySpecialLabelsAndComments() {
showCopySpecialDialog();
selectLabelsAndComments();
pressOkOnDialog();
}
private void selectLabelsAndComments() {
DialogComponentProvider copySpecialDialog = getDialog(CopyPasteSpecialDialog.class);
Object listPanel = getInstanceField("listPanel", copySpecialDialog);
final JList<?> list = (JList<?>) getInstanceField("list", listPanel);
runSwing(new Runnable() {
@Override
public void run() {
ListModel<?> model = list.getModel();
int size = model.getSize();
for (int i = 0; i < size; i++) {
Object value = model.getElementAt(i);
if ("Labels and Comments".equals(value.toString())) {
list.setSelectedIndex(i);
return;
}
}
throw new RuntimeException("Could not find 'Labels and Comments' copy action");
}
});
waitForSwing();
}
private void captureListingCallMnemonic(long start, long end) {
captureListingRange(start, end, 500);
Rectangle imageBounds = new Rectangle();
positionCursor(0x406606, MnemonicFieldFactory.FIELD_NAME);
Rectangle cursorBounds = getCursorBounds();
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
FieldPanel fieldPanel = plugin.getFieldPanel();
CodeViewerProvider provider = plugin.getProvider();
cursorBounds.setLocation(SwingUtilities.convertPoint(fieldPanel, cursorBounds.getLocation(),
provider.getListingPanel()));
imageBounds.x = cursorBounds.x - 30; // move back some
imageBounds.y = cursorBounds.y - 30; // move up some to get the previous instruction
imageBounds.width = 100;
imageBounds.height = image.getHeight(null);
crop(imageBounds);
}
private void showCopySpecialDialog() {
performAction("Copy Special", "ClipboardPlugin", false);
}
}

View file

@ -0,0 +1,372 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertEquals;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.*;
import org.junit.Test;
import docking.DockableComponent;
import docking.widgets.fieldpanel.FieldPanel;
import ghidra.GhidraOptions;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
import ghidra.app.util.viewer.field.*;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.CodeUnit;
public class CodeBrowserPluginScreenShots extends GhidraScreenShotGenerator {
private FieldPanel fieldPanel;
private CodeBrowserPlugin plugin;
public CodeBrowserPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
plugin = getPlugin(tool, CodeBrowserPlugin.class);
fieldPanel = plugin.getFieldPanel();
}
@Test
public void testCaptureClosedStructure() {
removeFlowArrows();
long structAddr = 0x0040be45;
createDetailedStructure(structAddr);
positionListingTop(0x0040be40);
goToListing(structAddr, AddressFieldFactory.FIELD_NAME, false);
Rectangle cursor = getCursorBounds();
captureListingRange(0x0040be40, 0x0040be56, 600);
drawBorder(Color.BLACK);
drawTextWithArrowNearOpenStructureIcon("Closed", cursor);
}
@Test
public void testCaptureOpenStructure() {
removeFlowArrows();
long structAddr = 0x0040be45;
createDetailedStructure(structAddr);
positionListingTop(0x0040be40);
positionCursor(structAddr, OpenCloseFieldFactory.FIELD_NAME);
leftClickCursor();
positionCursor(structAddr, AddressFieldFactory.FIELD_NAME);
Rectangle cursor = getCursorBounds();
captureListingRange(0x0040be40, 0x0040be56, 600);
drawBorder(Color.BLACK);
drawTextWithArrowNearOpenStructureIcon("Open", cursor);
}
private void drawTextWithArrowNearOpenStructureIcon(String text, Rectangle cursorBounds) {
//
// Make some room to draw our annotations (text and an arrow)
//
Dimension whitespace = new Dimension(150, 10);
padImage(Color.WHITE, whitespace.height, whitespace.width, 10, 10);
//
// Draw text inside of the newly padded space
//
int arrowStartY = 40;
int textStartX = 20;
int textStartY = arrowStartY - 4;// up just a bit
Point textPoint = new Point(textStartX, textStartY);
int size = 24;
Color textColor = Color.MAGENTA.darker();
drawText(text, textColor, textPoint, size);
//
// Draw an arrow from the text above to the 'open structure' icon
//
int arrowStartX = 60;
Color arrowColor = Color.GREEN.darker();
Point arrowStart = new Point(arrowStartX, arrowStartY);
int addressFieldStartX = 40;
int listingOffsetX = whitespace.width;
int listingOffsetY = whitespace.height;
int arrowEndX = listingOffsetX + (cursorBounds.x - addressFieldStartX);// a bit of fudge
int arrowEndY = listingOffsetY + (cursorBounds.y + (cursorBounds.height / 2));
Point arrowEnd = new Point(arrowEndX, arrowEndY);
drawArrow(arrowColor, arrowStart, arrowEnd);
}
@Test
public void testCaptureCodeBrowser_OperandHighlight() {
setToolSize(1000, 800);
positionListingTop(0x0405352);
positionCursor(0x0405354, OperandFieldFactory.FIELD_NAME);
middleClickCursor();
captureListingRange(0x0405352, 0x0405398, 700);
}
@Test
public void testCaptureSelectionTable() {
setToolSize(1100, 700);
positionListingTop(0x0406bd7);
makeSelection(0x0406be1, 0x0406bf1);
performAction("Create Table From Selection", "CodeBrowserPlugin", true);
Window window = waitForWindowByTitleContaining(null, "Selection Table", 2000);
Point loc = plugin.getListingPanel().getLocationOnScreen();
Dimension size = window.getSize();
window.setBounds(loc.x + 300, loc.y + 150, size.width, 300);
captureProvider(CodeViewerProvider.class);
}
@Test
public void testCaptureCodeBrowser() {
closeProvider(DataTypesProvider.class);
goToListing(0x0408363);
captureToolWindow(1000, 500);
}
@Test
public void testCaptureCodeBrowserColors() {
showOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
captureDialog(1020, 630);
}
@Test
public void testCaptureCodeBrowserReferencePopup() {
closeProvider(DataTypesProvider.class);
closeProvider(ViewManagerComponentProvider.class);
removeFlowArrows();
removeField("Bytes");
setToolSize(1000, 600);
positionListingTop(0x00404936);
positionCursor(0x00404946, OperandFieldFactory.FIELD_NAME);
Rectangle cursor = getCursorBounds();
initiateHover(cursor);
resizeHoverWindow();
paintFix(null);// This doesn't use its parameter right now
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
captureProviderWithScreenShot(provider);
}
@Test
public void testCaptureCodeBrowserWithFlowArrows() {
long topAddr = 0x00040a435L;
long bottomAddr = 0x00040a454L;
long conditionalJumpAddr = 0x040a442;
long unconditionalJumpAddr = 0x040a44e;
positionListingTop(topAddr);
positionCursor(conditionalJumpAddr);
Rectangle conditional = getCursorBounds();
positionCursor(unconditionalJumpAddr);
Rectangle unconditional = getCursorBounds();
captureListingRange(topAddr, bottomAddr, 600);
int padX = 100;
padImage(Color.LIGHT_GRAY, 0, padX, 0, 0);
int y = conditional.y + 10;
drawText("Conditional", Color.BLACK, new Point(10, y), 12);
drawText(" Jump", Color.BLACK, new Point(10, y + 15), 12);
y = unconditional.y + 10;
drawText("Unconditional", Color.BLACK, new Point(10, y), 12);
drawText(" Jump", Color.BLACK, new Point(10, y + 15), 12);
}
@Test
public void testCaptureCodeBrowserWithMarkers() throws Exception {
createBookmark(0x41cea0);
createBookmark(0x41ceaa);
performMemorySearch("61 73");
waitForTasks();
positionListingTop(0x41ce9f);
captureIsolatedProvider(CodeViewerProvider.class, 700, 550);
}
@Test
public void testCaptureDataTypeHover() {
removeFlowArrows();
setToolSize(875, 500);
long structAddr = 0x0040be45;
createDetailedStructure(structAddr);
positionListingTop(0x0040be43);
positionCursor(structAddr, MnemonicFieldFactory.FIELD_NAME);
Rectangle cursor = getCursorBounds();
initiateHover(cursor);
JWindow popup = (JWindow) waitForWindowByName("ListingHoverProvider");
paintFix(popup);
captureProvider(CodeViewerProvider.class);
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
captureProviderWithScreenShot(provider);
}
@Test
public void testCaptureHighlight_Example() {
setToolSize(1000, 800);
positionListingTop(0x040364c);
createComment(0x403653, CodeUnit.PRE_COMMENT, "PUSH some stuff");
positionCursor(0x0403653, MnemonicFieldFactory.FIELD_NAME);
middleClickCursor();
captureListingRange(0x040364c, 0x040366f, 700);
}
@Test
public void testCaptureMarkerPopup() {
setToolSize(1400, 1200);
ListingPanel listingPanel = plugin.getListingPanel();
List<OverviewProvider> overviewProviders = listingPanel.getOverviewProviders();
assertEquals(1, overviewProviders.size());
OverviewProvider provider = overviewProviders.get(0);
rightClick(provider.getComponent(), 1, 1);
captureMenu();
}
@Test
public void testCaptureMouseHoverButton() {
setToolSize(500, 400);
CodeViewerProvider provider = plugin.getProvider();
JButton button = findProviderToolBarButton(provider, "Toggle Mouse Hover Popups");
Rectangle bounds = button.getBounds();
Point p = bounds.getLocation();
DockableComponent dockableComponent = getDockableComponent(provider);
dockableComponent.getHeader().setSelected(true);
p = SwingUtilities.convertPoint(button.getParent(), p, dockableComponent);
captureProvider(CodeViewerProvider.class);
int width = image.getWidth(null);
crop(new Rectangle(0, 0, width, 30));
drawOval(new Color(107, 47, 109),
new Rectangle(p.x - 13, p.y - 1, bounds.width + 26, bounds.height + 2), 4);
}
@Test
public void testCaptureNavigationMarkerOptions() {
showOptions("Navigation Markers");
captureDialog(600, 500);
}
@Test
public void testCaptureOpenHeader() {
performAction("Toggle Header", "CodeBrowserPlugin", true);
goToListing(0x00400280);
CodeViewerProvider provider = plugin.getProvider();
JButton button = findProviderToolBarButton(provider, "Toggle Header");
Rectangle bounds = button.getBounds();
Point p = bounds.getLocation();
DockableComponent dockableComponent = getDockableComponent(provider);
dockableComponent.getHeader().setSelected(true);
p = SwingUtilities.convertPoint(button.getParent(), p, dockableComponent);
captureProvider(CodeViewerProvider.class);
int x = p.x - 18;
int y = p.y - 2;
int height = bounds.height + 12;
int width = bounds.width + 34;
Color color = new Color(120, 0, 64);
drawOval(color, new Rectangle(x, y, width, height), 5);
int arrowHeadX = x + (width / 4);
int spacer = 4;
int ovalBottom = y + height + spacer;
int length = 75;
int offset = 30;// tilt the arrow a bit
Point arrorTop = new Point(arrowHeadX - offset, ovalBottom + length);
Point arrowBottom = new Point(arrowHeadX, ovalBottom);
drawArrow(color, arrorTop, arrowBottom);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void resizeHoverWindow() {
final Window window = waitForWindowByName("ListingHoverProvider");
runSwing(() -> window.setSize(650, 350));
waitForSwing();
}
private void initiateHover(final Rectangle cursor) {
runSwing(() -> {
ActionListener al = (ActionListener) getInstanceField("hoverHandler", fieldPanel);
setInstanceField("lastMouseMovedEvent", al,
new MouseEvent(fieldPanel, 0, 0L, 0, cursor.x + 1, cursor.y + 1, 0, false));
al.actionPerformed(null);
});
}
private void createDetailedStructure(long address) {
goToListing(address);
StructureDataType struct = new StructureDataType("MyStruct", 0);
struct.add(new ByteDataType(), "byte1", "This is a comment for the byte datatype");
struct.add(new DoubleDataType(), "????", "Not sure what this double is for");
struct.add(new WordDataType(), "User ID", null);
struct.setDescription(
"This comment describes my struct and spans multiple lines. This structure\nis for demonstration purposes only.");
CreateDataCmd createDataCmd = new CreateDataCmd(addr(address), struct);
tool.execute(createDataCmd, program);
waitForBusyTool(tool);
}
private void createComment(long address, int commentType, String comment) {
goToListing(address);
SetCommentCmd cmd = new SetCommentCmd(addr(address), commentType, comment);
tool.execute(cmd, program);
waitForBusyTool(tool);
}
}

View file

@ -0,0 +1,81 @@
/* ###
* 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 help.screenshot;
import javax.swing.JComponent;
import org.junit.Test;
import docking.ComponentProvider;
import docking.widgets.filter.FilterTextField;
import docking.widgets.table.GTable;
import docking.widgets.table.GTableFilterPanel;
import docking.widgets.table.threaded.ThreadedTableModel;
import ghidra.program.model.listing.*;
public class CommentWindowPluginScreenShots extends GhidraScreenShotGenerator {
public CommentWindowPluginScreenShots() {
super();
}
@Test
public void testCommentsWindow() throws Exception {
//create some interesting comments for the image
createComments(program);
// open the comments window
performAction("Comments", "DockingWindows", true);
// set the filter text for our comments
ComponentProvider provider = getProvider("Comment Window");
setFilterText(provider, "My");
captureIsolatedProviderWindow(provider.getClass(), 440, 260);
}
private void setFilterText(ComponentProvider provider, String text) {
JComponent component = provider.getComponent();
GTable commentTable = (GTable) findComponentByName(component, "CommentTable");
ThreadedTableModel<?, ?> tableModel = (ThreadedTableModel<?, ?>) commentTable.getModel();
FilterTextField filterField = (FilterTextField) findComponentByName(component,
GTableFilterPanel.FILTER_TEXTFIELD_NAME);
setFilterText(filterField, text);
waitForTableModel(tableModel);
}
private void setFilterText(FilterTextField field, String text) {
runSwing(() -> field.setText(text));
waitForSwing();
}
private void createComments(Program prog) throws Exception {
int id = prog.startTransaction("Test");
Listing listing = prog.getListing();
listing.setComment(addr(0x00401006), CodeUnit.EOL_COMMENT, "My EOL comment");
listing.setComment(addr(0x0040101b), CodeUnit.PRE_COMMENT, "My Pre comment");
listing.setComment(addr(0x0040101c), CodeUnit.POST_COMMENT, "My Post comment");
listing.setComment(addr(0x00401020), CodeUnit.PLATE_COMMENT, "My Plate comment");
listing.setComment(addr(0x0040100d), CodeUnit.REPEATABLE_COMMENT, "My Repeatable comment");
prog.endTransaction(id, true);
prog.flushEvents();
waitForSwing();
}
}

View file

@ -0,0 +1,58 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.comments.CommentsDialog;
import ghidra.program.model.address.Address;
public class CommentsPluginScreenShots extends GhidraScreenShotGenerator {
public CommentsPluginScreenShots() {
super();
}
@Test
public void testCaptureComment() {
positionListingTop(0x401000);
performAction("Edit Comments", "CommentsPlugin", false);
captureDialog();
}
@Test
public void testShowCommentHistory() throws Exception {
setCommentFieldText("This is my first comment.", addr(0x401000));
sleep(1000);
setCommentFieldText("This is my second comment.", addr(0x401000));
performAction("Show Comment History", "CommentsPlugin", false);
captureDialog();
}
private void setCommentFieldText(String text, Address addr) {
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
plugin.goToField(addr, "Address", 0, 0);
performAction("Set EOL Comment", "CommentsPlugin", false);
CommentsDialog dialog = (CommentsDialog) getDialog();
prepareCommentsDialog(dialog, text);
pressButtonByText(dialog, "OK");
}
}

View file

@ -0,0 +1,47 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import docking.action.DockingAction;
import ghidra.app.plugin.core.checksums.ComputeChecksumsPlugin;
import ghidra.app.plugin.core.checksums.ComputeChecksumsProvider;
public class ComputeChecksumsPluginScreenShots extends GhidraScreenShotGenerator {
public ComputeChecksumsPluginScreenShots() {
super();
}
@Test
public void testDialog_Blank() {
positionListingTop(0x4014b0);
performAction("GenerateChecksum", "ComputeChecksumsPlugin", true);
captureProvider(ComputeChecksumsProvider.class);
}
@Test
public void testDialog() {
positionListingTop(0x4014b0);
performAction("GenerateChecksum", "ComputeChecksumsPlugin", true);
ComputeChecksumsPlugin plugin = getPlugin(tool, ComputeChecksumsPlugin.class);
DockingAction computeAction = (DockingAction) getAction(plugin, "Compute Checksum");
performAction(computeAction, true);
captureProvider(ComputeChecksumsProvider.class);
}
}

View file

@ -0,0 +1,45 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import ghidra.app.plugin.core.console.ConsoleComponentProvider;
import ghidra.app.services.ConsoleService;
public class ConsolePluginScreenShots extends GhidraScreenShotGenerator {
public ConsolePluginScreenShots() {
super();
}
@Override
public void loadProgram() {
// don't load a program
}
@Test
public void testConsole() {
showProvider(ConsoleComponentProvider.class);
ConsoleService service = tool.getService(ConsoleService.class);
service.addMessage("Sample", "This is a sample console message.");
service.addMessage("MyScript", "This is a sample script output.\n\n");
service.addErrorMessage("Sample", "This is an error message.");
captureIsolatedProvider(ConsoleComponentProvider.class, 600, 300);
}
}

View file

@ -0,0 +1,79 @@
/* ###
* 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 help.screenshot;
import javax.swing.JRadioButton;
import org.junit.Test;
import docking.DialogComponentProvider;
import ghidra.util.table.GhidraTable;
public class DataPluginScreenShots extends GhidraScreenShotGenerator {
public DataPluginScreenShots() {
super();
}
@Test
public void testCreateStructureDialog() {
positionListingTop(0x40d3a4);
makeSelection(0x40d3a4, 0x40d3ab);
performAction("Create Structure", "DataPlugin", false);
DialogComponentProvider dialog = getDialog();
JRadioButton button = (JRadioButton) getInstanceField("exactMatchButton", dialog);
setSelected(button, true);
captureDialog(500, 400);
}
@Test
public void testCreateStructureDialogWithTableSelection() {
positionListingTop(0x40d3a4);
makeSelection(0x40d3a4, 0x40d3ab);
performAction("Create Structure", "DataPlugin", false);
DialogComponentProvider dialog = getDialog();
JRadioButton button = (JRadioButton) getInstanceField("exactMatchButton", dialog);
setSelected(button, true);
GhidraTable table = (GhidraTable) getInstanceField("matchingStructuresTable", dialog);
selectRow(table, 2);
captureDialog(500, 400);
}
@Test
public void testDataSelectionSettings() {
positionListingTop(0x40d3a4);
makeSelection(0x40d3a4, 0x40d3ab);
performAction("Data Settings", "DataPlugin", false);
captureDialog();
}
@Test
public void testDefaultSettings() {
positionListingTop(0x40d3a4);
performAction("Default Data Settings", "DataPlugin", false);
captureDialog();
}
@Test
public void testInstanceSettings() {
positionListingTop(0x40d3a4);
performAction("Data Settings", "DataPlugin", false);
captureDialog();
}
}

View file

@ -0,0 +1,372 @@
/* ###
* 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 help.screenshot;
import java.awt.Component;
import java.awt.Window;
import java.util.*;
import javax.swing.*;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import docking.options.editor.ButtonPanelFactory;
import docking.widgets.DropDownSelectionTextField;
import docking.widgets.tree.GTree;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.plugin.core.compositeeditor.*;
import ghidra.app.plugin.core.datamgr.editor.EnumEditorProvider;
import ghidra.app.plugin.core.datamgr.util.DataTypeChooserDialog;
import ghidra.app.services.DataTypeManagerService;
import ghidra.program.model.data.*;
public class DataTypeEditorsScreenShots extends GhidraScreenShotGenerator {
public DataTypeEditorsScreenShots() {
super();
}
@Test
public void testDialog() {
positionListingTop(0x40D3B8);
performAction("Choose Data Type", "DataPlugin", false);
captureDialog();
}
@Test
public void testDialog_Multiple_Match() throws Exception {
positionListingTop(0x40D3B8);
DropDownSelectionTextField<?> textField = showTypeChooserDialog();
triggerText(textField, "undefined");
DialogComponentProvider dialog = getDialog();
JComponent component = dialog.getComponent();
Window dataTypeDialog = windowForComponent(component);
Window[] popUpWindows = dataTypeDialog.getOwnedWindows();
List<Component> dataTypeWindows = new ArrayList<>(Arrays.asList(popUpWindows));
dataTypeWindows.add(dataTypeDialog);
captureComponents(dataTypeWindows);
closeAllWindowsAndFrames();
}
private DropDownSelectionTextField<?> showTypeChooserDialog() throws Exception {
// type something to trigger indexing so that we avoid the modal dialog, which steals focus
// and then, when done, triggers the text field to select all its text
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
service.getSortedDataTypeList();
performAction("Choose Data Type", "DataPlugin", false);
DropDownSelectionTextField<?> textField =
findComponent(getDialog(), DropDownSelectionTextField.class);
return textField;
}
@Test
public void testDialog_Single_Match() throws Exception {
positionListingTop(0x40D3B8);
DropDownSelectionTextField<?> textField = showTypeChooserDialog();
triggerText(textField, "qword");
DialogComponentProvider dialog = getDialog();
JComponent component = dialog.getComponent();
Window dataTypeDialog = windowForComponent(component);
Window[] popUpWindows = dataTypeDialog.getOwnedWindows();
List<Component> dataTypeWindows = new ArrayList<>(Arrays.asList(popUpWindows));
dataTypeWindows.add(dataTypeDialog);
captureComponents(dataTypeWindows);
}
@Test
public void testDialog_Create_Pointer() throws Exception {
positionListingTop(0x40D3B8);
DropDownSelectionTextField<?> textField = showTypeChooserDialog();
setText(textField, "word*");
captureDialog();
}
@Test
public void testDialog_Select_Tree() {
positionListingTop(0x40D3B8);
performAction("Choose Data Type", "DataPlugin", false);
DialogComponentProvider dialog = getDialog();
final JButton browseButton = findButtonByIcon(dialog, ButtonPanelFactory.BROWSE_ICON);
pressButton(browseButton, false);
waitForSwing();
dialog = getDialog(DataTypeChooserDialog.class);
GTree tree = (GTree) getInstanceField("tree", dialog);
selectPath(tree, "Data Types", "BuiltInTypes", "char");
captureDialog(DataTypeChooserDialog.class, 408, 324);
}
@Test
public void testBytesNumberInputDialog() {
createDetailedStructure(0x40d2b8, false);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
ComponentProvider structureEditor = getProvider(StructureEditorProvider.class);
// get structure table and select a row
CompositeEditorPanel editorPanel =
(CompositeEditorPanel) getInstanceField("editorPanel", structureEditor);
JTable table = editorPanel.getTable();
int numRows = table.getRowCount();
selectRow(table, numRows - 2);
performAction("Cycle: char,string,unicode", "DataTypeManagerPlugin", structureEditor, true);
performAction("Cycle: char,string,unicode", "DataTypeManagerPlugin", structureEditor,
false);
waitForSwing();
captureDialog();
}
@Test
public void testEnumEditor() {
createEnum(0x40d2b8);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
captureIsolatedProvider(EnumEditorProvider.class, 600, 300);
}
@Test
public void testNumDuplicates() {
createDetailedStructure(0x40d2b8, false);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
ComponentProvider structureEditor = getProvider(StructureEditorProvider.class);
// get structure table and select a row
CompositeEditorPanel editorPanel =
(CompositeEditorPanel) getInstanceField("editorPanel", structureEditor);
JTable table = editorPanel.getTable();
int numRows = table.getRowCount();
selectRow(table, numRows - 2);
performAction("Editor: Duplicate Multiple of Component", "DataTypeManagerPlugin",
structureEditor, false);
waitForSwing();
captureDialog();
closeAllWindowsAndFrames();
}
@Test
public void testNumElementsPrompt() {
createDetailedStructure(0x40d2b8, false);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
ComponentProvider structureEditor = getProvider(StructureEditorProvider.class);
// get structure table and select a row
CompositeEditorPanel editorPanel =
(CompositeEditorPanel) getInstanceField("editorPanel", structureEditor);
JTable table = editorPanel.getTable();
int numRows = table.getRowCount();
selectRow(table, numRows - 2);
performAction("Editor: Create Array", "DataTypeManagerPlugin", structureEditor, false);
waitForSwing();
captureDialog();
}
@Test
public void testStructureEditor() {
createDetailedStructure(0x40d2b8, false);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
captureProvider(StructureEditorProvider.class);
}
@Test
public void testStructureEditorAligned() {
createAlignedDetailedStructure(0x40d2b8, false);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
captureProvider(StructureEditorProvider.class);
}
@Test
public void testStructureEditorWithFlexArray() {
createAlignedDetailedStructure(0x40d2b8, true);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
captureProvider(StructureEditorProvider.class);
}
@Test
public void testUnionEditor() {
createUnion(0x40d2b8);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
captureIsolatedProvider(UnionEditorProvider.class, 700, 425);
}
@Test
public void testUnionEditorAligned() {
createAlignedUnion(0x40d2b8);
goToListing(0x40d2b8, true);
performAction("Edit Data Type", "DataPlugin", true);
captureIsolatedProvider(UnionEditorProvider.class, 700, 425);
}
private void createDetailedStructure(long address, boolean includeFlexArray) {
goToListing(address);
StructureDataType struct = new StructureDataType("MyUnalignedStruct", 0);
struct.add(new ByteDataType(), "myByteElement", "unaligned byte");
struct.add(new ByteDataType(), "", "undefined element");
struct.add(new WordDataType(), "myWordElement", "unaligned word");
struct.add(new ByteDataType(), "myByteElement2", "another unaligned byte");
struct.add(new DWordDataType(), "myDWordElement", "unaligned dword");
if (includeFlexArray) {
struct.setFlexibleArrayComponent(CharDataType.dataType, "flex",
"unsized flexible array");
}
struct.clearComponent(1);
struct.setDescription("This is an example of an unaligned structure " +
(includeFlexArray ? "with a flexible char array" : "of size 9") + ".");
CreateDataCmd createDataCmd = new CreateDataCmd(addr(address), struct);
tool.execute(createDataCmd, program);
waitForBusyTool(tool);
}
private void createAlignedDetailedStructure(long address, boolean includeFlexArray) {
goToListing(address);
StructureDataType struct = new StructureDataType("MyAlignedStruct", 0);
struct.add(new ByteDataType(), "myByteElement", "alignment 1");
struct.add(new ByteDataType(), "", "This is my undefined element");
struct.add(new WordDataType(), "myWordElement", "alignment 2");
struct.add(new ByteDataType(), "myByteElement2", "alignment 1");
struct.add(new DWordDataType(), "myDWordElement", "alignment 4");
if (includeFlexArray) {
struct.setFlexibleArrayComponent(CharDataType.dataType, "flex",
"unsized flexible array");
}
struct.clearComponent(1);
struct.setDescription(
"Members internally aligned " + (includeFlexArray ? "with a flexible char array"
: "according to their alignment size") +
". ");
struct.setInternallyAligned(true);
CreateDataCmd createDataCmd = new CreateDataCmd(addr(address), struct);
tool.execute(createDataCmd, program);
waitForBusyTool(tool);
}
private void createUnion(long address) {
goToListing(address);
UnionDataType union = new UnionDataType("MyUnion");
union.add(new ByteDataType(), "myByteElement", "unaligned byte");
union.add(new WordDataType(), "myWordElement", "unaligned word");
union.add(new DWordDataType(), "myDWordElement", "unaligned dword");
union.add(new QWordDataType(), "myQWordElement", "unaligned qword");
union.setDescription("This is an example of an unaligned union.");
CreateDataCmd createDataCmd = new CreateDataCmd(addr(address), union);
tool.execute(createDataCmd, program);
waitForBusyTool(tool);
}
private void createAlignedUnion(long address) {
goToListing(address);
UnionDataType union = new UnionDataType("MyUnion");
union.add(new ByteDataType(), "myByteElement", "aligned byte");
union.add(new WordDataType(), "myWordElement", "aligned word");
union.add(new DWordDataType(), "myDWordElement", "aligned dword");
union.add(new QWordDataType(), "myQWordElement", "aligned qword");
union.setDescription("This is an example of an aligned union.");
union.setInternallyAligned(true);
CreateDataCmd createDataCmd = new CreateDataCmd(addr(address), union);
tool.execute(createDataCmd, program);
waitForBusyTool(tool);
}
private void createEnum(long address) {
goToListing(address);
EnumDataType myEnum = new EnumDataType("ExpressionType", 1);
myEnum.add("TYPE_INT", 1);
myEnum.add("TYPE_FLOAT", 2);
myEnum.add("TYPE_STRING", 3);
myEnum.add("TYPE_UNKNOWN", 4);
myEnum.setDescription("Enumerated data type.");
CreateDataCmd createDataCmd = new CreateDataCmd(addr(address), myEnum);
tool.execute(createDataCmd, program);
waitForBusyTool(tool);
}
}

View file

@ -0,0 +1,351 @@
/* ###
* 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 help.screenshot;
import java.io.File;
import java.util.*;
import javax.swing.*;
import javax.swing.table.TableColumn;
import org.junit.Assert;
import org.junit.Test;
import docking.*;
import docking.action.DockingActionIf;
import docking.widgets.table.GTable;
import docking.widgets.table.GTableCellRenderer;
import docking.widgets.tree.*;
import ghidra.app.plugin.core.datamgr.*;
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
import ghidra.app.plugin.core.datamgr.archive.InvalidFileArchive;
import ghidra.app.plugin.core.datamgr.util.ConflictDialog;
import ghidra.framework.preferences.Preferences;
import ghidra.program.model.data.*;
import ghidra.util.UniversalID;
import ghidra.util.table.GhidraTable;
public class DataTypeManagerPluginScreenShots extends GhidraScreenShotGenerator {
public DataTypeManagerPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
removeInvalidArchives();
}
@Test
public void testCommitDialog() {
DataTypeManagerPlugin plugin = getPlugin(tool, DataTypeManagerPlugin.class);
List<DataTypeSyncInfo> list = new ArrayList<>();
Set<DataTypeSyncInfo> set = new HashSet<>();
createChangedDatatypesFromArchive(list, set);
final DataTypeSyncDialog dialog =
new DataTypeSyncDialog(plugin, "WinHelloCPP.exe", "MyArchive", list, set, "Commit",
"Commit Datatype Changes From \"WinHelloCpp.exe\" to Archive \"MyArchive\"");
showModalDialogInTool(dialog);
runSwing(() -> {
Object syncPanel = getInstanceField("syncPanel", dialog);
GhidraTable table = (GhidraTable) getInstanceField("syncTable", syncPanel);
table.selectRow(0);
});
captureDialog(900, 500);
}
@Test
public void testDataTypeConflict() {
ConflictDialog dialog = new ConflictDialog("SIZE_T", "/baseDTs", "SIZE_T.conflict");
showModalDialogInTool(dialog);
captureDialog();
}
@Test
public void testDataTypeManager() {
captureIsolatedProvider(DataTypesProvider.class, 500, 400);
}
@Test
public void testDataTypeTreeWithAssociations() {
DataTypesProvider provider = getProvider(DataTypesProvider.class);
GTree tree = (GTree) getInstanceField("archiveGTree", provider);
GTreeRootNode rootNode = tree.getRootNode();
GTreeNode child = rootNode.getChild("WinHelloCPP.exe");
child = child.getChild("basetsd.h");
tree.expandPath(child);
captureIsolatedProvider(DataTypesProvider.class, 500, 400);
}
@Test
public void testDisassociateDialog() {
DataTypeManagerPlugin plugin = getPlugin(tool, DataTypeManagerPlugin.class);
List<DataTypeSyncInfo> list = new ArrayList<>();
Set<DataTypeSyncInfo> set = new HashSet<>();
createChangedDatatypesFromArchive(list, set);
final DataTypeSyncDialog dialog =
new DataTypeSyncDialog(plugin, "WinHelloCPP.exe", "MyArchive", list, set, "Diassociate",
"Disassociate DataType In \"WinHelloCpp.exe\" From Archive \"MyArchive\"");
showModalDialogInTool(dialog);
runSwing(() -> {
Object syncPanel = getInstanceField("syncPanel", dialog);
GhidraTable table = (GhidraTable) getInstanceField("syncTable", syncPanel);
table.selectRow(0);
});
captureDialog(900, 500);
}
@Test
public void testEditPaths() {
Preferences.setProperty(DataTypeManagerHandler.DATA_TYPE_ARCHIVE_PATH_KEY,
"/archives/subPath" + File.pathSeparator + "/otherArchives/subpath");
performAction("Edit Archive Paths", "DataTypeManagerPlugin", false);
// change the renderer so that it doesn't paint red for the missing paths
DialogComponentProvider dialog = getDialog();
GTable table = findComponent(dialog, GTable.class);
TableColumn pathColumn = table.getColumnModel().getColumn(1);
pathColumn.setCellRenderer(new GTableCellRenderer());
// give our new render a chance to paint the non-red font
table.paintImmediately(table.getBounds());
waitForSwing();
captureDialog();
}
@Test
public void testFavoriteDts() {
DataTypesProvider provider = getProvider(DataTypesProvider.class);
GTree tree = (GTree) getInstanceField("archiveGTree", provider);
GTreeRootNode rootNode = tree.getRootNode();
GTreeNode child = rootNode.getChild("BuiltInTypes");
tree.expandPath(child);
captureIsolatedProvider(DataTypesProvider.class, 500, 400);
}
@Test
public void testFindDataTypes() {
performAction("Find Data Types", "DataTypeManagerPlugin", false);
JDialog d = waitForJDialog("Find Data Types");
captureDialog();
pressButtonByText(d, "Cancel");
}
@Test
public void testPreviewWindow() {
String fullActionName = "Show Preview Window (DataTypeManagerPlugin)";
List<DockingActionIf> action = tool.getDockingActionsByFullActionName(fullActionName);
performAction(action.get(0));
// performAction("Show Preview Window", "DataTypeManagerPlugin", false);
DataTypesProvider provider = getProvider(DataTypesProvider.class);
GTree tree = (GTree) getInstanceField("archiveGTree", provider);
GTreeRootNode rootNode = tree.getRootNode();
GTreeNode child = rootNode.getChild("WinHelloCPP.exe");
child = child.getChild("DOS");
tree.expandPath(child);
child = child.getChild("IMAGE_DOS_HEADER");
tree.setSelectedNode(child);
final JSplitPane splitPane = (JSplitPane) getInstanceField("splitPane", provider);
runSwing(() -> {
splitPane.setDividerLocation(0.5);
splitPane.setResizeWeight(0.4);
});
captureIsolatedProvider(DataTypesProvider.class, 500, 1000);
}
@Test
public void testRevertDialog() {
DataTypeManagerPlugin plugin = getPlugin(tool, DataTypeManagerPlugin.class);
List<DataTypeSyncInfo> list = new ArrayList<>();
Set<DataTypeSyncInfo> set = new HashSet<>();
createChangedDatatypesFromArchive(list, set);
final DataTypeSyncDialog dialog =
new DataTypeSyncDialog(plugin, "WinHelloCPP.exe", "MyArchive", list, set, "Revert",
"Revert DataType Changes In \"WinHelloCpp.exe\" From Archive \"MyArchive\"");
showModalDialogInTool(dialog);
runSwing(() -> {
Object syncPanel = getInstanceField("syncPanel", dialog);
GhidraTable table = (GhidraTable) getInstanceField("syncTable", syncPanel);
table.selectRow(0);
});
captureDialog(900, 500);
}
@Test
public void testSearchResults() {
closeNonProgramArchives();
closeProvider(DataTypesProvider.class);
runSwing(() -> performAction("Find Data Types", "DataTypeManagerPlugin", false), false);
final DialogComponentProvider dialog = getDialog();
runSwing(() -> {
JTextField[] textFields = (JTextField[]) getInstanceField("textFields", dialog);
textFields[0].setText("type");
});
pressOkOnDialog();
waitForSwing();
DataTypesProvider provider = getVisibleProvider();
GTree tree = (GTree) getInstanceField("archiveGTree", provider);
waitForTree(tree);
captureIsolatedProvider(provider, 500, 500);
}
@Test
public void testUpdateDialog() {
DataTypeManagerPlugin plugin = getPlugin(tool, DataTypeManagerPlugin.class);
List<DataTypeSyncInfo> list = new ArrayList<>();
Set<DataTypeSyncInfo> set = new HashSet<>();
createChangedDatatypesFromArchive(list, set);
DataTypeManager dtm = program.getDataTypeManager();
StandAloneDataTypeManager sourceDTM = new StandAloneDataTypeManager("MyArhcive");
StructureDataType sdt1 = new StructureDataType("MyDataType1", 0);
sdt1.add(new PointerDataType(new StringDataType()), "name", null);
sdt1.add(new IntegerDataType(), "age", null);
sdt1.add(new PointerDataType(new VoidDataType()), "data", null);
StructureDataType sdt2 = new StructureDataType("MyDataType2", 0);
sdt2.add(new PointerDataType(new IntegerDataType()));
sdt2.add(new IntegerDataType());
sdt2.add(new WordDataType());
int id = sourceDTM.startTransaction("Test");
DataType dt1 = sourceDTM.addDataType(sdt1, null);
sourceDTM.endTransaction(id, true);
int txID = program.startTransaction("Test");
Structure struct = (Structure) dtm.addDataType(dt1, null);
program.endTransaction(txID, true);
id = sourceDTM.startTransaction("Test2");
((Structure) dt1).add(new IntegerDataType(), "id", null);
sourceDTM.endTransaction(id, true);
DataTypeSyncInfo sync1 = new DataTypeSyncInfo(struct, sourceDTM);
list.add(sync1);
set.add(sync1);
final DataTypeSyncDialog dialog =
new DataTypeSyncDialog(plugin, "WinHelloCPP.exe", "MyArchive", list, set, "Update",
"Update DataType Changes From Archive \"MyArchive\" To \"WinHelloCpp.exe\" ");
showModalDialogInTool(dialog);
runSwing(() -> {
Object syncPanel = getInstanceField("syncPanel", dialog);
GhidraTable table = (GhidraTable) getInstanceField("syncTable", syncPanel);
table.selectRow(0);
});
captureDialog(900, 500);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void removeInvalidArchives() {
DataTypeManagerPlugin plugin = env.getPlugin(DataTypeManagerPlugin.class);
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
@SuppressWarnings("unchecked")
Map<UniversalID, InvalidFileArchive> invalid =
(Map<UniversalID, InvalidFileArchive>) getInstanceField("invalidArchives", handler);
Collection<InvalidFileArchive> values = invalid.values();
for (InvalidFileArchive invalidFileArchive : values) {
removeArchive(handler, invalidFileArchive);
}
}
private void removeArchive(final DataTypeManagerHandler handler,
final InvalidFileArchive archive) {
runSwing(() -> handler.removeInvalidArchive(archive));
}
private DataTypesProvider getVisibleProvider() {
DockingWindowManager dwm = DockingWindowManager.getActiveInstance();
List<DataTypesProvider> providers = dwm.getComponentProviders(DataTypesProvider.class);
for (ComponentProvider provider : providers) {
if (provider.isVisible()) {
return (DataTypesProvider) provider;
}
}
Assert.fail("Unable to find a visible provider");
return null;// cannot get here
}
private void createChangedDatatypesFromArchive(List<DataTypeSyncInfo> list,
Set<DataTypeSyncInfo> set) {
DataTypeManager dtm = program.getDataTypeManager();
StandAloneDataTypeManager sourceDTM = new StandAloneDataTypeManager("MyArhcive");
StructureDataType sdt1 = new StructureDataType("MyDataType1", 0);
sdt1.add(new PointerDataType(new StringDataType()), "name", null);
sdt1.add(new IntegerDataType(), "age", null);
sdt1.add(new PointerDataType(new VoidDataType()), "data", null);
StructureDataType sdt2 = new StructureDataType("MyDataType2", 0);
sdt2.add(new PointerDataType(new IntegerDataType()));
sdt2.add(new IntegerDataType());
sdt2.add(new WordDataType());
int id = sourceDTM.startTransaction("Test");
DataType dt1 = sourceDTM.addDataType(sdt1, null);
DataType dt2 = sourceDTM.addDataType(sdt2, null);
sourceDTM.endTransaction(id, true);
int txID = program.startTransaction("Test");
try {
Structure struct = (Structure) dtm.addDataType(dt1, null);
struct.add(new IntegerDataType(), "id", null);
Structure struct2 = (Structure) dtm.addDataType(dt2, null);
struct2.add(new IntegerDataType());
DataTypeSyncInfo sync1 = new DataTypeSyncInfo(struct, sourceDTM);
DataTypeSyncInfo sync2 = new DataTypeSyncInfo(struct2, sourceDTM);
list.add(sync1);
list.add(sync2);
set.add(sync1);
}
finally {
program.endTransaction(txID, true);
}
}
private void showModalDialogInTool(final DialogComponentProvider dialog) {
runSwing(() -> tool.showDialog(dialog), false);
waitForSwing();
}
}

View file

@ -0,0 +1,38 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import docking.ComponentProvider;
public class DataTypePreviewPluginScreenShots extends GhidraScreenShotGenerator {
public DataTypePreviewPluginScreenShots() {
super();
}
@Test
public void testData_Type_Preview() {
positionListingTop(0x41ccba);
performAction("Data Type Preview", "DockingWindows", true);
ComponentProvider provider = getProvider("Data Type Preview");
captureIsolatedProviderWindow(provider.getClass(), 500, 300);
}
}

View file

@ -0,0 +1,54 @@
/* ###
* 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 help.screenshot;
import javax.swing.JTable;
import org.junit.Test;
import docking.ComponentProvider;
public class DataWindowPluginScreenShots extends GhidraScreenShotGenerator {
public DataWindowPluginScreenShots() {
super();
}
@Test
public void testDataWindow() {
performAction("Defined Data", "DockingWindows", true);
ComponentProvider provider = getProvider("Data Window");
// show some interesting data
JTable table = findComponent(provider.getComponent(), JTable.class);
int row = findRowByPartialText(table, "bad allocation");
scrollToRow(table, row);
captureIsolatedProviderWindow(provider.getClass(), 500, 300);
}
@Test
public void testDataWindowFilter() {
performAction("Defined Data", "DockingWindows", true);
performAction("Filter Data Types", "DataWindowPlugin", false);
captureDialog();
}
}

View file

@ -0,0 +1,53 @@
/* ###
* 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 help.screenshot;
import javax.swing.JComboBox;
import org.junit.Test;
import ghidra.app.plugin.debug.DbViewerPlugin;
import ghidra.app.plugin.debug.DbViewerProvider;
public class DbViewerPluginScreenShots extends GhidraScreenShotGenerator {
public DbViewerPluginScreenShots() {
super();
}
@Test
public void testDatabaseViewer() {
loadPlugin(DbViewerPlugin.class);
DbViewerProvider provider = showProvider(DbViewerProvider.class);
Object comp = getInstanceField("comp", provider);
final JComboBox<?> combo = (JComboBox<?>) getInstanceField("combo", comp);
runSwing(new Runnable() {
@Override
public void run() {
int count = combo.getItemCount();
for (int i = 0; i < count; i++) {
Object item = combo.getItemAt(i);
if (item.toString().startsWith("Metadata")) {
combo.setSelectedIndex(i);
break;
}
}
}
});
captureIsolatedProvider(provider, 1000, 400);
}
}

View file

@ -0,0 +1,281 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.SwingUtilities;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DockableComponent;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
public class DecompilePluginScreenShots extends GhidraScreenShotGenerator {
private static final Color DARK_BLUE = new Color(0, 0, 128);
private static final Color DARK_GREEN = new Color(0, 128, 0);
private static final Color YELLOW_ORANGE = new Color(155, 150, 50);
private static final Color PURPLE = new Color(155, 50, 155);
public DecompilePluginScreenShots() {
super();
}
@Test
public void testDecompWindow() {
removeFlowArrows();
goToListing(0x401055);
closeProvider(ViewManagerComponentProvider.class);
closeProvider(DataTypesProvider.class);
ComponentProvider provider = getProvider("Decompiler");
showProvider(provider.getClass());
setDividerPercentage(CodeViewerProvider.class, provider.getClass(), .50f);
captureWindow(tool.getToolFrame(), 1000, 500);
DockableComponent comp = getDockableComponent(provider.getClass());
Rectangle bounds = comp.getBounds();
bounds = SwingUtilities.convertRectangle(comp.getParent(), bounds, null);
crop(new Rectangle(0, bounds.y, 1000, bounds.height));
}
@Test
public void testDefuse() {
TextFormatter tf = new TextFormatter(17, 400, 4, 5, 0);
TextFormatterContext hl = new TextFormatterContext(Color.BLACK, Color.YELLOW);
TextFormatterContext red = new TextFormatterContext(Color.RED, Color.WHITE);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE, Color.WHITE);
TextFormatterContext green = new TextFormatterContext(Color.GREEN, Color.WHITE);
TextFormatterContext cursorhl =
new TextFormatterContext(Color.BLACK, Color.YELLOW, Color.RED);
tf.writeln("|void| |max_retry|(node *ptr)", blue, red);
tf.writeln("");
tf.writeln("{");
tf.writeln(" dword a;");
tf.writeln(" sdword b;");
tf.writeln(" ");
tf.writeln(" |a| = ptr->max + |7|", cursorhl, green);
tf.writeln(" b = ptr->prev->max + |a|;", hl);
tf.writeln(" |if| ((sdword)(ptr->next->max + |a|) < |7|) {", blue, hl, green);
tf.writeln(" ptr->max = |a|;", hl);
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" a = ptr->max + |6|", green);
tf.writeln(" }");
tf.writeln(" ptr->next->max = a + b");
tf.writeln(" |return|;", blue);
tf.writeln("}");
image = tf.getImage();
}
@Test
public void testForwardSlice() {
TextFormatter tf = new TextFormatter(16, 500, 4, 5, 0);
TextFormatterContext hl = new TextFormatterContext(Color.BLACK, Color.YELLOW);
TextFormatterContext red = new TextFormatterContext(Color.RED);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE);
TextFormatterContext green = new TextFormatterContext(Color.GREEN);
TextFormatterContext cursorhl =
new TextFormatterContext(Color.BLACK, Color.YELLOW, Color.RED);
tf.writeln(" a = psParm2->id;");
tf.writeln(" |b| = |max_alpha|(psParm1->next,psParm1->id);", cursorhl, red);
tf.writeln(" c = |max_beta|(psParm1->prev, a);", red);
tf.writeln(" |c| = c + |b|;", hl, hl);
tf.writeln(" dStack8 = |0|;", green);
tf.writeln(" |while| (psParm1->count != dStack8 && (sdword)dStack8) {", blue);
tf.writeln(" |if| (|c| < (sdword)(dStack8 + |b|)) {", blue, hl, hl);
tf.writeln(" |c| = |c| + a;", hl, hl);
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" a = a + |10|;", green);
tf.writeln(" }");
tf.writeln(" dStack8 = dStack8 + |1|;", green);
tf.writeln(" }");
tf.writeln(" psParm1->count = a + |c|;", hl);
tf.writeln(" |return|;", blue);
image = tf.getImage();
}
@Test
public void testBackwardSlice() {
TextFormatter tf = new TextFormatter(16, 500, 4, 5, 0);
TextFormatterContext hl = new TextFormatterContext(Color.BLACK, Color.YELLOW);
TextFormatterContext red = new TextFormatterContext(Color.RED, Color.WHITE);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE, Color.WHITE);
TextFormatterContext green = new TextFormatterContext(Color.GREEN, Color.WHITE);
TextFormatterContext greenhl = new TextFormatterContext(Color.GREEN, Color.YELLOW);
TextFormatterContext cursorhl =
new TextFormatterContext(Color.BLACK, Color.YELLOW, Color.RED);
tf.writeln(" |a| = |psParm2|->id;", hl, hl);
tf.writeln(" b = |max_alpha|(|psParm1|->next,|psParm1|->id);", red, hl, hl);
tf.writeln(" c = |max_beta|(psParm1->prev, |a|);", red, hl);
tf.writeln(" c = c + b;");
tf.writeln(" dStack8 = |0|;", green);
tf.writeln(" |while| (psParm1->count != dStack8 && (sdword)dStack8) {", blue);
tf.writeln(" |if| (c < (sdword)(dStack8 + b)) {", blue);
tf.writeln(" c = c + |a|;", hl);
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" |a| = |a| + |10|;", hl, hl, greenhl);
tf.writeln(" }");
tf.writeln(" dStack8 = dStack8 + |1|;", green);
tf.writeln(" }");
tf.writeln(" psParm1->count = |a| + c;", cursorhl);
tf.writeln(" |return|;", blue);
image = tf.getImage();
}
@Test
public void testStructnotapplied() {
Image listingImage = getListingImage();
Image decompImage = getDecompilerNoStructImage();
int listingWidth = listingImage.getWidth(null);
int decompWidth = decompImage.getWidth(null);
int height = Math.max(listingImage.getHeight(null), decompImage.getHeight(null));
BufferedImage combined = createEmptyImage(listingWidth + decompWidth, height);
Graphics2D g = combined.createGraphics();
g.drawImage(listingImage, 0, 0, null);
g.drawImage(decompImage, listingWidth, 0, null);
g.dispose();
image = combined;
}
public void testStructApplied() {
Image listingImage = getListingImage();
Image decompImage = getDecompilerStructAppliedImage();
int listingWidth = listingImage.getWidth(null);
int decompWidth = decompImage.getWidth(null);
int height = Math.max(listingImage.getHeight(null), decompImage.getHeight(null));
BufferedImage combined = createEmptyImage(listingWidth + decompWidth, height);
Graphics2D g = combined.createGraphics();
g.drawImage(listingImage, 0, 0, null);
g.drawImage(decompImage, listingWidth, 0, null);
g.dispose();
image = combined;
}
@Test
public void testEditFunctionSignature() {
goToListing(0x401040);
ComponentProvider provider = getProvider("Decompiler");
showProvider(provider.getClass());
waitForSwing();
performAction("Edit Function Signature", "DecompilePlugin", provider, false);
captureDialog();
}
private Image getListingImage() {
Font font = new Font("Monospaced", Font.PLAIN, 12);
TextFormatter tf = new TextFormatter(font, 15, 400, 4, 14, 1);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE);
TextFormatterContext darkBlue = new TextFormatterContext(DARK_BLUE);
TextFormatterContext darkGreen = new TextFormatterContext(DARK_GREEN);
TextFormatterContext orange = new TextFormatterContext(YELLOW_ORANGE);
TextFormatterContext purple = new TextFormatterContext(PURPLE);
tf.colorLines(new Color(180, 255, 180), 9, 1);
// @formatter:off
tf.writeln("|8b 40 0c| |MOV| |EAX|,|Oxc|[|EAX|]", blue, darkBlue, orange, darkGreen, orange );
tf.writeln("|3b 45 fc| |CMP| |EAX|,|local_8|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|79 29| |JLE| |LAB_080483c6|", blue, darkBlue, darkBlue );
tf.writeln("|8b 55 08| |MOV| |EDX|,|psParm1|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 45 fc| |MOV| |EAX|,|local_8|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|89 42 0c| |MOV| |0xC|,|[EDX]||EAX|", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 45 08| |MOV| |EAX|,|psParm1|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 50 08| |MOV| |EAX|,|0x4|[|EAX|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 45 08| |MOV| |EAX|,|psParm1|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 40 04| |MOV| |EAX|,|0x4|[|EAX|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|89 42 04| |MOV| |0x4|,|[EDX]||EAX|", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 45 08| |MOV| |EAX|,|psParm1|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 50 04| |MOV| |EDX|,|0x4|[|EAX|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 45 08| |MOV| |EAX|,|psParm1|[|EBP|]", blue, darkBlue, orange, purple, orange );
tf.writeln("|8b 40 08| |MOV| |EAX|,|0x8|[|EAX|]", blue, darkBlue, orange, purple, orange );
// @formatter:on
return tf.getImage();
}
private Image getDecompilerNoStructImage() {
Font font = new Font("Monospaced", Font.PLAIN, 13);
TextFormatter tf = new TextFormatter(font, 15, 400, 4, 2, 0);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE);
TextFormatterContext green = new TextFormatterContext(Color.GREEN);
TextFormatterContext hl = new TextFormatterContext(Color.BLACK, Color.YELLOW);
TextFormatterContext greenhl = new TextFormatterContext(Color.GREEN, Color.YELLOW);
TextFormatterContext cursor = new TextFormatterContext(Color.WHITE, Color.WHITE, Color.RED);
// @formatter:off
tf.writeln(" dword dVar1:");
tf.writeln(" ");
tf.writeln(" dVar1 = sParm2[*psParm1];");
tf.writeln(" |if| ((sdword)dVar1 < psParm1[|3|]) {", blue, green);
tf.writeln(" psParm1[|3|] = dVar1;", green);
tf.writeln("| | |*(sdword *)psParm1[2] + ||4||) == psParm1[||1||];|",cursor, hl, greenhl, hl, greenhl, hl);
tf.writeln(" *(sdword *)psParm1[1] + |8|) == psParm1[|2|];", green, green);
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" |if| (dVar1 - psParm1[|3|] == |0|) {", blue, green, green);
tf.writeln(" psParm1[|4|] = |100|;", green, green);
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" psParm1[|4|] = dVar1 - psParm1[|3|];", green, green);
tf.writeln(" }");
// @formatter:on
return tf.getImage();
}
private Image getDecompilerStructAppliedImage() {
Font font = new Font("Monospaced", Font.PLAIN, 13);
TextFormatter tf = new TextFormatter(font, 15, 400, 4, 2, 0);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE);
TextFormatterContext green = new TextFormatterContext(Color.GREEN);
TextFormatterContext hl = new TextFormatterContext(Color.BLACK, Color.YELLOW);
TextFormatterContext cursor = new TextFormatterContext(Color.WHITE, Color.WHITE, Color.RED);
// @formatter:off
tf.writeln(" dword dVar1:");
tf.writeln(" ");
tf.writeln(" dVar1 = sParm2[psParm1->id];");
tf.writeln(" |if| ((sdword)dVar1 < (sdword)psParm1->max) {", blue);
tf.writeln(" psParm1->max = dVar1;");
tf.writeln("| | |psParm1->prev->next == psParm1->next;|",cursor,hl);
tf.writeln(" psParm1->next->prev == psParm1->prev;");
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" |if| (dVar1 - psParm1->max == |0|) {", blue, green);
tf.writeln(" psParm1->count = |100|;", green);
tf.writeln(" }");
tf.writeln(" |else| {", blue);
tf.writeln(" psParm1->count = dVar1 - psParm1->max;");
tf.writeln(" }");
// @formatter:on
return tf.getImage();
}
}

View file

@ -0,0 +1,244 @@
/* ###
* 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 help.screenshot;
import java.awt.Color;
import java.awt.Font;
import javax.swing.*;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import ghidra.app.nav.ListingPanelContainer;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.services.ProgramManager;
import ghidra.framework.main.OpenVersionedFileDialog;
import ghidra.framework.main.datatree.DataTree;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.task.TaskMonitor;
public class DiffScreenShots extends GhidraScreenShotGenerator {
private static TaskMonitor dummyMonitor = TaskMonitor.DUMMY;
@Test
public void testSelectOtherProgram() throws Exception {
addProgramsToProject();
program = env.getProgram("WinHelloCPP.exe");
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
captureDialog(dialog.getPreferredSize().width, 500);
}
@Test
public void testSelectOtherVersionedProgram() throws Exception {
addProgramsToProject();
createProgramVersions();
waitForSwing();
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
waitForSwing();
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
JButton historyButton = findButtonByText(dialog.getComponent(), "History>>");
pressButton(historyButton);
captureDialog();
}
@Test
public void testDetermineDiffs() throws Exception {
addProgramsToProject();
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
waitForSwing();
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
waitForSwing();
pressButtonByText(dialog.getComponent(), "OK", false);
waitForSwing();
captureDialog();
}
@Test
public void testDiff() throws Exception {
addProgramsToProject();
createDifferences();
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
waitForSwing();
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
waitForSwing();
pressButtonByText(dialog.getComponent(), "OK", false);
waitForSwing();
pressButtonByText(getDialog().getComponent(), "OK", false);
waitForBusyTool(tool);
evenDiffWindow();
nextDiff();
nextDiff();
goToListing(0x408dd9);
captureProvider(CodeViewerProvider.class);
}
@Test
public void testDiffApplySettings() throws Exception {
addProgramsToProject();
createDifferences();
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
waitForSwing();
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
waitForSwing();
pressButtonByText(dialog.getComponent(), "OK", false);
waitForSwing();
pressButtonByText(getDialog().getComponent(), "OK", false);
waitForBusyTool(tool);
evenDiffWindow();
nextDiff();
nextDiff();
goToListing(0x408dd9);
performAction("Show Diff Apply Settings", "ProgramDiffPlugin", true);
ComponentProvider provider = getProvider("Diff Apply Settings");
captureIsolatedProvider(provider.getClass(), 1100, 260);
}
@Test
public void testDiffApplySettingsPopup() throws Exception {
JMenu jMenu = new JMenu();
Font font = jMenu.getFont().deriveFont(11f);
TextFormatter tf = new TextFormatter(font, 3, 220, 0, 20, 3);
TextFormatterContext white = new TextFormatterContext(Color.WHITE);
tf.colorLines(new Color(60, 115, 200), 2, 1);
tf.writeln("Set Ignore for All Apply Settings");
tf.writeln("Set Replace for All Apply Settings");
tf.writeln("|Set Merge for All Apply Settings|", white);
image = tf.getImage();
}
@Test
public void testDiffDetails() throws Exception {
addProgramsToProject();
createDifferencesAt401417();
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
waitForSwing();
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
waitForSwing();
pressButtonByText(dialog.getComponent(), "OK", false);
waitForSwing();
pressButtonByText(getDialog().getComponent(), "OK", false);
waitForBusyTool(tool);
evenDiffWindow();
nextDiff();
performAction("Diff Location Details", "ProgramDiffPlugin", true);
ComponentProvider provider = getProvider("Diff Location Details");
captureIsolatedProvider(provider.getClass(), 510, 350);
}
private void nextDiff() {
runSwing(() -> {
Plugin plugin = getPluginByName(tool, "ProgramDiffPlugin");
invokeInstanceMethod("nextDiff", plugin);
});
}
private void evenDiffWindow() {
runSwing(() -> {
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
ListingPanelContainer container = (ListingPanelContainer) provider.getComponent();
JSplitPane splitPane = (JSplitPane) getInstanceField("splitPane", container);
splitPane.setDividerLocation(0.5);
});
}
private void createProgramVersions() throws Exception {
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
DomainFile file = projectData.getRootFolder().getFile("WinHelloCpp.exe");
file.addToVersionControl("First Version", true, dummyMonitor);
}
private void addProgramsToProject() throws Exception {
program = env.getProgram("WinHelloCPP.exe");
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program, TaskMonitor.DUMMY);
projectData.getRootFolder().createFile("OldWinHelloCpp.exe", program, TaskMonitor.DUMMY);
waitForSwing();
}
private void createDifferences() throws Exception {
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
DomainFile file = projectData.getRootFolder().getFile("WinHelloCpp.exe");
Program p = (Program) file.getDomainObject(this, false, false, dummyMonitor);
int id = p.startTransaction("Test");
Listing listing = p.getListing();
listing.clearCodeUnits(addr(0x408dcd), addr(0x408dcd), false);
SymbolTable symbolTable = p.getSymbolTable();
symbolTable.createLabel(addr(0x408dd9), "BOB", SourceType.USER_DEFINED);
symbolTable.createLabel(addr(0x408deb), "EXTRA", SourceType.USER_DEFINED);
p.endTransaction(id, true);
p.save("some changes", dummyMonitor);
p.release(this);
}
private void createDifferencesAt401417() throws Exception {
Address addr = addr(0x401417);
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
DomainFile file = projectData.getRootFolder().getFile("WinHelloCpp.exe");
Program p = (Program) file.getDomainObject(this, false, false, dummyMonitor);
int id = p.startTransaction("Test");
Function function = p.getFunctionManager().getFunctionContaining(addr);
SymbolTable symbolTable = p.getSymbolTable();
symbolTable.createLabel(addr, "MyLabel", function, SourceType.USER_DEFINED);
p.endTransaction(id, true);
p.save("some changes", dummyMonitor);
p.release(this);
// now make a similar change in the current program, but use the global namespace
ProgramManager service = tool.getService(ProgramManager.class);
p = service.getCurrentProgram();
id = p.startTransaction("Test");
symbolTable = p.getSymbolTable();
symbolTable.createLabel(addr, "MyLabel", SourceType.USER_DEFINED);
p.endTransaction(id, true);
}
}

View file

@ -0,0 +1,66 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import javax.swing.SwingUtilities;
import org.junit.Test;
import docking.ComponentProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
public class DisassembledViewPluginScreenShots extends GhidraScreenShotGenerator {
public DisassembledViewPluginScreenShots() {
super();
}
@Test
public void testDisassembledViewPluginMain() {
setToolSize(900, 600);
positionListingTop(0x4017ad);
closeProvider(DataTypesProvider.class);
closeProvider(ViewManagerComponentProvider.class);
performAction("Disassembled View", "DockingWindows", true);
captureWindow();
ComponentProvider provider = getProvider("Virtual Disassembler - Current Instruction");
Component component = getDockableComponent(provider);
Rectangle r = component.getBounds();
Point p = r.getLocation();
p = SwingUtilities.convertPoint(component.getParent(), p, tool.getToolFrame());
r.setLocation(p);
// Highlight the component
// Adjust the highlight.
int offset = 2;
Point location = r.getLocation();
location.x += offset;// over
location.y += offset;// down
r.setLocation(location);
Dimension size = r.getSize();
size.width -= (2 * offset);// in
size.height -= (2 * offset);// up
r.setSize(size);
drawRectangle(Color.YELLOW, r, 10);
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
public class DisassemblerPluginScreenShots extends GhidraScreenShotGenerator {
public DisassemblerPluginScreenShots() {
super();
}
@Test
public void testProcessorOptions() {
positionListingTop(0x401000);
performAction("Processor Options", "DisassemblerPlugin", false);
captureDialog(400, 400);
}
}

View file

@ -0,0 +1,67 @@
/* ###
* 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 help.screenshot;
import java.awt.Rectangle;
import java.awt.Window;
import org.junit.Test;
import docking.DockingWindowManager;
import generic.util.image.ImageUtils;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
public class DockingWindowsScreenShots extends GhidraScreenShotGenerator {
public DockingWindowsScreenShots() {
super();
}
@Test
public void testCaptureTool() {
goToListing(0x405a90); // 405a90
setDividerPercentage(ViewManagerComponentProvider.class, DataTypesProvider.class, .5f);
setDividerPercentage(ViewManagerComponentProvider.class, CodeViewerProvider.class, .30f);
captureToolWindow(900, 700);
}
@Test
public void testCaptureWindow_Menu() throws Exception {
performMemorySearch("85d2");
performMemorySearch("9000");
waitForTasks();
DockingWindowManager mgr = DockingWindowManager.getActiveInstance();
Window mainWindow = mgr.getMainWindow();
mainWindow.toFront();
waitForSwing();
captureMenuBarMenuHierachy("Window");
ImageUtils.waitForImage(null, image);
int width = image.getWidth(null);
int height = image.getHeight(null);
// trim the image a bit, it is much wider than it needs to be, as the menu bar is large
int extra = 300; // this is anecdotal; if this becomes wrong, then we can use the tool's size
Rectangle newBounds = new Rectangle(0, 0, width - 300, height);
crop(newBounds);
}
}

View file

@ -0,0 +1,311 @@
/* ###
* 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 help.screenshot;
import java.awt.Rectangle;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.junit.Test;
import docking.action.DockingActionIf;
import docking.widgets.OptionDialog;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.events.ProgramLocationPluginEvent;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.equate.EquatePlugin;
import ghidra.app.plugin.core.equate.EquateTableProvider;
import ghidra.app.plugin.core.flowarrow.FlowArrowPlugin;
import ghidra.app.util.bean.SetEquateDialog;
import ghidra.app.util.datatype.ApplyEnumDialog;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.util.OperandFieldLocation;
import ghidra.program.util.ProgramSelection;
/**
* Generates screenshots associated with Equate dialog.
*/
public class EquatePluginScreenShots extends GhidraScreenShotGenerator {
private CodeBrowserPlugin cb;
private DockingActionIf setAction;
private EquatePlugin equatePlugin;
private Listing listing;
private DockingActionIf removeAction;
private DockingActionIf applyEnum;
@Override
public void tearDown() throws Exception {
closeAllWindows();
super.tearDown();
}
@Override
public void setUp() throws Exception {
super.setUp();
FlowArrowPlugin flowArrowPlugin = getPlugin(tool, FlowArrowPlugin.class);
tool.removePlugins(new Plugin[] { flowArrowPlugin });
equatePlugin = getPlugin(tool, EquatePlugin.class);
cb = getPlugin(tool, CodeBrowserPlugin.class);
env.showTool(program);
setAction = getAction(equatePlugin, "Set Equate");
removeAction = getAction(equatePlugin, "Remove Equate");
applyEnum = getAction(equatePlugin, "Apply Enum");
listing = program.getListing();
createEquateData();
}
private void createEquateData() throws Exception {
int txId = program.startTransaction("TEST");
// Set some equates. These address must contain valid scalars or the equates
// will fail to be set and our tests will not operate as expected. So make
// sure these locations are defined.
CreateDataCmd cmd = new CreateDataCmd(addr(0x0040e00d), new ByteDataType());
cmd.applyTo(program);
cmd = new CreateDataCmd(addr(0x00401013), new ByteDataType());
cmd.applyTo(program);
cmd = new CreateDataCmd(addr(0x00401031), new ByteDataType());
cmd.applyTo(program);
cmd = new CreateDataCmd(addr(0x00401053), new ByteDataType());
cmd.applyTo(program);
cmd = new CreateDataCmd(addr(0x0040c27c), new ByteDataType()); //Bad equate addr
cmd.applyTo(program);
cmd = new CreateDataCmd(addr(0x0040c238), new ByteDataType()); //Enum based equate addr
cmd.applyTo(program);
// Now set some equates...
setEquate(0x0040e00d, "EQ_1");
setEquate(0x00401013, "EQ_2");
setEquate(0x00401031, "EQ_3");
setEquate(0x00401053, "EQ_4");
setEquate(0x0040c27c, "dtID:0123456789012345678:0");
setEquate(0x0040c238, "__FAVOR_ATOM");
program.endTransaction(txId, true);
}
/**
* Captures the Equate Table dialog.
*/
@Test
public void testEquatesTable() {
showProvider(EquateTableProvider.class);
captureIsolatedProvider(EquateTableProvider.class, 611, 345);
}
/**
* Captures the confirmation dialog that is shown before allowing a delete from
* the Equate Table.
*/
@Test
public void testConfirmEquateDelete() {
showProvider(EquateTableProvider.class);
performAction("Delete Equate", "EquateTablePlugin", false);
waitForDialogComponent(OptionDialog.class);
captureDialog(OptionDialog.class);
}
/**
* Captures the info dialog that is shown when the user attempts to remove an
* equate on a selection.
*
* @throws Exception
*/
@Test
public void testRemoveSelection() throws Exception {
// Place the cursor on a known scalar.
Address addr = program.getMinAddress().getNewAddress(0x0040e00d);
fireOperandFieldLocationEvent(addr, 0);
// Make a selection containing the scalar above.
AddressFactory addressFactory = program.getAddressFactory();
AddressSet addressSet = new AddressSet();
addressSet.addRange(addressFactory.getAddress("0040e00d"),
addressFactory.getAddress("0040e00f"));
ProgramSelection programSelection = new ProgramSelection(addressSet);
tool.firePluginEvent(
new ProgramSelectionPluginEvent("Test Scalar Selection", programSelection, program));
// Call the action to remove the equates from the selection.
performAction(removeAction, cb.getProvider(), false);
// Capture the confirmation dialog.
waitForDialogComponent(OptionDialog.class);
captureDialog(OptionDialog.class);
}
/**
* Captures the Set Equate dialog.
*/
@Test
public void testSetEquate() {
goToListing(0x0040c238, "Operands", true);
performAction(setAction, cb.getProvider(), false);
SetEquateDialog d = waitForDialogComponent(SetEquateDialog.class);
JTextField tf = findComponent(d.getComponent(), JTextField.class);
setText(tf, "E");
captureDialog(SetEquateDialog.class);
}
/**
* Captures the listing before the apply enum action is executed.
*/
@Test
public void testBeforeApplyEnum() {
createEnum_myEnum();
AddressFactory addrFactory = program.getAddressFactory();
Address addr1 = addrFactory.getAddress("004019ac");
Address addr2 = addrFactory.getAddress("004019c2");
selectRange(addr1, addr2);
positionListingTop(0x004019aa);
long start = 0x004019aa;
long end = 0x004019c8;
captureListingRange(start, end, 630);
// remove sidebar from image
int h = image.getHeight(null);
int w = image.getWidth(null);
crop(new Rectangle(40, 0, w, h));
}
@Test
public void testApplyEnum() throws Exception {
DataTypeManager dtm = program.getDataTypeManager();
ApplyEnumDialog dialog = new ApplyEnumDialog(tool, dtm);
runSwing(() -> tool.showDialog(dialog), false);
waitForSwing();
captureDialog(dialog);
}
/**
* Captures the listing after the apply enum action is executed.
*/
@Test
public void testAfterApplyEnum() {
createEnum_myEnum();
AddressFactory addrFactory = program.getAddressFactory();
Address addr1 = addrFactory.getAddress("004019ac");
Address addr2 = addrFactory.getAddress("004019c2");
selectRange(addr1, addr2);
performAction(applyEnum, cb.getProvider(), false);
ApplyEnumDialog dialog = waitForDialogComponent(ApplyEnumDialog.class);
JTextField tf = findComponent(dialog, JTextField.class);
triggerText(tf, "myEnum");
triggerEnter(tf);
positionListingTop(0x004019aa);
long start = 0x004019aa;
long end = 0x004019c8;
captureListingRange(start, end, 630);
// remove sidebar from image
int h = image.getHeight(null);
int w = image.getWidth(null);
crop(new Rectangle(40, 0, w, h));
}
/**
* Captures the Rename Equate dialog.
*
* @throws Exception
*/
@Test
public void testRenameEquate() throws Exception {
setEquate(0x0040c279, "EQ_1");
goToListing(0x0040c238, "Operands", true);
performAction("Rename Equate", "EquatePlugin", false);
captureDialog();
}
/**
* Sets an equate on the given address.
*
* @param address the address of the equate
* @param name the equate name to set
* @throws Exception
*/
private void setEquate(long address, String name) throws Exception {
goToListing(address, "Operands", true);
performAction(setAction, cb.getProvider(), false);
SetEquateDialog d = waitForDialogComponent(SetEquateDialog.class);
final JTextField tf = findComponent(d.getComponent(), JTextField.class);
setText(tf, name);
SwingUtilities.invokeAndWait(() -> tf.getActionListeners()[0].actionPerformed(null));
program.flushEvents();
}
/**
* Sets the cursor to point to the given address and operand.
*
* @param addr the address to point to
* @param opIndex the specific operand index
*/
private void fireOperandFieldLocationEvent(Address addr, int opIndex) {
CodeUnit cu = listing.getCodeUnitAt(addr);
String str = CodeUnitFormat.DEFAULT.getOperandRepresentationString(cu, opIndex);
OperandFieldLocation loc =
new OperandFieldLocation(program, addr, null, null, str, opIndex, 0);
tool.firePluginEvent(new ProgramLocationPluginEvent("test", loc, program));
waitForPostedSwingRunnables();
}
private AddressSet selectRange(Address start, Address end) {
AddressSet addressSet = new AddressSet();
addressSet.addRange(start, end);
ProgramSelection programSelection = new ProgramSelection(addressSet);
tool.firePluginEvent(
new ProgramSelectionPluginEvent("Test Scalar Selection", programSelection, program));
return addressSet;
}
private void createEnum_myEnum() {
DataTypeManager dataTypeManager = program.getDataTypeManager();
int id = dataTypeManager.startTransaction("EquatePluginTest enum");
EnumDataType enumm = new EnumDataType("myEnum", 3);
enumm.add("zeros", 0x0);
enumm.add("oneTwoThree", 0x123);
enumm.add("oneC", 0x1c);
dataTypeManager.addDataType(enumm, null);
dataTypeManager.endTransaction(id, true);
}
}

View file

@ -0,0 +1,109 @@
/* ###
* 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 help.screenshot;
import javax.swing.JComboBox;
import org.junit.Test;
import ghidra.app.plugin.core.exporter.ExporterDialog;
import ghidra.app.util.OptionsDialog;
import ghidra.app.util.exporter.Exporter;
import ghidra.framework.model.*;
import ghidra.framework.preferences.Preferences;
import ghidra.program.model.listing.Program;
public class ExporterPluginScreenShots extends GhidraScreenShotGenerator {
@Test
public void testExport_Dialog() {
// override the user of 'user.home' in the dialog
Preferences.setProperty(Preferences.LAST_EXPORT_DIRECTORY, "/path");
DomainFile df = createDomainFile();
ExporterDialog dialog = new ExporterDialog(tool, df);
runSwing(() -> tool.showDialog(dialog), false);
waitForSwing();
captureDialog(dialog);
}
@Test
public void testAscii_Options() throws Exception {
performAction("Export Program", "ExporterPlugin", false);
ExporterDialog d = waitForDialogComponent(ExporterDialog.class);
chooseExporter(d, "Ascii");
OptionsDialog optionDialog = waitForDialogComponent(OptionsDialog.class);
captureDialog(optionDialog);
}
@Test
public void testC_Options() throws Exception {
performAction("Export Program", "ExporterPlugin", false);
ExporterDialog d = waitForDialogComponent(ExporterDialog.class);
chooseExporter(d, "C/C++");
OptionsDialog optionDialog = waitForDialogComponent(OptionsDialog.class);
captureDialog(optionDialog);
}
@Test
public void testIntel_Hex_Options() throws Exception {
performAction("Export Program", "ExporterPlugin", false);
ExporterDialog d = waitForDialogComponent(ExporterDialog.class);
chooseExporter(d, "Intel Hex");
OptionsDialog optionDialog = waitForDialogComponent(OptionsDialog.class);
captureDialog(optionDialog);
}
private void chooseExporter(ExporterDialog d, String formatName) {
JComboBox<?> exportersCombo = findComponent(d, JComboBox.class);
setSelectedExporter(exportersCombo, formatName);
pressButtonByText(d.getComponent(), "Options...", false);
}
private void setSelectedExporter(final JComboBox<?> exportersCombo, final String exporterName) {
runSwing(() -> {
for (int i = 0; i < exportersCombo.getItemCount(); ++i) {
Object obj = exportersCombo.getItemAt(i);
if (obj instanceof Exporter) {
Exporter exp = (Exporter) obj;
if (exp.getName().equals(exporterName)) {
exportersCombo.setSelectedItem(exp);
return;
}
}
}
});
}
private DomainFile createDomainFile() {
TestDummyDomainFolder root = new TestDummyDomainFolder(null, "Project");
DomainFile df = new TestDummyDomainFile(root, "Program_A") {
@Override
public Class<? extends DomainObject> getDomainObjectClass() {
return Program.class;
}
};
return df;
}
}

View file

@ -0,0 +1,32 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
public class FallThroughPluginScreenShots extends GhidraScreenShotGenerator {
public FallThroughPluginScreenShots() {
super();
}
@Test
public void testSetFallThrough() {
goToListing(0x004033b5, "Operands", true);
performAction("Set Fallthrough", "FallThroughPlugin", false);
captureDialog();
}
}

View file

@ -0,0 +1,757 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import javax.swing.*;
import org.junit.Assert;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.DockingDialog;
import docking.widgets.OptionDialog;
import docking.widgets.PasswordChangeDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.table.GTable;
import docking.wizard.WizardManager;
import docking.wizard.WizardPanel;
import ghidra.app.plugin.core.archive.RestoreDialog;
import ghidra.framework.data.GhidraFileData;
import ghidra.framework.main.*;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.dialog.*;
import ghidra.framework.preferences.Preferences;
import ghidra.framework.remote.User;
import ghidra.framework.store.LockException;
import ghidra.program.database.ProgramContentHandler;
import ghidra.program.model.lang.Language;
import ghidra.test.ProjectTestUtils;
import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import resources.MultiIcon;
public class FrontEndPluginScreenShots extends GhidraScreenShotGenerator {
private static final String OTHER_PROJECT = "Other_Project";
private final static String TEMP_DIR = System.getProperty("java.io.tmpdir");
Icon icon = (Icon) getInstanceField("CONVERT_ICON", ProjectInfoDialog.class);
public FrontEndPluginScreenShots() {
super();
}
@Override
public void prepareTool() {
tool = getFrontEndTool();
}
@Override
public void loadProgram() {
// don't need to load a program
}
@Test
public void testArchiveFileExists() {
runSwing(() -> OptionDialog.showOptionDialog(null, "Archive File Exists",
"/Projects/Demo" + " exists.\n " + "Do you want to overwrite existing file?", "Yes"),
false);
sleep(500);
captureDialog();
}
@Test
public void testArchiveProject() {
performAction("Archive Project", "ArchivePlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JTextField textField = (JTextField) getInstanceField("archiveField", dialog);
setText(textField, "/projects/testPrj.gar");
paintImmediately(dialog);
captureDialog();
}
@Test
public void testChangeAccessList() {
String[] knownUsers = { "user1", "user2", "user3", "user4", "user5", "user6" };
ArrayList<User> userList = new ArrayList<>();
userList.add(new User("user4", 2));
runSwing(() -> {
WizardPanel panel =
new ProjectAccessPanel(knownUsers, "Bob", userList, "Demo", false, false, tool);
TestDummyPanelManager panelMgr =
new TestDummyPanelManager(panel, true, false, true, 650, 250);
WizardManager wizard =
new WizardManager("Change Shared Project Information", false, panelMgr, icon);
wizard.showWizard();
});
waitForSwing();
captureDialog();
}
@Test
public void testChangePassword() {
final PasswordChangeDialog pcd =
new PasswordChangeDialog("Change Password", "Repository Server", "server1", "user-1");
runSwing(() -> tool.showDialog(pcd), false);
PasswordChangeDialog dialog =
waitForDialogComponent(null, PasswordChangeDialog.class, DEFAULT_WINDOW_TIMEOUT);
captureDialog(dialog);
}
@Test
public void testChangeRepositoryPanel() {
RepositoryPanel panel =
new RepositoryPanel(null, "MyServer", new String[] { "Demo", "Test", "Sample" }, false);
TestDummyPanelManager panelMgr =
new TestDummyPanelManager(panel, false, true, false, 600, 375);
WizardManager wizard =
new WizardManager("Change Shared Project Information", false, panelMgr, icon);
wizard.showWizard();
waitForSwing();
captureDialog();
}
@Test
public void testChangeServerInfoPanel() {
TestDummyPanelManager panelMgr =
new TestDummyPanelManager(null, false, true, false, 600, 180);
ServerInfoPanel panel = new ServerInfoPanel(panelMgr);
panelMgr.setPanel(panel);
WizardManager wizard =
new WizardManager("Change Shared Project Information", false, panelMgr, icon);
panel.setServerInfo(new ServerInfo("server1", 13100));
wizard.showWizard();
waitForSwing();
captureDialog();
}
@Test
public void testCheckedOutNotLatest() {
MultiIcon multiIcon = new MultiIcon(GhidraFileData.VERSION_ICON);
multiIcon.addIcon(ProgramContentHandler.PROGRAM_ICON);
multiIcon.addIcon(GhidraFileData.NOT_LATEST_CHECKED_OUT_ICON);
captureIconAndText(multiIcon, "Example (2 of 3)*");
}
@Test
public void testConfigureTool() {
performAction("Configure Tool", "Project Window", false);
waitForSwing();
captureDialog();
}
@Test
public void testConfigureExtensions() {
performAction("Extensions", "Project Window", false);
waitForSwing();
ExtensionTableProvider provider =
(ExtensionTableProvider) getDialog(ExtensionTableProvider.class);
Object panel = getInstanceField("extensionTablePanel", provider);
GTable table = (GTable) getInstanceField("table", panel);
// Create some extensions to put in the table.
ExtensionDetails ext1 = new ExtensionDetails("extension 1", "This is a sample extension",
"John B. Author", "09/21/1974", "1.0.0");
ExtensionDetails ext2 = new ExtensionDetails("extension 2",
"This is another sample extension", "Gertrude B. Author", "09/22/1974", "1.0.1");
Set<ExtensionDetails> exts = new HashSet<>();
exts.add(ext1);
exts.add(ext2);
ExtensionTablePanel ePanel = (ExtensionTablePanel) panel;
ePanel.setExtensions(exts);
selectRow(table, 1);
captureDialog();
}
@Test
public void testConfirmChangePassword() {
runSwing(() -> OptionDialog.showOptionDialog(tool.getToolFrame(), "Confirm Password Change",
"You are about to change your repository server password for:\n" + "server1:13100" +
"\n \nThis password is used when connecting to project\n" +
"repositories associated with this server",
"Continue", OptionDialog.WARNING_MESSAGE), false);
sleep(50);
waitForSwing();
captureDialog();
}
@Test
public void testConfirmDeleteProject() {
runSwing(() -> OptionDialog.showOptionDialog(tool.getToolFrame(), "Confirm Delete",
"Are you sure you want to delete\n" + "Project: /users/user/Sample?\n" +
"\n \nWARNING: Delete CANNOT be undone!",
"Delete", OptionDialog.INFORMATION_MESSAGE), false);
sleep(50);
waitForSwing();
captureDialog();
}
@Test
public void testConnectTools() {
loadDefaultTool();
loadDefaultTool();
waitForSwing();
performAction("Connect Tools", "FrontEndPlugin", false);
DialogComponentProvider dialog = getDialog();
Object panel = getInstanceField("panel", dialog);
final JList<?> consumerList = (JList<?>) getInstanceField("consumerList", panel);
final JList<?> producerList = (JList<?>) getInstanceField("producerList", panel);
runSwing(() -> {
producerList.setSelectedIndices(new int[] { 0 });
consumerList.setSelectedIndices(new int[] { 1 });
});
dialog.toFront();
waitForSwing();
captureDialog();
}
@Test
public void testDeleteProject() {
performAction("Delete Project", "FrontEndPlugin", false);
captureDialog();
}
@Test
public void testEditPluginPath() {
Preferences.setProperty(Preferences.USER_PLUGIN_JAR_DIRECTORY, "/MyPlugins");
Preferences.setPluginPaths(new String[] { "/myJar.jar", "/MyPlugins/classes" });
performAction("Edit Plugin Path", "FrontEndPlugin", false);
DialogComponentProvider dialog = getDialog();
final JList<?> jList = (JList<?>) getInstanceField("pluginPathsList", dialog);
runSwing(() -> {
jList.setCellRenderer(new DefaultListCellRenderer());// files don't exist - don't want them in red
jList.setSelectedIndex(0);
});
captureDialog();
}
@Test
public void testEditProjectAccessList() {
String[] knownUsers = { "user1", "user2", "user3", "user4", "user5", "user6" };
ArrayList<User> userList = new ArrayList<>();
userList.add(new User("user2", 2));
userList.add(new User("user4", 0));
userList.add(new User("user5", 1));
runSwing(() -> {
JPanel panel =
new ProjectAccessPanel(knownUsers, "Bob", userList, "What", false, false, tool);
DummyDialogComponentProvider dialog =
new DummyDialogComponentProvider("Edit Project Access List for Demo", panel);
tool.showDialog(dialog);
});
waitForSwing();
captureDialog();
}
@Test
public void testhijack_file() {
MultiIcon multiIcon = new MultiIcon(GhidraFileData.VERSION_ICON);
multiIcon.addIcon(ProgramContentHandler.PROGRAM_ICON);
multiIcon.addIcon(GhidraFileData.HIJACKED_ICON);
captureIconAndText(multiIcon, "Example (Highjacked)");
}
@Test
public void testNonSharedProjectInfo() {
performAction("View Project Info", "FrontEndPlugin", false);
captureDialog();
}
@Test
public void testOpenProject() {
performAction("Open Project", "FrontEndPlugin", false);
captureDialog();
}
@Test
public void testPrivateFileIcon() {
Icon programIcon = ProgramContentHandler.PROGRAM_ICON;
MultiIcon multiIcon = new MultiIcon(programIcon);
captureIconAndText(multiIcon, "Example");
}
@Test
public void testProjectDataTable()
throws CancelledException, IOException, InvalidNameException {
program = env.getProgram("WinHelloCPP.exe");
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program, TaskMonitor.DUMMY);
projectData.getRootFolder().createFile("OldWinHelloCpp.exe", program, TaskMonitor.DUMMY);
FrontEndPlugin plugin = getPlugin(tool, FrontEndPlugin.class);
JComponent projectDataPanel = (JComponent) getInstanceField("projectDataPanel", plugin);
JTabbedPane tabbedPane =
(JTabbedPane) getInstanceField("projectTabPanel", projectDataPanel);
tabbedPane.setSelectedIndex(1);
setToolSize(800, 600);
captureComponent(projectDataPanel);
}
@Test
public void testProjectDataTree() throws InvalidNameException, CancelledException, IOException {
program = env.getProgram("WinHelloCPP.exe");
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program, TaskMonitor.DUMMY);
projectData.getRootFolder().createFile("OldWinHelloCpp.exe", program, TaskMonitor.DUMMY);
FrontEndPlugin plugin = getPlugin(tool, FrontEndPlugin.class);
JComponent projectDataPanel = (JComponent) getInstanceField("projectDataPanel", plugin);
setToolSize(800, 600);
captureComponent(projectDataPanel);
}
@Test
public void testProjectExists() {
final OptionDialog dialog = new OptionDialog("Project Exists",
"Cannot restore project because project named " + "TestPrj" + " already exists.",
OptionDialog.PLAIN_MESSAGE, null);
runSwing(() -> tool.showDialog(dialog), false);
captureDialog();
}
@Test
public void testProjectWindow() throws InvalidNameException, CancelledException, IOException {
program = env.getProgram("WinHelloCPP.exe");
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program, TaskMonitor.DUMMY);
projectData.getRootFolder().createFile("OldWinHelloCpp.exe", program, TaskMonitor.DUMMY);
Msg.info(FrontEndService.class, "This is a log message...");// something nice in the status area
captureToolWindow(800, 600);
}
@Test
public void testReopenProject() {
FrontEndPlugin plugin = getPlugin(tool, FrontEndPlugin.class);
ProjectManager pm = (ProjectManager) getInstanceField("projectManager", plugin);
@SuppressWarnings("unchecked")
List<ProjectLocator> recentProjects =
(List<ProjectLocator>) getInstanceField("recentlyOpenedProjectsList", pm);
recentProjects.add(new ProjectLocator("/projects", "Demo"));
recentProjects.add(new ProjectLocator("/projects", "Sample"));
recentProjects.add(new ProjectLocator("/projects", "Test"));
runSwing(() -> tool.setVisible(true));
Msg.info(FrontEndService.class, "This is a log message...");// something nice in the status area
setToolSize(500, 550);
showMenuBarMenu("File", "Reopen");
captureComponent(tool.getToolFrame());
}
@Test
public void testRepositoryNamePanel() {
TestDummyPanelManager panelMgr =
new TestDummyPanelManager(null, false, true, true, 600, 375);
final RepositoryPanel panel = new RepositoryPanel(panelMgr, "Server1",
new String[] { "Demo", "Test", "Sample" }, false);
panelMgr.setPanel(panel);
WizardManager wizard =
new WizardManager("Specify Repository Name on Server1", false, panelMgr, icon);
wizard.showWizard();
runSwing(() -> {
JList<?> jlist = (JList<?>) getInstanceField("nameList", panel);
jlist.setSelectedIndex(0);
});
waitForSwing();
captureDialog();
}
@Test
public void testRestoreProjectFilledIn() {
runSwing(() -> {
RestoreDialog restoreDialog = new RestoreDialog(null);
JTextField textField = (JTextField) getInstanceField("archiveField", restoreDialog);
textField.setText("/Projects/Demo.gar");
textField = (JTextField) getInstanceField("restoreField", restoreDialog);
textField.setText("/Projects");
textField = (JTextField) getInstanceField("projectNameField", restoreDialog);
textField.setText("Demo");
tool.showDialog(restoreDialog);
}, false);
captureDialog();
}
@Test
public void testSaveFiles() throws InvalidNameException, CancelledException, IOException {
program = env.getProgram("WinHelloCPP.exe");
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program, TaskMonitor.DUMMY);
int tx = program.startTransaction("Test");
program.setName("Bob");
program.setName("WinHelloCPP.exe");
program.endTransaction(tx, true);
runSwing(() -> {
SaveDataDialog dialog = new SaveDataDialog(tool);
dialog.showDialog(Arrays.asList(new DomainFile[] { program.getDomainFile() }));
}, false);
captureDialog();
}
@Test
public void testSaveReadOnly() {
program = env.getProgram("WinHelloCPP.exe");
final StringBuffer sb = new StringBuffer();
sb.append("The following files are Read-Only and cannot be\n" +
" saved 'As Is.' You must do a manual 'Save As' for these\n" + " files: \n \n");
sb.append(program.getDomainFile().getPathname());
sb.append("\n");
// note: put the extra space in or else OptionDialog will not show
// the new line char
sb.append(" \nChoose 'Cancel' to cancel Close Project, or \n");
sb.append("'Lose Changes' to continue.");
runSwing(() -> OptionDialog.showOptionDialog(tool.getToolFrame(), "Read-Only Files",
sb.toString(), "Lose Changes", OptionDialog.QUESTION_MESSAGE), false);
captureDialog();
}
@Test
public void testSelectProjectLocation() {
performAction("New Project", "FrontEndPlugin", false);
DialogComponentProvider dialog = getDialog();
final WizardManager wm = (WizardManager) dialog;
runSwing(() -> {
wm.next();
WizardPanel panel = wm.getCurrentWizardPanel();
JTextField textField = (JTextField) getInstanceField("directoryField", panel);
textField.setText("/Projects");
wm.setStatusText("");
});
captureDialog(700, 350);
}
@Test
public void testSelectProjectType() {
performAction("New Project", "FrontEndPlugin", false);
captureDialog(700, 350);
}
@Test
public void testSelectSharedProjectLocation() {
performAction("New Project", "FrontEndPlugin", false);
DialogComponentProvider dialog = getDialog();
final WizardManager wm = (WizardManager) dialog;
runSwing(() -> {
wm.next();
WizardPanel panel = wm.getCurrentWizardPanel();
JTextField textField = (JTextField) getInstanceField("directoryField", panel);
textField.setText("/Projects");
textField = (JTextField) getInstanceField("projectNameField", panel);
textField.setText("Demo");
wm.setStatusText("");
JLabel label = (JLabel) getInstanceField("titleLabel", wm);
label.setText("Select Local Project Location for Repository Demo");
JButton button = (JButton) getInstanceField("finishButton", wm);
button.setEnabled(true);
});
captureDialog(700, 300);
}
@Test
public void testSelectSharedProjectType() {
performAction("New Project", "FrontEndPlugin", false);
DialogComponentProvider dialog = getDialog();
final WizardManager wm = (WizardManager) dialog;
runSwing(() -> {
WizardPanel panel = wm.getCurrentWizardPanel();
JRadioButton sharedRB = (JRadioButton) getInstanceField("sharedRB", panel);
sharedRB.setSelected(true);
wm.setStatusText("");
});
captureDialog(700, 350);
}
@Test
public void testServerInfo() {
performAction("New Project", "FrontEndPlugin", false);
DialogComponentProvider dialog = getDialog();
final WizardManager wm = (WizardManager) dialog;
runSwing(() -> {
WizardPanel panel = wm.getCurrentWizardPanel();
JRadioButton sharedRB = (JRadioButton) getInstanceField("sharedRB", panel);
sharedRB.setSelected(true);
wm.next();
panel = wm.getCurrentWizardPanel();
Component comp = (Component) getInstanceField("serverInfoComponent", panel);
JTextField textField = (JTextField) getInstanceField("nameField", comp);
textField.setText("Server1");
});
captureDialog(700, 300);
}
@Test
public void testSharedProjectInfo() {
performAction("View Project Info", "FrontEndPlugin", true);
final DialogComponentProvider dialog = getDialog();
runSwing(() -> {
JLabel label = (JLabel) getInstanceField("projectDirLabel", dialog);
label.setText("/Projects/TestPrj.rep");
label = (JLabel) getInstanceField("serverLabel", dialog);
label.setText("Server1");
label = (JLabel) getInstanceField("portLabel", dialog);
label.setText("13100");
label = (JLabel) getInstanceField("repNameLabel", dialog);
label.setText("Demo");
JButton button = (JButton) getInstanceField("connectionButton", dialog);
button.setEnabled(true);
button = (JButton) getInstanceField("changeConvertButton", dialog);
button.setText(ProjectInfoDialog.CHANGE);
});
captureDialog(400, 500);
}
@Test
public void testEditProjectAccessPanel() {
String[] knownUsers = { "user1", "user2", "user3", "user4", "user5", "user6" };
ArrayList<User> userList = new ArrayList<>();
userList.add(new User("user2", 2));
userList.add(new User("user4", 0));
userList.add(new User("user5", 1));
runSwing(() -> {
WizardPanel panel =
new ProjectAccessPanel(knownUsers, "user2", userList, "Demo", false, false, tool);
TestDummyPanelManager panelMgr =
new TestDummyPanelManager(panel, true, false, true, 650, 250);
WizardManager wizard = new WizardManager("New Project", false, panelMgr, icon);
wizard.showWizard();
});
waitForSwing();
captureDialog();
}
@Test
public void testViewProjectAccessPanel() {
String[] knownUsers = { "user1", "user2", "user3", "user4", "user5", "user6" };
ArrayList<User> userList = new ArrayList<>();
userList.add(new User("user2", 2));
userList.add(new User("user4", 0));
userList.add(new User("user5", 1));
runSwing(() -> {
JPanel panel = new ViewProjectAccessPanel(knownUsers, "user2", userList, "Demo", false,
false, tool);
DummyDialogComponentProvider dialog =
new DummyDialogComponentProvider("View Project Access List for Demo", panel);
tool.showDialog(dialog);
});
waitForSwing();
captureDialog();
}
@Test
public void testVersionedFileCOnoServer() {
MultiIcon multiIcon = new MultiIcon(GhidraFileData.VERSION_ICON);
multiIcon.addIcon(ProgramContentHandler.PROGRAM_ICON);
multiIcon.addIcon(GhidraFileData.CHECKED_OUT_ICON);
captureIconAndText(multiIcon, "Example (1 of 1)");
}
@Test
public void testVersionedFileCOwithServer() {
MultiIcon multiIcon = new MultiIcon(GhidraFileData.VERSION_ICON);
multiIcon.addIcon(ProgramContentHandler.PROGRAM_ICON);
multiIcon.addIcon(GhidraFileData.CHECKED_OUT_ICON);
captureIconAndText(multiIcon, "Example (3 of 3)*");
}
@Test
public void testVersionedFileIcon() {
MultiIcon multiIcon = new MultiIcon(GhidraFileData.VERSION_ICON);
multiIcon.addIcon(ProgramContentHandler.PROGRAM_ICON);
captureIconAndText(multiIcon, "Example (1)");
}
@Test
public void testMemoryUsage() {
performFrontEndAction("Show VM memory", "MemoryUsagePlugin", false);
waitForVMMemoryInitialilzed();// this is asynchronous and takes a while
captureDialog();
}
@Test
public void testViewOtherProjects()
throws IOException, LockException, InvalidNameException, CancelledException {
ProjectTestUtils.deleteProject(TEMP_DIR, OTHER_PROJECT);
Project project = env.getProject();
program = env.getProgram("WinHelloCPP.exe");
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("HelloCpp.exe", program, TaskMonitor.DUMMY);
project.close();
Project otherProject = ProjectTestUtils.getProject(TEMP_DIR, OTHER_PROJECT);
Language language = getZ80_LANGUAGE();
ProjectTestUtils.createProgramFile(otherProject, "Program1", language,
language.getDefaultCompilerSpec(), null);
ProjectTestUtils.createProgramFile(otherProject, "Program2", language,
language.getDefaultCompilerSpec(), null);
otherProject.close();
waitForSwing();
project = ProjectTestUtils.getProject(TEMP_DIR, PROJECT_NAME);
performAction("View Project", "FrontEndPlugin", false);
final GhidraFileChooser fileChooser = (GhidraFileChooser) getDialog();
runSwing(() -> fileChooser.setSelectedFile(new File(TEMP_DIR, OTHER_PROJECT)));
pressButtonOnDialog("Select Project");
setToolSize(500, 600);
captureToolWindow(700, 600);
ProjectTestUtils.deleteProject(TEMP_DIR, OTHER_PROJECT);
ProjectTestUtils.deleteProject(TEMP_DIR, OTHER_PROJECT);
}
private void waitForVMMemoryInitialilzed() {
Window w = waitForWindow("VM Memory Usage", 2000);
DialogComponentProvider dc = ((DockingDialog) w).getDialogComponent();
Boolean initialized = (Boolean) invokeInstanceMethod("isInitialized", dc);
int sleepyTime = 10;
int totalTime = 0;
while (!initialized && totalTime < 3000) {
sleep(sleepyTime);
initialized = (Boolean) invokeInstanceMethod("isInitialized", dc);
totalTime += sleepyTime;
}
initialized = (Boolean) invokeInstanceMethod("isInitialized", dc);
if (!initialized) {
Assert.fail("VM Memory window did not show its real values.");
}
}
private void paintImmediately(final DialogComponentProvider dialog) {
runSwing(() -> {
Rectangle bounds = dialog.getComponent().getBounds();
dialog.getComponent().paintImmediately(bounds);
});
waitForSwing();
sleep(40);
}
private void captureIconAndText(Icon labelImage, String text) {
final JLabel label = new JLabel(text);
label.setBackground(Color.WHITE);
label.setOpaque(true);
label.setIcon(labelImage);
label.setHorizontalAlignment(SwingConstants.CENTER);
runSwing(() -> {
JDialog dialog = new JDialog();
Container contentPane = dialog.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
contentPane.add(panel, BorderLayout.CENTER);
panel.add(label, BorderLayout.CENTER);
dialog.pack();
Dimension size = dialog.getSize();
size.width += 6;
size.height += 6;
dialog.setSize(size);
dialog.setVisible(true);
});
waitForSwing();
label.paintImmediately(label.getBounds());
captureComponent(label);
}
class DummyDialogComponentProvider extends DialogComponentProvider {
DummyDialogComponentProvider(String title, JPanel mainPanel) {
super(title, false);
addWorkPanel(mainPanel);
addOKButton();
addCancelButton();
}
}
}

View file

@ -0,0 +1,62 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import ghidra.bitpatterns.gui.*;
import ghidra.framework.plugintool.util.PluginException;
import ghidra.util.Msg;
public class FunctionBitPatternsExplorerPluginScreenShots extends GhidraScreenShotGenerator {
@Test
public void testDataGatheringParams() {
runSwing(() -> {
FunctionBitPatternsExplorerPlugin plugin = new FunctionBitPatternsExplorerPlugin(tool);
try {
tool.addPlugin(plugin);
}
catch (PluginException e) {
Msg.error(this, e);
}
});
performAction(FunctionBitPatternsMainProvider.EXPLORE_FUNCTION_PATTERNS_TEXT, "TestCodeBrowser", false);
waitForSwing();
captureDialog();
DataGatheringParamsDialog dialogComponent =
waitForDialogComponent(null, DataGatheringParamsDialog.class, 2000);
runSwing(() -> dialogComponent.close());
}
@Test
public void testTabbedView() {
runSwing(() -> {
FunctionBitPatternsExplorerPlugin plugin = new FunctionBitPatternsExplorerPlugin(tool);
try {
tool.addPlugin(plugin);
}
catch (PluginException e) {
Msg.error(this, e);
}
});
performAction(FunctionBitPatternsMainProvider.EXPLORE_FUNCTION_PATTERNS_TEXT, "TestCodeBrowser", false);
pressOkOnDialog();
waitForSwing();
captureIsolatedProvider(FunctionBitPatternsMainProvider.class, 1600, 600);
}
}

View file

@ -0,0 +1,336 @@
/* ###
* 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 help.screenshot;
import java.util.HashMap;
import java.util.HashSet;
import org.junit.Test;
import docking.ComponentProvider;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.plugin.core.functioncompare.*;
import ghidra.app.util.viewer.listingpanel.ListingCodeComparisonPanel;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
public class FunctionComparisonScreenShots extends GhidraScreenShotGenerator {
private static final String TEST_SOURCE_PROGRAM_NAME = "VersionTracking/WallaceSrc";
private static final String TEST_DESTINATION_PROGRAM_NAME = "VersionTracking/WallaceVersion2";
private FunctionComparisonPlugin plugin;
private Program sourceProgram;
private Program destinationProgram;
public FunctionComparisonScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
plugin = getPlugin(tool, FunctionComparisonPlugin.class);
}
@Test
public void testFunctionComparisonWindow() {
destinationProgram = loadProgram(TEST_DESTINATION_PROGRAM_NAME);
sourceProgram = loadProgram(TEST_SOURCE_PROGRAM_NAME);
positionListingTop(0x004118f0);
int txId1 = sourceProgram.startTransaction("Modify Program1");
int txId2 = destinationProgram.startTransaction("Modify Program2");
try {
sourceProgram.setName("TestProgram");
destinationProgram.setName("OtherProgram");
Listing sourceListing = sourceProgram.getListing();
Listing destListing = destinationProgram.getListing();
Memory sourceMemory = sourceProgram.getMemory();
Function f1 = getFunction(sourceProgram, addr(0x004118f0));
f1.setName("FunctionA", SourceType.USER_DEFINED);
sourceListing.setComment(addr(0x004118f0), CodeUnit.PLATE_COMMENT, null);
sourceListing.clearCodeUnits(addr(0x004119b1), addr(0x004119b4), false);
sourceMemory.setByte(addr(0x004119b2), (byte) 0x55);
sourceMemory.setByte(addr(0x004119b4), (byte) 0x52);
disassemble(sourceProgram, 0x004119b1, 4, false);
Function f2 = getFunction(destinationProgram, addr(0x004118c0));
f2.setName("FunctionB", SourceType.USER_DEFINED);
destListing.setComment(addr(0x004118c0), CodeUnit.PLATE_COMMENT, null);
Function[] functions = new Function[] { f1, f2 };
FunctionComparisonProviderManager providerMgr =
getInstanceFieldByClassType(FunctionComparisonProviderManager.class, plugin);
FunctionComparisonProvider functionComparisonProvider =
providerMgr.showFunctionComparisonProvider(functions);
FunctionComparisonPanel functionComparisonPanel =
functionComparisonProvider.getComponent();
runSwing(() -> {
functionComparisonPanel.setCurrentTabbedComponent("Listing View");
ListingCodeComparisonPanel dualListing =
(ListingCodeComparisonPanel) functionComparisonPanel.getDisplayedPanel();
ListingPanel leftPanel = dualListing.getLeftPanel();
dualListing.setLeftTitle("FunctionA() in /TestProgram");
dualListing.setRightTitle("FunctionB() in /OtherProgram");
leftPanel.goTo(addr(0x004119aa));
});
waitForSwing();
captureIsolatedProvider(FunctionComparisonProvider.class, 1200, 550);
}
catch (DuplicateNameException e) {
e.printStackTrace();
}
catch (InvalidInputException e) {
e.printStackTrace();
}
catch (MemoryAccessException e) {
e.printStackTrace();
}
finally {
destinationProgram.endTransaction(txId2, false);
sourceProgram.endTransaction(txId1, false);
}
}
@Test
public void testFunctionComparisonWindowFromMap() throws CircularDependencyException {
destinationProgram = loadProgram(TEST_DESTINATION_PROGRAM_NAME);
sourceProgram = loadProgram(TEST_SOURCE_PROGRAM_NAME);
positionListingTop(0x004118f0);
int txId1 = sourceProgram.startTransaction("Modify Program1");
int txId2 = destinationProgram.startTransaction("Modify Program2");
try {
sourceProgram.setName("TestProgram");
destinationProgram.setName("OtherProgram");
Listing sourceListing = sourceProgram.getListing();
Listing destListing = destinationProgram.getListing();
Memory sourceMemory = sourceProgram.getMemory();
Function f1 = getFunction(sourceProgram, addr(0x004118f0));
f1.setName("Function1", SourceType.USER_DEFINED);
Namespace parentNamespace = sourceProgram.getSymbolTable().createNameSpace(
program.getGlobalNamespace(), "Namespace1", SourceType.USER_DEFINED);
f1.setParentNamespace(parentNamespace);
sourceListing.setComment(addr(0x004118f0), CodeUnit.PLATE_COMMENT, null);
sourceListing.clearCodeUnits(addr(0x004119b1), addr(0x004119b4), false);
sourceMemory.setByte(addr(0x004119b2), (byte) 0x55);
sourceMemory.setByte(addr(0x004119b4), (byte) 0x52);
disassemble(sourceProgram, 0x004119b1, 4, false);
Function f2 = getFunction(destinationProgram, addr(0x004118c0));
f2.setName("Function2", SourceType.USER_DEFINED);
destListing.setComment(addr(0x004118c0), CodeUnit.PLATE_COMMENT, null);
Function fA = getFunction(sourceProgram, addr(0x00411a30));
fA.setName("FunctionA", SourceType.USER_DEFINED);
sourceListing.setComment(addr(0x00411a30), CodeUnit.PLATE_COMMENT, null);
Function fB = getFunction(destinationProgram, addr(0x00411a10));
fB.setName("FunctionB", SourceType.USER_DEFINED);
destListing.setComment(addr(0x00411a10), CodeUnit.PLATE_COMMENT, null);
Function fC = getFunction(sourceProgram, addr(0x00411ab0));
fC.setName("FunctionC", SourceType.USER_DEFINED);
sourceListing.setComment(addr(0x00411ab0), CodeUnit.PLATE_COMMENT, null);
Function fD = getFunction(destinationProgram, addr(0x00411a90));
fD.setName("FunctionD", SourceType.USER_DEFINED);
destListing.setComment(addr(0x00411a90), CodeUnit.PLATE_COMMENT, null);
HashMap<Function, HashSet<Function>> functionMap = new HashMap<>();
HashSet<Function> functionSet = new HashSet<>();
functionSet.add(fA);
functionSet.add(fB);
functionMap.put(f1, functionSet);
functionSet = new HashSet<>();
functionSet.add(fC);
functionSet.add(fD);
functionMap.put(f2, functionSet);
FunctionComparisonProviderManager providerMgr =
getInstanceFieldByClassType(FunctionComparisonProviderManager.class, plugin);
FunctionComparisonProvider functionComparisonProvider =
providerMgr.showFunctionComparisonProvider(functionMap);
FunctionComparisonPanel functionComparisonPanel =
functionComparisonProvider.getComponent();
runSwing(() -> {
functionComparisonPanel.setCurrentTabbedComponent("Listing View");
ListingCodeComparisonPanel dualListing =
(ListingCodeComparisonPanel) functionComparisonPanel.getDisplayedPanel();
ListingPanel leftPanel = dualListing.getLeftPanel();
leftPanel.goTo(addr(0x004119aa));
});
waitForSwing();
captureIsolatedProvider(FunctionComparisonProvider.class, 1200, 550);
}
catch (DuplicateNameException | InvalidInputException | MemoryAccessException e) {
e.printStackTrace();
}
finally {
destinationProgram.endTransaction(txId2, false);
sourceProgram.endTransaction(txId1, false);
}
}
@Test
public void testListingCodeComparisonOptions() {
destinationProgram = loadProgram(TEST_DESTINATION_PROGRAM_NAME);
sourceProgram = loadProgram(TEST_SOURCE_PROGRAM_NAME);
positionListingTop(0x004118f0);
int txId1 = sourceProgram.startTransaction("Modify Program1");
int txId2 = destinationProgram.startTransaction("Modify Program2");
try {
sourceProgram.setName("TestProgram");
destinationProgram.setName("OtherProgram");
Listing sourceListing = sourceProgram.getListing();
Listing destListing = destinationProgram.getListing();
Memory sourceMemory = sourceProgram.getMemory();
Function f1 = getFunction(sourceProgram, addr(0x004118f0));
f1.setName("FunctionA", SourceType.USER_DEFINED);
sourceListing.setComment(addr(0x004118f0), CodeUnit.PLATE_COMMENT, null);
sourceListing.clearCodeUnits(addr(0x004119b1), addr(0x004119b4), false);
sourceMemory.setByte(addr(0x004119b2), (byte) 0x55);
sourceMemory.setByte(addr(0x004119b4), (byte) 0x52);
disassemble(sourceProgram, 0x004119b1, 4, false);
Function f2 = getFunction(destinationProgram, addr(0x004118c0));
f2.setName("FunctionB", SourceType.USER_DEFINED);
destListing.setComment(addr(0x004118c0), CodeUnit.PLATE_COMMENT, null);
Function[] functions = new Function[] { f1, f2 };
FunctionComparisonProviderManager providerMgr =
getInstanceFieldByClassType(FunctionComparisonProviderManager.class, plugin);
FunctionComparisonProvider functionComparisonProvider =
providerMgr.showFunctionComparisonProvider(functions);
FunctionComparisonPanel functionComparisonPanel =
functionComparisonProvider.getComponent();
runSwing(() -> {
functionComparisonPanel.setCurrentTabbedComponent("Listing View");
});
waitForSwing();
ComponentProvider provider = getProvider("Function Comparison");
performAction("Listing Code Comparison Options", "Function Comparison", provider,
false);
captureDialog(600, 300);
pressButtonByText(getDialog(), "Cancel");
waitForSwing();
}
catch (DuplicateNameException e) {
e.printStackTrace();
}
catch (InvalidInputException e) {
e.printStackTrace();
}
catch (MemoryAccessException e) {
e.printStackTrace();
}
finally {
destinationProgram.endTransaction(txId2, false);
sourceProgram.endTransaction(txId1, false);
}
}
@Test
public void testMultiFunctionComparisonWindow() {
destinationProgram = loadProgram(TEST_DESTINATION_PROGRAM_NAME);
sourceProgram = loadProgram(TEST_SOURCE_PROGRAM_NAME);
positionListingTop(0x004118f0);
int txId1 = sourceProgram.startTransaction("Modify Program1");
int txId2 = destinationProgram.startTransaction("Modify Program2");
try {
sourceProgram.setName("TestProgram");
destinationProgram.setName("OtherProgram");
Listing sourceListing = sourceProgram.getListing();
Listing destListing = destinationProgram.getListing();
Memory sourceMemory = sourceProgram.getMemory();
Function f1 = getFunction(sourceProgram, addr(0x004118f0));
f1.setName("FunctionA", SourceType.USER_DEFINED);
sourceListing.setComment(addr(0x004118f0), CodeUnit.PLATE_COMMENT, null);
sourceListing.clearCodeUnits(addr(0x004119b1), addr(0x004119b4), false);
sourceMemory.setByte(addr(0x004119b2), (byte) 0x55);
sourceMemory.setByte(addr(0x004119b4), (byte) 0x52);
disassemble(sourceProgram, 0x004119b1, 4, false);
Function f2 = getFunction(destinationProgram, addr(0x004118c0));
f2.setName("FunctionB", SourceType.USER_DEFINED);
destListing.setComment(addr(0x004118c0), CodeUnit.PLATE_COMMENT, null);
Function f3 = getFunction(sourceProgram, addr(0x004117c0));
f3.setName("FunctionC", SourceType.USER_DEFINED);
sourceListing.setComment(addr(0x004117c0), CodeUnit.PLATE_COMMENT, null);
Function f4 = getFunction(destinationProgram, addr(0x004117b0));
f4.setName("FunctionD", SourceType.USER_DEFINED);
destListing.setComment(addr(0x004117b0), CodeUnit.PLATE_COMMENT, null);
Function[] functions = new Function[] { f1, f2, f3, f4 };
FunctionComparisonProviderManager providerMgr =
getInstanceFieldByClassType(FunctionComparisonProviderManager.class, plugin);
FunctionComparisonProvider functionComparisonProvider =
providerMgr.showFunctionComparisonProvider(functions);
FunctionComparisonPanel functionComparisonPanel =
functionComparisonProvider.getComponent();
runSwing(() -> {
functionComparisonPanel.setCurrentTabbedComponent("Listing View");
ListingCodeComparisonPanel dualListing =
(ListingCodeComparisonPanel) functionComparisonPanel.getDisplayedPanel();
ListingPanel leftPanel = dualListing.getLeftPanel();
leftPanel.goTo(addr(0x004119a5));
});
waitForSwing();
captureIsolatedProvider(FunctionComparisonProvider.class, 1200, 598);
}
catch (DuplicateNameException | InvalidInputException | MemoryAccessException e) {
e.printStackTrace();
}
finally {
destinationProgram.endTransaction(txId2, false);
sourceProgram.endTransaction(txId1, false);
}
}
Function getFunction(Program program1, Address entryPoint) {
FunctionManager functionManager = program1.getFunctionManager();
return functionManager.getFunctionAt(entryPoint);
}
public void disassemble(Program pgm1, long addressAsLong, int length, boolean followFlows) {
Address address = addr(addressAsLong);
DisassembleCommand cmd = new DisassembleCommand(address,
new AddressSet(address, address.add(length - 1)), followFlows);
cmd.applyTo(pgm1);
}
}

View file

@ -0,0 +1,943 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertNotNull;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import javax.swing.*;
import org.junit.*;
import docking.*;
import docking.action.DockingAction;
import docking.menu.ActionState;
import docking.menu.MultiStateDockingAction;
import docking.util.image.Callout;
import docking.util.image.CalloutComponentInfo;
import docking.widgets.dialogs.MultiLineInputDialog;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationServer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.picking.PickedState;
import generic.test.TestUtils;
import ghidra.app.cmd.function.DeleteFunctionCmd;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.plugin.core.functiongraph.AbstractFunctionGraphTest;
import ghidra.app.plugin.core.functiongraph.FGProvider;
import ghidra.app.plugin.core.functiongraph.graph.*;
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutProvider;
import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
import ghidra.app.plugin.core.functiongraph.graph.vertex.GroupedFunctionGraphVertex;
import ghidra.app.plugin.core.functiongraph.mvc.FGController;
import ghidra.app.plugin.core.functiongraph.mvc.FGView;
import ghidra.graph.viewer.GraphViewerUtils;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.TestEnv;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
public class FunctionGraphPluginScreenShots extends AbstractFunctionGraphTest {
private MyScreen screen;
private int width = 400;
private int height = 400;
public FunctionGraphPluginScreenShots() {
super();
}
@Override
@Before
public void setUp() throws Exception {
screen = new MyScreen();
try {
screen.setUp();
}
catch (Exception e) {
failWithException("Unepected exception in setup", e);
}
super.setUp();
screen.program = program;
setLayout();
}
@Override
@After
public void tearDown() throws Exception {
// We share the program--don't let the screen release it's copy
// screen.env.release(screen.program);
super.tearDown();
screen.saveOrDisplayImage(testName.getMethodName());
}
@Override
protected TestEnv getEnv() {
return screen.env;
}
@Override
protected String getStartingProgramName() {
return "WinHelloCPP.exe";
}
@Override
protected void openProgram() {
program = env.getProgram(getStartingProgramName());
}
@Override
protected String getStartingAddress() {
return "406630";
}
@Test
public void testFunctionGraphWindow() {
go("406630");// _strlen function
setSize(750, 560);// size first, as the positioning is sensitive to the size
setZoom(1.0);// full zoom
centerDisplay();
captureProviderWindow();
}
@Test
public void testFunctionGraph_Provider_Undefined() {
createUndefinedFunction();
isolateProvider();
hideSatellite();
setSize(700, 500);// size first, as the positioning is sensitive to the size
setZoom(.25);// zoom out a bit to show more vertices
centerDisplay();
captureProvider();
cropAndRemoveHeader(388, 194);
}
@Test
public void testFunctionGraph_Stale_Graph() {
String address = "406630";
go(address);// _strlen function
hideSatellite();
setSize(612, 300);
// make a change to trigger the 'stale graph' message
changeLabel(getAddress(address));
captureProviderWindow();
cropAndKeepMessageSection();
drawRectangleAroundMessageText();
}
public void testFunctionGraph_Vertex_Header() {
String address = "406630";
go(address);// _strlen function
setSize(1000, 1000);// size first, as the positioning is sensitive to the size
setZoom(1.0);// full zoom
centerDisplay();
captureProvider();
cropRootVertexHeader();
}
@Test
public void testFunctionGraph_Grouped_Vertex_Header() {
String functionAddress = "405d29";
go(functionAddress);// ___updatetmbcinfo function
setSize(1000, 1000);// size first, as the positioning is sensitive to the size
setZoom(1.0);// full zoom
String a1 = "405d46";
String a2 = "405d4c";
FGVertex v1 = vertex(a1);
FGVertex v2 = vertex(a2);
GroupedFunctionGraphVertex group = group(null, v1, v2);
centerDisplay();
captureProvider();
cropVertexHeader(group);
}
@Test
public void testFunctionGraph_Pre_Group() {
String functionAddress = "405d29";
go(functionAddress);// ___updatetmbcinfo function
hideSatellite();
setNestedLayout();
setSize(1000, 600);// size first, as the positioning is sensitive to the size
setZoom(1d);// full zoom
FGVertex root = vertex(functionAddress);
String a1 = "405d46";
String a2 = "405d4c";
FGVertex v1 = vertex(a1);
FGVertex v2 = vertex(a2);
pickVertices(v1, v2);
moveGraphToUpperLeftCorner(root);
captureProvider();
cropVertices(root, v1, v2);
// createGroupButtonCallout_PlayArea(v1, "FunctionGraph_Pre_Group.png");
createGroupButtonCallout(v1);
}
@Test
public void testFunctionGraph_Post_Group() {
String functionAddress = "405d29";
go(functionAddress);// ___updatetmbcinfo function
setNestedLayout();
setSize(1000, 500);// size first, as the positioning is sensitive to the size
setZoom(.85);
FGVertex root = vertex(functionAddress);
moveGraphToUpperLeftCorner(root);
String a1 = "405d46";
String a2 = "405d4c";
FGVertex v1 = vertex(a1);
FGVertex v2 = vertex(a2);
GroupedFunctionGraphVertex group = group(null, v1, v2);
captureProvider();
cropVertices(root, group);
}
@Test
public void testFunctionGraph_Group_Text_Dialog() throws Exception {
String functionAddress = "405d29";
go(functionAddress);// ___updatetmbcinfo function
FGVertex root = vertex(functionAddress);
moveGraphToUpperLeftCorner(root);
String a1 = "405d46";
String a2 = "405d4c";
FGVertex v1 = vertex(a1);
FGVertex v2 = vertex(a2);
DialogComponentProvider dialog = showGroupTextDialog(v1, v2);
screen.captureDialog(dialog);
pressButtonByText(dialog.getComponent(), "Cancel");
}
@Test
public void testFunctionGraph_Provider_Header() {
setSize(800, 400);
captureProviderWindow();
GenericHeader providerHeader = getHeader();
cropHeaderToActions(providerHeader);
}
@Test
public void testFunctionGraph_Vertex_Drop_Shadow() {
//
// This image is a bit abnormal. It is a picture of a vertex next to itself after it
// has been zoomed out past its 'interaction threshold'. Further, both vertices are
// zoomed out past the point of readability.
//
String functionAddress = "4057c4";
go(functionAddress);// __fflush_nolock
setNestedLayout();
setSize(500, 500);// size first, as the positioning is sensitive to the size
double beforeThresholdZoom = GraphViewerUtils.INTERACTION_ZOOM_THRESHOLD + .01;
setZoom(beforeThresholdZoom);
moveGraphToUpperLeftCorner();
Image graphImage1 = captureGraph();
double pastThresholdZoom = GraphViewerUtils.INTERACTION_ZOOM_THRESHOLD - .01;
setZoom(pastThresholdZoom);
moveGraphToUpperLeftCorner();
Image graphImage2 = captureGraph();
// create an empty image onto which we will place both images, side-by-side
int bufferSpace = 50;
int graphWidth = graphImage1.getWidth(null) * 2 + bufferSpace;
int graphHeight = graphImage1.getHeight(null);
BufferedImage fullImage = screen.createEmptyImage(graphWidth, graphHeight);
Graphics2D g = (Graphics2D) fullImage.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(graphImage1, 0, 0, null);
int xOffset = graphImage1.getWidth(null) + bufferSpace;
g.drawImage(graphImage2, xOffset, 0, null);
int w = 3;
int x1 = graphImage1.getWidth(null) + (bufferSpace / 2) - (w / 2);// between images
int y1 = 10;// down a bit
int h = (graphImage1.getHeight(null) - 10) - y1;
g.setColor(Color.BLACK);
g.fillRect(x1, y1, w, h);
screen.image = fullImage;
}
// For Debug of callout
// public void testCallout() {
// go("406630"); // _strlen function
//
// setSize(750, 560); // size first, as the positioning is sensitive to the size
// centerDisplay();
//
// doTestCallout();
// }
//
// private void doTestCallout() {
// ComponentProvider provider = screen.getComponentProvider(FunctionGraphProvider.class);
// JComponent providerComponent = provider.getComponent();
// DockableComponent parent = getDockableComponent(providerComponent);
// JButton component = getToolbarButton(provider, "Go To Function Entry Point");
//
// Rectangle bounds = component.getBounds();
// Point relativeLocation = bounds.getLocation();
// Dimension size = bounds.getSize();
// Point screenLocation = new Point(relativeLocation);
// SwingUtilities.convertPointToScreen(screenLocation, component.getParent());
// CalloutComponentInfo info =
// new CalloutComponentInfo(parent, component, screenLocation, relativeLocation, size);
//
// createCallout(parent, info);
// showImage("FunctionGraphPlugin", "FunctionGraph_Post_Group.png");
// }
//==================================================================================================
// Private Methods
//==================================================================================================
private Image captureGraph() {
FGController controller = getFunctionGraphController();
FGView view = controller.getView();
VisualizationViewer<FGVertex, FGEdge> viewer = view.getPrimaryGraphViewer();
FunctionGraph functionGraph = getFunctionGraph();
Graph<FGVertex, FGEdge> graph = functionGraph;
Collection<FGVertex> vertices = graph.getVertices();
Rectangle layoutBounds =
GraphViewerUtils.getBoundsForVerticesInLayoutSpace(viewer, vertices);
Rectangle viewBounds =
GraphViewerUtils.translateRectangleFromLayoutSpaceToViewSpace(viewer, layoutBounds);
// add some padding
int padding = 40;
viewBounds.x -= padding;
viewBounds.y -= padding;
viewBounds.width += (2 * padding);
viewBounds.height += (2 * padding);
FGProvider provider = screen.getProvider(FGProvider.class);
JComponent parent = provider.getComponent();
DockableComponent dc = getDockableComponent(parent);
viewBounds = SwingUtilities.convertRectangle(provider.getComponent(), viewBounds, dc);
captureProvider();
screen.crop(viewBounds);
return screen.image;
}
private Image captureVertex(FGVertex v) {
// make sure the vertex is showing
moveGraphToUpperLeftCorner(v);
FGController controller = getFunctionGraphController();
FGView view = controller.getView();
VisualizationViewer<FGVertex, FGEdge> viewer = view.getPrimaryGraphViewer();
FGProvider provider = screen.getProvider(FGProvider.class);
JComponent parent = provider.getComponent();
DockableComponent dc = getDockableComponent(parent);
Rectangle vertexBounds = GraphViewerUtils.getVertexBoundsInViewSpace(viewer, v);
JComponent component = v.getComponent();
vertexBounds = SwingUtilities.convertRectangle(component.getParent(), vertexBounds, dc);
captureProvider();
screen.crop(vertexBounds);
return screen.image;
}
private void cropHeaderToActions(final GenericHeader header) {
final AtomicReference<Rectangle> ref = new AtomicReference<>();
runSwing(() -> {
int actionsWidth = header.getToolBarWidth();
Window window = windowForComponent(header);
Rectangle headerBounds = header.getBounds();
Rectangle bounds = new Rectangle(headerBounds);
// ugh--apparently the toolbar does not correctly calculate its minimum size
int padding = 30;
bounds = SwingUtilities.convertRectangle(header.getParent(), headerBounds, window);
bounds.x = bounds.x + bounds.width - (actionsWidth + padding);
padding = 8;// now some vertical padding
bounds.y -= padding;
bounds.height += (2 * padding);
ref.set(bounds);
});
Rectangle bounds = ref.get();
screen.crop(bounds);
}
private GenericHeader getHeader() {
FGController controller = getFunctionGraphController();
ComponentProvider provider = controller.getProvider();
DockableComponent dc = getDockableComponent(provider.getComponent());
return dc.getHeader();
}
private void createCallout(JComponent parentComponent, CalloutComponentInfo calloutInfo) {
// create image of parent with extra space for callout feature
Image parentImage = screen.captureComponent(parentComponent);
Callout callout = new Callout();
screen.image = callout.createCalloutOnImage(parentImage, calloutInfo);
// createCalloutOnImage(parentImage, parentComponent, calloutInfo);
}
private void createGroupButtonCallout(FGVertex v) {
JButton component = getToolbarButton(v, "Group Vertices");
FGProvider provider = screen.getProvider(FGProvider.class);
JComponent parent = provider.getComponent();
FGController controller = getFunctionGraphController();
FGView view = controller.getView();
VisualizationViewer<FGVertex, FGEdge> viewer = view.getPrimaryGraphViewer();
Rectangle bounds = component.getBounds();
Dimension size = bounds.getSize();
Point location = bounds.getLocation();
JComponent vertexComponent = v.getComponent();
Point newLocation =
SwingUtilities.convertPoint(component.getParent(), location, vertexComponent);
Point relativePoint = GraphViewerUtils.translatePointFromVertexRelativeSpaceToViewSpace(
viewer, v, newLocation);
Point screenLocation = new Point(relativePoint);
SwingUtilities.convertPointToScreen(screenLocation, parent);
CalloutComponentInfo calloutInfo = new FGCalloutComponentInfo(parent, component,
screenLocation, relativePoint, size, viewer, v);
createCallout(parent, calloutInfo);
}
private JButton getToolbarButton(FGVertex vertex, String actionName) {
JComponent component = vertex.getComponent();
GenericHeader header = (GenericHeader) getInstanceField("genericHeader", component);
return getToolbarButton(header, actionName);
}
private JButton getToolbarButton(GenericHeader header, String actionName) {
// get the header's 'toolBarMgr' - DockableToolBarManager
Object toolBarMgr = getInstanceField("toolBarMgr", header);
// get the toolbar manager's 'toolBarManager' - ToolBarManager
Object toolBarManager = getInstanceField("toolBarManager", toolBarMgr);
// get the tool bar manager's manager's 'toolBar'
JComponent toolbar = (JComponent) getInstanceField("toolBar", toolBarManager);
Component[] components = toolbar.getComponents();
for (Component c : components) {
if (!(c instanceof JButton)) {
continue;
}
String name = c.getName();
if (actionName.equals(name)) {
return (JButton) c;
}
}
Assert.fail("Could not find action button");
return null;
}
private void drawRectangleAroundMessageText() {
int imageHeight = screen.image.getHeight(null);
int boxSize = 60;
int boxThickness = 3;
int x = 1;
int y = imageHeight - boxSize;
int w = 250;
int h = boxSize - boxThickness;
Rectangle rect = new Rectangle(x, y, w, h);
// drop shadow
Color color = Color.GRAY;
screen.drawRectangle(color, rect, boxThickness);
// box
x -= 1;
y -= 2;
color = new Color(0xB5, 0xDE, 0x2F);
rect.x = x;
rect.y = y;
screen.drawRectangle(color, rect, boxThickness);
}
private void changeLabel(Address address) {
AddLabelCmd cmd = new AddLabelCmd(address, "Test.Label", SourceType.USER_DEFINED);
int id = program.startTransaction("Test");
try {
cmd.applyTo(program);
}
finally {
program.endTransaction(id, true);
}
}
private void cropRootVertexHeader() {
FunctionGraph functionGraph = getFunctionGraph();
FGVertex rootVertex = functionGraph.getRootVertex();
cropVertexHeader(rootVertex);
}
private void cropVertexHeader(FGVertex vertex) {
FGPrimaryViewer viewer = getPrimaryGraphViewer();
Rectangle bounds = GraphViewerUtils.getVertexBoundsInViewSpace(viewer, vertex);
DockableComponent dockableComponent = getDockableComponent(viewer);
Point loc = SwingUtilities.convertPoint(viewer, bounds.getLocation(), dockableComponent);
bounds.setLocation(loc);
//
// We want to keep the whole header, with a buffer space around it of about 10px
//
Rectangle area = new Rectangle(bounds);
int offset = 10;
area.x -= offset;
area.y -= offset;
area.width += (2 * offset);
area.height = 50;
screen.crop(area);
}
private void cropVertices(FGVertex... vertices) {
FGPrimaryViewer viewer = getPrimaryGraphViewer();
List<FGVertex> list = Arrays.asList(vertices);
Rectangle bounds = GraphViewerUtils.getBoundsForVerticesInLayoutSpace(viewer, list);
bounds = GraphViewerUtils.translateRectangleFromLayoutSpaceToViewSpace(viewer, bounds);
DockableComponent dockableComponent = getDockableComponent(viewer);
bounds = SwingUtilities.convertRectangle(viewer, bounds, dockableComponent);
//
// Put a buffer space around the area
//
Rectangle area = new Rectangle(bounds);
int offset = 20;
area.x -= offset;
area.y -= offset;
area.width += (2 * offset);
area.height += (2 * offset);
screen.crop(area);
}
private void cropAndKeepMessageSection() {
int imageWidth = screen.image.getWidth(null);
int imageHeight = screen.image.getHeight(null);
// keep about 100 pixels of display to get the message area and a bit above
Rectangle area = new Rectangle();
area.x = 0;
area.y = imageHeight - 120;
area.width = imageWidth;
area.height = 120;
screen.crop(area);
}
private void go(String address) {
goToAddress(address);
}
private void centerDisplay() {
FunctionGraph functionGraph = getFunctionGraph();
FGVertex v = functionGraph.getRootVertex();
setVertexToCenterTop(v);
}
private void moveGraphToUpperLeftCorner(final FGVertex anchorVertex) {
waitForBusyGraph();
runSwing(() -> {
FGPrimaryViewer viewer = getPrimaryGraphViewer();
Point p = getOffsetFromUpperLeftForVertexInLayoutSpace(viewer, anchorVertex);
moveViewerLocationWithoutAnimation(p);
});
}
private void moveGraphToUpperLeftCorner() {
waitForBusyGraph();
final FunctionGraph functionGraph = getFunctionGraph();
runSwing(() -> {
FGController controller = getFunctionGraphController();
FGView view = controller.getView();
VisualizationViewer<FGVertex, FGEdge> viewer = view.getPrimaryGraphViewer();
FunctionGraph graph = functionGraph;
Collection<FGVertex> vertices = graph.getVertices();
Rectangle layoutBounds =
GraphViewerUtils.getBoundsForVerticesInLayoutSpace(viewer, vertices);
Rectangle viewBounds =
GraphViewerUtils.translateRectangleFromLayoutSpaceToViewSpace(viewer, layoutBounds);
Point location = viewBounds.getLocation();
Point layoutPoint = getOffsetFromUpperLeftForViewPointInLayoutSpace(viewer, location);
moveViewerLocationWithoutAnimation(layoutPoint);
});
}
private <V, E> Point getOffsetFromUpperLeftForVertexInLayoutSpace(
VisualizationServer<V, E> viewer, V vertex) {
//
// We need an offset from the current vertex to the center top of the viewer
//
Rectangle vertexBoundsInViewSpace =
GraphViewerUtils.getVertexBoundsInViewSpace(viewer, vertex);
Point vertexLocationInViewSpace = vertexBoundsInViewSpace.getLocation();
// this padding is enough to not see the edges for most operations--it can be increased
int xWithPadding = 20;
int yWithPadding = 20;
Double point = new Point2D.Double(xWithPadding, yWithPadding);// upper, left
Point vertexPointInLayoutSpace = GraphViewerUtils.translatePointFromViewSpaceToLayoutSpace(
vertexLocationInViewSpace, viewer);
Point upperLeftInLayoutSpace =
GraphViewerUtils.translatePointFromViewSpaceToLayoutSpace(point, viewer);
double offsetX = upperLeftInLayoutSpace.getX() - vertexPointInLayoutSpace.getX();
double offsetY = upperLeftInLayoutSpace.getY() - vertexPointInLayoutSpace.getY();
return new Point((int) offsetX, (int) offsetY);
}
private <V, E> Point getOffsetFromUpperLeftForViewPointInLayoutSpace(
VisualizationServer<V, E> viewer, Point viewPoint) {
// this padding is enough to not see the edges for most operations--it can be increased
int xWithPadding = 50;
int yWithPadding = 50;
Double offsetPoint = new Point2D.Double(xWithPadding, yWithPadding);// upper, left
Point vertexPointInLayoutSpace =
GraphViewerUtils.translatePointFromViewSpaceToLayoutSpace(viewPoint, viewer);
Point viewOffsetPointInLayoutSpace =
GraphViewerUtils.translatePointFromViewSpaceToLayoutSpace(offsetPoint, viewer);
double offsetX = viewOffsetPointInLayoutSpace.getX() - vertexPointInLayoutSpace.getX();
double offsetY = viewOffsetPointInLayoutSpace.getY() - vertexPointInLayoutSpace.getY();
return new Point((int) offsetX, (int) offsetY);
}
private void isolateProvider() {
ComponentProvider provider = tool.getWindowManager().getComponentProvider(FGProvider.class);
screen.moveProviderToItsOwnWindow(provider);
}
private void setSize(final int width, final int height) {
this.width = width;
this.height = height;
final ComponentProvider provider =
tool.getWindowManager().getComponentProvider(FGProvider.class);
runSwing(() -> {
Window window = tool.getWindowManager().getProviderWindow(provider);
if (window == null) {
throw new AssertException("Could not find window for " +
"provider--is it showing?: " + provider.getName());
}
window.setSize(new Dimension(width, height));
});
}
private void captureProvider() {
screen.captureIsolatedProvider(FGProvider.class, width, height);
}
private void captureProviderWindow() {
screen.captureIsolatedProviderWindow(FGProvider.class, width, height);
}
private void cropAndRemoveHeader(int w, int h) {
int imageWidth = screen.image.getWidth(null);
int x = (imageWidth / 2) - (w / 2);
int y = 20;// down a bit from the top
Rectangle newBounds = new Rectangle(x, y, w, h);
screen.crop(newBounds);
}
private void createUndefinedFunction() {
String address = "00401c25";
go(address);
DeleteFunctionCmd cmd = new DeleteFunctionCmd(getAddress(address));
int id = program.startTransaction("Test");
try {
cmd.applyTo(program);
}
finally {
program.endTransaction(id, true);
}
}
private DialogComponentProvider showGroupTextDialog(FGVertex... vertices) {
HashSet<FGVertex> set = new HashSet<>();
for (FGVertex v : vertices) {
set.add(v);
}
pickVertices(set);
FGVertex aVertex = vertices[0];
JComponent component = getComponent(aVertex);
DockingAction action = (DockingAction) TestUtils.getInstanceField("groupAction", component);
performAction(action, graphProvider, false);
waitForAnimation();
return waitForDialogComponent(MultiLineInputDialog.class);
}
private void pickVertices(FGVertex... vertices) {
pickVertices(new HashSet<>(Arrays.asList(vertices)));
}
private void pickVertices(final Set<FGVertex> vertices) {
runSwing(() -> {
PickedState<FGVertex> pickedState = getPickedState();
pickedState.clear();
for (FGVertex vertex : vertices) {
pickedState.pick(vertex, true);
}
});
}
private PickedState<FGVertex> getPickedState() {
FGComponent functionGraphViewer = getGraphComponent();
VisualizationViewer<FGVertex, FGEdge> primaryViewer =
functionGraphViewer.getPrimaryViewer();
return primaryViewer.getPickedVertexState();
}
private JComponent getComponent(final FGVertex vertex) {
final AtomicReference<JComponent> reference = new AtomicReference<>();
runSwing(() -> reference.set(vertex.getComponent()));
return reference.get();
}
private void setNestedLayout() {
Object actionManager = getInstanceField("actionManager", graphProvider);
@SuppressWarnings("unchecked")
final MultiStateDockingAction<Class<? extends FGLayoutProvider>> action =
(MultiStateDockingAction<Class<? extends FGLayoutProvider>>) getInstanceField(
"layoutAction", actionManager);
runSwing(() -> {
List<ActionState<Class<? extends FGLayoutProvider>>> states =
action.getAllActionStates();
for (ActionState<Class<? extends FGLayoutProvider>> state : states) {
Class<? extends FGLayoutProvider> layoutClass = state.getUserData();
if (layoutClass.getSimpleName().equals("DecompilerNestedLayoutProvider")) {
action.setCurrentActionState(state);
return;
}
}
throw new RuntimeException("Could not find layout!!");
});
}
private void createGroupButtonCallout_PlayArea(final FGVertex v, final String imageName) {
FGProvider provider = screen.getProvider(FGProvider.class);
Window window = windowForComponent(provider.getComponent());
final JDialog dialog = new JDialog(window);
dialog.setModal(true);
JPanel panel = new JPanel(new BorderLayout());
JButton button = new JButton("Repaint");
button.addActionListener(e -> new Thread() {
@Override
public void run() {
Thread.currentThread().setName("Show Image[" + System.identityHashCode(this) + "]");
createGroupButtonCallout(v);
screen.saveOrDisplayImage(imageName);
}
}.start());
JButton closeButton = new JButton("Close");
closeButton.addActionListener(e -> dialog.setVisible(false));
panel.add(button);
panel.add(closeButton, BorderLayout.SOUTH);
dialog.getContentPane().add(panel);
dialog.setSize(300, 200);
dialog.setLocation(1300, 100);
dialog.setVisible(true);
}
@SuppressWarnings("rawtypes")
private void setLayout() {
long start = System.currentTimeMillis();
Object actionManager = getInstanceField("actionManager", graphProvider);
final MultiStateDockingAction<?> action =
(MultiStateDockingAction<?>) getInstanceField("layoutAction", actionManager);
Object minCrossState = null;
List<?> states = action.getAllActionStates();
for (Object state : states) {
if (((ActionState) state).getName().indexOf("Nested Code Layout") != -1) {
minCrossState = state;
break;
}
}
assertNotNull("Could not find min cross layout!", minCrossState);
//@formatter:off
invokeInstanceMethod( "setCurrentActionState",
action,
new Class<?>[] { ActionState.class },
new Object[] { minCrossState });
//@formatter:on
runSwing(() -> action.actionPerformed(new ActionContext()));
// wait for the threaded graph layout code
FGController controller = getFunctionGraphController();
waitForBusyRunManager(controller);
waitForAnimation();
getPrimaryGraphViewer().repaint();
waitForPostedSwingRunnables();
long end = System.currentTimeMillis();
Msg.debug(this, "relayout time: " + ((end - start) / 1000.0) + "s");
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class MyScreen extends GhidraScreenShotGenerator {
public MyScreen() {
super();
}
@Override
public void loadProgram() {
// do nothing, we will put our own copy inside the screen
}
@Override
// overridden so that we use the outer class's name when finding the help topic
protected File getHelpTopic() {
Class<?> clazz = FunctionGraphPluginScreenShots.class;
String simpleName = clazz.getSimpleName();
simpleName = simpleName.replace("ScreenShots", "");
File helpTopicDir = getHelpTopicDir(simpleName);
assertNotNull("Unable to find help topic for test file: " + clazz.getName(),
helpTopicDir);
return helpTopicDir;
}
}
private class FGCalloutComponentInfo extends CalloutComponentInfo {
private VisualizationViewer<FGVertex, FGEdge> viewer;
private FGVertex vertex;
FGCalloutComponentInfo(Component destinationComponent, Component component,
Point locationOnScreen, Point relativeLocation, Dimension size,
VisualizationViewer<FGVertex, FGEdge> viewer, FGVertex vertex) {
super(destinationComponent, component, locationOnScreen, relativeLocation, size);
this.viewer = viewer;
this.vertex = vertex;
}
@Override
public Point convertPointToParent(Point location) {
// TODO: this won't work for now if the graph is scaled. This is because there is
// point information that is calculated by the client of this class that does
// not take into account the scaling of the graph. This is a known issue--
// don't use this class when the graph is scaled.
return location;
}
}
}

View file

@ -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 help.screenshot;
import org.junit.Assert;
import org.junit.Test;
import docking.widgets.dialogs.NumberInputDialog;
import ghidra.app.plugin.core.function.editor.StorageAddressEditorDialog;
import ghidra.app.services.DataTypeManagerService;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Parameter;
import ghidra.program.model.symbol.Symbol;
public class FunctionPluginScreenShots extends GhidraScreenShotGenerator {
public FunctionPluginScreenShots() {
super();
}
@Test
public void testEditStorage() {
Symbol symbol = getUniqueSymbol(program, "_memcpy");
Function function = (Function) symbol.getObject();
Parameter parameter = function.getParameter(0);
DataTypeManagerService dtService = env.getTool().getService(DataTypeManagerService.class);
Assert.assertNotNull(dtService);
final StorageAddressEditorDialog dialog =
new StorageAddressEditorDialog(program, dtService, parameter, 0);
runSwing(new Runnable() {
@Override
public void run() {
tool.showDialog(dialog);
}
}, false);
captureDialog(600, 400);
}
@Test
public void testFunctionEditor() {
Symbol symbol = getUniqueSymbol(program, "_memcpy");
goToListing(symbol.getAddress().getOffset(), "Function Signature", true);
performAction("Edit Function", "FunctionPlugin", false);
captureDialog(700, 550);
}
@Test
public void testSetStackDepthChange() {
final NumberInputDialog dialog = new NumberInputDialog("Set Stack Depth Change at 0x401482",
"Stack Depth Change", 5, Integer.MIN_VALUE, Integer.MAX_VALUE, false);
runSwing(new Runnable() {
@Override
public void run() {
tool.showDialog(dialog);
}
}, false);
captureDialog();
}
@Test
public void testStackDepthChangeOrFunctionPurge() {
goToListing(0x0040888c); // position at a call
performAction("Set Stack Depth Change", "FunctionPlugin", false);
pressOkOnDialog();
captureDialog();
}
}

View file

@ -0,0 +1,183 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertTrue;
import java.awt.Rectangle;
import javax.swing.*;
import org.junit.Test;
import docking.widgets.OptionDialog;
import docking.widgets.dialogs.InputDialog;
import ghidra.app.plugin.core.function.tags.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.util.ProgramLocation;
import ghidra.util.exception.UsrException;
public class FunctionTagPluginScreenShots extends GhidraScreenShotGenerator {
@Test
public void testFullWindow() {
showProvider(FunctionTagsComponentProvider.class);
waitForSwing();
addTableData();
captureIsolatedProvider(FunctionTagsComponentProvider.class, 400, 300);
}
@Test
public void testInputField() {
showProvider(FunctionTagsComponentProvider.class);
waitForSwing();
FunctionTagsComponentProvider provider = getProvider(FunctionTagsComponentProvider.class);
final JPanel inputPanel = (JPanel) getInstanceField("inputPanel", provider);
captureComponent(inputPanel);
}
@Test
public void testFilterField() {
showProvider(FunctionTagsComponentProvider.class);
waitForSwing();
FunctionTagsComponentProvider provider = getProvider(FunctionTagsComponentProvider.class);
final JPanel filterPanel = (JPanel) getInstanceField("filterPanel", provider);
captureComponent(filterPanel);
}
/**
* For this test the item in row 1 of the available tags table must be an editable
* item. If not, edit the function_tags.xml file to remove all items and re-run this.
*/
@Test
public void testEditTag() {
showProvider(FunctionTagsComponentProvider.class);
waitForSwing();
addTableData();
FunctionTagsComponentProvider provider = getProvider(FunctionTagsComponentProvider.class);
SourceTagsPanel sourcePanel = (SourceTagsPanel) getInstanceField("sourcePanel", provider);
FunctionTagList list = (FunctionTagList) getInstanceField("list", sourcePanel);
Rectangle bounds = list.getCellBounds(7, 7); // Cell 7 is an editable item
doubleClick(list, bounds.x, bounds.y);
InputDialog warningDialog = waitForDialogComponent(InputDialog.class);
captureDialog(warningDialog);
}
/**
* Captures the warning dialog when trying to delete a tag. Note that this assumes the
* tag in row 1 is NOT read-only. If that's the not the case, modify the function_tags.xml
* file to remove any tags that may be interfering with this.
*
* @throws UsrException
*/
@Test
public void testDeleteWarning() throws UsrException {
showProvider(FunctionTagsComponentProvider.class);
waitForSwing();
addTableData();
FunctionTagsComponentProvider provider = getProvider(FunctionTagsComponentProvider.class);
SourceTagsPanel sourcePanel = (SourceTagsPanel) getInstanceField("sourcePanel", provider);
FunctionTagList list = (FunctionTagList) getInstanceField("list", sourcePanel);
list.setSelectedIndex(7);
FunctionTagButtonPanel buttonPanel =
(FunctionTagButtonPanel) getInstanceField("buttonPanel", provider);
pressButtonByName(buttonPanel, "deleteBtn", false);
OptionDialog warningDialog = waitForDialogComponent(OptionDialog.class);
captureDialog(warningDialog);
}
/**
* Captures the read-only warning when trying to edit a tag
*
* @throws UsrException
*/
@Test
public void testEditNotAllowedWarning() throws UsrException {
showProvider(FunctionTagsComponentProvider.class);
waitForSwing();
addTableData();
FunctionTagsComponentProvider provider = getProvider(FunctionTagsComponentProvider.class);
SourceTagsPanel sourcePanel = (SourceTagsPanel) getInstanceField("sourcePanel", provider);
FunctionTagList list = (FunctionTagList) getInstanceField("list", sourcePanel);
doubleClickItem(list, "LIBRARY"); // pick a known read-only tag
OptionDialog warningDialog = waitForDialogComponent(OptionDialog.class);
captureDialog(warningDialog);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void doubleClickItem(FunctionTagList list, String text) {
ListModel<FunctionTag> model = list.getModel();
int n = model.getSize();
int row = -1;
for (int i = 0; i < n; i++) {
FunctionTag tag = model.getElementAt(i);
String name = tag.getName();
if (text.equals(name)) {
row = i;
break;
}
}
assertTrue("Could not find tag '" + text + "'", row > -1);
Rectangle bounds = list.getCellBounds(row, row);
doubleClick(list, bounds.x, bounds.y);
}
private void addTableData() {
FunctionTagsComponentProvider provider = getProvider(FunctionTagsComponentProvider.class);
provider.programActivated(program);
navigateToFunction(provider);
JTextField inputField = (JTextField) getInstanceField("tagInputTF", provider);
setText(inputField, "Tag 2, Tag 3");
triggerEnter(inputField);
waitForSwing();
}
/**
* Simulates a location change on the listing so the dialog thinks the user has
* navigated to a function.
*
* @param provider the component provider
*/
private void navigateToFunction(FunctionTagsComponentProvider provider) {
FunctionIterator iter = program.getFunctionManager().getFunctions(true);
while (iter.hasNext()) {
Function func = iter.next();
Address addr = func.getEntryPoint();
ProgramLocation loc = new ProgramLocation(program, addr);
provider.locationChanged(loc);
// We only need to find one function, so exit after we've got one.
return;
}
}
}

View file

@ -0,0 +1,65 @@
/* ###
* 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 help.screenshot;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.junit.Test;
import docking.widgets.table.GTable;
import ghidra.app.plugin.core.functionwindow.FunctionWindowProvider;
public class FunctionWindowPluginScreenShots extends GhidraScreenShotGenerator {
public FunctionWindowPluginScreenShots() {
super();
}
@Test
public void testFunctionWindow() {
showProvider(FunctionWindowProvider.class);
setColumnSizes();
captureIsolatedProvider(FunctionWindowProvider.class, 700, 300);
}
private void setColumnSizes() {
// note: these values are rough values found my trial-and-error
FunctionWindowProvider provider = getProvider(FunctionWindowProvider.class);
final GTable table = (GTable) getInstanceField("functionTable", provider);
runSwing(new Runnable() {
@Override
public void run() {
TableColumnModel columnModel = table.getColumnModel();
int columnCount = columnModel.getColumnCount();
for (int i = 0; i < columnCount; i++) {
TableColumn column = columnModel.getColumn(i);
Object headerValue = column.getHeaderValue();
if ("Label".equals(headerValue)) {
column.setPreferredWidth(50);
}
else if ("Location".equals(headerValue)) {
column.setPreferredWidth(30);
}
else if ("Function Signature".equals(headerValue)) {
column.setPreferredWidth(400);
}
}
}
});
}
}

View file

@ -0,0 +1,319 @@
/* ###
* 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 help.screenshot;
import java.io.*;
import java.util.*;
import javax.swing.*;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DockingWindowManager;
import docking.widgets.pathmanager.PathManager;
import docking.widgets.tree.*;
import generic.jar.ResourceFile;
import generic.util.Path;
import ghidra.app.plugin.core.console.ConsoleComponentProvider;
import ghidra.app.plugin.core.script.*;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.services.ConsoleService;
import ghidra.util.HelpLocation;
public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator {
public GhidraScriptMgrPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
}
@Test
public void testNew_Script_Editor() throws Exception {
performAction("New", "GhidraScriptMgrPlugin", false);
JDialog d = waitForJDialog(null, "New Script: Type", 5000);
pressButtonByText(d, "OK");
d = waitForJDialog(null, "New Script", 5000);
pressButtonByText(d, "OK");
captureIsolatedProvider(GhidraScriptEditorComponentProvider.class, 597, 600);
}
@Test
public void testSaveAs() throws Exception {
final ResourceFile scriptFile = createHelloWorldScript("HelloWorldScript");
final GhidraScriptComponentProvider provider =
showProvider(GhidraScriptComponentProvider.class);
runSwing(() -> {
HelpLocation helpLocation = new HelpLocation("", "");
List<ResourceFile> scriptDirs = new ArrayList<>();
scriptDirs.add(new ResourceFile("/User/home/ghidra_scripts"));
SaveDialog dialog = new SaveDialog(tool.getToolFrame(), "Save Script", provider,
scriptDirs, scriptFile, helpLocation);
tool.showDialog(dialog);
}, false);
SaveDialog dialog = waitForDialogComponent(SaveDialog.class);
captureDialog(dialog);
}
@Test
public void testAssign_Key_Binding() throws Exception {
ComponentProvider componentProvider = showProvider(GhidraScriptComponentProvider.class);
JComponent component = componentProvider.getComponent();
DraggableScriptTable scriptTable =
(DraggableScriptTable) findComponentByName(component, "SCRIPT_TABLE");
selectRow(scriptTable, "HelloWorldScript.java");
performAction("Key Binding", "GhidraScriptMgrPlugin", false);
captureDialog();
}
@Test
public void testSelect_Font() throws Exception {
ComponentProvider componentProvider = showProvider(GhidraScriptComponentProvider.class);
JComponent component = componentProvider.getComponent();
DraggableScriptTable scriptTable =
(DraggableScriptTable) findComponentByName(component, "SCRIPT_TABLE");
selectRow(scriptTable, "HelloWorldScript.java");
performAction("Edit", "GhidraScriptMgrPlugin", false);
performAction("Select Font", "GhidraScriptMgrPlugin", false);
captureDialog();
}
@Test
public void testScript_Dirs() throws Exception {
List<Path> paths = new ArrayList<>();
paths.add(new Path("$USER_HOME/ghidra_scripts"));
paths.add(new Path("$GHIDRA_HOME/Features/Base/ghidra_scripts"));
paths.add(new Path("/User/defined/invalid/directory"));
ComponentProvider provider = showProvider(GhidraScriptComponentProvider.class);
PathManager pathManager = (PathManager) getInstanceField("pathManager", provider);
pathManager.setPaths(paths);
final PickPathsDialog pathsDialog = new PickPathsDialog(null, pathManager);
runSwing(() -> DockingWindowManager.showDialog(null, pathsDialog), false);
PickPathsDialog dialog = waitForDialogComponent(PickPathsDialog.class);
captureDialog(dialog);
}
@Test
public void testEdit_Script() throws Exception {
ResourceFile newScript = createHelloWorldScript("MyHelloWorldScript");
ComponentProvider componentProvider = showProvider(GhidraScriptComponentProvider.class);
JComponent component = componentProvider.getComponent();
DraggableScriptTable scriptTable =
(DraggableScriptTable) findComponentByName(component, "SCRIPT_TABLE");
selectRow(scriptTable, newScript.getName());
performAction("Edit", "GhidraScriptMgrPlugin", false);
waitForSwing();
GhidraScriptEditorComponentProvider provider =
getProvider(GhidraScriptEditorComponentProvider.class);
moveProviderToFront(provider, 557, 378);
captureProvider(provider);
}
@Test
public void testScript_Manager() {
ComponentProvider scriptManager = showProvider(GhidraScriptComponentProvider.class);
JComponent component = scriptManager.getComponent();
final JSplitPane splitPane =
(JSplitPane) findComponentByName(component, "dataDescriptionSplit");
runSwing(() -> splitPane.setDividerLocation(0.63));
DraggableScriptTable scriptTable =
(DraggableScriptTable) findComponentByName(component, "SCRIPT_TABLE");
GTree scriptCategoryTree = (GTree) findComponentByName(component, "CATEGORY_TREE");
removeSuspectNodes(scriptCategoryTree);
selectPath(scriptCategoryTree, "Scripts", "Examples");
collapse(scriptCategoryTree, "Examples");// don't open examples (silly JTree)
selectRow(scriptTable, "HelloWorldScript.java");
scriptTable.scrollToSelectedRow();
moveProviderToFront(scriptManager, 1333, 570);
captureProvider(scriptManager);
}
@Test
public void testConsole() throws Exception {
ConsoleService service = tool.getService(ConsoleService.class);
//@formatter:off
service.addErrorMessage("",
"/User/home/ghidra_scripts/HellowWorldScript1.java:29: ';' expected\n"+
"\t}\n"+
"\t^\n"+
"1 error\n" +
"> Unable to compile script class: HellowWorldScript1.java\n");
//@formatter:on
ConsoleComponentProvider provider = showProvider(ConsoleComponentProvider.class);
moveProviderToFront(provider, 700, 225);
captureProvider(provider);
}
@Test
public void testDelete_Script_Confirm() throws Exception {
createHelloWorldScript("FooScript");
ComponentProvider componentProvider = showProvider(GhidraScriptComponentProvider.class);
JComponent component = componentProvider.getComponent();
DraggableScriptTable scriptTable =
(DraggableScriptTable) findComponentByName(component, "SCRIPT_TABLE");
selectRow(scriptTable, "FooScript.java");
performAction("Delete", "GhidraScriptMgrPlugin", false);
captureDialog();
}
@Test
public void testRename() throws Exception {
final ResourceFile scriptFile = createHelloWorldScript("HelloWorldScript");
final GhidraScriptComponentProvider provider =
showProvider(GhidraScriptComponentProvider.class);
runSwing(() -> {
HelpLocation helpLocation = new HelpLocation("", "");
List<ResourceFile> scriptDirs = new ArrayList<>();
scriptDirs.add(new ResourceFile("/User/home/ghidra_scripts"));
SaveDialog dialog = new SaveDialog(tool.getToolFrame(), "Rename Script", provider,
scriptDirs, scriptFile, helpLocation);
tool.showDialog(dialog);
}, false);
SaveDialog dialog = waitForDialogComponent(SaveDialog.class);
captureDialog(dialog);
}
@Test
public void testPick() {
List<String> items = new ArrayList<>();
items.add("Java");
items.add("Python");
final PickProviderDialog pickDialog = new PickProviderDialog(items, "Java");
runSwing(() -> tool.showDialog(pickDialog), false);
PickProviderDialog dialog = waitForDialogComponent(PickProviderDialog.class);
captureDialog(dialog);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void collapse(final GTree tree, final String nodeName) {
runSwing(() -> {
GTreeRootNode rootNode = tree.getRootNode();
GTreeNode exmaplesNode = rootNode.getChild(nodeName);
tree.collapseAll(exmaplesNode);
});
}
private void removeSuspectNodes(final GTree scriptCategoryTree) {
List<String> accepted = new ArrayList<>(
Arrays.asList("Examples", "Data Types", "Binary", "Functions", "Import", "Analysis"));
List<GTreeNode> toRemove = new ArrayList<>();
final GTreeRootNode rootNode = scriptCategoryTree.getRootNode();
List<GTreeNode> children = rootNode.getChildren();
for (GTreeNode child : children) {
String name = child.getName();
if (!accepted.contains(name)) {
toRemove.add(child);
}
}
for (GTreeNode node : toRemove) {
rootNode.removeNode(node);
}
waitForTree(scriptCategoryTree);
}
private ResourceFile createTempScriptFile(String name) {
File userScriptsDir = new File(GhidraScriptUtil.USER_SCRIPTS_DIR);
if (name.length() > 50) {
// too long and the script manager complains
name = name.substring(name.length() - 50);
}
File tempFile = new File(userScriptsDir + File.separator + name + ".java");
tempFile.deleteOnExit();
return new ResourceFile(tempFile);
}
private void writeStringToFile(ResourceFile file, String string) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(file.getFile(false)));
writer.write(string);
writer.close();
}
private ResourceFile createHelloWorldScript(String name) throws Exception {
ResourceFile newScriptFile = createTempScriptFile(name);
String filename = newScriptFile.getName();
String className = filename.replaceAll("\\.java", "");
//@formatter:off
String newScript = "//Writes \"Hello World\" to console.\n" +
"//@category Examples.Test\n" +
"//@menupath Help.Examples.Hello World\n" +
"//@keybinding ctrl shift COMMA\n" +
"//@toolbar world.png\n\n" +
"import ghidra.app.script.GhidraScript;\n\n" +
"public class "+className+" extends GhidraScript {\n" +
" @Override\n" +
" public void run() throws Exception {\n" +
" println(\"Hello World\");\n" +
" }\n" +
"}\n";
//@formatter:on
writeStringToFile(newScriptFile, newScript);
return newScriptFile;
}
}

View file

@ -0,0 +1,116 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.awt.image.BufferedImage;
import org.junit.Test;
public class GlossaryScreenShots extends GhidraScreenShotGenerator {
public GlossaryScreenShots() {
super();
}
@Test
public void testBigEndian() {
//Draw empty white rectangle
image = new BufferedImage(450, 100, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 450, 125);
//Draw box with line in the middle
Point p1 = new Point(30, 10);
Point p2 = new Point(430, 10);
Point p3 = new Point(430, 50);
Point p4 = new Point(30, 50);
Point p5 = new Point(225, 10);
Point p6 = new Point(225, 50);
drawLine(Color.BLACK, 1, p1, p2);
drawLine(Color.BLACK, 1, p2, p3);
drawLine(Color.BLACK, 1, p3, p4);
drawLine(Color.BLACK, 1, p4, p1);
drawLine(Color.BLACK, 1, p5, p6);
//Draw Text in boxes
drawText("high-order byte", Color.BLACK, new Point(80, 35), 12);
drawText("low-order byte", Color.BLACK, new Point(285, 35), 12);
//Draw arrows
Point p7 = new Point(30, 50);
Point p8 = new Point(30, 80);
Point p9 = new Point(225, 50);
Point p10 = new Point(225, 80);
drawArrow(Color.BLACK, 1, p8, p7, 6);
drawArrow(Color.BLACK, 1, p10, p9, 6);
//Draw arrow text
drawText("addr A", Color.BLACK, new Point(15, 93), 12);
drawText("addr A+1", Color.BLACK, new Point(200, 93), 12);
}
@Test
public void testLittleEndian() {
//Draw empty white rectangle
image = new BufferedImage(450, 100, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 450, 125);
//Draw box with line in the middle
Point p1 = new Point(30, 10);
Point p2 = new Point(430, 10);
Point p3 = new Point(430, 50);
Point p4 = new Point(30, 50);
Point p5 = new Point(225, 10);
Point p6 = new Point(225, 50);
drawLine(Color.BLACK, 1, p1, p2);
drawLine(Color.BLACK, 1, p2, p3);
drawLine(Color.BLACK, 1, p3, p4);
drawLine(Color.BLACK, 1, p4, p1);
drawLine(Color.BLACK, 1, p5, p6);
//Draw Text in boxes
drawText("high-order byte", Color.BLACK, new Point(80, 35), 12);
drawText("low-order byte", Color.BLACK, new Point(285, 35), 12);
//Draw arrows
Point p7 = new Point(430, 50);
Point p8 = new Point(430, 80);
Point p9 = new Point(225, 50);
Point p10 = new Point(225, 80);
drawArrow(Color.BLACK, 1, p8, p7, 6);
drawArrow(Color.BLACK, 1, p10, p9, 6);
//Draw arrow text
drawText("addr A+1", Color.BLACK, new Point(200, 93), 12);
drawText("addr A", Color.BLACK, new Point(413, 93), 12);
}
}

View file

@ -0,0 +1,156 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.*;
import java.awt.Component;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import org.junit.Test;
import docking.widgets.filechooser.GhidraFileChooser;
import ghidra.app.util.importer.LibrarySearchPathManager;
import ghidra.app.util.opinion.*;
import ghidra.plugin.importer.ImporterDialog;
import ghidra.plugin.importer.ImporterLanguageDialog;
import ghidra.plugins.importer.batch.BatchImportDialog;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
public class ImporterPluginScreenShots extends GhidraScreenShotGenerator {
public ImporterPluginScreenShots() {
super();
}
@Test
public void testImporterDialog() throws Exception {
performAction("Import File", "ImporterPlugin", false);
selectFileForImport("WinHelloCPP.exe");
redactImportDialog();
captureDialog();
}
@Test
public void testBatchImportDialog() throws Exception {
performAction("Batch Import", "ImporterPlugin", false);
selectDirForBatchImport("WinHelloCPP.exe");
redactImportSource();
captureDialog(850, 500);
}
@Test
public void testSearchPathsDialog() throws Exception {
LibrarySearchPathManager.setLibraryPaths(new String[] { ".", "/Users/Joe" });
runSwing(() -> {
LibraryPathsDialog dialog = new LibraryPathsDialog();
tool.showDialog(dialog);
}, false);
waitForDialogComponent(LibraryPathsDialog.class);
captureDialog();
}
@Test
public void testLanguagePickerDialog() throws Exception {
PeLoader peLoader = new PeLoader();
List<LoadSpec> loadSpecs = new ArrayList<>();
loadSpecs.add(new LoadSpec(peLoader, 0,
new LanguageCompilerSpecPair("x86:LE:32:default", "windows"), true));
loadSpecs.add(new LoadSpec(peLoader, 0,
new LanguageCompilerSpecPair("x86:LE:32:default", "gcc"), false));
loadSpecs.add(new LoadSpec(peLoader, 0,
new LanguageCompilerSpecPair("x86:LE:32:default", "borland"), false));
loadSpecs.add(new LoadSpec(peLoader, 0,
new LanguageCompilerSpecPair("x86:LE:32:System Management Mode", "default"), false));
runSwing(() -> {
ImporterLanguageDialog dialog = new ImporterLanguageDialog(loadSpecs, tool, null);
dialog.show(null);
}, false);
waitForDialogComponent(ImporterLanguageDialog.class);
captureDialog();
}
private ImporterDialog selectFileForImport(String fileToImport) throws Exception {
GhidraFileChooser fileChooser = waitForDialogComponent(GhidraFileChooser.class);
File testDataFile = getTestDataFile(fileToImport);
fileChooser.setSelectedFile(testDataFile);
waitForUpdateOnChooser(fileChooser);
pressButtonByName(fileChooser.getComponent(), "OK");
ImporterDialog importerDialog = waitForDialogComponent(ImporterDialog.class);
assertNotNull(importerDialog);
return importerDialog;
}
private BatchImportDialog selectDirForBatchImport(String rootDir) throws Exception {
GhidraFileChooser fileChooser = waitForDialogComponent(GhidraFileChooser.class);
File testDataFile = getTestDataDir("pe");
fileChooser.setSelectedFile(testDataFile);
waitForUpdateOnChooser(fileChooser);
pressButtonByName(fileChooser.getComponent(), "OK");
BatchImportDialog dialog = waitForDialogComponent(BatchImportDialog.class);
assertNotNull(dialog);
return dialog;
}
private void redactImportSource() {
BatchImportDialog dialog = waitForDialogComponent(BatchImportDialog.class);
JList<?> list = (JList<?>) findComponentByName(dialog, "batch.import.source.list");
runSwing(() -> {
list.setCellRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<? extends Object> theList,
Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel renderer = (JLabel) super.getListCellRendererComponent(theList, value,
index, isSelected, cellHasFocus);
renderer.setText("/Users/Joe/dir/with/binaries");
return renderer;
}
});
});
list.repaint();
}
private void redactImportDialog() {
ImporterDialog dialog = waitForDialogComponent(ImporterDialog.class);
runSwing(() -> {
String title = dialog.getTitle();
int indexOf = title.indexOf("/Ghidra/Test");
title = title.substring(indexOf);
dialog.setTitle(title);
});
}
}

View file

@ -0,0 +1,219 @@
/* ###
* 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 help.screenshot;
import java.awt.Component;
import javax.swing.JButton;
import org.junit.Before;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.action.DockingActionIf;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin;
import ghidra.app.plugin.core.instructionsearch.ui.*;
import ghidra.app.plugin.core.table.TableComponentProvider;
/**
* Screenshots for help/topics/Search/Search_Instruction_Patterns.htm
*/
public class InstructionPatternSearchScreenShots extends AbstractSearchScreenShots {
private InstructionSearchPlugin instructionSearchPlugin;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
instructionSearchPlugin = env.getPlugin(InstructionSearchPlugin.class);
env.showTool();
}
@Test
public void testSearchInstructionsManualSearchDialog() {
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JButton manualEntryButton =
(JButton) AbstractGenericTest.findComponentByName(dialog.getComponent(), "manual entry");
pressButton(manualEntryButton);
InsertBytesWidget comp = waitForDialogComponent(InsertBytesWidget.class);
captureComponent(comp.getComponent());
}
/**
* Grabs a screenshot of the full {@link InstructionSearchDialog} window.
*/
@Test
public void testSearchInstructionPatterns() {
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
captureDialog(DialogComponentProvider.class, 900, 461);
}
/**
* Grabs a screenshot of the {@link InstructionTable} panel within the main
* instruction search dialog.
*/
@Test
public void testSearchInstructionPatternsInstructionTable() {
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
Component instrTable =
findComponentByName(this.getDialog().getComponent(), "InstructionTablePanel");
captureComponent(instrTable);
}
/**
* Grabs a screenshot of the {@link PreviewTable} panel within the main
* instruction search dialog.
*/
@Test
public void testSearchInstructionPatternsPreviewTable() {
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
Component previewTable =
this.findChildWithType(this.getDialog().getComponent(), PreviewTablePanel.class, null);
captureComponent(previewTable);
}
/**
* Grabs a screenshot of the {@link ControlPanel} within the main instruction search dialog.
*/
@Test
public void testSearchInstructionPatternsControlPanel() {
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
Component controlPanel =
this.findChildWithType(this.getDialog().getComponent(), ControlPanel.class, null);
captureComponent(controlPanel);
}
/**
* Grabs a screenshot of the toolbar for the {@link InstructionTable} within the main
* instruction search dialog.
*/
@Test
public void testSearchInstructionPatternsInstructionTableToolbar() {
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
Component instructionTable =
this.findChildWithType(this.getDialog().getComponent(), InstructionTable.class, null);
InstructionTable instrTable = (InstructionTable) instructionTable;
captureComponent(instrTable.getToolbar());
}
/**
* Grabs a screenshot of the toolbar for the {@link PreviewTable} within the main
* instruction search dialog.
*/
@Test
public void testSearchInstructionPatternsPreviewTableToolbar() {
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
Component previewTable =
this.findChildWithType(this.getDialog().getComponent(), PreviewTable.class, null);
PreviewTable prevTable = (PreviewTable) previewTable;
captureComponent(prevTable.getToolbar());
}
/**
* Grabs a screenshot of the results table displayed when performing a search using the
* {@link InstructionSearchDialog}.
*/
@Test
public void testSearchInstructionPatternsResultsTable() {
moveTool(500, 500);
goToListing(0x00401221, "Address", false);
makeSelection(0x00401221, 0x00401236);
waitForSwing();
DockingActionIf openSearchDialogAction =
getAction(instructionSearchPlugin, "Search Instruction Patterns");
performAction(openSearchDialogAction, true);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JButton searchButton =
(JButton) AbstractGenericTest.findAbstractButtonByText(dialog.getComponent(), "Search All");
pressButton(searchButton);
waitForComponentProvider(TableComponentProvider.class);
captureIsolatedProvider(TableComponentProvider.class, 500, 450);
}
}

View file

@ -0,0 +1,100 @@
/* ###
* 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 help.screenshot;
import java.io.IOException;
import org.junit.Test;
import docking.DockingWindowManager;
import docking.ErrLogDialog;
import docking.widgets.OptionDialog;
import ghidra.framework.model.Project;
import ghidra.framework.model.ProjectData;
import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitorAdapter;
public class IntroScreenShots extends GhidraScreenShotGenerator {
public IntroScreenShots() {
super();
}
@Override
public void prepareTool() {
tool = getFrontEndTool();
}
@Override
public void loadProgram() {
// don't need to load a program
}
@Test
public void testEmpty_ghidra() {
performAction("Close Project", "FrontEndPlugin", true);
Msg.info("RecoverySnapshotMgrPlugin", "Recovery snapshot timer set to 5 minute(s)");
captureToolWindow(600, 500);
}
@Test
public void testErr_Dialog() {
runSwing(new Runnable() {
@Override
public void run() {
ErrLogDialog dialog =
ErrLogDialog.createLogMessageDialog("Unexpected Error",
"Oops, this is really bad!", "");
DockingWindowManager.showDialog(null, dialog);
}
}, false);
waitForSwing();
captureDialog();
}
@Test
public void testOpen_ghidra() throws InvalidNameException, CancelledException, IOException {
program = env.getProgram("WinHelloCPP.exe");
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program,
TaskMonitorAdapter.DUMMY_MONITOR);
projectData.getRootFolder().createFile("AnotherProgram.exe", program,
TaskMonitorAdapter.DUMMY_MONITOR);
waitForSwing();
Msg.info("ProjectImpl", "Opening project: " + tool.getProject().getName());
captureToolWindow(600, 500);
}
@Test
public void testSimple_err_dialog() {
runSwing(new Runnable() {
@Override
public void run() {
OptionDialog dialog =
new OptionDialog("Some Resonable Error",
"Your operation did not complete because... (i.e File Not Found)",
OptionDialog.ERROR_MESSAGE, null);
DockingWindowManager.showDialog(null, dialog);
}
}, false);
captureDialog();
}
}

View file

@ -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 help.screenshot;
import java.util.*;
import javax.swing.*;
import org.junit.Test;
import docking.widgets.combobox.GhidraComboBox;
import ghidra.app.plugin.core.label.*;
import ghidra.app.util.AddEditDialog;
import ghidra.app.util.EditFieldNameDialog;
import ghidra.program.model.address.*;
import ghidra.program.model.symbol.LabelHistory;
public class LabelMgrPluginScreenShots extends GhidraScreenShotGenerator {
public LabelMgrPluginScreenShots() {
super();
}
@Test
public void testAddLabel() {
final AddEditDialog dialog = new AddEditDialog("Edit Label at 100122591", tool);
runSwing(new Runnable() {
@Override
public void run() {
JComboBox combo = (JComboBox) getInstanceField("labelNameChoices", dialog);
combo.setSelectedItem("reset");
combo = (JComboBox) getInstanceField("namespaceChoices", dialog);
combo.addItem("MyFunction");
combo.setSelectedItem("MyFunction");
JCheckBox checkbox = (JCheckBox) getInstanceField("primaryCheckBox", dialog);
checkbox.setSelected(true);
checkbox.setEnabled(false);
}
});
showDialogWithoutBlocking(tool, dialog);
captureDialog();
}
@Test
public void testEditFieldNameDialog() {
EditFieldNameDialog dialog =
new EditFieldNameDialog("Edit Field Name: struct.field2", tool);
final JTextField textField = (JTextField) getInstanceField("fieldName", dialog);
runSwing(new Runnable() {
@Override
public void run() {
textField.setText("field2");
}
});
showDialogWithoutBlocking(tool, dialog);
captureDialog();
}
@Test
public void testLabelHistoryInputDialog() {
LabelHistoryInputDialog dialog = new LabelHistoryInputDialog(tool, null);
showDialogWithoutBlocking(tool, dialog);
captureDialog();
}
@Test
public void testSetLabel() {
LabelMgrPlugin plugin = getPlugin(tool, LabelMgrPlugin.class);
final OperandLabelDialog dialog = new OperandLabelDialog(plugin);
final GhidraComboBox combo = (GhidraComboBox) getInstanceField("myChoice", dialog);
runSwing(new Runnable() {
@Override
public void run() {
dialog.setTitle("Set Label at 004a671");
combo.setSelectedItem("LAB_0040a671");
}
});
showDialogWithoutBlocking(tool, dialog);
captureDialog(350, 116);
}
@Test
public void testShowLabelHistory() {
AddressSpace space = new GenericAddressSpace("Test", 32, AddressSpace.TYPE_RAM, 0);
Address addr = space.getAddress(0x0040a671);
List<LabelHistory> list = new ArrayList<LabelHistory>();
list.add(new LabelHistory(addr, "User1", (byte) 0, "MyLabel", new Date()));
list.add(new LabelHistory(addr, "User2", (byte) 2, "Bob to John", new Date()));
list.add(new LabelHistory(addr, "User1", (byte) 1, "Phil", new Date()));
LabelHistoryDialog dialog = new LabelHistoryDialog(tool, null, addr, list);
showDialogWithoutBlocking(tool, dialog);
captureDialog(600, 200);
}
}

View file

@ -0,0 +1,98 @@
/* ###
* 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 help.screenshot;
import javax.swing.JButton;
import org.junit.Test;
import docking.widgets.OptionDialog;
import docking.widgets.table.GTableFilterPanel;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.processors.SetLanguageDialog;
import ghidra.app.plugin.processors.generic.PcodeFieldFactory;
import ghidra.app.util.viewer.field.SpacerFieldFactory;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.format.FormatManager;
public class LanguageProviderPluginScreenShots extends GhidraScreenShotGenerator {
public LanguageProviderPluginScreenShots() {
super();
}
@Test
public void testLanguages() {
final SetLanguageDialog dialog = new SetLanguageDialog(tool, program);
Object newLanguagePanel = getInstanceField("selectLangPanel", dialog);
final GTableFilterPanel<?> filterPanel =
(GTableFilterPanel<?>) getInstanceField("tableFilterPanel", newLanguagePanel);
runSwing(new Runnable() {
@Override
public void run() {
filterPanel.setFilterText("x86");
}
});
showDialogWithoutBlocking(tool, dialog);
runSwing(new Runnable() {
@Override
public void run() {
dialog.setStatusText("");
JButton okButton = (JButton) getInstanceField("okButton", dialog);
okButton.setEnabled(true);
}
});
captureDialog();
}
@Test
public void testPCodeDisplay() {
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
performAction("Toggle Header", "CodeBrowserPlugin", true);
FormatManager formatMgr = (FormatManager) getInstanceField("formatMgr", plugin);
FieldFormatModel formatModel = formatMgr.getCodeUnitFormat();
formatModel.addRow(4);
formatModel.addFactory(new SpacerFieldFactory(), 4, 0);
formatModel.addFactory(new SpacerFieldFactory(), 4, 0);
formatModel.addFactory(new SpacerFieldFactory(), 4, 0);
formatModel.addFactory(new SpacerFieldFactory(), 4, 0);
formatModel.addFactory(new PcodeFieldFactory(), 4, 4);
goToListing(0x00401002, "PCode", true);
captureProvider(CodeViewerProvider.class);
}
@Test
public void testWarning() {
final String msg =
"Setting the language can not be undone!\n \nIt is highly "
+ "recommended that you make a copy of the\nselected file before performing "
+ "this operation. \n \nWhen complete you can Save the results or Open the results\n"
+ "in the CodeBrowser tool";
runSwing(new Runnable() {
@Override
public void run() {
OptionDialog.showOptionDialog(tool.getToolFrame(),
"Set Language: " + program.getName(), msg + "\n \n" + "" +
"\n \nDo you want to continue?", "Ok", OptionDialog.WARNING_MESSAGE);
}
}, false);
captureDialog();
}
}

View file

@ -0,0 +1,62 @@
/* ###
* 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 help.screenshot;
import java.awt.Rectangle;
import org.junit.Test;
import docking.ComponentProvider;
import ghidra.app.util.viewer.field.OperandFieldFactory;
import ghidra.app.util.viewer.field.XRefFieldFactory;
public class LocationReferencesPluginScreenShots extends GhidraScreenShotGenerator {
public LocationReferencesPluginScreenShots() {
super();
}
@Test
public void testReferencesToDialog() {
goToListing(0x4075db);
performAction("Find References To", "LocationReferencesPlugin", true);
ComponentProvider provider = getProvider("Location References Provider");
captureIsolatedProviderWindow(provider.getClass(), 600, 350);
}
@Test
public void testLabelReferencesSample() {
positionListingCenter(0x407685);
positionCursor(0x407685, OperandFieldFactory.FIELD_NAME);
captureToolWindow(1000, 1000);
crop(new Rectangle(300, 338, 400, 28));
}
@Test
public void testXRefLabelReferencesSample() {
positionListingCenter(0x40768a);
positionCursor(0x4078d7, XRefFieldFactory.FIELD_NAME);
captureToolWindow(1200, 1000);
crop(new Rectangle(480, 300, 590, 90));
}
}

View file

@ -0,0 +1,288 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.table.TableModel;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import docking.action.DockingAction;
import docking.widgets.combobox.GhidraComboBox;
import ghidra.util.exception.AssertException;
import ghidra.util.table.GhidraTable;
public class MemoryMapPluginScreenShots extends GhidraScreenShotGenerator {
public MemoryMapPluginScreenShots() {
super();
}
@Test
public void testMemoryMap() {
performAction("Memory Map", "DockingWindows", true);
ComponentProvider provider = getProvider("Memory Map");
moveProviderToItsOwnWindow(provider);
JComponent component = getDockableComponent(provider);
captureIsolatedComponent(component, 650, 225);
}
@Test
public void testAddMemoryBlock() {
performAction("Add Block", "MemoryMapPlugin", false);
captureDialog();
}
@Test
public void testBitOverlayAddresses() {
//Draw empty white rectangle
image = new BufferedImage(450, 175, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 450, 175);
//Draw Title and subtitle
drawText("Bit Overlay Addresses", Color.BLACK, new Point(160, 30), 18);
drawText("Byte Memory", Color.BLACK, new Point(15, 30), 10);
drawText("Addresses", Color.BLACK, new Point(20, 40), 10);
//Draw text inside and next to boxes
drawText("00008100", Color.BLACK, new Point(15, 80), 12);
drawText("00008100", Color.BLACK, new Point(15, 130), 12);
drawText("MSB", Color.BLACK, new Point(90, 60), 10);
drawText("LSB", Color.BLACK, new Point(370, 60), 10);
drawText("0007", Color.BLACK, new Point(90, 80), 10);
drawText("0006", Color.BLACK, new Point(130, 80), 10);
drawText("0005", Color.BLACK, new Point(170, 80), 10);
drawText("0004", Color.BLACK, new Point(210, 80), 10);
drawText("0003", Color.BLACK, new Point(250, 80), 10);
drawText("0002", Color.BLACK, new Point(290, 80), 10);
drawText("0001", Color.BLACK, new Point(330, 80), 10);
drawText("0000", Color.BLACK, new Point(370, 80), 10);
drawText("000f", Color.BLACK, new Point(90, 130), 10);
drawText("000e", Color.BLACK, new Point(130, 130), 10);
drawText("000d", Color.BLACK, new Point(170, 130), 10);
drawText("000c", Color.BLACK, new Point(210, 130), 10);
drawText("000b", Color.BLACK, new Point(250, 130), 10);
drawText("000a", Color.BLACK, new Point(290, 130), 10);
drawText("0009", Color.BLACK, new Point(330, 130), 10);
drawText("0008", Color.BLACK, new Point(370, 130), 10);
//Draw boxes
Point p1 = new Point(80, 65);
Point p2 = new Point(400, 65);
Point p3 = new Point(400, 90);
Point p4 = new Point(80, 90);
Point p5 = new Point(80, 115);
Point p6 = new Point(400, 115);
Point p7 = new Point(400, 140);
Point p8 = new Point(80, 140);
drawLine(Color.BLACK, 1, p1, p2);
drawLine(Color.BLACK, 1, p2, p3);
drawLine(Color.BLACK, 1, p3, p4);
drawLine(Color.BLACK, 1, p4, p1);
drawLine(Color.BLACK, 1, p5, p6);
drawLine(Color.BLACK, 1, p6, p7);
drawLine(Color.BLACK, 1, p7, p8);
drawLine(Color.BLACK, 1, p8, p5);
for (int i = 1; i < 8; i++) {
drawLine(Color.BLACK, 1, new Point(80 + i * 40, 65), new Point(80 + i * 40, 90));
drawLine(Color.BLACK, 1, new Point(80 + i * 40, 115), new Point(80 + i * 40, 140));
}
}
@Test
public void testAddMappedBlock() {
performAction("Add Block", "MemoryMapPlugin", false);
DialogComponentProvider dialog = getDialog();
GhidraComboBox<?> comboBox = (GhidraComboBox<?>) getInstanceField("comboBox", dialog);
selectItem(comboBox, "Byte Mapped");
captureDialog();
drawRectangleAround(comboBox, Color.GREEN, 10);
}
@Test
public void testMoveMemory() {
performAction("Memory Map", "DockingWindows", true);
ComponentProvider provider = getProvider("Memory Map");
JComponent component = provider.getComponent();
GhidraTable table = findComponent(component, GhidraTable.class);
waitForSwing();
selectRow(table, ".text");
waitForSwing();
DockingAction action = (DockingAction) getInstanceField("moveAction", provider);
performAction(action, false);
captureDialog();
}
@Test
public void testSplitMemoryBlock() {
performAction("Memory Map", "DockingWindows", true);
ComponentProvider provider = getProvider("Memory Map");
JComponent component = provider.getComponent();
GhidraTable table = findComponent(component, GhidraTable.class);
waitForSwing();
selectRow(table, ".text");
waitForSwing();
DockingAction action = (DockingAction) getInstanceField("splitAction", provider);
performAction(action, false);
captureDialog();
}
@Test
public void testMemoryExpandUp() {
performAction("Memory Map", "DockingWindows", true);
ComponentProvider provider = getProvider("Memory Map");
JComponent component = provider.getComponent();
GhidraTable table = findComponent(component, GhidraTable.class);
waitForSwing();
selectRow(table, ".text");
waitForSwing();
DockingAction action = (DockingAction) getInstanceField("expandUpAction", provider);
performAction(action, false);
captureDialog();
}
@Test
public void testMemoryExpandDown() {
performAction("Memory Map", "DockingWindows", true);
ComponentProvider provider = getProvider("Memory Map");
JComponent component = provider.getComponent();
GhidraTable table = findComponent(component, GhidraTable.class);
waitForSwing();
selectRow(table, ".text");
waitForSwing();
DockingAction action = (DockingAction) getInstanceField("expandDownAction", provider);
performAction(action, false);
captureDialog();
}
@Test
public void testSetImageBaseDialog() {
performAction("Memory Map", "DockingWindows", true);
ComponentProvider provider = getProvider("Memory Map");
JComponent component = provider.getComponent();
GhidraTable table = findComponent(component, GhidraTable.class);
waitForSwing();
selectRow(table, ".text");
waitForSwing();
DockingAction action = (DockingAction) getInstanceField("setBaseAction", provider);
performAction(action, false);
captureDialog();
}
private void selectRow(final GhidraTable table, final String text) {
final TableModel model = table.getModel();
runSwing(new Runnable() {
@Override
public void run() {
int columnCount = model.getColumnCount();
int columnIndex = -1;
int rowIndex = -1;
for (int i = 0; i < columnCount; i++) {
if (model.getColumnName(i).equals("Name")) {
columnIndex = i;
break;
}
}
if (columnIndex != -1) {
int rowCount = model.getRowCount();
for (int i = 0; i < rowCount; i++) {
if (model.getValueAt(i, columnIndex).equals(text)) {
rowIndex = i;
break;
}
}
}
if (rowIndex == -1) {
throw new AssertException();
}
table.selectRow(rowIndex);
}
});
}
private void selectItem(final GhidraComboBox<?> comboBox, final String text) {
runSwing(new Runnable() {
@Override
public void run() {
int itemCount = comboBox.getItemCount();
Object item = null;
for (int i = 0; i < itemCount; i++) {
Object itemAt = comboBox.getItemAt(i);
if (itemAt.toString().equals(text)) {
item = itemAt;
break;
}
}
if (item == null) {
throw new AssertException();
}
comboBox.setSelectedItem(item);
}
});
}
}

View file

@ -0,0 +1,264 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import javax.swing.*;
import org.junit.Before;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.action.DockingActionIf;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.searchmem.mask.MnemonicSearchPlugin;
import ghidra.program.model.address.*;
/**
* Screenshots for help/topics/Search/Search_Memory.htm
*/
public class MemorySearchScreenShots extends AbstractSearchScreenShots {
private CodeBrowserPlugin cb;
private MnemonicSearchPlugin mnemonicSearchPlugin;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
mnemonicSearchPlugin = env.getPlugin(MnemonicSearchPlugin.class);
cb = env.getPlugin(CodeBrowserPlugin.class);
env.showTool();
}
@Test
public void testSearchMemoryHex() {
moveTool(500, 500);
performAction("Search Memory", "MemSearchPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "12 34");
JToggleButton button = (JToggleButton) getInstanceField("advancedButton", dialog);
pressButton(button);
waitForSwing();
captureDialog(DialogComponentProvider.class);
}
@Test
public void testSearchMemoryRegex() {
moveTool(500, 500);
performAction("Search Memory", "MemSearchPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JRadioButton regexRadioButton =
(JRadioButton) findAbstractButtonByText(dialog.getComponent(), "Regular Expression");
pressButton(regexRadioButton);
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "\\x50.{0,10}\\x55");
JToggleButton button = (JToggleButton) getInstanceField("advancedButton", dialog);
pressButton(button);
waitForSwing();
captureDialog(DialogComponentProvider.class);
}
@Test
public void testSearchMemoryBinary() {
moveTool(500, 500);
performAction("Search Memory", "MemSearchPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JRadioButton binaryRadioButton =
(JRadioButton) findAbstractButtonByText(dialog.getComponent(), "Binary");
pressButton(binaryRadioButton);
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "10xx0011");
JToggleButton button = (JToggleButton) getInstanceField("advancedButton", dialog);
pressButton(button);
waitForSwing();
captureDialog(DialogComponentProvider.class);
}
@Test
public void testSearchMemoryDecimal() {
moveTool(500, 500);
performAction("Search Memory", "MemSearchPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JRadioButton decimalRadioButton =
(JRadioButton) findAbstractButtonByText(dialog.getComponent(), "Decimal");
pressButton(decimalRadioButton);
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "1234");
JToggleButton button = (JToggleButton) getInstanceField("advancedButton", dialog);
pressButton(button);
waitForSwing();
captureDialog(DialogComponentProvider.class);
}
@Test
public void testSearchMemoryString() {
moveTool(500, 500);
performAction("Search Memory", "MemSearchPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JRadioButton stringRadioButton =
(JRadioButton) findAbstractButtonByText(dialog.getComponent(), "String");
pressButton(stringRadioButton);
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "Hello");
JToggleButton button = (JToggleButton) getInstanceField("advancedButton", dialog);
pressButton(button);
waitForSwing();
captureDialog(DialogComponentProvider.class);
}
@Test
public void testSearchInstructions() {
Font font = new Font("Monospaced", Font.PLAIN, 14);
Color selectionColor = new Color(180, 255, 180);
TextFormatter tf = new TextFormatter(font, 8, 500, 4, 5, 2);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE);
TextFormatterContext darkBlue = new TextFormatterContext(DARK_BLUE);
TextFormatterContext darkGreen = new TextFormatterContext(DARK_GREEN);
TextFormatterContext orange = new TextFormatterContext(YELLOW_ORANGE);
tf.colorLines(selectionColor, 3, 4);
// @formatter:off
tf.writeln(" LAB_00401e8c");
tf.writeln(" 00401e8c |a1 20 0d| |MOV| |EAX|,DAT_00410d20]", blue, darkBlue, orange);
tf.writeln(" |41 00| ", blue);
tf.writeln(" 00401e91 |85 c0| |TEST| |EAX|,|EAX|", blue, darkBlue, orange, orange);
tf.writeln(" 00401e93 |56| |PUSH| |ESI|", blue, darkBlue, orange);
tf.writeln(" 00401e94 |6a 14| |PUSH| |0x14|", blue, darkBlue, darkGreen);
tf.writeln(" 00401e96 |5e| |POP| |ESI|", blue, darkBlue, orange);
tf.writeln(" 00401e97 |75 07| |JNZ| LAB_00401ea0", blue, darkBlue);
// @formatter:on
image = tf.getImage();
}
@Test
public void testSearchInstructionsIncludeOperands() {
Font font = new Font("Monospaced", Font.PLAIN, 14);
TextFormatter tf = new TextFormatter(font, 4, 300, 4, 5, 2);
TextFormatterContext blue = new TextFormatterContext(Color.BLUE);
TextFormatterContext darkBlue = new TextFormatterContext(DARK_BLUE);
TextFormatterContext darkGreen = new TextFormatterContext(DARK_GREEN);
TextFormatterContext orange = new TextFormatterContext(YELLOW_ORANGE);
tf.writeln(" |85 c0| |TEST| |EAX|,|EAX|", blue, darkBlue, orange, orange);
tf.writeln(" |56| |PUSH| |ESI| ", blue, darkBlue, orange);
tf.writeln(" |6a 14| |PUSH| |0x14| ", blue, darkBlue, darkGreen);
tf.writeln(" |5e| |POP| |ESI| ", blue, darkBlue, orange);
image = tf.getImage();
}
@Test
public void testSearchInstructionsExcludeOperands() {
Font font = new Font("Monospaced", Font.PLAIN, 14);
TextFormatter tf = new TextFormatter(font, 4, 80, 4, 5, 2);
TextFormatterContext darkBlue = new TextFormatterContext(DARK_BLUE);
tf.writeln(" |TEST|", darkBlue);
tf.writeln(" |PUSH|", darkBlue);
tf.writeln(" |PUSH|", darkBlue);
tf.writeln(" |POP| ", darkBlue);
image = tf.getImage();
}
@Test
public void testSearchInstructionsIncludeOperandsNoConsts() {
Font font = new Font("Monospaced", Font.PLAIN, 14);
TextFormatter tf = new TextFormatter(font, 4, 200, 4, 5, 2);
TextFormatterContext darkBlue = new TextFormatterContext(DARK_BLUE);
TextFormatterContext darkGreen = new TextFormatterContext(DARK_GREEN);
TextFormatterContext orange = new TextFormatterContext(YELLOW_ORANGE);
tf.writeln(" |TEST| |EAX|,|EAX|", darkBlue, orange, orange);
tf.writeln(" |PUSH| |ESI| ", darkBlue, orange);
tf.writeln(" |PUSH| N ", darkBlue, darkGreen);
tf.writeln(" |POP| |ESI| ", darkBlue, orange);
image = tf.getImage();
}
/**
* Captures the error dialog displayed when trying to search with multiple selections.
*/
@Test
public void testMultipleSelectionError() {
// First set up two selection ranges.
AddressRange range1 = new AddressRangeImpl(addr(0x00407267), addr(0x00407268));
AddressRange range2 = new AddressRangeImpl(addr(0x0040726c), addr(0x0040726e));
AddressSet addrSet = new AddressSet();
addrSet.add(range1);
addrSet.add(range2);
// Create an event that we can fire to all subscribers, and send it.
makeSelection(tool, program, addrSet);
// Now invoke the menu option we want to test.
CodeViewerProvider provider = cb.getProvider();
DockingActionIf action = getAction(mnemonicSearchPlugin, "Include Operands");
performAction(action, provider, false);
// And capture the error dialog.
Window errorDialog = waitForWindow("Mnemonic Search Error", 2000);
captureWindow(errorDialog);
}
}

View file

@ -0,0 +1,58 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import org.junit.rules.TestName;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.MergeTestFacilitator;
public class MergeScreenShotGenerator extends GhidraScreenShotGenerator {
protected MergeTestFacilitator mtf;
private String testFilename;
public MergeScreenShotGenerator(String testFilename, String testNameStr,
MergeTestFacilitator mtf, TestName testName) {
super();
this.testName = testName;
this.testFilename = testFilename;
this.mtf = mtf;
}
@Override
public void setUp() {
env = mtf.getTestEnvironment();
}
public void setTool(PluginTool tool) {
this.tool = tool;
}
@Override
// overridden so that we use the outer class's name when finding the help topic
protected File getHelpTopic() {
String simpleName = testFilename.replace("ScreenShots", "");
File helpTopicDir = getHelpTopicDir(simpleName);
assertNotNull("Unable to find help topic for test file: " + testFilename, helpTopicDir);
return helpTopicDir;
}
}

View file

@ -0,0 +1,205 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertNotNull;
import java.awt.Window;
import org.junit.Test;
import docking.ComponentProvider;
import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.table.GTable;
import docking.widgets.table.threaded.GThreadedTablePanel;
import generic.test.TestUtils;
import ghidra.app.cmd.memory.AddMemoryBlockCmd;
import ghidra.app.plugin.core.gotoquery.GoToServicePlugin;
import ghidra.app.plugin.core.table.TableComponentProvider;
import ghidra.app.plugin.core.table.TableServicePlugin;
import ghidra.app.services.GoToService;
import ghidra.app.util.navigation.GoToAddressLabelDialog;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemoryBlockType;
import ghidra.util.table.GhidraProgramTableModel;
public class NavigationScreenShots extends GhidraScreenShotGenerator {
public NavigationScreenShots() {
super();
}
@Test
public void testGoToDialog() {
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
captureDialog();
}
@Test
public void testGoto_Ambiguous() {
//add fake memory blocks to mimic a multiple address space program
tool.execute(new AddMemoryBlockCmd("CODE", "comments", "test1", addr(0), 0x100, true, true,
true, false, (byte) 0x69, MemoryBlockType.OVERLAY, null, true), program);
tool.execute(new AddMemoryBlockCmd("INTMEM", "comments", "test2", addr(0), 0x100, true,
true, true, false, (byte) 1, MemoryBlockType.OVERLAY, null, false), program);
tool.execute(new AddMemoryBlockCmd("DUMMY", "comments", "test3", addr(20), 0x100, true,
true, true, false, (byte) 1, MemoryBlockType.OVERLAY, null, true), program);
// go to an address outside the blocks that will be displayed
goToAddress(program.getMemory().getBlock("DUMMY").getStart());
// goto address 5
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
GoToAddressLabelDialog dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "5");
pressOkOnDialog();
waitForSwing();
ComponentProvider provider = getProvider("Goto");
captureIsolatedProvider(provider.getClass(), 475, 275);
}
@Test
public void testGoto_Wildcard() throws Exception {
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
GoToAddressLabelDialog dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "FUN_004081?d");
pressOkOnDialog();
waitForSwing();
waitForModel();
ComponentProvider provider = getProvider("Goto");
captureIsolatedProvider(provider.getClass(), 500, 275);
}
@Test
public void testGoto_PreviousList() throws Exception {
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
GoToAddressLabelDialog dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "FUN_004081?d");
pressOkOnDialog();
waitForSwing();
waitForModel();
waitForSwing();
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "5");
pressOkOnDialog();
waitForSwing();
waitForModel();
waitForSwing();
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "FUN*");
pressOkOnDialog();
waitForSwing();
waitForModel();
waitForSwing();
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "40344d");
pressOkOnDialog();
waitForSwing();
waitForModel();
waitForSwing();
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "entry");
pressOkOnDialog();
waitForSwing();
waitForModel();
waitForSwing();
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
dialog = (GoToAddressLabelDialog) getDialog();
setGotoText(dialog, "LAB*");
pressOkOnDialog();
Window window =
waitForWindowByTitleContaining(null, "Search Limit Exceeded!", DEFAULT_WINDOW_TIMEOUT);
assertNotNull(window);
pressButtonByText(window, "OK");
waitForSwing();
waitForModel();
waitForSwing();
performAction("Go To Address/Label", "GoToAddressLabelPlugin", false);
dialog = (GoToAddressLabelDialog) getDialog();
GhidraComboBox comboBox = (GhidraComboBox) getInstanceField("comboBox", dialog);
setPullDownItem(comboBox, 2);
captureDialog();
}
private void setPullDownItem(final GhidraComboBox comboBox, final int index) {
runSwing(() -> {
comboBox.setEnabled(true);
comboBox.setSelectedIndex(1);
comboBox.showPopup();
});
}
private void setGotoText(final GoToAddressLabelDialog dialog, final String text) {
runSwing(() -> dialog.setText(text));
}
private void goToAddress(final Address address) {
GoToServicePlugin goToPlugin = env.getPlugin(GoToServicePlugin.class);
final GoToService goToService;
goToService = (GoToService) invokeInstanceMethod("getGotoService", goToPlugin);
runSwing(() -> goToService.goTo(address));
}
private GhidraProgramTableModel<?> waitForModel() throws Exception {
int i = 0;
while (i++ < 50) {
TableComponentProvider<?>[] providers = getProviders();
if (providers.length > 0) {
GThreadedTablePanel<?> panel =
(GThreadedTablePanel<?>) TestUtils.getInstanceField("threadedPanel",
providers[0]);
GTable table = panel.getTable();
while (panel.isBusy()) {
Thread.sleep(50);
}
return (GhidraProgramTableModel<?>) table.getModel();
}
Thread.sleep(50);
}
throw new Exception("Unable to get threaded table model");
}
private TableComponentProvider<?>[] getProviders() {
TableServicePlugin tableServicePlugin = getPlugin(tool, TableServicePlugin.class);
return tableServicePlugin.getManagedComponents();
}
}

View file

@ -0,0 +1,144 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import org.junit.Test;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.overview.OverviewColorLegendDialog;
import ghidra.app.plugin.core.overview.OverviewColorPlugin;
import ghidra.app.plugin.core.overview.addresstype.AddressTypeOverviewColorService;
import ghidra.app.plugin.core.overview.addresstype.AddressTypeOverviewLegendPanel;
import ghidra.app.plugin.core.overview.entropy.*;
public class OverviewPluginScreenShots extends GhidraScreenShotGenerator {
private AddressTypeOverviewColorService addressTypeService;
private EntropyOverviewColorService entropyService;
public OverviewPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
addressTypeService = new AddressTypeOverviewColorService();
entropyService = new EntropyOverviewColorService();
addressTypeService.initialize(tool);
entropyService.initialize(tool);
}
@Test
public void testOverviewPanel() {
showProvider(CodeViewerProvider.class);
OverviewColorPlugin plugin = getPlugin(tool, OverviewColorPlugin.class);
runSwing(() -> {
plugin.installOverview(addressTypeService);
});
captureIsolatedProvider(CodeViewerProvider.class, 700, 400);
padImage(new Color(0, 0, 0, 0), 10, 0, 50, 0);
drawOval(Color.RED, new Rectangle(630, 2, 40, 40), 3);
drawOval(Color.RED, new Rectangle(668, 55, 40, 240), 3);
}
@Test
public void testAddressTypeOverviewLegend() {
AddressTypeOverviewLegendPanel legendPanel =
new AddressTypeOverviewLegendPanel(addressTypeService);
OverviewColorLegendDialog legendDialog =
new OverviewColorLegendDialog("Overview Legend", legendPanel, null);
tool.showDialog(legendDialog);
captureDialog();
}
@Test
public void testEntropyLegend() {
EntropyOverviewOptionsManager options =
new EntropyOverviewOptionsManager(tool, entropyService);
Palette palette = options.getPalette();
LegendPanel legendPanel = new LegendPanel();
legendPanel.setPalette(palette);
OverviewColorLegendDialog legendDialog =
new OverviewColorLegendDialog("Entropy Legend", legendPanel, null);
tool.showDialog(legendDialog);
captureDialog();
}
@Test
public void testEntropyOptions() {
showOptions("Entropy");
captureDialog(900, 510);
}
@Test
public void testEquation() {
int margin = 20;
image = createEmptyImage(10, 10);
Graphics g = image.getGraphics();
Font font = new Font("Times New Roman", Font.PLAIN, 30);
FontMetrics metrics = g.getFontMetrics(font);
Font bigFont = font.deriveFont(55f);
FontMetrics bigMetrics = g.getFontMetrics(bigFont);
Font mediumFont = new Font("STIXGeneral", Font.PLAIN, 30);
Font smallFont = new Font("STIXGeneral", Font.PLAIN, 16);
FontMetrics smallMetrics = g.getFontMetrics(font);
char[] pChars = Character.toChars(0x1d45d);
char[] iChars = Character.toChars(0x1d456);
String mathyP = "" + pChars[0] + pChars[1];
String mathyI = "" + iChars[0] + iChars[1];
String sum = "\u2211";
String sumTop = " 255";
String sumBottom = " " + mathyI + "=0";
String equation = " -" + mathyP + "(" + iChars[0] + iChars[1] + ") \u22c5 log\u2082(" +
mathyP + "(" + mathyI + "))";
int width = bigMetrics.stringWidth(sum) + metrics.stringWidth(equation);
int bigFontHeight = bigMetrics.getAscent();
int smallFontHeight = smallMetrics.getAscent();
int height = bigFontHeight + 2 * smallFontHeight;
image = createEmptyImage(width + margin * 2, height + margin * 2);
Point p = new Point(margin, margin + smallFontHeight);
drawText(sumTop, Color.BLACK, p, smallFont);
p.y += bigMetrics.getAscent() - bigMetrics.getDescent() / 2;
drawText(sum, Color.BLACK, p, bigFont);
p.y += smallFontHeight;
drawText(sumBottom, Color.BLACK, p, smallFont);
p.x += bigMetrics.stringWidth(sum);
p.y = margin + smallFontHeight + bigFontHeight / 2 + metrics.getHeight() / 2 -
bigMetrics.getDescent() / 2;
drawText(equation, Color.BLACK, p, mediumFont);
}
}

View file

@ -0,0 +1,35 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
public class PrintingPluginScreenShots extends GhidraScreenShotGenerator {
public PrintingPluginScreenShots() {
super();
}
@Test
public void testPrintOptions() {
makeSelection(0x0406c21, 0x0406c31);
performAction("Print", "PrintingPlugin", false);
captureDialog();
}
}

View file

@ -0,0 +1,387 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.awt.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.*;
import org.junit.Assert;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.options.editor.DateEditor;
import docking.options.editor.OptionsDialog;
import docking.widgets.OptionDialog;
import docking.widgets.tree.*;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.progmgr.MultiTabPlugin;
import ghidra.app.services.ProgramManager;
import ghidra.app.util.dialog.CheckoutDialog;
import ghidra.framework.data.CheckinHandler;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.main.OpenVersionedFileDialog;
import ghidra.framework.model.*;
import ghidra.framework.remote.User;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskMonitorAdapter;
public class ProgramManagerPluginScreenShots extends GhidraScreenShotGenerator
implements CheckinHandler {
private String checkinComment;
private boolean keepCheckedOut = true;
public ProgramManagerPluginScreenShots() {
super();
}
@Test
public void testClosedTab() throws Exception {
createAndOpenPrograms(2, 1);
closeProvider(DataTypesProvider.class);
captureToolWindow(900, 400);
drawOval(new Color(108, 0, 0), new Rectangle(280, 92, 190, 60), 8);
}
@Test
public void testEditDate() {
DateEditor dateEditor = new DateEditor();
Component datePanel = dateEditor.getCustomEditor();
final JButton button = (JButton) getInstanceField("browseButton", datePanel);
runSwing(() -> pressButton(button), false);
captureDialog(-1, -1);// Let is keep its size, lest we get a bunch of "..."
}
@Test
public void testFileNotCheckedOut() {
User user = new User("User 1", User.WRITE);
CheckoutDialog checkoutDialog = new CheckoutDialog(program.getDomainFile(), user);
showDialogWithoutBlocking(tool, checkoutDialog);
captureDialog();
}
@Test
public void testFrontEnd3() throws Exception {
createAndOpenPrograms(3, 1);
tool.setConfigChanged(false);
env.closeTool(tool);
FrontEndTool frontEndTool = getFrontEndTool();
captureWindow(frontEndTool.getActiveWindow(), 500, 500);
}
@Test
public void testFrontEndWithProgram() throws Exception {
createAndOpenPrograms(3, 1);
tool.setConfigChanged(false);
FrontEndTool frontEndTool = getFrontEndTool();
captureWindow(frontEndTool.getActiveWindow(), 500, 500);
}
@Test
public void testOpenHistory() throws Exception {
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
projectData.getRootFolder().createFile("WinHelloCpp.exe", program,
TaskMonitorAdapter.DUMMY_MONITOR);
DomainFile df = program.getDomainFile();
addItemToVersionControl(df, "Added to Version Control", true);
// Make change
Program p = (Program) df.getDomainObject(this, false, false, null);
changeProgram(p, "aaa");
checkinComment = "Version 2";
keepCheckedOut = true;
assertTrue(df.canCheckin());
df.checkin(this, false, null);
changeProgram(p, "bbb");
checkinComment = "Version 3";
keepCheckedOut = true;
assertTrue(df.canCheckin());
df.checkin(this, false, null);
p.release(this);
performAction("Open File", "ProgramManagerPlugin", false);
final OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
waitForSwing();
Object treePanel = getInstanceField("treePanel", dialog);
final GTree tree = (GTree) getInstanceField("tree", treePanel);
GTreeRootNode rootNode = tree.getRootNode();
GTreeNode child = rootNode.getChild(0);
tree.setSelectedNode(child);
assertNotNull(dialog);
runSwing(() -> invokeInstanceMethod("advancedButtonCallback", dialog));
captureDialog(850, 400);
closeAllWindowsAndFrames();
}
@Test
public void testOpenProgram() throws Exception {
createAndOpenPrograms(3, 1);
performAction("Open File", "ProgramManagerPlugin", false);
captureDialog(500, 400);
closeAllWindowsAndFrames();
}
@Test
public void testOpenProgramMenu() throws Exception {
createAndOpenPrograms(3, 1);
performAction("Open File", "ProgramManagerPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
Object treePanel = getInstanceField("treePanel", dialog);
GTree tree = (GTree) getInstanceField("tree", treePanel);
JTree jTree = (JTree) getInstanceField("tree", tree);
Rectangle rowBounds = jTree.getRowBounds(1);
waitForTree(tree);
rightClick(jTree, rowBounds.x + 25, rowBounds.y + 10);
waitForSwing();
captureDialog();
closeAllWindowsAndFrames();
}
@Test
public void testProgramOptionsDialog() {
performAction("Program Options", "ProgramManagerPlugin", false);
OptionsDialog dialog = (OptionsDialog) getDialog();
Object optionsPanel = getInstanceField("panel", dialog);
GTree tree = (GTree) getInstanceField("gTree", optionsPanel);
GTreeRootNode rootNode = tree.getRootNode();
GTreeNode child = rootNode.getChild("Program Information");
tree.setSelectedNode(child);
waitForTree(tree);
waitForSwing();
captureDialog();
}
@Test
public void testProgramTabs_No_Hidden() throws Exception {
createAndOpenPrograms(4, 2);
setToolSize(800, 400);
goToListing(0x04002ba);
captureIsolatedProvider(CodeViewerProvider.class, 600, 350);
}
@Test
public void testProgramTabs_With_Hidden_Go_to_Program() throws Exception {
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
moveProviderToItsOwnWindow(provider);
createAndOpenPrograms(6, 2);
goToListing(0x04002ba);
Window window = windowForComponent(provider.getComponent());
setWindowSize(window, 600, 350);
waitForSwing();
performAction("Go To Program", "MultiTabPlugin", true);
captureProviderWithScreenShot(provider);
}
@Test
public void testProgramTabs_With_Hidden_More_Button() throws Exception {
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
moveProviderToItsOwnWindow(provider);
Window window = windowForComponent(provider.getComponent());
setWindowSize(window, 600, 350);
waitForSwing();
createAndOpenPrograms(6, 3);
captureProvider(CodeViewerProvider.class);
drawOval(new Color(108, 0, 0), new Rectangle(440, 16, 70, 50), 8);
}
@Test
public void testProgramTabs_With_Hidden_Popup_Window() throws Exception {
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
moveProviderToItsOwnWindow(provider);
createAndOpenPrograms(6, 2);
goToListing(0x04002ba);
Window window = windowForComponent(provider.getComponent());
setWindowSize(window, 600, 350);
waitForSwing();
MultiTabPlugin plugin = getPlugin(tool, MultiTabPlugin.class);
Object tabPanel = getInstanceField("tabPanel", plugin);
JLabel label = (JLabel) getInstanceField("showHiddenListLabel", tabPanel);
leftClick(label, 5, 5);
waitForSwing();
Component popupDialog = (Component) getInstanceField("listWindow", tabPanel);
Component dockableComponent = getDockableComponent(provider.getComponent());
captureComponents(Arrays.asList(dockableComponent, popupDialog));
}
@Test
public void testProgramTabs_With_Highlighted_Tab() throws Exception {
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
moveProviderToItsOwnWindow(provider);
Window window = windowForComponent(provider.getComponent());
setWindowSize(window, 600, 350);
waitForSwing();
createAndOpenPrograms(6, 1);
runSwing(() -> {
MultiTabPlugin plugin = getPlugin(tool, MultiTabPlugin.class);
invokeInstanceMethod("highlightNextProgram", plugin, new Class<?>[] { boolean.class },
new Object[] { true });
});
captureProvider(CodeViewerProvider.class);
drawOval(new Color(108, 0, 0), new Rectangle(221, 16, 140, 50), 8);
}
@Test
public void testSaveProgram() {
runSwing(() -> OptionDialog.showOptionDialog(tool.getToolFrame(), "Save Program?",
"program1" + " has changed. Do you want to save it?", "&Save", "Do&n't Save",
OptionDialog.QUESTION_MESSAGE), false);
captureDialog();
}
@Test
public void testSaveProgramAs() throws Exception {
Program p = createAndOpenPrograms(4, 0);
changeProgram(p, "Hey");
performAction("Save As File", "ProgramManagerPlugin", false);
captureDialog(300, 300);
pressButtonOnDialog("Cancel");
}
@Test
public void testTabs() throws Exception {
createAndOpenPrograms(2, 1);
goToListing(0x04002ba);
captureIsolatedProvider(CodeViewerProvider.class, 600, 230);
}
private Program createAndOpenPrograms(int count, int currentProgramIndex) throws Exception {
program = env.getProgram("WinHelloCPP.exe");
CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
Project project = env.getProject();
ProjectData projectData = project.getProjectData();
List<DomainFile> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
String programName = "Program" + (i + 1) + ".exe";
list.add(projectData.getRootFolder().createFile(programName, program,
TaskMonitorAdapter.DUMMY_MONITOR));
}
program.flushEvents();
ProgramManager service = tool.getService(ProgramManager.class);
service.closeAllPrograms(true);
List<Program> programs = new ArrayList<>();
for (DomainFile domainFile : list) {
programs.add(service.openProgram(domainFile));
}
service.setCurrentProgram(programs.get(currentProgramIndex));
return programs.get(currentProgramIndex);
}
private void changeProgram(Program p, String labelName) {
int txId = p.startTransaction("create symbol");
try {
p.getSymbolTable().createLabel(getAddr(p, 0), labelName, SourceType.USER_DEFINED);
}
catch (Exception e) {
Assert.fail("Unexpected Exception creating symbol");
}
finally {
p.endTransaction(txId, true);
}
try {
p.save(null, null);
}
catch (Exception e) {
Assert.fail("Unexpected Exception saving Exception");
}
}
private void addItemToVersionControl(DomainFile domainFile, String comment,
boolean keepItCheckedOut) throws Exception {
TaskLauncher.launchModal(comment, () -> {
try {
domainFile.addToVersionControl(comment, keepItCheckedOut,
TaskMonitorAdapter.DUMMY_MONITOR);
}
catch (CancelledException | IOException e) {
throw new RuntimeException(e);
}
});
waitForSwing();
}
private Address getAddr(Program p, long offset) {
AddressFactory addrMap = p.getAddressFactory();
AddressSpace space = addrMap.getDefaultAddressSpace();
return space.getAddress(offset);
}
/*
* @see ghidra.framework.data.CheckinHandler#getComment()
*/
@Override
public String getComment() {
return checkinComment;
}
/*
* @see ghidra.framework.data.CheckinHandler#keepCheckedOut()
*/
@Override
public boolean keepCheckedOut() {
return keepCheckedOut;
}
@Override
public boolean createKeepFile() throws CancelledException {
return false;
}
}

View file

@ -0,0 +1,37 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
public class ProgramTreePluginScreenShots extends GhidraScreenShotGenerator {
public ProgramTreePluginScreenShots() {
super();
}
@Test
public void testViewManager() {
removeFlowArrows();
closeProvider(DataTypesProvider.class);
setDividerPercentage(DataTypesProvider.class, CodeViewerProvider.class, .25f);
captureWindow(tool.getToolFrame(), 1000, 600);
}
}

View file

@ -0,0 +1,79 @@
/* ###
* 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 help.screenshot;
import javax.swing.JTable;
import org.junit.Test;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.debug.propertymanager.PropertyManagerPlugin;
import ghidra.app.plugin.debug.propertymanager.PropertyManagerProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.IntPropertyMap;
import ghidra.program.model.util.PropertyMapManager;
public class PropertyManagerPluginScreenShots extends GhidraScreenShotGenerator {
public PropertyManagerPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
// create some properties
int id = program.startTransaction("test");
PropertyMapManager pm = program.getUsrPropertyManager();
pm.createIntPropertyMap("Foo Property");
IntPropertyMap map1 = pm.createIntPropertyMap("Bar Property");
Memory memory = program.getMemory();
MemoryBlock block = memory.getBlock(".text");
Address addr = block.getStart();
for (int i = 0; i < 5000; i++) {
map1.add(addr, i);
addr = addr.add(10);
}
program.endTransaction(id, true);
loadPlugin(PropertyManagerPlugin.class);
showProvider(PropertyManagerProvider.class);
PropertyManagerProvider provider = getProvider(PropertyManagerProvider.class);
goToListing(0x00401082);
final JTable table = (JTable) getInstanceField("table", provider);
runSwing(new Runnable() {
@Override
public void run() {
table.setRowSelectionInterval(0, 0);
}
});
}
@Test
public void testMarkers() {
captureProvider(CodeViewerProvider.class);
}
@Test
public void testPropertyViewer() {
captureIsolatedProvider(PropertyManagerProvider.class, 400, 300);
}
}

View file

@ -0,0 +1,300 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.swing.*;
import org.junit.Test;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.references.*;
import ghidra.app.util.importer.*;
import ghidra.app.util.opinion.LoaderService;
import ghidra.framework.main.DataTreeDialog;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class ReferencesPluginScreenShots extends GhidraScreenShotGenerator {
public ReferencesPluginScreenShots() {
super();
}
@Test
public void testAddReferenceDialog() {
goToListing(0x401008);
performAction("Add Reference From", "ReferencesPlugin", false);
captureDialog();
}
@Test
public void testChoose_external_prog() throws Exception {
importFile(getTestDataFile("pe/w7sp1/user32.dll"));
importFile(getTestDataFile("pe/w7sp1/shlwapi.dll"));
runSwing(() -> {
DataTreeDialog dialog = new DataTreeDialog(tool.getToolFrame(),
"Choose External Program (" + "Kernel32.dll" + ")", DataTreeDialog.OPEN);
tool.showDialog(dialog);
}, false);
captureDialog();
}
@Test
public void testCreateOffsetTable() {
goToListing(0x400fd0);
makeSelection(0x400fd0, 0x400fd8);
performAction("Create Offset References", "OffsetTablePlugin", false);
JDialog d = waitForJDialog("Create Offset References");
captureDialog();
pressButtonByText(d, "Cancel");
}
@Test
public void testDropZones() {
goToListing(0x4010ae);
performAction("View/Edit References From", "ReferencesPlugin", false);
EditReferencesProvider provider = getProvider(EditReferencesProvider.class);
captureIsolatedProvider(provider, 700, 300);
captureProvider(provider);
int topMargin = 60;
int leftMargin = 10;
padImage(Color.WHITE, topMargin, leftMargin, 10, 10);
JComponent rootComp = getDockableComponent(EditReferencesProvider.class);
JComponent comp =
(JComponent) findComponentByName(provider.getComponent(), "operandLabels[0]");
Point origin = new Point(leftMargin, topMargin);
explainComponent(rootComp, comp, Color.GREEN, origin, new Point(250, 20),
"Operand-specific Drop Zones");
comp = (JComponent) findComponentByName(provider.getComponent(), "mnemonicLabel");
explainComponent(rootComp, comp, Color.GREEN, origin, new Point(250, 20),
"Operand-specific Drop Zones");
comp = (JComponent) findComponentByName(provider.getComponent(), "RefsTable");
explainComponent(rootComp, comp, Color.GREEN, origin, new Point(450, 40),
"Active-operand Drop Zones");
}
private void explainComponent(JComponent rootComp, JComponent comp, Color color, Point origin,
Point point, String text) {
Rectangle bounds = getBounds(comp);
Rectangle converted = SwingUtilities.convertRectangle(comp.getParent(), bounds, rootComp);
converted.x += origin.x;
converted.y += origin.y;
drawRectangle(color, converted, 2);
Point startLine = new Point(converted.x + converted.width / 2, converted.y);
drawLine(color, 2, startLine, point);
Point p2 = new Point(point.x + 20, point.y);
drawLine(color, 2, point, p2);
Point p3 = new Point(p2.x + 4, p2.y + 5);
drawText(text, Color.BLACK, p3, 12f);
}
@Test
public void testExternal_names_dialog() {
showProvider(ExternalReferencesProvider.class);
captureProvider(ExternalReferencesProvider.class);
}
@Test
public void testExtRefPanel() {
goToListing(0x0401008);
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
dialog.initDialog(cu, 0, 0, null);
runSwing(() -> {
JRadioButton choiceButton = (JRadioButton) getInstanceField("extRefChoice", dialog);
invokeInstanceMethod("refChoiceActivated", dialog,
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
}, true);
showDialogWithoutBlocking(tool, dialog);
JPanel panel = (JPanel) getInstanceField("extRefPanel", dialog);
Rectangle bounds = panel.getBounds();
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
captureDialog();
takeSnippet(bounds);
}
@Test
public void testOffsetRefsExample() throws MemoryAccessException { // gif
removeFlowArrows();
goToListing(0x0400280);
int id = program.startTransaction("Test");
Memory memory = program.getMemory();
memory.setByte(addr(0x400284), (byte) 0x14);
memory.setByte(addr(0x400288), (byte) 0x18);
memory.setByte(addr(0x40028c), (byte) 0x1c);
memory.setByte(addr(0x400290), (byte) 0x20);
program.endTransaction(id, true);
makeSelection(0x400284, 0x400293);
performAction("Create Offset References", "OffsetTablePlugin", false);
runSwing(() -> {
OffsetTableDialog dialog = (OffsetTableDialog) getDialog();
dialog.setBaseAddress(addr(0x4f5000));
});
pressOkOnDialog();
captureIsolatedProvider(CodeViewerProvider.class, 800, 600);
}
@Test
public void testRefProvider() {
goToListing(0x402355);
performAction("View/Edit References From", "ReferencesPlugin", false);
EditReferencesProvider provider = getProvider(EditReferencesProvider.class);
captureIsolatedProvider(provider, 700, 400);
}
@Test
public void testRegRefPanel() {
goToListing(0x0401008);
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
dialog.initDialog(cu, 0, 0, null);
runSwing(() -> {
JRadioButton choiceButton = (JRadioButton) getInstanceField("regRefChoice", dialog);
invokeInstanceMethod("refChoiceActivated", dialog,
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
}, true);
showDialogWithoutBlocking(tool, dialog);
JPanel panel = (JPanel) getInstanceField("regRefPanel", dialog);
Rectangle bounds = panel.getBounds();
bounds.height = bounds.height / 2;
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
captureDialog();
takeSnippet(bounds);
}
@Test
public void testStackRefPanel() {
goToListing(0x0401008);
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
dialog.initDialog(cu, 0, 0, null);
runSwing(() -> {
JRadioButton choiceButton = (JRadioButton) getInstanceField("stackRefChoice", dialog);
invokeInstanceMethod("refChoiceActivated", dialog,
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
}, true);
showDialogWithoutBlocking(tool, dialog);
JPanel panel = (JPanel) getInstanceField("stackRefPanel", dialog);
Rectangle bounds = panel.getBounds();
bounds.height = bounds.height / 2;
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
captureDialog();
takeSnippet(bounds);
}
@Test
public void testMemRefPanel() {
goToListing(0x0401008);
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
dialog.initDialog(cu, 0, 0, null);
runSwing(() -> {
JRadioButton choiceButton = (JRadioButton) getInstanceField("memRefChoice", dialog);
invokeInstanceMethod("refChoiceActivated", dialog,
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
}, true);
showDialogWithoutBlocking(tool, dialog);
final JPanel panel = (JPanel) getInstanceField("memRefPanel", dialog);
JButton button = (JButton) getInstanceField("addrHistoryButton", panel);
Rectangle buttonBounds = button.getBounds();
buttonBounds = SwingUtilities.convertRectangle(button.getParent(), buttonBounds, panel);
buttonBounds.x += 20; // padding added by takeSnippet
buttonBounds.y += buttonBounds.height / 2 + 20; // half button height + padding added by takeSnippet()
System.out.println("Button bounds = " + buttonBounds);
Rectangle bounds = panel.getBounds();
bounds.height = 3 * bounds.height / 5; // get rid of empty space
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
captureDialog();
takeSnippet(bounds);
Image image1 = image;
runSwing(() -> {
JCheckBox checkbox = (JCheckBox) getInstanceField("offsetCheckbox", panel);
checkbox.setSelected(true);
});
bounds = panel.getBounds();
bounds.height = 3 * bounds.height / 5;
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
captureDialog();
takeSnippet(bounds);
Image image2 = image;
int gap = 40;
int width = image1.getWidth(null);
int height = image1.getHeight(null);
BufferedImage newImage = createEmptyImage(width, 2 * height + gap);
Graphics2D g2 = (Graphics2D) newImage.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.drawImage(image1, 0, 0, null);
g2.drawImage(image2, 0, height + gap, null);
g2.setColor(Color.BLACK);
String label = "Address History";
int x = 150;
int y = height + gap / 2;
g2.drawString(label, x, y);
x += g2.getFontMetrics().stringWidth(label) + 5;
y -= g2.getFontMetrics().getAscent() / 3;
g2.drawLine(x, y, x + 10, y);
x += 10;
g2.drawLine(buttonBounds.x, buttonBounds.y, x, y);
g2.drawLine(buttonBounds.x, buttonBounds.y + height + gap, x, y);
image = newImage;
}
private void importFile(File file) throws CancelledException, DuplicateNameException,
InvalidNameException, VersionException, IOException {
String programNameOverride = null;
List<Program> programs = AutoImporter.importFresh(file, null, this, new MessageLog(),
TaskMonitor.DUMMY, LoaderService.ACCEPT_ALL, LoadSpecChooser.CHOOSE_THE_FIRST_PREFERRED,
programNameOverride, OptionChooser.DEFAULT_OPTIONS,
MultipleProgramsStrategy.ALL_PROGRAMS);
Program p = programs.get(0);
env.getProject().getProjectData().getRootFolder().createFile(p.getName(), p,
TaskMonitor.DUMMY);
}
}

View file

@ -0,0 +1,129 @@
/* ###
* 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 help.screenshot;
import java.math.BigInteger;
import org.junit.Test;
import docking.action.DockingActionIf;
import ghidra.app.cmd.register.SetRegisterCmd;
import ghidra.app.plugin.core.register.*;
import ghidra.app.util.viewer.field.OperandFieldFactory;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.lang.Register;
public class RegisterPluginScreenShots extends GhidraScreenShotGenerator {
private RegisterPlugin plugin;
public RegisterPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
plugin = getPlugin(tool, RegisterPlugin.class);
}
@Test
public void testRegisterManager() {
set("EAX", addr(0x401000), addr(0x401013), 0x23);
set("EAX", addr(0x401c37), addr(0x401c5a), 0x56);
showProvider(RegisterManagerProvider.class);
selectProviderRegister("EAX");
captureIsolatedProvider(RegisterManagerProvider.class, 700, 500);
}
@Test
public void testEditRegisterValueRange() {
String reg = "EDI";
set(reg, addr(0x401c5b), addr(0x401c6a), 0x343);
showProvider(RegisterManagerProvider.class);
selectProviderRegister(reg);
editRow(0);
captureDialog();
}
@Test
public void testSetRegisterValues() {
goToListing(0x401cbd, OperandFieldFactory.FIELD_NAME, true);
AddressSet addrs = new AddressSet();
addrs.addRange(addr(0x401c9c), addr(0x401c9e));
addrs.addRange(addr(0x401ca8), addr(0x401cab));
addrs.addRange(addr(0x401cbd), addr(0x401cc1));
makeSelection(addrs);
DockingActionIf setAction = getAction(plugin, "Set Register Values");
performAction(setAction, false);
captureDialog(700, 300);
}
@Test
public void testClearRegisterValues() {
go(0x401c5b);
DockingActionIf setAction = getAction(plugin, "Clear Register Values");
performAction(setAction, false);
captureDialog(700, 300);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void editRow(final int row) {
RegisterManagerProvider provider = getProvider(RegisterManagerProvider.class);
final Object registerValuesPanel = getInstanceField("values", provider);
runSwing(() -> {
//@formatter:off
invokeInstanceMethod(
"editRow",
registerValuesPanel,
new Class[] {int.class},
new Object[] {row});
//@formatter:on
}, false);
}
private void set(String registerName, Address start, Address end, int value) {
Register register = program.getRegister(registerName);
SetRegisterCmd regCmd = new SetRegisterCmd(register, start, end, BigInteger.valueOf(value));
tool.execute(regCmd, program);
waitForBusyTool(tool);
}
private void selectProviderRegister(String registerName) {
RegisterManagerProvider provider = getProvider(RegisterManagerProvider.class);
RegisterTree tree = (RegisterTree) getInstanceField("tree", provider);
Register register = program.getRegister(registerName);
tree.selectRegister(register);
waitForTree(tree);
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
public class RelocationTablePluginScreenShots extends GhidraScreenShotGenerator {
public RelocationTablePluginScreenShots() {
super();
}
@Test
public void testRelocation_Table() {
performAction("Relocation Table", "DockingWindows", false);
captureProvider("Relocation Table");
}
}

View file

@ -0,0 +1,316 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertNotNull;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.*;
import org.junit.Test;
import ghidra.app.merge.MergeProgressPanel;
import ghidra.util.layout.VerticalLayout;
import resources.ResourceManager;
public class RepositoryCustomScreenShots extends GhidraScreenShotGenerator {
public RepositoryCustomScreenShots() {
super();
}
@Test
public void testMultiUser() {
image = createEmptyImage(800, 600);
Color purple = new Color(255, 0, 255);
Color green = new Color(100, 255, 100);
int y = 50;
int x = 450;
int spacing = 100;
int hSpacing = 170;
Point p_v0 = new Point(x, y);
Point p_v1 = new Point(x, y + spacing);
Point p_v2 = new Point(x, y + 3 * spacing);
Point p_v3 = new Point(x, y + 5 * spacing);
Point p_co_v1 = new Point(x - hSpacing, y + (2 * spacing));
Point p_co_v2 = new Point(x + hSpacing, y + (2 * spacing));
Point p_box1 = new Point(x - hSpacing * 2, y + 3 * spacing);
Point p_box2 = new Point(x - (hSpacing * 3) / 2, y + 4 * spacing);
Point p_text1 = new Point(x + hSpacing / 2, y);
Point p_text2 = new Point(x + hSpacing / 2, y + spacing / 2);
Point p_text3 = new Point(x - 5 * hSpacing / 4, y + 5 * spacing / 4);
Point p_text4 = new Point(x + 3 * hSpacing / 4, y + 5 * spacing / 4);
Point p_text5 = new Point(x + hSpacing / 2, y + 11 * spacing / 4);
Point p_text8 = new Point(x - 3 * hSpacing / 2, y + 5 * spacing);
Point p_legend = new Point(x + hSpacing / 2, y + 4 * spacing);
int indent = 50;
int legendSpacing = 20;
Point p_leg1 = new Point(x + hSpacing / 2, y + 4 * spacing + 2 * legendSpacing);
Point p_leg2 = new Point(x + hSpacing / 2, y + 4 * spacing + 3 * legendSpacing);
Point p_leg3 = new Point(x + hSpacing / 2, y + 4 * spacing + 4 * legendSpacing);
Point p_leg1_text = new Point(p_leg1.x + indent, p_leg1.y);
Point p_leg2_text = new Point(p_leg2.x + indent, p_leg2.y);
Point p_leg3_text = new Point(p_leg3.x + indent, p_leg3.y);
drawLine(purple, p_v0, p_v3, false);
drawLine(Color.BLACK, p_v1, p_co_v1, true);
drawLine(Color.BLACK, p_v1, p_co_v2, true);
drawLine(green, p_co_v1, p_box1, false);
drawLine(green, p_box1, p_box2, false);
drawLine(Color.BLUE, p_co_v2, p_v2, false);
drawLine(Color.BLUE, p_box2, p_v3, false);
drawBubble("Version 0", null, p_v0);
drawBubble("Version 1", null, p_v1);
drawBubble("Version 2", null, p_v2);
drawBubble("Version 3", null, p_v3);
drawBubble("Check out", "Version 1", p_co_v1);
drawBubble("Check out", "Version 1", p_co_v2);
drawBox(p_box1, 6, "User A checks", "in his file");
drawBox(p_box2, 7, "Ghidra Server merges file", "with the latest version which is",
"Version 2, and creates", "Version 3");
drawText(p_text1, 1, "File is added to Version Control", "Version 0 is created.");
drawText(p_text2, 2, "A user checks out Version 0", "checks it in and creates Version 1.");
drawText(p_text3, 3, "User A checks out", "Version 1.");
drawText(p_text4, 4, "User B checks out", "Version 1.");
drawText(p_text5, 5, "User B checks in his file", "and creates Version 2.");
drawText(p_text8, 8, "User A must resolve any conflicts", "that may occur in order to",
"complete the check in process.");
drawText(p_legend, -1, "Note: The different colored lines denote",
"phases of the check in process.");
drawText(p_leg1_text, -1, " Check Out");
drawText(p_leg2_text, -1, " Make changes and merge");
drawText(p_leg3_text, -1, " Create new version");
drawLine(Color.BLACK, p_leg1, p_leg1_text, true);
drawLine(green, p_leg2, p_leg2_text, false);
drawLine(Color.BLUE, p_leg3, p_leg3_text, false);
}
private void drawLine(Color color, Point p1, Point p2, boolean dashed) {
Graphics2D g = ((BufferedImage) image).createGraphics();
BasicStroke dash = new BasicStroke(2f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 1f,
new float[] { 10f }, 0f);
BasicStroke stroke = dashed ? dash : new BasicStroke(2f);
g.setStroke(stroke);
g.setColor(color);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
g.dispose();
}
private void drawBubble(String text1, String text2, Point p) {
int radius = 30;
Graphics2D g = ((BufferedImage) image).createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
BasicStroke stroke = new BasicStroke(1);
g.setStroke(stroke);
int x = p.x - radius;
int y = p.y - radius;
g.fillOval(x, y, radius * 2, 2 * radius);
Font f = g.getFont().deriveFont(12f);
g.setFont(f);
FontMetrics metrics = g.getFontMetrics();
int height = metrics.getHeight();
g.setColor(Color.BLACK);
g.drawOval(x, y, radius * 2, radius * 2);
if (text2 == null) {
g.drawString(text1, p.x - metrics.stringWidth(text1) / 2,
p.y + metrics.getAscent() / 2);
}
else {
g.drawString(text1, p.x - metrics.stringWidth(text1) / 2,
p.y - height / 2 + metrics.getAscent() / 2);
g.drawString(text2, p.x - metrics.stringWidth(text2) / 2,
p.y + height / 2 + metrics.getAscent() / 2);
}
g.dispose();
}
private void drawBox(Point p, int order, String... text) {
Graphics2D g = ((BufferedImage) image).createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
BasicStroke stroke = new BasicStroke(1);
g.setStroke(stroke);
Font f = g.getFont().deriveFont(12f);
g.setFont(f);
FontMetrics metrics = g.getFontMetrics();
int margin = 5;
int height = metrics.getHeight() * text.length + 2 * margin;
int width = 0;
for (String string : text) {
width = Math.max(width, metrics.stringWidth(string));
}
width += 2 * margin;
int x = p.x - width / 2;
int y = p.y - height / 2;
g.fillRect(x, y, width, height);
g.setColor(Color.BLACK);
g.drawRect(x, y, width, height);
y += margin;
for (String string : text) {
g.drawString(string, p.x - metrics.stringWidth(string) / 2, y + metrics.getAscent());
y += metrics.getHeight();
}
String orderString = "(" + order + ") ";
g.drawString(orderString, x - metrics.stringWidth(orderString),
p.y + metrics.getAscent() / 2);
g.dispose();
}
private void drawText(Point p, int order, String... text) {
Graphics2D g = ((BufferedImage) image).createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Font f = g.getFont().deriveFont(12f);
g.setFont(f);
FontMetrics metrics = g.getFontMetrics();
// int margin = 5;
int height = metrics.getHeight() * text.length;
// int width = 0;
// for (String string : text) {
// width = Math.max(width, metrics.stringWidth(string));
// }
// width += 2 * margin;
//
// int x = p.x - width / 2;
// int y = p.y - height / 2;
// g.fillRect(x, y, width, height);
g.setColor(Color.BLACK);
int y = p.y - height / 2;
int x = p.x;
for (String string : text) {
g.drawString(string, x, y + metrics.getAscent());
y += metrics.getHeight();
}
if (order > 0) {
String orderString = "(" + order + ") ";
g.drawString(orderString, x - metrics.stringWidth(orderString),
p.y + metrics.getAscent() / 2);
}
g.dispose();
}
@Test
public void testAutoMergeCodeUnits() {
closeAllWindowsAndFrames();
final MergeProgressPanel panel = new MergeProgressPanel();
final String[] MEMORY = new String[] { "Memory" };
final String[] PROGRAM_TREE = new String[] { "Program Tree" };
final String[] DATA_TYPES = new String[] { "Data Types" };
final String[] PROGRAM_CONTEXT = new String[] { "Program Context" };
final String[] LISTING = new String[] { "Listing" };
final String[] BYTES = new String[] { "Listing", "Bytes & Code Units" };
final String[] FUNCTIONS = new String[] { "Listing", "Functions" };
final String[] SYMBOLS = new String[] { "Listing", "Symbols" };
final String[] COMMENTS = new String[] { "Listing",
"Equates, User Defined Properties, References, Bookmarks & Comments" };
final String[] EXTERNAL_PROGRAM = new String[] { "External Program" };
final String[] PROPERTY_LIST = new String[] { "Property List" };
panel.addInfo(MEMORY);
panel.addInfo(PROGRAM_TREE);
panel.addInfo(DATA_TYPES);
panel.addInfo(PROGRAM_CONTEXT);
panel.addInfo(LISTING);
panel.addInfo(BYTES);
panel.addInfo(FUNCTIONS);
panel.addInfo(SYMBOLS);
panel.addInfo(COMMENTS);
panel.addInfo(EXTERNAL_PROGRAM);
panel.addInfo(PROPERTY_LIST);
runSwing(new Runnable() {
@Override
public void run() {
panel.setCompleted(MEMORY);
panel.setCompleted(PROGRAM_TREE);
panel.setCompleted(DATA_TYPES);
panel.setCompleted(PROGRAM_CONTEXT);
panel.setCompleted(LISTING);
panel.setCompleted(BYTES);
panel.setInProgress(FUNCTIONS);
}
});
JPanel mainPanel = new JPanel(new VerticalLayout(20));
ImageIcon icon = ResourceManager.loadImage("images/Merge.png");
JLabel topLabel =
new JLabel("Merge of Byte * Code Unit changes", icon, SwingConstants.LEFT);
mainPanel.add(topLabel);
mainPanel.add(panel);
JPanel progressPanel = new JPanel(new VerticalLayout(2));
progressPanel.add(new JLabel("Progress In Current Phase"));
JProgressBar progress = new JProgressBar(0, 100);
progress.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 150));
progress.setValue(22);
progressPanel.add(progress);
ImageIcon infoIcon = ResourceManager.loadImage("images/information.png");
progressPanel.add(
new JLabel("Finding conflicting code unit chagnes...", infoIcon, SwingConstants.LEFT));
progressPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 100, 0));
mainPanel.add(progressPanel);
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 10, 100, 10));
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
JButton apply = new JButton("Apply");
JButton cancel = new JButton("Cancel");
apply.setEnabled(false);
buttonPanel.add(apply);
buttonPanel.add(cancel);
mainPanel.add(buttonPanel);
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.setVisible(true);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(mainPanel, BorderLayout.CENTER);
frame.validate();
frame.setTitle("Merge Tool");
frame.setVisible(true);
captureWindow(frame);
}
@Override
// overridden so that we use the outer class's name when finding the help topic
protected File getHelpTopic() {
File helpTopicDir = getHelpTopicDir("Repository");
assertNotNull("Unable to find help topic for test file: " + getClass().getName(),
helpTopicDir);
return helpTopicDir;
}
}

View file

@ -0,0 +1,49 @@
/* ###
* 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 help.screenshot;
import org.junit.Test;
import docking.action.DockingActionIf;
import ghidra.app.plugin.core.scalartable.*;
public class ScalarSearchPluginScreenShots extends GhidraScreenShotGenerator {
@Test
public void testSearchAllScalarsDialog() {
ScalarSearchPlugin plugin = env.getPlugin(ScalarSearchPlugin.class);
DockingActionIf action = getAction(plugin, "Search for Scalars");
performAction(action, false);
captureDialog(ScalarSearchDialog.class);
}
@Test
public void testScalarWindow() {
ScalarSearchPlugin plugin = env.getPlugin(ScalarSearchPlugin.class);
DockingActionIf action = getAction(plugin, "Search for Scalars");
performAction(action, false);
ScalarSearchDialog dialog = waitForDialogComponent(ScalarSearchDialog.class);
pressButtonByText(dialog, "Search");
waitForSwing();
ScalarSearchProvider provider = getProvider(ScalarSearchProvider.class);
waitForTableModel(provider.getScalarModel());
captureIsolatedProvider(provider.getClass(), 800, 500);
}
}

View file

@ -0,0 +1,232 @@
/* ###
* 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 help.screenshot;
import java.awt.Window;
import javax.swing.*;
import javax.swing.table.TableModel;
import org.junit.Before;
import org.junit.Test;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import docking.widgets.table.threaded.ThreadedTableModel;
import ghidra.GhidraOptions;
import ghidra.app.plugin.core.searchtext.SearchTextPlugin;
import ghidra.app.plugin.core.string.StringTableProvider;
import ghidra.app.plugin.core.table.TableComponentProvider;
/**
* Captures screenshots associated with Memory Search.
*/
public class SearchScreenShots extends AbstractSearchScreenShots {
private SearchTextPlugin searchPlugin;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
searchPlugin = env.getPlugin(SearchTextPlugin.class);
env.showTool();
}
/**
* Captures the Direct References search dialog.
*/
@Test
public void testDirectReferences() {
moveTool(500, 500);
goToListing(0x407b44, "Address", false);
performAction("Search for Direct References", "FindPossibleReferencesPlugin", false);
waitForSwing();
ComponentProvider provider = getProvider(TableComponentProvider.class);
JComponent component = provider.getComponent();
JTable table = findComponent(component, JTable.class);
TableModel model = table.getModel();
waitForTableModel((ThreadedTableModel<?, ?>) model);
captureIsolatedProvider(TableComponentProvider.class, 800, 350);
}
/**
* Captures the Direct References search dialog for a selection.
*/
@Test
public void testDirectRefsOnSelection() {
moveTool(500, 500);
goToListing(0x407b44, "Address", false);
makeSelection(0x40e626, 0x40e748);
performAction("Search for Direct References", "FindPossibleReferencesPlugin", false);
waitForSwing();
ComponentProvider provider = getProvider(TableComponentProvider.class);
JComponent component = provider.getComponent();
JTable table = findComponent(component, JTable.class);
TableModel model = table.getModel();
waitForTableModel((ThreadedTableModel<?, ?>) model);
captureIsolatedProvider(TableComponentProvider.class, 800, 350);
}
@Test
public void testQueryResultsSearch() {
moveTool(500, 500);
performAction("Search Text", "SearchTextPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JRadioButton rbAll = (JRadioButton) getInstanceField("searchAllRB", dialog);
rbAll.setSelected(true);
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "LAB");
final JButton allButton = (JButton) getInstanceField("allButton", dialog);
pressButton(allButton);
waitForSwing();
ComponentProvider provider = getProvider(TableComponentProvider.class);
JComponent component = provider.getComponent();
JTable table = findComponent(component, JTable.class);
TableModel model = table.getModel();
waitForTableModel((ThreadedTableModel<?, ?>) model);
Window window = getWindowByTitle(null, "Search Limit Exceeded!");
pressButtonByText(window, "OK");
captureIsolatedProvider(TableComponentProvider.class, 500, 450);
}
@Test
public void testSearchForAddressTables() {
moveTool(500, 500);
performAction("Search for Address Tables", "AutoTableDisassemblerPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
waitForSwing();
pressButtonByText(dialog, "Search");
JComponent component = dialog.getComponent();
JTable table = findComponent(component, JTable.class);
TableModel model = table.getModel();
waitForTableModel((ThreadedTableModel<?, ?>) model);
captureDialog(DialogComponentProvider.class, 800, 525);
}
/**
* Captures the warning dialog displayed when the search results reach the maximum
* limit.
*/
@Test
public void testSearchLimitExceeded() {
moveTool(500, 500);
// Set the search results max to a low number that we know will be hit with the
// custom program we've loaded. Also, we are NOT changing the option so that dialog
// that is shown will have the default value
searchPlugin = env.getPlugin(SearchTextPlugin.class);
searchPlugin.optionsChanged(null, GhidraOptions.OPTION_SEARCH_LIMIT, null, 10);
performAction("Search Text", "SearchTextPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JRadioButton rbAll = (JRadioButton) getInstanceField("searchAllRB", dialog);
rbAll.setSelected(true);
JTextField textField = (JTextField) getInstanceField("valueField", dialog);
setText(textField, "0");
final JButton allButton = (JButton) getInstanceField("allButton", dialog);
pressButton(allButton);
ComponentProvider provider = getProvider(TableComponentProvider.class);
JComponent component = provider.getComponent();
JTable table = findComponent(component, JTable.class);
TableModel model = table.getModel();
waitForTableModel((ThreadedTableModel<?, ?>) model);
Window errorDialog = waitForWindow("Search Limit Exceeded!", 2000);
captureWindow(errorDialog);
}
@Test
public void testSearchText() {
moveTool(500, 500);
performAction("Search Text", "SearchTextPlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
JCheckBox button = (JCheckBox) getInstanceField("commentsCB", dialog);
setSelected(button, true);
captureDialog(DialogComponentProvider.class);
}
@Test
public void testStringSearchDialog() {
moveTool(500, 500);
performAction("Search for Strings", "StringTablePlugin", false);
waitForSwing();
captureDialog(DialogComponentProvider.class, 500, 325);
}
@Test
public void testStringSearchResults() {
moveTool(1000, 1000);
performAction("Search for Strings", "StringTablePlugin", false);
waitForSwing();
DialogComponentProvider dialog = getDialog();
pressButtonByText(dialog, "Search");
waitForSwing();
ComponentProvider provider = getProvider(StringTableProvider.class);
JComponent component = provider.getComponent();
JTable table = findComponent(component, JTable.class);
TableModel model = table.getModel();
waitForTableModel((ThreadedTableModel<?, ?>) model);
captureIsolatedProvider(StringTableProvider.class, 1000, 750);
}
}

View file

@ -0,0 +1,84 @@
/* ###
* 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 help.screenshot;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import org.junit.Test;
import docking.DialogComponentProvider;
public class SelectBlockPluginScreenShots extends GhidraScreenShotGenerator {
public SelectBlockPluginScreenShots() {
super();
}
@Test
public void testDialog() {
performAction("SelectBlock", "SelectBlockPlugin", false);
captureDialog();
}
@Test
public void testToBadAddr() {
performAction("SelectBlock", "SelectBlockPlugin", false);
DialogComponentProvider dialog = getDialog();
JRadioButton toButton = (JRadioButton) getInstanceField("toButton", dialog);
clickButton(toButton);
waitForSwing();
JTextField addressField = (JTextField) getInstanceField("toAddressField", dialog);
enableTextField(addressField);
waitForSwing();
setText(addressField, "foobar");
pressButtonByText(dialog, "Select Bytes");
captureDialog();
}
private void clickButton(final JRadioButton button) {
runSwing(new Runnable() {
@Override
public void run() {
button.setSelected(true);
}
});
}
private void enableTextField(final JTextField field) {
runSwing(new Runnable() {
@Override
public void run() {
field.setEditable(true);
field.setEnabled(true);
}
});
}
}

View file

@ -0,0 +1,233 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.net.URL;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import org.junit.Test;
import docking.*;
import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.Layout;
import docking.widgets.fieldpanel.field.Field;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.processors.ShowInstructionInfoPlugin;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
import ghidra.app.util.viewer.field.MnemonicFieldFactory;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.util.LaunchErrorDialog;
public class ShowInstructionInfoPluginScreenShots extends GhidraScreenShotGenerator {
private ShowInstructionInfoPlugin plugin;
public ShowInstructionInfoPluginScreenShots() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
plugin = getPlugin(tool, ShowInstructionInfoPlugin.class);
}
@Test
public void testProcessorManualOptions() {
showOptions("Processor Manuals");
captureDialog(800, 354);
// finished("ShowInstructionInfoPlugin", "ProcessorManualOptions.png");
}
@Test
public void testRawInstructionDisplay() {
closeProvider(ViewManagerComponentProvider.class);
closeProvider(DataTypesProvider.class);
setToolSize(975, 325);
CodeViewerProvider listing = getProvider(CodeViewerProvider.class);
goToListing(0x40100d, MnemonicFieldFactory.FIELD_NAME, true);
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
ListingPanel listingPanel = cb.getListingPanel();
Window window = windowForComponent(listing.getComponent());
captureWindow(window);
Graphics2D g = (Graphics2D) image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Rectangle labelBounds = getInstructionLabelBounds(); // the label in the status bar
Point location = labelBounds.getLocation();
// move over a bit so the oval doesn't overwrite the text
int labelPadding = 10;
location.x -= labelPadding * 2;
location.y -= labelPadding * 1.5; // a bit of fudge here; trial and error
Dimension labelSize = labelBounds.getSize();
labelSize.width += labelPadding;
labelSize.height += (1.85 * labelPadding); // a bit of fudge here; trial and error
Rectangle shapeBounds = new Rectangle(location, labelSize);
int thickness = 5;
drawRectangle(Color.RED, shapeBounds, thickness);
Point start = getEndOfRow(cb, listingPanel, window);
Point end = new Point(location.x, location.y);
drawLine(Color.RED, thickness, start, end);
cropListingWithStatusArea();
// finished("ShowInstructionInfoPlugin", "RawInstructionDisplay.png");
}
@Test
public void testShowInstructionInfo() {
goToListing(0x40100d, MnemonicFieldFactory.FIELD_NAME, true);
performAction("Show Instruction Info", plugin.getName(), true);
captureProviderWindow("Instruction Info", 1200, 500);
// finished("ShowInstructionInfoPlugin", "ShowInstructionInfo.png");
}
@Test
public void testUnableToLaunch() throws Exception {
URL url1 = new URL("http://localhost:11046/1234567//pentium.pdf#page=701");
URL url2 = new URL("file:/Ghidra/docs/manuals/pentium.pdf#page=701");
final LaunchErrorDialog dialog = new LaunchErrorDialog(url1, url2);
runSwing(() -> dialog.setVisible(true), false);
captureDialog(dialog);
// finished("ShowInstructionInfoPlugin", "ShowInstructionInfo.png");
}
//==================================================================================================
// Private Methods
//==================================================================================================
private Rectangle getInstructionLabelBounds() {
JLabel label = (JLabel) getInstanceField("instructionLabel", plugin);
Window window = windowForComponent(label);
Rectangle bounds = label.getBounds();
return SwingUtilities.convertRectangle(label.getParent(), bounds, window);
}
private void cropListingWithStatusArea() {
CodeBrowserPlugin cb = getPlugin(tool, CodeBrowserPlugin.class);
ListingPanel listingPanel = cb.getListingPanel();
Window window = windowForComponent(listingPanel);
StatusBar statusBar = getStatusBar();
int statusHeight = statusBar.getHeight();
DockableComponent dc = getDockableComponent(listingPanel);
Rectangle cropBounds = dc.getBounds();
cropBounds = SwingUtilities.convertRectangle(dc.getParent(), cropBounds, window);
cropBounds.height += statusHeight;
crop(cropBounds);
}
private StatusBar getStatusBar() {
DockingWindowManager windowManager = tool.getWindowManager();
Object root = getInstanceField("root", windowManager);
StatusBar statusBar = (StatusBar) getInstanceField("statusBar", root);
return statusBar;
}
private Point getEndOfRow(CodeBrowserPlugin cb, ListingPanel listingPanel, Window window) {
Layout layout = listingPanel.getLayout(cb.getCurrentAddress());
int numFields = layout.getNumFields();
// note: The y of the field bounds always starts at 0. So, we have to use the cursor
// bounds, whose y is correct, which we can do, since we put the cursor on the
// line in which we are interested.
Point cursorPoint = listingPanel.getCursorPoint();
Rectangle fieldBounds = layout.getFieldBounds(numFields - 1);
fieldBounds.y = cursorPoint.y;
// find the *visible* width of the field (it is longer than the text)
Field field = layout.getField(numFields - 1);
int charCount = field.getNumCols(numFields - 1);
int x = field.getX(0, charCount);
fieldBounds.width = x - fieldBounds.x;
// offset a bit from the end, so the line doesn't touch the text
int padding = 10;
Point start = new Point(fieldBounds.x + fieldBounds.width + padding,
fieldBounds.y + (fieldBounds.height / 2));
FieldPanel fieldPanel = listingPanel.getFieldPanel();
start = SwingUtilities.convertPoint(fieldPanel, start, window);
return start;
}
// private void bob() {
//
// CodeViewerProvider provider = getProvider(CodeViewerProvider.class);
// Window window = SwingUtilities.windowForComponent(provider.getComponent());
// final JDialog dialog = new JDialog(window);
// dialog.setModal(true);
//
// JPanel panel = new JPanel(new BorderLayout());
// JButton button = new JButton("Repaint");
// button.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// new Thread() {
// @Override
// public void run() {
// Thread.currentThread().setName(
// "Show Image[" + System.identityHashCode(this) + "]");
//
// doIt();
// showImage("ShowInstructionInfoPlugin", "RawInstructionDisplay.png");
// }
// }.start();
// }
// });
//
// JButton closeButton = new JButton("Close");
// closeButton.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// dialog.setVisible(false);
// }
// });
//
// panel.add(button);
// panel.add(closeButton, BorderLayout.SOUTH);
// dialog.getContentPane().add(panel);
//
// dialog.setSize(300, 200);
// dialog.setLocation(1300, 100);
// dialog.setVisible(true);
// }
}

View file

@ -0,0 +1,113 @@
/* ###
* 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 help.screenshot;
import java.awt.Rectangle;
import java.awt.Window;
import javax.swing.JTable;
import javax.swing.table.TableModel;
import org.junit.Test;
import ghidra.app.plugin.core.stackeditor.StackEditorProvider;
import ghidra.app.util.viewer.field.FunctionSignatureFieldFactory;
import ghidra.util.exception.AssertException;
public class StackEditorScreenShots extends GhidraScreenShotGenerator {
public StackEditorScreenShots() {
super();
}
@Test
public void testStackEditor() throws Exception {
goToListing(0x40699c);
positionCursor(0x40699c, FunctionSignatureFieldFactory.FIELD_NAME);
performAction("Edit Stack Frame", "StackEditorManagerPlugin", false);
waitForSwing();
StackEditorProvider provider = (StackEditorProvider) getProvider("Stack Editor");
final JTable table = provider.getTable();
waitForSwing();
moveProviderToItsOwnWindow(provider);
Window window = windowForComponent(table);
setWindowSize(window, 650, 350);
selectTableRow(table, "param_3");
waitForSwing();
captureProvider(provider);
}
@Test
public void testNumElementsPrompt() {
goToListing(0x40699c);
positionCursor(0x40699c, FunctionSignatureFieldFactory.FIELD_NAME);
performAction("Edit Stack Frame", "StackEditorManagerPlugin", false);
waitForSwing();
StackEditorProvider stackEditor = (StackEditorProvider) getProvider("Stack Editor");
final JTable table = stackEditor.getTable();
waitForSwing();
selectTableRow(table, "param_3");
waitForSwing();
performAction("Editor: Create Array", "StackEditorManagerPlugin", stackEditor, false);
waitForSwing();
captureDialog();
}
private void selectTableRow(final JTable table, final String text) {
final TableModel model = table.getModel();
runSwing(() -> {
int columnCount = model.getColumnCount();
int columnIndex = -1;
int rowIndex = -1;
for (int i1 = 0; i1 < columnCount; i1++) {
if (model.getColumnName(i1).equals("Name")) {
columnIndex = i1;
break;
}
}
if (columnIndex != -1) {
int rowCount = model.getRowCount();
for (int i2 = 0; i2 < rowCount; i2++) {
if (model.getValueAt(i2, columnIndex).equals(text)) {
rowIndex = i2;
break;
}
}
}
if (rowIndex == -1) {
throw new AssertException();
}
table.setRowSelectionInterval(rowIndex, rowIndex);
Rectangle rect = table.getCellRect(rowIndex, columnIndex, true);
table.scrollRectToVisible(rect);
});
}
}

View file

@ -0,0 +1,187 @@
/* ###
* 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 help.screenshot;
import java.awt.Window;
import javax.swing.JCheckBox;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.junit.Test;
import docking.ComponentProvider;
import docking.WindowPosition;
import docking.action.ToggleDockingAction;
import docking.widgets.table.GTable;
import docking.widgets.table.threaded.ThreadedTableModel;
import ghidra.app.plugin.core.symtable.FilterDialog;
import ghidra.app.plugin.core.symtable.SymbolTablePlugin;
public class SymbolTablePluginScreenShots extends GhidraScreenShotGenerator {
public SymbolTablePluginScreenShots() {
super();
}
@Test
public void testCaptureRefs_To() {
ComponentProvider symbolProvider = getProvider("Symbol Table");
tool.showComponentProvider(symbolProvider, true);
moveProviderToItsOwnWindow(symbolProvider, 940, 642);
ComponentProvider referencesProvider = showAndArrangeReferencesProvider(symbolProvider);
setReferenceType(referencesProvider, "References To");
GTable table = getTable(symbolProvider);
setColumnSizes(table);
selectRow(table, "WideCharToMultiByte");
triggerText(table, "\n"); // hack to kick the references table
Window window = windowForComponent(symbolProvider.getComponent());
captureWindow(window);
}
@Test
public void testCaptureInstr_From() {
ComponentProvider symbolProvider = getProvider("Symbol Table");
tool.showComponentProvider(symbolProvider, true);
moveProviderToItsOwnWindow(symbolProvider, 940, 642);
ComponentProvider referencesProvider = showAndArrangeReferencesProvider(symbolProvider);
setReferenceType(referencesProvider, "Instruction References From");
GTable table = getTable(symbolProvider);
setColumnSizes(table);
selectRow(table, "_malloc00403762");
triggerText(table, "\n"); // hack to kick the references table
Window window = windowForComponent(symbolProvider.getComponent());
captureWindow(window);
}
@Test
public void testCaptureData_From() {
ComponentProvider symbolProvider = getProvider("Symbol Table");
tool.showComponentProvider(symbolProvider, true);
moveProviderToItsOwnWindow(symbolProvider, 940, 642);
ComponentProvider referencesProvider = showAndArrangeReferencesProvider(symbolProvider);
setReferenceType(referencesProvider, "Data References From");
GTable table = getTable(symbolProvider);
setColumnSizes(table);
selectRow(table, "FUN_004010e0");
triggerText(table, "\n"); // hack to kick the references table
Window window = windowForComponent(symbolProvider.getComponent());
captureWindow(window);
}
@Test
public void testCaptureSymbol_Table() {
ComponentProvider provider = getProvider("Symbol Table");
tool.showComponentProvider(provider, true);
moveProviderToItsOwnWindow(provider, 950, 750);
GTable table = getTable(provider);
setColumnSizes(table);
// Pick a good section of the table:
// entry 00401e7c Function Label undefined Global IMPORTED 1 0
selectRow(table, "entry00401e46");
captureProvider(provider);
}
@Test
public void testCaptureFilter() {
ComponentProvider provider = getProvider("Symbol Table");
tool.showComponentProvider(provider, true);
performAction("Set Filter", "SymbolTablePlugin", false);
captureDialog(FilterDialog.class);
}
@Test
public void testCaptureFilter2() {
ComponentProvider provider = getProvider("Symbol Table");
tool.showComponentProvider(provider, true);
performAction("Set Filter", "SymbolTablePlugin", false);
FilterDialog dialog =
waitForDialogComponent(null, FilterDialog.class, DEFAULT_WINDOW_TIMEOUT);
final JCheckBox advancedCheckBox =
(JCheckBox) getInstanceField("advancedFilterCheckbox", dialog);
runSwing(() -> advancedCheckBox.doClick());
captureDialog(dialog);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private ComponentProvider showAndArrangeReferencesProvider(ComponentProvider symbolProvider) {
ComponentProvider referencesProvider = getProvider("Symbol References");
tool.showComponentProvider(referencesProvider, true);
moveProvider(referencesProvider, symbolProvider, WindowPosition.BOTTOM);
return referencesProvider;
}
private void setReferenceType(ComponentProvider referencesProvider, String referenceType) {
SymbolTablePlugin plugin = env.getPlugin(SymbolTablePlugin.class);
ToggleDockingAction action = (ToggleDockingAction) getAction(plugin, referenceType);
performAction(action, referencesProvider, true);
Object refProvider = getInstanceField("refProvider", plugin);
ThreadedTableModel<?, ?> model =
(ThreadedTableModel<?, ?>) getInstanceField("referenceKeyModel", refProvider);
waitForTableModel(model);
}
private GTable getTable(ComponentProvider provider) {
Object symbolPanel = getInstanceField("symbolPanel", provider);
return (GTable) getInstanceField("symTable", symbolPanel);
}
private void setColumnSizes(final GTable table) {
// note: these values are rough values found my trial-and-error
runSwing(() -> {
TableColumnModel columnModel = table.getColumnModel();
int columnCount = columnModel.getColumnCount();
for (int i = 0; i < columnCount; i++) {
TableColumn column = columnModel.getColumn(i);
Object headerValue = column.getHeaderValue();
if ("Name".equals(headerValue)) {
column.setPreferredWidth(175);
}
else if ("Reference Count".equals(headerValue)) {
column.setPreferredWidth(15);
}
else if ("Offcut Ref Count".equals(headerValue)) {
column.setPreferredWidth(15);
}
}
});
}
}

View file

@ -0,0 +1,96 @@
/* ###
* 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 help.screenshot;
import javax.swing.JTextField;
import org.junit.Test;
import docking.widgets.tree.GTree;
import ghidra.app.plugin.core.symboltree.EditExternalLocationDialog;
import ghidra.app.plugin.core.symboltree.SymbolTreeProvider;
import ghidra.app.util.AddressInput;
import ghidra.program.model.listing.GhidraClass;
import ghidra.program.model.listing.Library;
import ghidra.program.model.symbol.*;
public class SymbolTreePluginScreenShots extends GhidraScreenShotGenerator {
public SymbolTreePluginScreenShots() {
super();
}
@Test
public void testSymbolTree() {
showProvider(SymbolTreeProvider.class);
SymbolTreeProvider provider = getProvider(SymbolTreeProvider.class);
GTree tree = (GTree) getInstanceField("tree", provider);
expandPath(tree, "Global", "Exports");
expandTree(tree, "Global", "Labels");
captureIsolatedProvider(provider, 400, 600);
}
@Test
public void testCreateExternalLocation() {
final EditExternalLocationDialog dialog =
new EditExternalLocationDialog(program, "TestLibrary");
dialog.setTitle("Create External Location");
showDialogWithoutBlocking(tool, dialog);
Object panel = getInstanceField("extLocPanel", dialog);
JTextField textField = (JTextField) getInstanceField("extLibPathTextField", panel);
setText(textField, "/Test/libraryA");
JTextField extLabelTextField = (JTextField) getInstanceField("extLabelTextField", panel);
extLabelTextField.setText("Sample");
AddressInput extAddressInputWidget =
(AddressInput) getInstanceField("extAddressInputWidget", panel);
extAddressInputWidget.setAddress(addr(0x010012345));
captureDialog();
}
@Test
public void testEditExternalLocation() throws Exception {
ExternalLocation extLoc;
int txId = program.startTransaction("Test");
try {
ExternalManager extMgr = program.getExternalManager();
Library lib = extMgr.addExternalLibraryName("TestLibrary", SourceType.IMPORTED);
extLoc = extMgr.addExtFunction("TestLibrary", "??1type_info@@UEAA@XZ",
addr(0x010012345), SourceType.IMPORTED);
GhidraClass typeInfoClass =
program.getSymbolTable().createClass(lib, "type_info", SourceType.ANALYSIS);
extLoc.setName(typeInfoClass, "~type_info", SourceType.ANALYSIS);
}
finally {
program.endTransaction(txId, true);
}
final EditExternalLocationDialog dialog = new EditExternalLocationDialog(extLoc);
dialog.setTitle("Edit External Location");
showDialogWithoutBlocking(tool, dialog);
Object panel = getInstanceField("extLocPanel", dialog);
JTextField textField = (JTextField) getInstanceField("extLibPathTextField", panel);
setText(textField, "/Test/libraryA");
captureDialog();
}
}

View file

@ -0,0 +1,96 @@
/* ###
* 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 help.screenshot;
import javax.swing.table.TableColumnModel;
import org.junit.Test;
import docking.ComponentProvider;
import docking.widgets.table.*;
import docking.widgets.table.ColumnSortState.SortDirection;
import docking.widgets.table.threaded.GThreadedTablePanel;
import docking.widgets.table.threaded.ThreadedTableModel;
import ghidra.app.plugin.core.functionwindow.FunctionWindowProvider;
import ghidra.app.plugin.core.table.TableComponentProvider;
import ghidra.program.model.address.Address;
public class TablesScreenShots extends GhidraScreenShotGenerator {
public TablesScreenShots() {
super();
}
@Test
public void testBytesSettingsDialog() throws Exception {
performMemorySearch("55");
waitForTasks();
@SuppressWarnings("unchecked")
TableComponentProvider<Address> provider = getProvider(TableComponentProvider.class);
GThreadedTablePanel<Address> threadedTablePanel = provider.getThreadedTablePanel();
GTable table = threadedTablePanel.getTable();
showTableColumn(table, "Bytes");
showColumnSettings(table, "Bytes");
captureDialog();
}
@Test
public void testMultipleColumnSortDialog() {
showProvider(FunctionWindowProvider.class);
ComponentProvider provider = getProvider(FunctionWindowProvider.class);
ThreadedTableModel<?, ?> model =
(ThreadedTableModel<?, ?>) getInstanceField("functionModel", provider);
TableSortStateEditor editor = new TableSortStateEditor();
editor.addSortedColumn(0, SortDirection.ASCENDING);
editor.addSortedColumn(1, SortDirection.ASCENDING);
editor.addSortedColumn(2, SortDirection.ASCENDING);
setSort(model, editor.createTableSortState());
captureIsolatedProvider(FunctionWindowProvider.class, 600, 300);
}
@Test
public void testSelectColumnsDialog() {
showProvider(FunctionWindowProvider.class);
ComponentProvider provider = getProvider(FunctionWindowProvider.class);
GTable table = (GTable) getInstanceField("functionTable", provider);
showColumnAddRemove(table);
captureDialog();
}
private void setSort(final ThreadedTableModel<?, ?> model, final TableSortState sortState) {
runSwing(new Runnable() {
@Override
public void run() {
model.setTableSortState(sortState);
}
});
}
private void showColumnAddRemove(final GTable table) {
runSwing(new Runnable() {
@Override
public void run() {
TableColumnModel model = table.getColumnModel();
SelectColumnsDialog dialog =
new SelectColumnsDialog((GTableColumnModel) model, table.getModel());
tool.showDialog(dialog);
}
}, false);
waitForSwing();
}
}

View file

@ -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 help.screenshot;
import java.awt.Dimension;
import docking.wizard.*;
class TestDummyPanelManager implements PanelManager {
private WizardPanel panel;
private boolean canFinish;
private boolean hasNextPanel;
private boolean hasPreviousPanel;
private Dimension dimension;
private WizardManager wizard;
TestDummyPanelManager(WizardPanel panel, boolean canFinish, boolean hasNextPanel,
boolean hasPreviousPanel, int width, int height) {
this.panel = panel;
this.canFinish = canFinish;
this.hasNextPanel = hasNextPanel;
this.hasPreviousPanel = hasPreviousPanel;
this.dimension = new Dimension(width, height);
}
public void setPanel(WizardPanel panel) {
this.panel = panel;
}
@Override
public boolean canFinish() {
return canFinish;
}
@Override
public boolean hasNextPanel() {
return hasNextPanel;
}
@Override
public boolean hasPreviousPanel() {
return hasPreviousPanel;
}
@Override
public WizardPanel getNextPanel() {
return panel;
}
@Override
public WizardPanel getInitialPanel() {
return panel;
}
@Override
public WizardPanel getPreviousPanel() {
return panel;
}
@Override
public String getStatusMessage() {
return null;
}
@Override
public void finish() {
// stub
}
@Override
public void cancel() {
// stub
}
@Override
public void initialize() {
// stub
}
@Override
public Dimension getPanelSize() {
return dimension;
}
@Override
public void setWizardManager(WizardManager wm) {
this.wizard = wm;
}
@Override
public WizardManager getWizardManager() {
return wizard;
}
}

View file

@ -0,0 +1,165 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Each line is sized based on the font height and line padding on the top and bottom of the line.
* The y coordinate tracks the top of the line, so a lines baseline (position to draw the text)
* is y + line padding + font accent.
*/
public class TextFormatter {
private static final Pattern PATTERN = Pattern.compile("\\|(.+?)\\|");
private BufferedImage image;
private Font font;
private FontMetrics metrics;
private int lineHeight;
private int x;
private int y;
private int leftMargin;
private int baselineOffset;
private TextFormatterContext defaultContext = new TextFormatterContext(Color.BLACK);
private int width;
private int linePadding;
private int topMargin;
public TextFormatter(int lineCount, int width, int topMargin, int leftMargin, int linePadding) {
this(null, lineCount, width, topMargin, leftMargin, linePadding);
}
public TextFormatter(Font f, int lineCount, int width, int topMargin, int leftMargin,
int linePadding) {
this.width = width;
this.topMargin = topMargin;
this.leftMargin = leftMargin;
this.linePadding = linePadding;
initializeSizes(f);
createEmptyImage(lineCount);
x = leftMargin;
y = topMargin;
}
private void createEmptyImage(int lineCount) {
int height = lineCount * (lineHeight) + topMargin * 2;
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
g.dispose();
}
private void initializeSizes(Font f) {
// dummy image to get font sizes.
image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
if (f == null) {
f = new Font("Monospaced", Font.PLAIN, 14);
}
font = f;
metrics = g.getFontMetrics(font);
lineHeight = metrics.getHeight() + 2 * linePadding;
baselineOffset = metrics.getAscent() + linePadding;
g.dispose();
}
public void write(String text, TextFormatterContext... context) {
int contextIndex = 0;
int last = 0;
Matcher matcher = PATTERN.matcher(text);
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
print(text, last, start, defaultContext);
print(text, start + 1, end - 1, context[contextIndex++]);
last = end;
}
print(text, last, text.length(), defaultContext);
}
public void writeln(String text, TextFormatterContext... context) {
write(text, context);
newLine();
}
private void print(String text, int start, int end, TextFormatterContext context) {
if (start >= text.length()) {
return;
}
if (start == end) {
return; // empty text
}
String s = text.substring(start, end);
out(s, context.fg, context.bg, context.cursor);
}
private TextFormatter out(String text, Color fg, Color bg, Color cursor) {
Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setFont(font);
metrics = g.getFontMetrics(font);
int stringWidth = metrics.stringWidth(text);
if (bg != null) {
g.setColor(bg);
g.fillRect(x, y + linePadding, stringWidth, lineHeight - 2 * linePadding);
}
g.setColor(fg);
g.drawString(text, x, y + baselineOffset);
if (cursor != null) {
g.setColor(cursor);
g.setStroke(new BasicStroke(2f));
g.drawLine(x, y + linePadding, x, y + baselineOffset);
}
g.dispose();
x += stringWidth;
return this;
}
public void colorLines(Color c, int line, int nLines) {
Graphics2D g = image.createGraphics();
g.setColor(c);
int yPos = topMargin + line * lineHeight;
int h = nLines * lineHeight;
g.fillRect(0, yPos, width, h);
g.dispose();
}
public TextFormatter newLine() {
x = leftMargin;
y += lineHeight;
return this;
}
public Image getImage() {
return image;
}
}

View file

@ -0,0 +1,40 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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 help.screenshot;
import java.awt.Color;
public class TextFormatterContext {
public Color fg;
public Color bg;
public Color cursor;
public TextFormatterContext(Color fg) {
this(fg, null, null);
}
public TextFormatterContext(Color fg, Color bg) {
this(fg, bg, null);
}
public TextFormatterContext(Color fg, Color bg, Color cursor) {
this.fg = fg;
this.bg = bg;
this.cursor = cursor;
}
}

View file

@ -0,0 +1,327 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import org.junit.Before;
import org.junit.Test;
import docking.*;
import docking.action.DockingActionIf;
import docking.action.KeyEntryDialog;
import docking.widgets.OptionDialog;
import docking.widgets.table.GTable;
import generic.jar.ResourceFile;
import ghidra.framework.Application;
import ghidra.framework.LoggingInitialization;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.main.PickToolDialog;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.dialog.PluginInstallerDialog;
import ghidra.framework.plugintool.util.OptionsService;
import ghidra.test.TestEnv;
import ghidra.util.task.TaskDialog;
import ghidra.util.task.TaskMonitor;
import utilities.util.FileUtilities;
public class ToolScreenShots extends GhidraScreenShotGenerator {
@Override
@Before
public void setUp() throws Exception {
env = new TestEnv();
tool = env.showFrontEndTool();
}
@Test
public void testConfigTool() {
tool = env.launchDefaultTool();
performAction("Configure Tool", "Tool", false);
captureDialog(600, 500);
}
@Test
public void testConfigurePlugins() {
tool = env.launchDefaultTool();
performAction("Configure Tool", "Tool", false);
performDialogAction("Configure All Plugins", false);
PluginInstallerDialog installerProvider =
(PluginInstallerDialog) getDialog(PluginInstallerDialog.class);
JTable table = findComponent(installerProvider, JTable.class);
selectRow(table, 0);
captureDialog(PluginInstallerDialog.class, 800, 600);
}
@Test
public void testSaveTool() {
tool = env.launchDefaultTool();
performAction("Save Tool As", "Tool", false);
captureDialog();
}
@Test
public void testImportDefaultToolsDialog() {
performFrontEndAction("Import Ghidra Tools", "FrontEndPlugin", false);
captureDialog("Import Ghidra Tools");
}
@Test
public void testSetToolAssociations() {
performFrontEndAction("Set Tool Associations", "FrontEndPlugin", false);
captureDialog("Set Tool Associations");
}
@Test
public void testPickTool() {
performFrontEndAction("Set Tool Associations", "FrontEndPlugin", false);
DialogComponentProvider dialogProvider =
waitForDialogComponent(DialogComponentProvider.class);
GTable table = (GTable) getInstanceField("table", dialogProvider);
selectRow(table, 0);
pressButtonByText(dialogProvider, "Edit", false);
captureDialog(PickToolDialog.class);
}
@Test
public void testSaveChangesDialog() {
runSwing(() -> OptionDialog.showOptionDialog(tool.getToolFrame(), "Save Program?",
"WinHelloCPP.exe" + " has changed. Do you want to save it?", "&Save", "Do&n't Save",
OptionDialog.QUESTION_MESSAGE), false);
captureDialog();
}
@Test
public void testProgress() throws Exception {
tool = env.launchDefaultTool();
loadProgram();
int topBottomMargin = 60;
int leftRightMargin = 50;
goToListing(0x401008);
int id = program.startTransaction("Test");
StatusBar statusBar = findComponent(tool.getToolFrame(), StatusBar.class);
setWindowSize(tool.getToolFrame(), 1100, 500);
tool.executeBackgroundCommand(new DummyBackgroundCommand(), program);
Border inner = BorderFactory.createRaisedBevelBorder();
Border outer = BorderFactory.createLineBorder(Color.BLACK);
statusBar.setBorder(BorderFactory.createCompoundBorder(outer, inner));
captureComponent(statusBar);
program.endTransaction(id, false);
padImage(Color.WHITE, topBottomMargin, leftRightMargin, leftRightMargin, topBottomMargin);
JComponent statusLabel = (JComponent) getInstanceField("statusLabel", statusBar);
Font font = new Font("Ariel", Font.PLAIN, 12);
FontMetrics metrics = statusLabel.getFontMetrics(font);
Rectangle rect = statusLabel.getBounds();
int statusAreaWidth = rect.width + 10; // not sure why, but had to add a 10 fudge factor
labelTop(statusLabel.getName(), rect, font, metrics, topBottomMargin, leftRightMargin, 10);
int height = image.getHeight(null);
boolean top = false;
JComponent statusArea = (JComponent) getInstanceField("statusAreaPanel", statusBar);
for (Component component : statusArea.getComponents()) {
String name = component.getName();
Rectangle bounds = component.getBounds();
if (name == null) {
continue;
}
if (top) {
labelTop(name, bounds, font, metrics, topBottomMargin,
leftRightMargin + statusAreaWidth, 10);
}
else {
labelBottom(name, bounds, font, metrics, topBottomMargin,
leftRightMargin + statusAreaWidth, 10, height);
}
top = !top;
}
Rectangle b = statusBar.getBounds();
int cancelDistanceFromEnd = 60;
int space = b.width - cancelDistanceFromEnd;
b.x = b.x + space;
b.width = cancelDistanceFromEnd;
labelTop("Cancel Button", b, font, metrics, topBottomMargin, leftRightMargin, 10);
}
private void labelBottom(String label, Rectangle bounds, Font font, FontMetrics metrics,
int topMargin, int leftMargin, int textBottomMargin, int height) {
int textX = getTextStart(bounds, metrics, label) + leftMargin;
int textY = height - textBottomMargin;
int arrowX = bounds.x + bounds.width / 2 + leftMargin;
int arrowStartY = textY - metrics.getHeight() - 5;
int arrowEndY = height - topMargin;
drawText(label, Color.BLACK, new Point(textX, textY), font);
drawArrow(Color.BLACK, 1, new Point(arrowX, arrowStartY), new Point(arrowX, arrowEndY), 9);
}
private void labelTop(String label, Rectangle bounds, Font font, FontMetrics metrics,
int topMargin, int leftMargin, int textTopMargin) {
int textX = getTextStart(bounds, metrics, label) + leftMargin;
int textY = textTopMargin + metrics.getHeight();
int arrowX = bounds.x + bounds.width / 2 + leftMargin;
int arrowStartY = textY + 5;
int arrowEndY = topMargin;
drawText(label, Color.BLACK, new Point(textX, textY), font);
drawArrow(Color.BLACK, 1, new Point(arrowX, arrowStartY), new Point(arrowX, arrowEndY), 9);
}
private int getTextStart(Rectangle bounds, FontMetrics metrics, String string) {
int stringWidth = metrics.stringWidth(string);
return bounds.x + (bounds.width - stringWidth) / 2;
}
@Test
public void testModalTaskDialog() {
waitForSwing();
TaskDialog taskDialog = new TaskDialog("Clear with Options", true, false, true);
taskDialog.initialize(100);
taskDialog.setProgress(20);
taskDialog.setMessage("Clearing code at 0040785f");
tool.showDialog(taskDialog);
waitForSwing();
captureDialog(300, 140);
}
@Test
public void testShowLog() throws Exception {
tool = env.launchDefaultTool();
loadProgram();
File file = LoggingInitialization.getApplicationLogFile();
List<String> lines = FileUtilities.getLines(file);
List<String> lines2 = new ArrayList<>(lines.size());
// remove any users names
for (String string : lines) {
if (!string.contains("User")) {
lines2.add(string);
}
}
FileUtilities.writeLinesToFile(file, lines2);
performFrontEndAction("Show Log", "Tool", false);
captureDialog("Ghidra User Log");
}
@Test
public void testTip() {
performFrontEndAction("Tips of the day", "TipOfTheDayPlugin", false);
captureDialog("Tip of the Day");
}
@Test
public void testRestoreDefaults() {
tool = env.launchDefaultTool();
runSwing(() -> {
OptionsService service = tool.getService(OptionsService.class);
service.showOptionsDialog("Entropy", "");
}, false);
DialogComponentProvider dialog = getDialog();
Window window = windowForComponent(dialog.getComponent());
setWindowSize(window, 700, 350);
waitForSwing();
captureDialog();
JButton button = findButtonByText(window, "Restore Defaults");
drawRectangleWithDropShadowAround(button, Color.GREEN, 2);
crop(new Rectangle(0, 200, 700, 150));
}
@Test
public void testKeyBindings() {
tool = env.launchDefaultTool();
runSwing(() -> {
OptionsService service = tool.getService(OptionsService.class);
service.showOptionsDialog("Key Bindings", "");
}, false);
DialogComponentProvider dialog = getDialog();
Window window = windowForComponent(dialog.getComponent());
setWindowSize(window, 900, 600);
captureDialog();
}
@Test
public void testSetKeyBindings() {
tool = env.launchDefaultTool();
DockingWindowManager windowManager = tool.getWindowManager();
DockingActionManager actionMgr =
(DockingActionManager) getInstanceField("actionManager", windowManager);
String fullActionName = "Delete Function" + " (" + "FunctionPlugin" + ")";
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
final KeyEntryDialog keyEntryDialog = new KeyEntryDialog(actions.get(0), actionMgr);
runSwing(() -> tool.showDialog(keyEntryDialog), false);
captureDialog();
}
// Overridden because the ErrorReporting module has the same "Tool" help topic as Base
// make sure we get the right one.
@Override
protected List<File> getHelpTopicDirs() {
List<File> helpTopicDirs = new ArrayList<>();
Collection<ResourceFile> modules = Application.getModuleRootDirectories();
for (ResourceFile file : modules) {
if (file.getName().equals("Base")) {
helpTopicDirs.add(new File(file.getFile(false), "src/main/help/help/topics"));
break;
}
}
return helpTopicDirs;
}
private class DummyBackgroundCommand extends BackgroundCommand {
public DummyBackgroundCommand() {
super("Dummy", true, true, false);
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
monitor.initialize(1200);
monitor.setProgress(350);
monitor.setMessage("Scalar Operand Reference");
invokeInstanceMethod("update", monitor);
sleep(5000);
return true;
}
}
}

View file

@ -0,0 +1,243 @@
/* ###
* 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 help.screenshot;
import java.awt.*;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.table.JTableHeader;
import org.junit.Test;
import docking.DockableComponent;
import docking.menu.MultiStateDockingAction;
import docking.util.AnimationUtils;
import docking.util.image.Callout;
import docking.util.image.CalloutComponentInfo;
import docking.widgets.EmptyBorderButton;
import docking.widgets.filter.*;
import docking.widgets.table.columnfilter.ColumnBasedTableFilter;
import docking.widgets.table.columnfilter.LogicOperation;
import docking.widgets.table.constraint.*;
import docking.widgets.table.constraint.provider.EditorProvider;
import docking.widgets.table.constrainteditor.ColumnConstraintEditor;
import docking.widgets.table.constrainteditor.IntegerConstraintEditor;
import docking.widgets.table.threaded.ThreadedTableModel;
import docking.widgets.tree.*;
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
import ghidra.app.plugin.core.functionwindow.FunctionWindowProvider;
import ghidra.program.model.listing.Function;
import ghidra.util.table.GhidraTableFilterPanel;
public class TreesScreenShots extends GhidraScreenShotGenerator {
@Override
public void setUp() throws Exception {
super.setUp();
AnimationUtils.setAnimationEnabled(false);
closeNonProgramArchives();
}
@Test
public void testFilter() {
setTreeFilterText("byte");
captureIsolatedProvider(DataTypesProvider.class, 375, 350);
}
@Test
public void testFilterClearButton() {
setTreeFilterText("byte");
captureIsolatedProvider(DataTypesProvider.class, 375, 350);
calloutFilterIcon();
cropAndKeepFilter();
}
private void calloutFilterIcon() {
DataTypesProvider provider = getProvider(DataTypesProvider.class);
DataTypeArchiveGTree gTree = provider.getGTree();
GTreeFilterProvider filterProvider = gTree.getFilterProvider();
FilterTextField field = (FilterTextField) getInstanceField("filterField", filterProvider);
JLabel label = (JLabel) getInstanceField("clearLabel", field);
/*
The callout needs to know where to paint the callout. We want it over the
component we provide. But, we need to be able to translate that component's
location to a value that is relative to the image (we created the image above by
capturing the provider using it's DockableComponent).
*/
DockableComponent dc = getDockableComponent(provider);
CalloutComponentInfo calloutInfo = new CalloutComponentInfo(dc, label);
calloutInfo.setMagnification(2.75D); // make it a bit bigger than default
Callout callout = new Callout();
image = callout.createCalloutOnImage(image, calloutInfo);
}
private void cropAndKeepFilter() {
// keep the filter and callout in the image (trial and error)
Rectangle area = new Rectangle();
int height = 275;
area.x = 0;
area.y = 80;
area.width = 560;
area.height = height - area.y;
crop(area);
}
@Test
public void testTableColumnFilter() {
showProvider(FunctionWindowProvider.class);
captureIsolatedProvider(FunctionWindowProvider.class, 600, 300);
}
@Test
public void testTableColumnFilterDialog() {
showProvider(FunctionWindowProvider.class);
FunctionWindowProvider provider = getProvider(FunctionWindowProvider.class);
@SuppressWarnings({ "unchecked" })
GhidraTableFilterPanel<Function> panel =
(GhidraTableFilterPanel<Function>) getInstanceField("tableFilterPanel", provider);
ColumnBasedTableFilter<Function> filter =
new ColumnBasedTableFilter<>(panel.getTableFilterModel());
filter.addConstraintSet(LogicOperation.AND, 0,
Arrays.asList(new StringStartsWithColumnConstraint("FUN_00"),
new StringContainsColumnConstraint("401")));
filter.addConstraintSet(LogicOperation.AND, 3,
Arrays.asList(new AtLeastColumnConstraint<>(80, new IntEditorProvider())));
panel.setColumnTableFilter(filter);
MultiStateDockingAction<?> action =
(MultiStateDockingAction<?>) getInstanceField("columnFilterAction", panel);
performAction(action, false);
captureDialog(1000, 400);
}
@Test
@SuppressWarnings({ "unchecked" })
public void testTableColumnFilterAfterFilterApplied() {
showProvider(FunctionWindowProvider.class);
FunctionWindowProvider provider = getProvider(FunctionWindowProvider.class);
GhidraTableFilterPanel<Function> panel =
(GhidraTableFilterPanel<Function>) getInstanceField("tableFilterPanel", provider);
ColumnBasedTableFilter<Function> filter =
new ColumnBasedTableFilter<>(panel.getTableFilterModel());
filter.addConstraintSet(LogicOperation.AND, 0,
Arrays.asList(new StringStartsWithColumnConstraint("FUN_00"),
new StringContainsColumnConstraint("401")));
filter.addConstraintSet(LogicOperation.AND, 3,
Arrays.asList(new AtLeastColumnConstraint<>(80, new IntEditorProvider())));
panel.setColumnTableFilter(filter);
JTable table = (JTable) invokeInstanceMethod("getTable", panel);
waitForTableModel((ThreadedTableModel<?, ?>) table.getModel());
captureIsolatedProvider(FunctionWindowProvider.class, 600, 300);
JTableHeader header = table.getTableHeader();
// we are filtered on 0 and 3
highlightFilterIcon(provider.getComponent(), table, header, 0);
highlightFilterIcon(provider.getComponent(), table, header, 3);
}
private void highlightFilterIcon(Component provider, Component parent, JTableHeader header,
int column) {
Rectangle rectangle = header.getHeaderRect(column);
rectangle = SwingUtilities.convertRectangle(parent, rectangle, provider);
int padding = 8;
int thickness = 6;
int iconSize = 12;
int height = rectangle.height + (padding * 2);
int width = iconSize + (padding * 2);
int iconPadding = 2;
int x = rectangle.x + rectangle.width - (width - padding) - iconPadding;
int y = rectangle.y - padding;
Rectangle shapeBounds = new Rectangle(x, y, width, height);
drawOval(Color.GREEN.darker(), shapeBounds, thickness);
}
@Test
public void testFilterOptions() {
DataTypesProvider dataTypeManagerProvider = getProvider(DataTypesProvider.class);
DataTypeArchiveGTree gTree = dataTypeManagerProvider.getGTree();
GTreeFilterProvider filterProvider = gTree.getFilterProvider();
((DefaultGTreeFilterProvider) filterProvider).setFilterOptions(
new FilterOptions(TextFilterStrategy.CONTAINS, true, false, false, true, ','));
EmptyBorderButton filterButton =
(EmptyBorderButton) getInstanceField("filterStateButton", filterProvider);
pressButton(filterButton, false);
captureDialog();
}
private void setTreeFilterText(final String text) {
final DataTypesProvider dataTypeManagerProvider = getProvider(DataTypesProvider.class);
runSwing(() -> dataTypeManagerProvider.setFilterText(text));
GTree tree = (GTree) getInstanceField("archiveGTree", dataTypeManagerProvider);
waitForTree(tree);
scrollTreeToTop(tree);
}
private void scrollTreeToTop(GTree tree) {
JScrollPane scrollPane = (JScrollPane) getInstanceField("scrollPane", tree);
runSwing(() -> scrollPane.getVerticalScrollBar().setValue(0));
}
static class IntEditorProvider implements EditorProvider<Integer> {
@Override
public ColumnConstraintEditor<Integer> getEditor(ColumnConstraint<Integer> columnConstraint,
ColumnData<Integer> columnDataSource) {
return new IntegerConstraintEditor<>(columnConstraint, v -> (int) v);
}
@Override
public Integer parseValue(String value, Object dataSource) {
return (int) Long.parseLong(value);
}
@Override
public String toString(Integer value) {
return value.toString();
}
}
}

View file

@ -0,0 +1,73 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import docking.DialogComponentProvider;
import docking.widgets.conditiontestpanel.ConditionTestModel;
import ghidra.app.plugin.core.validator.ValidateProgramPlugin;
public class ValidateProgramScreenShots extends GhidraScreenShotGenerator {
public ValidateProgramScreenShots() {
super();
}
@Test
public void testValidateProgram() {
loadPlugin(ValidateProgramPlugin.class);
performAction("Validate Program", "ValidateProgramPlugin", false);
waitForPostedSwingRunnables();
captureDialog();
}
@Test
public void testValidateProgramDone() {
loadPlugin(ValidateProgramPlugin.class);
performAction("Validate Program", "ValidateProgramPlugin", false);
waitForPostedSwingRunnables();
DialogComponentProvider dialog = getDialog();
pressButtonByText(dialog, "Run Validators");
Object conditionTestPanel = getInstanceField("conditionTestPanel", dialog);
ConditionTestModel model =
(ConditionTestModel) getInstanceField("conditionTestModel", conditionTestPanel);
waitForValidators(model);
captureDialog();
}
private void waitForValidators(ConditionTestModel model) {
int sleepyTime = 100;
int totalTime = 0;
while (model.isInProgress() && totalTime < 10000) {
sleep(sleepyTime);
totalTime += sleepyTime;
}
assertTrue("Timed out waiting for condition tests", totalTime < 10000);
}
}

View file

@ -0,0 +1,182 @@
/* ###
* 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 help.screenshot;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import docking.DialogComponentProvider;
import generic.test.TestUtils;
import ghidra.app.util.dialog.CheckoutDialog;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.main.datatree.*;
import ghidra.framework.main.projectdata.actions.*;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.remote.User;
import ghidra.framework.store.*;
import ghidra.test.FrontEndTestEnv;
import ghidra.util.InvalidNameException;
public class VersionControlScreenShots extends GhidraScreenShotGenerator {
@Override
public void loadProgram() {
// don't need to load a program
}
@Test
public void testAddToVersionControlDialog() {
VersionControlDialog dialog = new VersionControlDialog(true);
dialog.setCurrentFileName("WinHelloCpp.exe");
runSwing(() -> tool.showDialog(dialog), false);
captureDialog();
}
@Test
public void testCheckInFile() {
VersionControlDialog dialog = new VersionControlDialog(false);
dialog.setCurrentFileName(FrontEndTestEnv.PROGRAM_A);
dialog.setKeepCheckboxEnabled(true);
runSwing(() -> tool.showDialog(dialog), false);
VersionControlDialog d = waitForDialogComponent(VersionControlDialog.class);
captureDialog(d);
}
@Test
public void testUndoHijack() {
Plugin plugin = getFrontEndPlugin();
VersionControlUndoHijackAction action = new VersionControlUndoHijackAction(plugin);
DomainFile df = createDomainFile();
List<DomainFile> hijackList = List.of(df);
runSwing(() -> {
TestUtils.invokeInstanceMethod("undoHijack", action, List.class, hijackList);
}, false);
UndoActionDialog d = waitForDialogComponent(UndoActionDialog.class);
captureDialog(d);
}
@Test
public void testUndoCheckoutDialog() {
DomainFile df = createDomainFile();
List<DomainFile> modifiedList = List.of(df);
Plugin plugin = getFrontEndPlugin();
VersionControlUndoCheckOutAction action = new VersionControlUndoCheckOutAction(plugin);
runSwing(() -> {
Class<?>[] paramTypes = new Class<?>[] { List.class, List.class };
Object[] paramValues = new Object[] { Collections.emptyList(), modifiedList };
TestUtils.invokeInstanceMethod("undoCheckOuts", action, paramTypes, paramValues);
}, false);
UndoActionDialog d = waitForDialogComponent(UndoActionDialog.class);
captureDialog(d);
}
@Test
public void testCheckOutFile() {
User user = new User("User-1", 1);
DomainFile df = createDomainFile();
CheckoutDialog dialog = new CheckoutDialog(df, user);
runSwing(() -> dialog.showDialog(), false);
CheckoutDialog d = waitForDialogComponent(CheckoutDialog.class);
captureDialog(d);
}
@Test
public void testViewCheckouts() throws Exception {
User user = new User("User-1", 0);
DomainFile df = createDomainFile();
//@formatter:off
ItemCheckoutStatus[] checkouts = new ItemCheckoutStatus[] {
new ItemCheckoutStatus(1, CheckoutType.NORMAL, "User-1", 1, System.currentTimeMillis(),
"host1::/path1/TestRepo"),
new ItemCheckoutStatus(1, CheckoutType.EXCLUSIVE, "User-1", 1, System.currentTimeMillis(),
"host1::/path2/TestRepo"),
};
//@formatter:on
CheckoutsDialog dialog = new CheckoutsDialog(tool, user, df, checkouts);
tool.showDialog(dialog);
DialogComponentProvider d =
waitForDialogComponent("View Checkouts for " + FrontEndTestEnv.PROGRAM_A);
captureDialog(d);
}
@Test
public void testVersionHistory() throws Exception {
VersionHistoryDialog dialog = new VersionHistoryDialog();
DomainFile df = createDomainFile();
dialog.setDomainFile(df);
runSwing(() -> tool.showDialog(dialog));
VersionHistoryDialog d = waitForDialogComponent(dialog.getClass());
captureDialog(d);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private DomainFile createDomainFile() {
TestDummyDomainFolder root = new TestDummyDomainFolder(null, "Project");
DomainFile df = new TestDummyDomainFile(root, "Program_A") {
@Override
public DomainFile setName(String newName) throws InvalidNameException, IOException {
// stubbed to prevent exception from dummy
return this;
}
@Override
public Version[] getVersionHistory() throws IOException {
long time = System.currentTimeMillis();
String user = "User-1";
//@formatter:off
return new Version[] {
new Version(1, time - 200000, user, "Comment 1"),
new Version(2, time - 100000, user, "Comment 2"),
new Version(3, time, user, "Comment 3"),
};
//@formatter:on
}
};
return df;
}
private Plugin getFrontEndPlugin() {
FrontEndTool feTool = env.showFrontEndTool();
Plugin plugin = (Plugin) getInstanceField("plugin", feTool);
return plugin;
}
}

View file

@ -0,0 +1,152 @@
/* ###
* 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 help.screenshot;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import javax.swing.JFrame;
import org.junit.*;
import docking.ActionContext;
import docking.action.DockingActionIf;
import docking.widgets.tree.GTreeNode;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.main.datatree.FindCheckoutsDialog;
import ghidra.framework.model.DomainFolder;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.test.FrontEndTestEnv;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
/**
* This screen shot generator houses code that needs to connect to a running server
*/
public class VersionControlSlowScreenShots extends GhidraScreenShotGenerator {
private FrontEndTestEnv frontEnd;
@Override
@Before
public void setUp() throws Exception {
// super.setUp(); don't do this; use our tool instead
frontEnd = new FrontEndTestEnv(true);
}
@Override
@After
public void tearDown() throws Exception {
// super.tearDown(); don't do this; use our tool instead
frontEnd.dispose();
showResults();
}
@Override
public void loadProgram() {
// don't need to load a program
}
@Override
protected String getHelpTopicName() {
// this is needed, since our filename does not match the help topic
return "VersionControl";
}
@Test
public void testCheckedOut() throws Exception {
frontEnd.createMultipleCheckins();
Program p1 = frontEnd.buildProgram(this);
DomainFolder rootFolder = frontEnd.getRootFolder();
// Program A created by the FrontEndTestEnv
rootFolder.createFile("Program_B", p1, TaskMonitor.DUMMY);
FrontEndTool t = frontEnd.getFrontEndTool();
JFrame frame = t.getToolFrame();
captureWindow(frame, 400, 550);
}
@Test
public void testFindMyCheckouts() throws Exception {
frontEnd.createMultipleCheckins();
DomainFolder rootFolder = frontEnd.getRootFolder();
DomainFolder folder = rootFolder.createFolder("myFolder_1");
folder = folder.createFolder("myFolder_2");
Program p = frontEnd.buildProgram(this);
folder.createFile("My_Program", p, TaskMonitor.DUMMY);
p.release(this);
GTreeNode node = frontEnd.waitForFolderNode("myFolder_1");
assertNotNull(node);
node = node.getChild("myFolder_2");
assertNotNull(node);
node = node.getChild("My_Program");
assertNotNull(node);
frontEnd.addToVersionControl(node, true);
GTreeNode rootNode = frontEnd.getRootNode();
frontEnd.selectNodes(rootNode);
DockingActionIf action = frontEnd.getAction("Find Checkouts");
frontEnd.performFrontEndAction(action);
FindCheckoutsDialog dialog = waitForDialogComponent(FindCheckoutsDialog.class);
assertNotNull(dialog);
captureDialog(dialog);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private ActionContext createContext(GTreeNode... nodes) {
return frontEnd.getDomainFileActionContext(nodes);
}
protected void createHistoryEntry(Program p, String symbolName)
throws InvalidInputException, IOException, CancelledException {
int transactionID = p.startTransaction("test");
try {
SymbolTable symTable = p.getSymbolTable();
symTable.createLabel(p.getMinAddress().getNewAddress(0x010001000), symbolName,
SourceType.USER_DEFINED);
}
finally {
p.endTransaction(transactionID, true);
p.save(null, TaskMonitor.DUMMY);
}
}
protected void showHistory(final GTreeNode node) {
final DockingActionIf historyAction = frontEnd.getAction("Show History");
runSwing(() -> historyAction.actionPerformed(createContext(node)));
}
}

View file

@ -0,0 +1,103 @@
/* ###
* 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 help.screenshot;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import javax.swing.table.TableColumn;
import org.junit.Test;
import ghidra.app.plugin.core.strings.ViewStringsProvider;
import ghidra.app.services.ProgramManager;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Data;
import ghidra.test.ToyProgramBuilder;
public class ViewStringsPluginScreenShots extends GhidraScreenShotGenerator {
public ViewStringsPluginScreenShots() {
super();
}
@Override
public void loadProgram() throws Exception {
ToyProgramBuilder builder = new ToyProgramBuilder("String Examples", false);
builder.createMemory("RAM", "0x0", 0x2000);
builder.createString("0x100", "Hello World!\n", StandardCharsets.US_ASCII, true,
StringDataType.dataType);
Data nonStringBytes =
builder.createString("0x150", bytes(0, 1, 2, 3, 4, 0x80, 0x81, 0x82, 0x83),
StandardCharsets.US_ASCII, StringDataType.dataType);
Data CN_HOVERCRAFT =
builder.createString("0x200", "\u6211\u96bb\u6c23\u588a\u8239\u88dd\u6eff\u6652\u9c54",
StandardCharsets.UTF_16, true, UnicodeDataType.dataType);
builder.createString("0x250", "Exception %s\n\tline: %d\n", StandardCharsets.US_ASCII, true,
StringDataType.dataType);
builder.createString("0x450",
"Roses are \u001b[0;31mred\u001b[0m, violets are \u001b[0;34mblue. Hope you enjoy terminal hue",
StandardCharsets.US_ASCII, true, StringDataType.dataType);
Data tempDegrees = builder.createString("0x500", "Temp \u2103", Charset.forName("UTF-32LE"),
true, Unicode32DataType.dataType);
builder.withTransaction(() -> {
RenderUnicodeSettingsDefinition.RENDER.setEnumValue(nonStringBytes,
RenderUnicodeSettingsDefinition.RENDER_ENUM.BYTE_SEQ);
RenderUnicodeSettingsDefinition.RENDER.setEnumValue(tempDegrees,
RenderUnicodeSettingsDefinition.RENDER_ENUM.ESC_SEQ);
TranslationSettingsDefinition.TRANSLATION.setTranslatedValue(CN_HOVERCRAFT,
"My hovercraft is full of eels");
TranslationSettingsDefinition.TRANSLATION.setShowTranslated(CN_HOVERCRAFT, true);
});
program = builder.getProgram();
runSwing(() -> {
ProgramManager pm = tool.getService(ProgramManager.class);
pm.openProgram(program.getDomainFile());
});
}
private static byte[] bytes(int... intValues) {
byte[] result = new byte[intValues.length];
for (int i = 0; i < intValues.length; i++) {
result[i] = (byte) (intValues[i]);
}
return result;
}
@Test
public void testDefined_String_Table() {
ViewStringsProvider provider = showProvider(ViewStringsProvider.class);
TableColumn addrCol = provider.getTable().getColumnModel().getColumn(0);
addrCol.setMaxWidth(200);
TableColumn dataTypeCol = provider.getTable().getColumnModel().getColumn(3);
dataTypeCol.setMaxWidth(200);
captureIsolatedProvider(ViewStringsProvider.class, 600, 300);
}
}