mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-07 09:11:15 -09:00
GP-6993: Add help docs for DebuggerVariableViewerPlugin
This commit is contained in:
@@ -68,6 +68,9 @@ src/main/help/help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManager
|
||||
src/main/help/help/topics/DebuggerTraceViewDiffPlugin/DebuggerTraceViewDiffPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTimeSelectionDialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTraceViewDiffPlugin.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerVariableViewerPlugin/DebuggerVariableViewerPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerVariableViewerPlugin/images/DebuggerVariableViewerPlugin.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerVariableViewerPlugin/images/DebuggerVariableViewerPluginRightClick.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerWatchesPlugin/images/DebuggerWatchesPlugin.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DynamicStaticSynchronizationPlugin/DynamicStaticSynchronizationPlugin.html||GHIDRA||||END|
|
||||
|
||||
@@ -130,6 +130,10 @@
|
||||
<tocdef id="DebuggerPlatformPlugin" text="Platform Selection"
|
||||
sortgroup="y"
|
||||
target="help/topics/DebuggerPlatformPlugin/DebuggerPlatformPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerVariableViewerPlugin" text="Variable Viewer"
|
||||
sortgroup="za"
|
||||
target="help/topics/DebuggerVariableViewerPlugin/DebuggerVariableViewerPlugin.html" />
|
||||
</tocdef>
|
||||
</tocref>
|
||||
</tocroot>
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
|
||||
<TITLE>Debugger: Variable Viewer</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
<H1><A name="plugin"></A>Debugger: Variable Viewer</H1>
|
||||
|
||||
<DIV class="image">
|
||||
<IMG alt="" src="images/DebuggerVariableViewerPlugin.png">
|
||||
</DIV>
|
||||
|
||||
<P>The Variable Viewer displays a table of local variables for the function at the current
|
||||
program counter, evaluated against the current thread's machine state at the current snapshot.
|
||||
Variables are gathered from two sources: the <A href=
|
||||
"help/topics/CodeBrowserPlugin/CodeBrowser.htm">Static Listing</A> and the <A href=
|
||||
"help/topics/DecompilePlugin/DecompilerIntro.html">Decompiler</A>.</P>
|
||||
|
||||
<P>The variable viewer uses colors to hint about changes and freshness of displayed values. By
|
||||
default, changed values are displayed in red, and stale values are displayed in dark gray. A
|
||||
<EM>stale</EM> value is one whose backing register or memory location has not been recorded in
|
||||
the current snap.</P>
|
||||
|
||||
<H2>Table Columns</H2>
|
||||
|
||||
<P>The table displays and allows modification of each variable. It has the following
|
||||
columns:</P>
|
||||
|
||||
<UL>
|
||||
<LI><B>Source</B> (hidden by default) - indicates where the variable was discovered. The
|
||||
value is either the <A href="help/topics/CodeBrowserPlugin/CodeBrowser.htm">Static
|
||||
Listing</A> or the <A href="help/topics/DecompilePlugin/DecompilerIntro.html">Decompiler</A>.
|
||||
When both sources produce a variable with the same symbol name, only one entry is shown; the
|
||||
Listing entry takes precedence.</LI>
|
||||
|
||||
<LI><B>Storage</B> - the location where the variable's value is stored. For register-backed
|
||||
variables this shows the register name. For memory-backed variables this shows the address.
|
||||
If the storage location could not be determined, <CODE>??</CODE> is shown.</LI>
|
||||
|
||||
<LI><B>Symbol</B> - the name of the variable. This field is user-modifiable when <A href=
|
||||
"#enable_edits">Enable Edits</A> is on.</LI>
|
||||
|
||||
<LI><B>Value</B> - the raw bytes of the variable's current value. For scalar variables whose
|
||||
size does not exceed the pointer size, the value is shown as a hexadecimal integer. For
|
||||
larger variables the bytes are shown as a space-separated hex sequence enclosed in braces.
|
||||
Very large values are truncated with an ellipsis. This field is user-modifiable when <A href=
|
||||
"#enable_edits">Enable Edits</A> is on and the variable's storage is writable. Edits may be
|
||||
directed toward a live target, the trace, or the emulator, according to the <A href=
|
||||
"help/topics/DebuggerControlPlugin/DebuggerControlPlugin.html">Control and Machine State
|
||||
Plugin</A>.</LI>
|
||||
|
||||
<LI><B>Type</B> - the data type assigned to the variable. This field is user-modifiable when
|
||||
<A href="#enable_edits">Enable Edits</A> is on. The type is used to compute the <B>Repr</B>
|
||||
column.</LI>
|
||||
|
||||
<LI><B>Repr</B> - the value of the variable as interpreted by its assigned data type. This
|
||||
field is user-modifiable when the <B>Value</B> column is modifiable and the selected data
|
||||
type provides an encoder. Editing this field encodes the entered representation back to raw
|
||||
bytes and writes them to the variable's storage location.</LI>
|
||||
|
||||
<LI><B>Error</B> - if an error occurs while evaluating the variable (for example, because the
|
||||
storage location is not accessible at the current snapshot, or the stack frame could not be
|
||||
unwound), the error message is shown here.</LI>
|
||||
</UL>
|
||||
|
||||
<H2>Actions</H2>
|
||||
|
||||
<P>The variable viewer provides the following actions:</P>
|
||||
|
||||
<H3><A name="enable_edits"></A><IMG alt="" src="icon.debugger.enable.edits">Enable Edits</H3>
|
||||
|
||||
<P>This toggle enables writes to the machine state. To modify a variable's symbol, value, type,
|
||||
or representation, this toggle must be enabled. It is available only when there is an active
|
||||
trace. Edits are directed according to the <A href=
|
||||
"help/topics/DebuggerControlPlugin/DebuggerControlPlugin.html">Control and Machine State
|
||||
Plugin</A>.</P>
|
||||
|
||||
<H3><A name="show_variables"></A><IMG alt="" src="icon.configure.filter">Show/Hide
|
||||
Variables</H3>
|
||||
|
||||
<P>This action controls which source of variables is displayed in the table. The three choices
|
||||
are:</P>
|
||||
|
||||
<UL>
|
||||
<LI><IMG alt="" src="icon.configure.filter"><B>Show Variables From Both</B> - displays
|
||||
variables gathered from both the Listing and the Decompiler. When both sources produce a
|
||||
variable with the same symbol name, only one entry is retained.</LI>
|
||||
|
||||
<LI><IMG alt="" src="icon.plugin.codebrowser.provider"><B>Show Listing Variables Only</B> -
|
||||
displays only variables derived from the static listing.</LI>
|
||||
|
||||
<LI><IMG alt="" src="icon.decompiler.action.provider"><B>Show Decompiler Variables Only</B> -
|
||||
displays only variables recovered by the decompiler.</LI>
|
||||
</UL>
|
||||
|
||||
<H3><A name="popup_actions"></A>Right Click Actions</H3>
|
||||
|
||||
<DIV class="image">
|
||||
<IMG alt="" src="images/DebuggerVariableViewerPluginRightClick.png">
|
||||
</DIV>
|
||||
|
||||
<UL>
|
||||
<LI><B>View [variable] @ 0x... in...</B> - This action is available when a single variable is
|
||||
selected and its storage address is a non-register memory address. It navigates to that
|
||||
address in a chosen listing window.</LI>
|
||||
|
||||
<LI><B>Deref *[variable] @ 0x... in...</B> - This action is available when a single variable
|
||||
is selected and its current value can be interpreted as a valid memory address (i.e., the
|
||||
variable is a pointer). It navigates to the dereferenced address in a chosen listing
|
||||
window.</LI>
|
||||
</UL>
|
||||
|
||||
<H4>Sub Menu Options</H4>
|
||||
|
||||
<P>Both actions share the same sub options of which listing window to show the result in:</P>
|
||||
|
||||
<UL>
|
||||
<LI><B>Main Listing</B> - navigates the primary dynamic listing to the variable's storage
|
||||
address.</LI>
|
||||
|
||||
<LI><B>[Additional Listing Windows]</B> - navigates any other open dynamic listing windows to
|
||||
the variable's storage address.</LI>
|
||||
|
||||
<LI><B>New Listing</B> - opens a new dynamic listing window, sets it to follow the current
|
||||
thread, and navigates it to the variable's storage address.</LI>
|
||||
</UL>
|
||||
</BODY>
|
||||
</HTML>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -80,14 +80,13 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
interface DebuggerVariableViewerPopupAction {
|
||||
String NAME = "Debugger variable viewer Popup Actions";
|
||||
String DESCRIPTION = "Popup actions for debugger variable viewer";
|
||||
String HELP_ANCHOR = "";
|
||||
String HELP_ANCHOR = "popup_actions";
|
||||
String GROUP1 = "z";
|
||||
String GROUP2 = "zz";
|
||||
|
||||
static ActionBuilder builder(ComponentProvider owner, String subgroup, String... path) {
|
||||
final String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName).description(DESCRIPTION)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR))
|
||||
static ActionBuilder builder(String subgroup, String... path) {
|
||||
return new ActionBuilder(NAME, "DebuggerVariableViewerPlugin").description(DESCRIPTION)
|
||||
.helpLocation(new HelpLocation("DebuggerVariableViewerPlugin", HELP_ANCHOR))
|
||||
.popupMenuGroup(GROUP1, subgroup)
|
||||
.popupMenuPath(path)
|
||||
.popupWhen(c -> true)
|
||||
@@ -142,6 +141,8 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
|
||||
public DebuggerVariableViewerProvider(DebuggerVariableViewerPlugin plugin) {
|
||||
super(plugin.getTool(), "Variable Viewer", plugin.getName());
|
||||
setHelpLocation(new HelpLocation("DebuggerVariableViewerPlugin", "plugin"));
|
||||
|
||||
autoServiceWiring = AutoService.wireServicesConsumed(plugin, this);
|
||||
pluginTool = plugin.getTool();
|
||||
model = new DebuggerVariableViewerModel(plugin.getTool(), this);
|
||||
@@ -174,6 +175,7 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
c -> currentCoordinates != null && currentCoordinates.getTrace() != null)
|
||||
.onAction(c -> {
|
||||
})
|
||||
.helpLocation(new HelpLocation("DebuggerVariableViewerPlugin", "enable_edits"))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
actionShowVariables =
|
||||
@@ -188,6 +190,7 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
new GIcon("icon.decompiler.action.provider"),
|
||||
VariableViewerStates.DECOMPILER)
|
||||
.toolBarGroup("z")
|
||||
.helpLocation(new HelpLocation("DebuggerVariableViewerPlugin", "show_variables"))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
setVisible(true);
|
||||
@@ -394,7 +397,7 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
.getAddressFactory()
|
||||
.getAddress(selected.getFirst().getValue());
|
||||
if (address != null) {
|
||||
addActions(result, "View *%s @ 0x%x in...".formatted(selected.getFirst().getSymbol(),
|
||||
addActions(result, "Deref *%s @ 0x%x in...".formatted(selected.getFirst().getSymbol(),
|
||||
address.getOffset()), address);
|
||||
}
|
||||
return result;
|
||||
@@ -403,7 +406,7 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
private void addActions(List<DockingActionIf> result, String name, Address address) {
|
||||
// Add action for each additional debugger listing window
|
||||
int i = 0;
|
||||
result.add(DebuggerVariableViewerPopupAction.builder(this, Integer.toString(i), name,
|
||||
result.add(DebuggerVariableViewerPopupAction.builder(Integer.toString(i), name,
|
||||
"Main Listing").onAction(ctx -> {
|
||||
if (listingService == null) {
|
||||
return;
|
||||
@@ -420,7 +423,7 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(DebuggerVariableViewerPopupAction.builder(this, Integer.toString(i), name,
|
||||
result.add(DebuggerVariableViewerPopupAction.builder(Integer.toString(i), name,
|
||||
dl.getTitle()).onAction(ctx -> {
|
||||
if (listingService == null) {
|
||||
return;
|
||||
@@ -433,8 +436,8 @@ public class DebuggerVariableViewerProvider extends ComponentProviderAdapter
|
||||
i++;
|
||||
}
|
||||
|
||||
result.add(DebuggerVariableViewerPopupAction.builder(this, Integer.toString(i), name,
|
||||
"New Listing")
|
||||
result.add(
|
||||
DebuggerVariableViewerPopupAction.builder(Integer.toString(i), name, "New Listing")
|
||||
.popupMenuGroup(DebuggerVariableViewerPopupAction.GROUP2)
|
||||
.onAction(ctx -> {
|
||||
if (listingService == null) {
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.variable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import db.Transaction;
|
||||
import generic.test.category.NightlyCategory;
|
||||
import ghidra.app.plugin.core.debug.gui.stack.vars.VariableValueHoverPlugin;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.progress.ProgressServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
|
||||
import ghidra.app.services.ProgressService;
|
||||
import ghidra.async.AsyncTestUtils;
|
||||
import ghidra.debug.api.progress.MonitorReceiver;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||
import ghidra.trace.model.memory.TraceMemorySpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.model.time.TraceSnapshot;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.ConsoleTaskMonitor;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import help.screenshot.GhidraScreenShotGenerator;
|
||||
import org.junit.*;
|
||||
import org.junit.experimental.categories.Category;
|
||||
|
||||
@Category(NightlyCategory.class) // this may actually be an @PortSensitive test
|
||||
public class DebuggerVariableViewerPluginScreenShots extends GhidraScreenShotGenerator
|
||||
implements AsyncTestUtils {
|
||||
|
||||
private static final TaskMonitor MONITOR = new ConsoleTaskMonitor();
|
||||
ToyDBTraceBuilder tb;
|
||||
Program progHw;
|
||||
private ProgramManagerPlugin programManager;
|
||||
private DebuggerTraceManagerServicePlugin traceManager;
|
||||
private DebuggerVariableViewerProvider provider;
|
||||
private DebuggerStaticMappingServicePlugin mappingService;
|
||||
private ProgressService progressService;
|
||||
|
||||
@Before
|
||||
public void setUpMine() throws Exception {
|
||||
programManager = addPlugin(tool, ProgramManagerPlugin.class);
|
||||
traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class);
|
||||
mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
|
||||
progressService = addPlugin(tool, ProgressServicePlugin.class);
|
||||
|
||||
addPlugin(tool, DebuggerVariableViewerPlugin.class);
|
||||
|
||||
// The unwinder has a dependency on this plugin so it's required
|
||||
addPlugin(tool, VariableValueHoverPlugin.class);
|
||||
|
||||
provider = waitForComponentProvider(DebuggerVariableViewerProvider.class);
|
||||
|
||||
populateTraceAndPrograms();
|
||||
}
|
||||
|
||||
private void populateTraceAndPrograms() throws Exception {
|
||||
ToyProgramBuilder helloworldBuilder = new ToyProgramBuilder("helloworld", false, this);
|
||||
helloworldBuilder.tx(() -> {
|
||||
helloworldBuilder.createMemory(".text", "0x00400000", 0x50);
|
||||
Function function =
|
||||
helloworldBuilder.createEmptyFunction("main", null, "__fastcall", false,
|
||||
"0x00400000", 6, IntegerDataType.dataType,
|
||||
new ParameterImpl("argc", IntegerDataType.dataType,
|
||||
helloworldBuilder.getProgram()),
|
||||
new ParameterImpl("argv", new PointerDataType(CharDataType.dataType),
|
||||
helloworldBuilder.getProgram()),
|
||||
new ParameterImpl("float_arg", FloatDataType.dataType,
|
||||
helloworldBuilder.getProgram()));
|
||||
|
||||
progHw = helloworldBuilder.getProgram();
|
||||
|
||||
helloworldBuilder.createReturnInstruction("0x00400000");
|
||||
|
||||
function.addLocalVariable(
|
||||
new LocalVariableImpl("StackVar", IntegerDataType.dataType, 4, progHw),
|
||||
SourceType.USER_DEFINED);
|
||||
});
|
||||
|
||||
tb = new ToyDBTraceBuilder("toy", progHw.getLanguage().getLanguageID().getIdAsString());
|
||||
|
||||
intoProject(progHw);
|
||||
intoProject(tb.trace);
|
||||
programManager.openProgram(progHw);
|
||||
|
||||
traceManager.openTrace(tb.trace);
|
||||
mappingService.changesSettled().get(1, TimeUnit.SECONDS);
|
||||
|
||||
try (Transaction tx = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA);
|
||||
|
||||
tb.trace.getModuleManager()
|
||||
.addLoadedModule("Modules[helloword]", "helloworld",
|
||||
tb.range(0x00400000, 0x00400050), 0);
|
||||
|
||||
tb.trace.getMemoryManager()
|
||||
.addRegion("Memory[ALL]", Lifespan.nowOn(0),
|
||||
tb.range(0x0, 0xFFFF_FFFF_FFFF_FFFFL), TraceMemoryFlag.READ,
|
||||
TraceMemoryFlag.EXECUTE, TraceMemoryFlag.WRITE);
|
||||
|
||||
mappingService.addIdentityMapping(tb.trace, progHw, Lifespan.nowOn(0), true);
|
||||
|
||||
TraceThread thread = tb.getOrAddThread("Threads[1]", 0);
|
||||
tb.createObjectsRegsForThread(thread, Lifespan.nowOn(0), tb.host);
|
||||
TraceMemorySpace regs =
|
||||
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, true);
|
||||
Register pc = tb.trace.getBaseLanguage().getProgramCounter();
|
||||
Register arg1 = tb.trace.getBaseLanguage().getRegister("r12");
|
||||
Register arg2 = tb.trace.getBaseLanguage().getRegister("r11");
|
||||
Register arg3 = tb.trace.getBaseLanguage().getRegister("r10");
|
||||
Register sp = tb.trace.getBaseLanguage().getRegister("sp");
|
||||
|
||||
TraceSnapshot snap = tb.trace.getTimeManager().createSnapshot("Start main");
|
||||
snap.setEventThread(thread);
|
||||
|
||||
regs.setValue(snap.getKey(), new RegisterValue(pc, BigInteger.valueOf(0x00400000)));
|
||||
regs.setValue(snap.getKey(), new RegisterValue(arg1, BigInteger.valueOf(0x3)));
|
||||
regs.setValue(snap.getKey(), new RegisterValue(arg2, BigInteger.valueOf(0xdeadbeefL)));
|
||||
regs.setValue(snap.getKey(),
|
||||
new RegisterValue(arg3, BigInteger.valueOf(Float.floatToIntBits(1.5f))));
|
||||
regs.setValue(snap.getKey(), new RegisterValue(sp, BigInteger.valueOf(0x00200000)));
|
||||
|
||||
tb.trace.getStackManager()
|
||||
.getStack(thread, snap.getKey(), true)
|
||||
.getFrame(snap.getKey(), 0, true)
|
||||
.setProgramCounter(Lifespan.at(snap.getKey()), tb.addr(0x00400000));
|
||||
|
||||
tb.trace.getMemoryManager()
|
||||
.putBytes(snap.getKey(), tb.addr(0x00200004),
|
||||
ByteBuffer.wrap(new byte[] { 0x21, 0x43, 0x65, (byte) 0x87 }));
|
||||
}
|
||||
|
||||
mappingService.changesSettled().get(1, TimeUnit.SECONDS);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
traceManager.activateSnap(0);
|
||||
}
|
||||
|
||||
protected void intoProject(DomainObject obj) {
|
||||
waitForDomainObject(obj);
|
||||
DomainFolder rootFolder = tool.getProject().getProjectData().getRootFolder();
|
||||
waitForCondition(() -> {
|
||||
try {
|
||||
rootFolder.createFile(obj.getName(), obj, MONITOR);
|
||||
return true;
|
||||
}
|
||||
catch (InvalidNameException | CancelledException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Usually "object is busy". Try again.
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void waitForDomainObject(DomainObject object) {
|
||||
object.flushEvents();
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownMine() {
|
||||
tb.close();
|
||||
|
||||
if (progHw != null) {
|
||||
progHw.release(this);
|
||||
progHw = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaptureDebuggerVariableViewerPlugin() throws InterruptedException {
|
||||
for (MonitorReceiver e : progressService.getAllMonitors()) {
|
||||
waitFor(() -> !e.isValid());
|
||||
}
|
||||
JTable table = findComponent(provider.getComponent(), JTable.class);
|
||||
Thread.sleep(2000);
|
||||
waitFor(() -> table.getRowCount() > 0);
|
||||
captureIsolatedProvider(provider, 500, 500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaptureDebuggerVariableViewerPluginRightClick() throws InterruptedException {
|
||||
for (MonitorReceiver e : progressService.getAllMonitors()) {
|
||||
waitFor(() -> !e.isValid());
|
||||
}
|
||||
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(500, 500));
|
||||
window.toFront();
|
||||
provider.getComponent().requestFocus();
|
||||
paintFix(window);
|
||||
});
|
||||
|
||||
waitForSwing();
|
||||
JTable table = findComponent(provider.getComponent(), JTable.class);
|
||||
Thread.sleep(2000);
|
||||
waitFor(() -> table.getRowCount() > 0);
|
||||
selectRow(table, 0);
|
||||
Rectangle cellRect = table.getCellRect(0, 0, true);
|
||||
rightClick(table, cellRect.x + cellRect.width / 2, cellRect.y + cellRect.height / 2);
|
||||
JPopupMenu popupMenu = getPopupMenu();
|
||||
MenuElement menuElement =
|
||||
Arrays.stream(popupMenu.getSubElements()).findFirst().orElseThrow();
|
||||
postEvent(new MouseEvent(menuElement.getComponent(), MouseEvent.MOUSE_ENTERED,
|
||||
System.currentTimeMillis(), 0, menuElement.getComponent().getWidth(), 0, 0,
|
||||
false));
|
||||
captureProviderWithScreenShot(provider);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user