GP-1431: Adding Help for DebuggerMemoryBytesPlugin

This commit is contained in:
Dan
2021-10-27 12:32:35 -04:00
parent 5e5b0790ad
commit e6a41bb5d1
5 changed files with 283 additions and 0 deletions
@@ -46,6 +46,8 @@ src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.ht
src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html||GHIDRA||||END|
src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerListingPlugin.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html||GHIDRA||||END|
src/main/help/help/topics/DebuggerMemoryBytesPlugin/images/DebuggerMemoryBytesPlugin.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html||GHIDRA||||END|
src/main/help/help/topics/DebuggerMemviewPlugin/images/DebuggerMemviewPlugin.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerMemviewPlugin/images/DebuggerMemviewPlugin_old.png||GHIDRA||||END|
@@ -102,6 +102,10 @@
sortgroup="h"
target="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html" />
<tocdef id="DebuggerMemoryBytesPlugin" text="Memory"
sortgroup="h1"
target="help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html" />
<tocdef id="DebuggerListingPlugin" text="Dynamic Listing"
sortgroup="i"
target="help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html" />
@@ -0,0 +1,149 @@
<!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: Memory (Dynamic Bytes)</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD>
<BODY lang="EN-US">
<H1><A name="plugin"></A>Debugger: Memory (Dynamic Bytes)</H1>
<TABLE width="100%">
<TBODY>
<TR>
<TD align="center" width="100%"><IMG alt="" border="1" src=
"images/DebuggerMemoryBytesPlugin.png"></TD>
</TR>
</TBODY>
</TABLE>
<P><A name="Toggle_Header"></A>The memory, or dynamic bytes, window is analogous to Ghidra's
bytes window for static analysis, but in the dynamic context. That is, it displays memory
contents from a target. More precisely, it displays recorded memory contents in a trace. In
most use cases, that trace is "at the present," meaning it is the most recent memory from a
live target. Multiple memory windows can be displayed simultaneously, using the same pattern as
many other Ghidra windows. The "primary" window is always displayed and generally tracks with
the rest of the tool. Any window can be "snapshotted," i.e., duplicated. This is where memory
windows differ from static bytes windows. Static snapshots remain in place; they do not
automatically navigate. Dynamic snapshots can still be configured to navigate, following the
rest of the tool. A common use is to configure a "snapshot" to follow the stack pointer. Still,
you can disable a window's automatic navigation, so it behaves like a true snapshot. A current
limitation is that you cannot use snapshots to display different points in time for the same
trace.</P>
<P>Because not all memory is captured, some background coloring is used to indicate the state
of attempted memory reads. Regardless of state, the most-recent contents, as recorded in the
trace, are displayed in the window, defaulting to 00. "Stale" memory, that is ranges of memory
which have not been read at the current time, are displayed with a darker background. Where
that memory is marked "read-only" and has been successfully read previously, that coloring is
subdued, since the contents are not likely to have changed. Where a read was attempted but
failed, the first address in the failed range is displayed with a pink background. Otherwise,
up-to-date contents are displayed with the default background color.</P>
<P>NOTE: Modification of trace byte contents is a work in progress. At the moment, the feature
is simply disabled. In general, modifications to bytes when the window is "at the present" are
directed to the target. Otherwise, they simply modify the historical or emulated values stored
in the trace. A modification at a given time remains in effect, but stale, for all future times
up to but excluding the time of the next recorded value.</P>
<H2>Actions</H2>
<P>The memory window provides a variety of actions, some for managing and configuring windows,
and others for capturing memory from a target.</P>
<H3><A name="follows_thread"></A>Follows Selected Thread</H3>
<P>This action is only available on snapshot memory windows. The primary window always follows
the tool's current thread. Disabling this toggle causes the snapshot to remain on its own
current thread rather than following the tool's. The current thread is used when computing a
location to navigate to automatically. It is only applicable when "Track Location" is set to
something other than "Do Not Track."</P>
<H3><A name="track_location"></A>Track Location</H3>
<P>This action is always available on all memory windows. It configures automatic navigation
for the window. When location tracking is enabled, the window is automatically navigated to an
address computed from the trace's or target's machine state. The address is also highlighted in
green. The computed address is affected by the tool's current "coordinates," that is the
selected thread, frame, and point in time. The options are pluggable, but currently consist
of:</P>
<UL>
<LI>Do Not Track - disables automatic navigation.</LI>
<LI>Track Program Counter - (default) navigates this window to the current program counter.
If the stack contains a record of the program counter, it is preferred to the recorded
register value. Note that debuggers may vary in how they report the program counter, and its
meaning may vary among platforms. While there may be some nuances to the register value, the
value recorded in the stack should indicate the next instruction to be executed.</LI>
<LI>Track Stack Pointer - navigates this window to the current stack pointer. Again,
platforms may vary in how they define the stack pointer.</LI>
</UL>
<H3><A name="go_to"></A>Go To (G)</H3>
<P>This action is available whenever a trace is active in the window. It prompts the user for
an address, which can be expressed in Sleigh, then attempts to navigate to it. The expression
is evaluated in the context of the current thread, frame, and point in time. If the current
trace is live and at the present, the target may be queried to retrieve any machine state
required to evaluate the expression.</P>
<TABLE width="100%">
<TBODY>
<TR>
<TD align="center" width="100%"><IMG alt="" src=
"help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png"></TD>
</TR>
</TBODY>
</TABLE>
<H3><A name="capture_memory"></A>Capture Memory</H3>
<P>This action is available when the current trace is "at the present" with a live target, and
there is a selection of addresses in the memory window. It will instruct the recorder to
capture the contents of memory for the selected range(s). Typically, the viewable addresses are
automatically captured &mdash; see the Auto-Read action.</P>
<H3><A name="auto_memory"></A>Auto-Read Memory</H3>
<P>This action is always available on all memory windows. It configures whether or not the
memory range(s) displayed in the window are automatically captured. Like the Capture Memory
action, capture can only occur when the current trace is "at the present" with a live target.
It occurs when the user scrolls the window, or when the window is otherwise navigated to a new
location. Note that other components may capture memory, regardless of this windows's
configuration. For example, the recorder typically captures the page of memory pointed to by
the program counter. In other words, this action <EM>cannot</EM> "disable all memory captures."
The options are pluggable, but currently consist of:</P>
<UL>
<LI>Do Not Read Memory - disables automatic memory capture <EM>for this window
only</EM>.</LI>
<LI>Read Visible Memory - automatically reads stale ranges that enter this window's
view.</LI>
<LI>Read Visible Memory, RO Once - (default) behaves like Read Visible Memory, except it will
neglect to capture read-only ranges that have been captured previously.</LI>
</UL>
<H3><A name="Byte_Viewer_Options"></A>Byte Viewer Options</H3>
<P>This action does the same as it does for the static context.</P>
<H3><A name="Enable_Disable_Byteviewer_Editing"></A>Toggle Editing</H3>
<P>This action does the same as it does for the static context. NOTE: This feature is currently
disabled, as it is a work in progress.</P>
<H2><A name="colors"></A>Tool Options: Colors</H2>
<P>The memory-state and tracked-location background colors are replicated from the <A href=
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic Listing</A>.</P>
</BODY>
</HTML>
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@@ -0,0 +1,128 @@
/* ###
* 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.memory;
import java.util.Set;
import org.junit.*;
import com.google.common.collect.Range;
import ghidra.app.plugin.assembler.Assembler;
import ghidra.app.plugin.assembler.Assemblers;
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.memory.TraceMemoryRegisterSpace;
import ghidra.trace.model.symbol.*;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.database.UndoableTransaction;
import help.screenshot.GhidraScreenShotGenerator;
public class DebuggerMemoryBytesPluginScreenShots extends GhidraScreenShotGenerator {
DebuggerTraceManagerService traceManager;
DebuggerMemoryBytesPlugin memoryPlugin;
DebuggerMemoryBytesProvider memoryProvider;
DebuggerListingPlugin listingPlugin; // For colors
ToyDBTraceBuilder tb;
@Before
public void setUpMine() throws Throwable {
traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class);
memoryPlugin = addPlugin(tool, DebuggerMemoryBytesPlugin.class);
listingPlugin = addPlugin(tool, DebuggerListingPlugin.class);
memoryProvider = waitForComponentProvider(DebuggerMemoryBytesProvider.class);
tool.showComponentProvider(memoryProvider, true);
tb = new ToyDBTraceBuilder("echo", ToyProgramBuilder._X64);
}
@After
public void tearDownMine() {
tb.close();
}
@Test
public void testCaptureDebuggerMemoryBytesPlugin() throws Throwable {
try (UndoableTransaction tid = tb.startTransaction()) {
long snap = tb.trace.getTimeManager().createSnapshot("First").getKey();
tb.trace.getMemoryManager()
.addRegion(".text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE));
TraceSymbolManager symbolManager = tb.trace.getSymbolManager();
TraceNamespaceSymbol global = symbolManager.getGlobalNamespace();
TraceSymbol mainLabel = symbolManager
.labels()
.create(snap, null, tb.addr(0x00400000),
"main", global, SourceType.USER_DEFINED);
@SuppressWarnings("unused")
TraceSymbol cloneLabel = symbolManager
.labels()
.create(snap, null, tb.addr(0x00400060),
"clone", global, SourceType.USER_DEFINED);
TraceSymbol childLabel = symbolManager
.labels()
.create(snap, null, tb.addr(0x00400034),
"child", global, SourceType.USER_DEFINED);
@SuppressWarnings("unused")
TraceSymbol exitLabel = symbolManager
.labels()
.create(snap, null, tb.addr(0x00400061),
"exit", global, SourceType.USER_DEFINED);
Assembler assembler = Assemblers.getAssembler(tb.trace.getProgramView());
assembler.assemble(mainLabel.getAddress(),
"PUSH RBP",
"MOV RBP,RSP",
"CALL clone",
"TEST EAX,EAX",
"JNZ child",
"SUB RSP,0x10",
"MOV dword ptr [RSP],0x6c6c6548",
"MOV dword ptr [RSP+4],0x57202c6f",
"MOV dword ptr [RSP+8],0x646c726f",
"MOV word ptr [RSP+0xc],0x21",
"CALL exit",
"SUB RSP,0x10",
"MOV dword ptr [RSP],0x2c657942",
"MOV dword ptr [RSP+4],0x726f5720",
"MOV dword ptr [RSP+8],0x21646c",
"CALL exit");
TraceThread thread = tb.getOrAddThread("[1]", snap);
TraceMemoryRegisterSpace regs =
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, true);
regs.setValue(snap, new RegisterValue(tb.language.getProgramCounter(),
childLabel.getAddress().getOffsetAsBigInteger()));
}
traceManager.openTrace(tb.trace);
traceManager.activateTrace(tb.trace);
captureIsolatedProvider(DebuggerMemoryBytesProvider.class, 600, 600);
}
}