mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-25 03:06:14 +08:00
Merge remote-tracking branch
'origin/GP-1547_Dan_listingChangeLanguages--SQUASHED' into Ghidra_10.1
This commit is contained in:
@@ -41,6 +41,8 @@ src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-enable-al
|
||||
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-make-effective.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerConsolePlugin/images/DebuggerConsolePlugin.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerCopyActionsPlugin/DebuggerCopyActionsPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerCopyActionsPlugin/images/DebuggerCopyIntoProgramDialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerEmulationServicePlugin/DebuggerEmulationServicePlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html||GHIDRA||||END|
|
||||
|
||||
@@ -52,109 +52,114 @@
|
||||
<tocref id="Ghidra Functionality">
|
||||
<tocdef id="Debugger" text="Debugger"
|
||||
target="help/topics/Debugger/Debugger.html" >
|
||||
|
||||
<tocdef id="DebuggerGettingStarted" text="Getting Started"
|
||||
sortgroup="a"
|
||||
target="help/topics/Debugger/GettingStarted.html" >
|
||||
<tocdef id="Launching" text="Launching a Target"
|
||||
sortgroup="a"
|
||||
target="help/topics/Debugger/GettingStarted.html#launching" />
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerTroubleshooting" text="Troubleshooting"
|
||||
sortgroup="b"
|
||||
target="help/topics/Debugger/Troubleshooting.html" />
|
||||
<tocdef id="DebuggerGettingStarted" text="Getting Started"
|
||||
sortgroup="a"
|
||||
target="help/topics/Debugger/GettingStarted.html" >
|
||||
|
||||
<tocdef id="DebuggerTargetsPlugin" text="Targets"
|
||||
sortgroup="c"
|
||||
target="help/topics/DebuggerTargetsPlugin/DebuggerTargetsPlugin.html" >
|
||||
<tocdef id="Launching" text="Launching a Target"
|
||||
sortgroup="a"
|
||||
target="help/topics/Debugger/GettingStarted.html#launching" />
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerModelServicePlugin" text="Tool Actions"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html" />
|
||||
</tocdef>
|
||||
<tocdef id="DebuggerTroubleshooting" text="Troubleshooting"
|
||||
sortgroup="b"
|
||||
target="help/topics/Debugger/Troubleshooting.html" />
|
||||
|
||||
<tocdef id="DebuggerTargetsPlugin" text="Targets"
|
||||
sortgroup="c"
|
||||
target="help/topics/DebuggerTargetsPlugin/DebuggerTargetsPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerModelServicePlugin" text="Tool Actions"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html" />
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerConsolePlugin" text="Debug Console"
|
||||
sortgroup="c1"
|
||||
target="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html" />
|
||||
sortgroup="c1"
|
||||
target="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerObjectsPlugin" text="Commands and Objects"
|
||||
sortgroup="d"
|
||||
target="help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html" />
|
||||
<tocdef id="DebuggerCopyActionsPlugin" text="Copy Actions"
|
||||
sortgroup="c2"
|
||||
target="help/topics/DebuggerCopyActionsPlugin/DebuggerCopyActionsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerInterpreterPlugin" text="Interpreters"
|
||||
sortgroup="e"
|
||||
target="help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html" />
|
||||
<tocdef id="DebuggerObjectsPlugin" text="Commands and Objects"
|
||||
sortgroup="d"
|
||||
target="help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerThreadsPlugin" text="Threads and Traces"
|
||||
sortgroup="f"
|
||||
target="help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html" />
|
||||
<tocdef id="DebuggerInterpreterPlugin" text="Interpreters"
|
||||
sortgroup="e"
|
||||
target="help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerThreadsPlugin" text="Threads and Traces"
|
||||
sortgroup="f"
|
||||
target="help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerTraceManagerServicePlugin" text="Trace Management"
|
||||
sortgroup="g"
|
||||
target="help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html" />
|
||||
sortgroup="g"
|
||||
target="help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerEmulationServicePlugin" text="Emulation"
|
||||
sortgroup="g1"
|
||||
target="help/topics/DebuggerEmulationServicePlugin/DebuggerEmulationServicePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerRegistersPlugin" text="Registers"
|
||||
sortgroup="h"
|
||||
target="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html" />
|
||||
<tocdef id="DebuggerMemoryBytesPlugin" text="Memory"
|
||||
sortgroup="h1"
|
||||
target="help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerMemoryBytesPlugin" text="Memory"
|
||||
sortgroup="h1"
|
||||
target="help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html" />
|
||||
<tocdef id="DebuggerRegistersPlugin" text="Registers"
|
||||
sortgroup="h"
|
||||
target="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerListingPlugin" text="Dynamic Listing"
|
||||
sortgroup="i"
|
||||
target="help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html" />
|
||||
<tocdef id="DebuggerListingPlugin" text="Dynamic Listing"
|
||||
sortgroup="i"
|
||||
target="help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerStackPlugin" text="Stack"
|
||||
sortgroup="j"
|
||||
target="help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html" />
|
||||
<tocdef id="DebuggerStackPlugin" text="Stack"
|
||||
sortgroup="j"
|
||||
target="help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerBreakpointsPlugin" text="Breakpoints"
|
||||
sortgroup="k"
|
||||
target="help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerBreakpointMarkerPlugin" text="In the Listings"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html" />
|
||||
</tocdef>
|
||||
<tocdef id="DebuggerBreakpointsPlugin" text="Breakpoints"
|
||||
sortgroup="k"
|
||||
target="help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerRegionsPlugin" text="Memory Regions"
|
||||
sortgroup="l"
|
||||
target="help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerTimePlugin" text="Time"
|
||||
sortgroup="m"
|
||||
target="help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerModulesPlugin" text="Modules and Sections"
|
||||
sortgroup="n"
|
||||
target="help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerStaticMappingPlugin" text="Static Mappings"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html" />
|
||||
<tocdef id="DebuggerBreakpointMarkerPlugin" text="In the Listings"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html" />
|
||||
</tocdef>
|
||||
|
||||
|
||||
<tocdef id="DebuggerRegionsPlugin" text="Memory Regions"
|
||||
sortgroup="l"
|
||||
target="help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerTimePlugin" text="Time"
|
||||
sortgroup="m"
|
||||
target="help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerModulesPlugin" text="Modules and Sections"
|
||||
sortgroup="n"
|
||||
target="help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerStaticMappingPlugin" text="Static Mappings"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html" />
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerWatchesPlugin" text="Watches"
|
||||
sortgroup="n"
|
||||
target="help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html" />
|
||||
|
||||
sortgroup="n"
|
||||
target="help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerMemviewPlugin" text="Memview Plot"
|
||||
sortgroup="o"
|
||||
target="help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html" />
|
||||
|
||||
sortgroup="o"
|
||||
target="help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerPcodeStepperPlugin" text="P-code Stepper"
|
||||
sortgroup="p"
|
||||
target="help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerBots" text="Bots: Workflow Automation"
|
||||
sortgroup="q"
|
||||
target="help/topics/DebuggerBots/DebuggerBots.html" />
|
||||
</tocdef>
|
||||
sortgroup="p"
|
||||
target="help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerBots" text="Bots: Workflow Automation"
|
||||
sortgroup="q"
|
||||
target="help/topics/DebuggerBots/DebuggerBots.html" />
|
||||
</tocdef>
|
||||
</tocref>
|
||||
</tocroot>
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
<!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: Copy Actions</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: Copy Actions</H1>
|
||||
|
||||
<P>In the course of debugging, the user may want to capture certain state and annotations from
|
||||
the dynamic context into the static. This might include the contents of the stack, the heap, or
|
||||
example data stored in uninitialized memory. The copy actions allow for the easy movement of
|
||||
data and annotations from traces into programs. The actions are all accessed via the <SPAN
|
||||
class="menu">Debugger</SPAN> menu.</P>
|
||||
|
||||
<H2>Actions</H2>
|
||||
|
||||
<H3><A name="copy_into_current"></A>Copy Into Current Program</H3>
|
||||
|
||||
<P>This action requires a selection of memory in a dynamic view. It copies selected contents
|
||||
from the current trace (at the current time) into the current program. The <A href=
|
||||
"#dialog">Copy Dialog</A> is presented with the current program set as the destination.</P>
|
||||
|
||||
<H3><A name="copy_into_new"></A>Copy Into New Program</H3>
|
||||
|
||||
<P>This action requires a selection of memory in a dynamic view. It copies selected contents
|
||||
from the current trace (at the current time) into a new program. The <A href="#dialog">Copy
|
||||
Dialog</A> is presented with <B><New Program></B> set as the destination.</P>
|
||||
|
||||
<H3><A name="export_view"></A>Export Trace View</H3>
|
||||
|
||||
<P>This action is available whenever a trace is open. The <A href=
|
||||
"help/topics/ExporterPlugin/exporter.htm#Exporter_Dialog">Export Dialog</A> is presented for
|
||||
the current trace at the current time. This provides a mechanism for capturing a particular
|
||||
point in time from a trace to a file. The exported image can be analyzed in Ghidra or another
|
||||
tool.</P>
|
||||
|
||||
<H2><A name="dialog"></A>Copy Dialog</H2>
|
||||
|
||||
<P>The <B>Copy Into...</B> actions both present the same dialog: (The <B>Export Trace View</B>
|
||||
action uses a different dialog.)</P>
|
||||
|
||||
<TABLE width="100%">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD align="center" width="100%"><IMG alt="" src=
|
||||
"images/DebuggerCopyIntoProgramDialog.png"></TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
|
||||
<P>The dialog consists of several options, followed by a table that displays the proposed
|
||||
ranges to copy. For selected ranges not contained in the destination program's memory, new
|
||||
blocks are proposed. The source selection is always broken apart by regions defined in the
|
||||
trace's memory manager.</P>
|
||||
|
||||
<H3>Options</H3>
|
||||
|
||||
<UL>
|
||||
<LI>The <B>Destination</B> drop down allows the choice of an alternative destination. All
|
||||
open programs, <B><New Program></B>, and <B><Temporary Program></B> are available
|
||||
for selection. Modifying this option will reset the proposal. Choosing <B><New
|
||||
Program></B> will prompt for a new destination program upon a successful copy. Choosing
|
||||
<B><Temporary Program></B> will create a temporary, read-only program. The temporary
|
||||
program can still be saved later.</LI>
|
||||
|
||||
<LI>The <B>Read live</B> checkbox includes the <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html#read_memory">Read Memory</A>
|
||||
action in the copy process. This is only available when the trace is live and at the present.
|
||||
This assures that bytes copied into the destination program are actually the bytes from the
|
||||
live target, not just a stale cache or default zeros. <B>Note:</B> The copy operation will
|
||||
proceed even if the read-live-memory step fails, or only partially succeeds. Include <A href=
|
||||
"#state">State</A> if you need to know which bytes are up to date in the destination
|
||||
program.</LI>
|
||||
|
||||
<LI>The <B>Relocate</B> checkbox enables the use of <A href=
|
||||
"help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html">Static
|
||||
Mappings</A> when determining the destination addresses. This is only available for existing
|
||||
programs, and will only operate on portions of the source trace that are mapped to the
|
||||
destination program. Modifying this option will reset the proposal.</LI>
|
||||
|
||||
<LI>The <B><A name="use_overlays"></A>Use overlays</B> checkbox causes the dialog to propose
|
||||
overlay blocks for destination ranges that already exist in the program's memory. When
|
||||
unchecked, ranges are broken apart so that portions already in the destination memory map
|
||||
will not modify the map. Portions not already in the memory map will generate new blocks.
|
||||
When checked, destination ranges are not broken apart. If any portion already exists in the
|
||||
destination memory map, the entire range will generate an overlay block. Modifying this
|
||||
option will reset the proposal.</LI>
|
||||
|
||||
<LI>The <B>Include</B> checkboxes determine which contents are transferred from the current
|
||||
trace view into the destination. The <B>Select All</B> and <B>Select None</B> buttons do as
|
||||
they say. <B>Note:</B> Even if no items are selected, the destination blocks will be created,
|
||||
if the dialog is confirmed.</LI>
|
||||
|
||||
<UL>
|
||||
<LI><B>Bookmarks</B> copies bookmarks contained in the selection.</LI>
|
||||
|
||||
<LI><B>Breakpoints</B> copies breakpoints contained in the selection. <B>Note:</B> Since
|
||||
programs do not support breakpoints, bookmarks are used instead. They are the same type
|
||||
and category as those used by the <A href=
|
||||
"help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html">Breakpoints</A>
|
||||
window.</LI>
|
||||
|
||||
<LI><B>Bytes</B> copies the actual memory contents of the selection. <B>Note:</B> When
|
||||
copying into an uninitialized block, the entire block becomes initialized, i.e., all
|
||||
<CODE>??</CODE>s become <CODE>00</CODE>s; however, only the selected ranges are actually
|
||||
copied in.</LI>
|
||||
|
||||
<LI><B>Comments</B> copies all comments contained in the selection.</LI>
|
||||
|
||||
<LI><B>Data</B> copies all (non-dynamic) data annotations contained in the selection. It
|
||||
is only available when the source and destination agree on data organization.</LI>
|
||||
|
||||
<LI><B>Dynamic Data</B> copies all data annotations for dynamic data types. This item
|
||||
requires <B>Bytes</B> to also be copied, since the properties (particularly length) of
|
||||
each unit may depend on the memory contents. It is only available when the source and
|
||||
destination agree on data organization.</LI>
|
||||
|
||||
<LI><B>Instructions</B> copies all disassembled instructions in the selection. This item
|
||||
requires <B>Bytes</B> to also be copied, since instructions depend on the memory
|
||||
contents. It is only available when the source and destination have identical
|
||||
languages.</LI>
|
||||
|
||||
<LI><B>Labels</B> copies all labels contained in the selection.</LI>
|
||||
|
||||
<LI><B>References</B> copies all memory references where both the "from" and "to"
|
||||
addresses are contained in the selection.</LI>
|
||||
|
||||
<LI><B><A name="state"></A>State</B> copies the memory states (stale, error, known) of
|
||||
the selection. <B>Note:</B> Since programs do not support memory state, the program's
|
||||
color map is used instead.</LI>
|
||||
</UL>
|
||||
</UL>
|
||||
|
||||
<H3>Table Columns</H3>
|
||||
|
||||
<P>The table displays the proposal and allows for some adjustments. It has the following
|
||||
columns:</P>
|
||||
|
||||
<UL>
|
||||
<LI>Remove - a button to remove the selected range from the proposal. If applicable, the
|
||||
destination block will no longer be created.</LI>
|
||||
|
||||
<LI>Region - the name of the source memory region of the trace.</LI>
|
||||
|
||||
<LI>Modules - the names of modules that touch the source range.</LI>
|
||||
|
||||
<LI>Sections - the names of sections that touch the source range.</LI>
|
||||
|
||||
<LI>SrcMin - the minimum address in the source range.</LI>
|
||||
|
||||
<LI>SrcMax - the maximum address in the source range.</LI>
|
||||
|
||||
<LI>Block - the name of the destination memory block of the program. If the block already
|
||||
exists, the name is displayed with an asterisk. The block will not be created, but contents
|
||||
will still be copied into it. If the block does not already exist, the name can be changed by
|
||||
editing this cell.</LI>
|
||||
|
||||
<LI>Overlay - indicates whether or not a created block will be an overlay block. This cannot
|
||||
be modified. See <A href="#use_overlays">Use overlays</A> above.</LI>
|
||||
|
||||
<LI>DstMin - the minimum address in the destination range.</LI>
|
||||
|
||||
<LI>DstMax - the maximum address in the destination range.</LI>
|
||||
</UL>
|
||||
|
||||
<P>The <B>Copy</B> button confirms the dialog and copies <EM>all proposed ranges</EM> in the
|
||||
table. If successful, the dialog is closed. The <B>Cancel</B> button dismisses the dialog
|
||||
without performing any operation. The <B>Reset</B> button resets the proposal, in case entries
|
||||
were accidentally removed or modified.</P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
+14
-15
@@ -49,7 +49,7 @@
|
||||
surprising. For example, disassembling some instructions and then stepping back in time will
|
||||
cause that disassembly to disappear.</P>
|
||||
|
||||
<P>Because not all memory is captured, some background coloring is used to indicate the state
|
||||
<P>Because not all memory is recorded, 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 listing, 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
|
||||
@@ -142,33 +142,32 @@
|
||||
and/or needs a version upgrade. It will attempt to open the program, allowing Ghidra to prompt
|
||||
you about the situation.</P>
|
||||
|
||||
<H3><A name="capture_memory"></A>Capture Memory</H3>
|
||||
<H3><A name="read_memory"></A>Read 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 dynamic listing. It will instruct the recorder to
|
||||
capture the contents of memory for the selected range(s). Typically, the viewable addresses are
|
||||
automatically captured — see the Auto-Read action.</P>
|
||||
there is a selection of addresses in the dynamic listing. It will instruct the recorder to read
|
||||
and record the contents of memory for the selected range(s). Typically, the viewable addresses
|
||||
are automatically read, anyway — see the Auto-Read action.</P>
|
||||
|
||||
<H3><A name="auto_memory"></A>Auto-Read Memory</H3>
|
||||
|
||||
<P>This action is always available on all dynamic listings. It configures whether or not the
|
||||
memory range(s) displayed in the listing 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 listing, or when the listing is otherwise navigated to a
|
||||
new location. Note that other components may capture memory, regardless of this listing'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>
|
||||
memory range(s) displayed in the listing are automatically read and recorded. Like the Read
|
||||
Memory action, it is only permitted when the current trace is "at the present" with a live
|
||||
target. It occurs when the user scrolls the listing, or when the listing is otherwise navigated
|
||||
to a new location. Note that other components may read memory, regardless of this listing's
|
||||
configuration. For example, the recorder typically reads the page of memory pointed to by the
|
||||
program counter. In other words, this action <EM>cannot</EM> "disable all memory reads." The
|
||||
options are pluggable, but currently consist of:</P>
|
||||
|
||||
<UL>
|
||||
<LI>Do Not Read Memory - disables automatic memory capture <EM>for this listing
|
||||
only</EM>.</LI>
|
||||
<LI>Do Not Read Memory - disables automatic memory reads <EM>for this listing only</EM>.</LI>
|
||||
|
||||
<LI>Read Visible Memory - automatically reads stale ranges that enter this listing'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>
|
||||
neglect read-only ranges that have been read previously.</LI>
|
||||
</UL>
|
||||
|
||||
<H2><A name="colors"></A>Tool Options: Colors</H2>
|
||||
|
||||
+14
-15
@@ -36,7 +36,7 @@
|
||||
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
|
||||
<P>Because not all memory is recorded, 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
|
||||
@@ -103,33 +103,32 @@
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
|
||||
<H3><A name="capture_memory"></A>Capture Memory</H3>
|
||||
<H3><A name="read_memory"></A>Read 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 — see the Auto-Read action.</P>
|
||||
there is a selection of addresses in the memory window. It will instruct the recorder to read
|
||||
and record the contents of memory for the selected range(s). Typically, the viewable addresses
|
||||
are automatically read — 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>
|
||||
memory range(s) displayed in the window are automatically read and recorded. Like the Read
|
||||
Memory action, it is only permitted 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 read memory, regardless of this windows's
|
||||
configuration. For example, the recorder typically reads the page of memory pointed to by the
|
||||
program counter. In other words, this action <EM>cannot</EM> "disable all memory reads." 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>Do Not Read Memory - disables automatic memory reads <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>
|
||||
neglect read-only ranges that have been read previously.</LI>
|
||||
</UL>
|
||||
|
||||
<H3><A name="Byte_Viewer_Options"></A>Byte Viewer Options</H3>
|
||||
|
||||
+47
-10
@@ -144,8 +144,8 @@ public interface DebuggerResources {
|
||||
ImageIcon ICON_AUTOREAD = ResourceManager.loadImage("images/autoread.png");
|
||||
|
||||
// TODO: Draw a real icon.
|
||||
ImageIcon ICON_CAPTURE_MEMORY = ICON_REGIONS;
|
||||
//ResourceManager.loadImage("images/capture-memory.png");
|
||||
ImageIcon ICON_READ_MEMORY = ICON_REGIONS;
|
||||
//ResourceManager.loadImage("images/read-memory.png");
|
||||
|
||||
// TODO: Draw an icon
|
||||
ImageIcon ICON_MAP_IDENTICALLY = ResourceManager.loadImage("images/doubleArrow.png");
|
||||
@@ -777,14 +777,15 @@ public interface DebuggerResources {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractCaptureSelectedMemoryAction extends DockingAction {
|
||||
public static final String NAME = "Capture Selected Memory";
|
||||
public static final Icon ICON = ICON_CAPTURE_MEMORY;
|
||||
public static final String HELP_ANCHOR = "capture_memory";
|
||||
abstract class AbstractReadSelectedMemoryAction extends DockingAction {
|
||||
public static final String NAME = "Read Selected Memory";
|
||||
public static final Icon ICON = ICON_READ_MEMORY;
|
||||
public static final String HELP_ANCHOR = "read_memory";
|
||||
|
||||
public AbstractCaptureSelectedMemoryAction(Plugin owner) {
|
||||
public AbstractReadSelectedMemoryAction(Plugin owner) {
|
||||
super(NAME, owner.getName());
|
||||
setDescription("Capture memory for the selected addresses into the trace database");
|
||||
setDescription(
|
||||
"(Re-)read and record memory for the selected addresses into the trace database");
|
||||
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
@@ -885,7 +886,7 @@ public interface DebuggerResources {
|
||||
|
||||
interface AutoReadMemoryAction {
|
||||
String NAME = "Auto-Read Target Memory";
|
||||
String DESCRIPTION = "Automatically capture visible memory from the live target";
|
||||
String DESCRIPTION = "Automatically read and record visible memory from the live target";
|
||||
String HELP_ANCHOR = "auto_memory";
|
||||
|
||||
String NAME_VIS_RO_ONCE = "Read Visible Memory, RO Once";
|
||||
@@ -1081,7 +1082,43 @@ public interface DebuggerResources {
|
||||
return new ActionBuilder(NAME, ownerName)
|
||||
.description(DESCRIPTION)
|
||||
.menuGroup(GROUP)
|
||||
.menuPath(NAME)
|
||||
.menuPath(DebuggerPluginPackage.NAME, NAME)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface CopyIntoProgramAction {
|
||||
String NAME_PAT = "Copy Into %s Program";
|
||||
String DESC_PAT = "Copy the current selection into %s program";
|
||||
String GROUP = GROUP_MAINTENANCE;
|
||||
}
|
||||
|
||||
interface CopyIntoCurrentProgramAction extends CopyIntoProgramAction {
|
||||
String NAME = String.format(NAME_PAT, "Current");
|
||||
String DESCRIPTION = String.format(DESC_PAT, "the current");
|
||||
String HELP_ANCHOR = "copy_into_current";
|
||||
|
||||
static ActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName)
|
||||
.description(DESCRIPTION)
|
||||
.menuGroup(GROUP)
|
||||
.menuPath(DebuggerPluginPackage.NAME, NAME)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface CopyIntoNewProgramAction extends CopyIntoProgramAction {
|
||||
String NAME = String.format(NAME_PAT, "New");
|
||||
String DESCRIPTION = String.format(DESC_PAT, "a new");
|
||||
String HELP_ANCHOR = "copy_into_new";
|
||||
|
||||
static ActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName)
|
||||
.description(DESCRIPTION)
|
||||
.menuGroup(GROUP)
|
||||
.menuPath(DebuggerPluginPackage.NAME, NAME)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
+14
-14
@@ -27,7 +27,7 @@ import docking.menu.MultiStateDockingAction;
|
||||
import docking.widgets.EventTrigger;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractCaptureSelectedMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractReadSelectedMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.utils.BackgroundUtils;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
@@ -49,10 +49,10 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
protected static final AutoConfigState.ClassHandler<DebuggerReadsMemoryTrait> CONFIG_STATE_HANDLER =
|
||||
AutoConfigState.wireHandler(DebuggerReadsMemoryTrait.class, MethodHandles.lookup());
|
||||
|
||||
protected class CaptureSelectedMemoryAction extends AbstractCaptureSelectedMemoryAction {
|
||||
protected class ReadSelectedMemoryAction extends AbstractReadSelectedMemoryAction {
|
||||
public static final String GROUP = DebuggerResources.GROUP_GENERAL;
|
||||
|
||||
public CaptureSelectedMemoryAction() {
|
||||
public ReadSelectedMemoryAction() {
|
||||
super(plugin);
|
||||
setToolBarData(new ToolBarData(ICON, GROUP));
|
||||
setEnabled(false);
|
||||
@@ -89,14 +89,14 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
}
|
||||
}
|
||||
|
||||
protected class ForCaptureTraceListener extends TraceDomainObjectListener {
|
||||
public ForCaptureTraceListener() {
|
||||
protected class ForReadsTraceListener extends TraceDomainObjectListener {
|
||||
public ForReadsTraceListener() {
|
||||
listenFor(TraceSnapshotChangeType.ADDED, this::snapshotAdded);
|
||||
listenFor(TraceMemoryStateChangeType.CHANGED, this::memStateChanged);
|
||||
}
|
||||
|
||||
private void snapshotAdded(TraceSnapshot snapshot) {
|
||||
actionCaptureSelected.updateEnabled(null);
|
||||
actionReadSelected.updateEnabled(null);
|
||||
}
|
||||
|
||||
private void memStateChanged(TraceAddressSnapRange range, TraceMemoryState oldIsNull,
|
||||
@@ -120,7 +120,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
@Override
|
||||
public void processMemoryAccessibilityChanged(TraceRecorder recorder) {
|
||||
Swing.runIfSwingOrRunLater(() -> {
|
||||
actionCaptureSelected.updateEnabled(null);
|
||||
actionReadSelected.updateEnabled(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
}
|
||||
|
||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoRead;
|
||||
protected CaptureSelectedMemoryAction actionCaptureSelected;
|
||||
protected ReadSelectedMemoryAction actionReadSelected;
|
||||
|
||||
private final AutoReadMemorySpec defaultAutoSpec =
|
||||
AutoReadMemorySpec.fromConfigName(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
@@ -149,8 +149,8 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
protected final Plugin plugin;
|
||||
protected final ComponentProvider provider;
|
||||
|
||||
protected final ForCaptureTraceListener traceListener =
|
||||
new ForCaptureTraceListener();
|
||||
protected final ForReadsTraceListener traceListener =
|
||||
new ForReadsTraceListener();
|
||||
protected final ForAccessRecorderListener recorderListener = new ForAccessRecorderListener();
|
||||
protected final ForVisibilityListener displayListener = new ForVisibilityListener();
|
||||
|
||||
@@ -257,10 +257,10 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
}
|
||||
}
|
||||
|
||||
public DockingAction installCaptureSelectedAction() {
|
||||
actionCaptureSelected = new CaptureSelectedMemoryAction();
|
||||
provider.addLocalAction(actionCaptureSelected);
|
||||
return actionCaptureSelected;
|
||||
public DockingAction installReadSelectedAction() {
|
||||
actionReadSelected = new ReadSelectedMemoryAction();
|
||||
provider.addLocalAction(actionReadSelected);
|
||||
return actionReadSelected;
|
||||
}
|
||||
|
||||
public AddressSetDisplayListener getDisplayListener() {
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/* ###
|
||||
* 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.copying;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import ghidra.app.context.ProgramLocationActionContext;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.core.debug.AbstractDebuggerPlugin;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||
import ghidra.app.plugin.core.exporter.ExporterDialog;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.framework.plugintool.PluginInfo;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceVariableSnapProgramView;
|
||||
|
||||
@PluginInfo(
|
||||
shortDescription = "Copy and export trace data",
|
||||
description = "Provides tool actions for moving data from traces to various destinations.",
|
||||
category = PluginCategoryNames.DEBUGGER,
|
||||
packageName = DebuggerPluginPackage.NAME,
|
||||
status = PluginStatus.RELEASED,
|
||||
eventsConsumed = {},
|
||||
eventsProduced = {},
|
||||
servicesRequired = {
|
||||
DebuggerStaticMappingService.class,
|
||||
ProgramManager.class,
|
||||
},
|
||||
servicesProvided = {})
|
||||
public class DebuggerCopyActionsPlugin extends AbstractDebuggerPlugin {
|
||||
|
||||
protected static ProgramSelection getSelectionFromContext(ActionContext context) {
|
||||
if (!(context instanceof ProgramLocationActionContext)) {
|
||||
return null;
|
||||
}
|
||||
ProgramLocationActionContext ctx = (ProgramLocationActionContext) context;
|
||||
return ctx.hasSelection() ? ctx.getSelection() : null;
|
||||
}
|
||||
|
||||
protected DebuggerCopyIntoProgramDialog copyDialog = new DebuggerCopyIntoProgramDialog();
|
||||
|
||||
protected DockingAction actionExportView;
|
||||
protected DockingAction actionCopyIntoCurrentProgram;
|
||||
protected DockingAction actionCopyIntoNewProgram;
|
||||
|
||||
@AutoServiceConsumed
|
||||
private ProgramManager programManager;
|
||||
@AutoServiceConsumed
|
||||
private DebuggerStaticMappingService mappingService;
|
||||
@AutoServiceConsumed
|
||||
private DebuggerModelService modelService;
|
||||
|
||||
public DebuggerCopyActionsPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
||||
createActions();
|
||||
}
|
||||
|
||||
protected void createActions() {
|
||||
actionExportView = ExportTraceViewAction.builder(this)
|
||||
.enabled(false)
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.enabledWhen(this::checkTrace)
|
||||
.onAction(this::activatedExportView)
|
||||
.buildAndInstall(tool);
|
||||
|
||||
// Using programManager here depends on it calling tool.updateContext()
|
||||
actionCopyIntoCurrentProgram = CopyIntoCurrentProgramAction.builder(this)
|
||||
.enabled(false)
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.enabledWhen(
|
||||
ctx -> checkTraceSelection(ctx) && programManager.getCurrentProgram() != null)
|
||||
.onAction(this::activatedCopyIntoCurrentProgram)
|
||||
.buildAndInstall(tool);
|
||||
|
||||
actionCopyIntoNewProgram = CopyIntoNewProgramAction.builder(this)
|
||||
.enabled(false)
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.enabledWhen(this::checkTraceSelection)
|
||||
.onAction(this::activatedCopyIntoNewProgram)
|
||||
.buildAndInstall(tool);
|
||||
}
|
||||
|
||||
protected boolean checkTrace(ProgramLocationActionContext context) {
|
||||
return context.getProgram() instanceof TraceProgramView;
|
||||
}
|
||||
|
||||
protected boolean checkTraceSelection(ProgramLocationActionContext context) {
|
||||
return checkTrace(context) && context.hasSelection();
|
||||
}
|
||||
|
||||
protected void activatedExportView(ProgramLocationActionContext context) {
|
||||
if (!checkTrace(context)) {
|
||||
return;
|
||||
}
|
||||
TraceProgramView view = (TraceProgramView) context.getProgram();
|
||||
// Avoid odd race conditions by fixing the snap
|
||||
TraceProgramView fixed = view instanceof TraceVariableSnapProgramView
|
||||
? view.getTrace().getFixedProgramView(view.getSnap())
|
||||
: view;
|
||||
|
||||
ExporterDialog dialog =
|
||||
new ExporterDialog(tool, fixed.getDomainFile(), fixed,
|
||||
getSelectionFromContext(context));
|
||||
tool.showDialog(dialog);
|
||||
}
|
||||
|
||||
protected void activatedCopyIntoCurrentProgram(ProgramLocationActionContext context) {
|
||||
if (!checkTraceSelection(context)) {
|
||||
return;
|
||||
}
|
||||
copyDialog.setSource((TraceProgramView) context.getProgram(), context.getSelection());
|
||||
copyDialog.setProgramManager(programManager);
|
||||
copyDialog.setStaticMappingService(mappingService);
|
||||
copyDialog.setModelService(modelService);
|
||||
copyDialog.setDestination(programManager.getCurrentProgram());
|
||||
copyDialog.reset();
|
||||
copyDialog.setStatusText("");
|
||||
tool.showDialog(copyDialog);
|
||||
}
|
||||
|
||||
protected void activatedCopyIntoNewProgram(ProgramLocationActionContext context) {
|
||||
if (!checkTraceSelection(context)) {
|
||||
return;
|
||||
}
|
||||
copyDialog.setSource((TraceProgramView) context.getProgram(), context.getSelection());
|
||||
copyDialog.setProgramManager(programManager);
|
||||
copyDialog.setStaticMappingService(mappingService);
|
||||
copyDialog.setModelService(modelService);
|
||||
copyDialog.setDestination(copyDialog.NEW_PROGRAM);
|
||||
copyDialog.reset();
|
||||
copyDialog.setStatusText("");
|
||||
tool.showDialog(copyDialog);
|
||||
}
|
||||
}
|
||||
+844
File diff suppressed because it is too large
Load Diff
+449
@@ -0,0 +1,449 @@
|
||||
/* ###
|
||||
* 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.copying;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.service.breakpoint.LogicalBreakpointInternal.ProgramBreakpoint;
|
||||
import ghidra.app.util.viewer.listingpanel.PropertyBasedBackgroundColorModel;
|
||||
import ghidra.program.database.IntRangeMap;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||
import ghidra.trace.model.memory.TraceMemoryManager;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DebuggerCopyPlan {
|
||||
public interface Copier {
|
||||
String getName();
|
||||
|
||||
boolean isAvailable(TraceProgramView from, Program into);
|
||||
|
||||
Collection<Copier> getRequires();
|
||||
|
||||
Collection<Copier> getRequiredBy();
|
||||
|
||||
boolean isRequiresInitializedMemory();
|
||||
|
||||
void copy(TraceProgramView from, AddressRange fromRange, Program into, Address intoAddress,
|
||||
TaskMonitor monitor) throws Exception;
|
||||
}
|
||||
|
||||
public enum AllCopiers implements Copier {
|
||||
BYTES("Bytes", List.of()) {
|
||||
@Override
|
||||
public boolean isRequiresInitializedMemory() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
// This is perhaps too heavy handed....
|
||||
into.getListing()
|
||||
.clearCodeUnits(intoAddress, intoAddress.add(fromRange.getLength() - 1),
|
||||
false);
|
||||
byte[] buf = new byte[4096];
|
||||
AddressRangeChunker chunker = new AddressRangeChunker(fromRange, buf.length);
|
||||
for (AddressRange chunk : chunker) {
|
||||
monitor.checkCanceled();
|
||||
Address addr = chunk.getMinAddress();
|
||||
int len = (int) chunk.getLength();
|
||||
from.getMemory().getBytes(addr, buf, 0, len);
|
||||
long off = addr.subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
into.getMemory().setBytes(dest, buf, 0, len);
|
||||
}
|
||||
}
|
||||
},
|
||||
STATE("State (as colors)", List.of()) {
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
IntRangeMap map =
|
||||
into.getIntRangeMap(PropertyBasedBackgroundColorModel.COLOR_PROPERTY_NAME);
|
||||
if (map == null) {
|
||||
map = into.createIntRangeMap(
|
||||
PropertyBasedBackgroundColorModel.COLOR_PROPERTY_NAME);
|
||||
}
|
||||
AddressSet rngAsSet = new AddressSet(fromRange);
|
||||
TraceMemoryManager mm = from.getTrace().getMemoryManager();
|
||||
AddressSetView knownSet = mm.getAddressesWithState(from.getSnap(), rngAsSet,
|
||||
s -> s == TraceMemoryState.KNOWN);
|
||||
AddressSetView errorSet = mm.getAddressesWithState(from.getSnap(), rngAsSet,
|
||||
s -> s == TraceMemoryState.ERROR);
|
||||
AddressSetView staleSet = rngAsSet.subtract(knownSet).subtract(errorSet);
|
||||
setShifted(map, fromRange.getMinAddress(), intoAddress, errorSet,
|
||||
DebuggerResources.DEFAULT_COLOR_BACKGROUND_ERROR.getRGB());
|
||||
setShifted(map, fromRange.getMinAddress(), intoAddress, staleSet,
|
||||
DebuggerResources.DEFAULT_COLOR_BACKGROUND_STALE.getRGB());
|
||||
}
|
||||
|
||||
public void setShifted(IntRangeMap map, Address src, Address dst, AddressSetView set,
|
||||
int value) {
|
||||
for (AddressRange rng : set) {
|
||||
long offMin = rng.getMinAddress().subtract(src);
|
||||
long offMax = rng.getMaxAddress().subtract(src);
|
||||
Address dMin = dst.add(offMin);
|
||||
Address dMax = dst.add(offMax);
|
||||
map.setValue(dMin, dMax, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
INSTRUCTIONS("Instructions", List.of(BYTES)) {
|
||||
@Override
|
||||
protected boolean checkAvailable(TraceProgramView from, Program into) {
|
||||
return into == null || from.getLanguage() == into.getLanguage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
Listing intoListing = into.getListing();
|
||||
for (Instruction ins : from.getListing()
|
||||
.getInstructions(new AddressSet(fromRange), true)) {
|
||||
monitor.checkCanceled();
|
||||
if (!ins.getPrototype().getLanguage().equals(into.getLanguage())) {
|
||||
// Filter out "guest" instructions
|
||||
continue;
|
||||
}
|
||||
long off = ins.getMinAddress().subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
intoListing.createInstruction(dest, ins.getPrototype(), ins, ins);
|
||||
}
|
||||
}
|
||||
},
|
||||
DATA("Data", List.of()) {
|
||||
@Override
|
||||
protected boolean checkAvailable(TraceProgramView from, Program into) {
|
||||
return into == null || sameDataOrganization(from, into);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor)
|
||||
throws Exception {
|
||||
Listing intoListing = into.getListing();
|
||||
for (Data data : from.getListing()
|
||||
.getDefinedData(new AddressSet(fromRange), true)) {
|
||||
monitor.checkCanceled();
|
||||
long off = data.getMinAddress().subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
DataType dt = data.getDataType();
|
||||
if (!(dt instanceof DynamicDataType)) {
|
||||
intoListing.createData(dest, dt, data.getLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
DYNAMIC_DATA("Dynamic Data", List.of(BYTES)) {
|
||||
@Override
|
||||
protected boolean checkAvailable(TraceProgramView from, Program into) {
|
||||
return into == null || sameDataOrganization(from, into);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
Listing intoListing = into.getListing();
|
||||
for (Data data : from.getListing()
|
||||
.getDefinedData(new AddressSet(fromRange), true)) {
|
||||
monitor.checkCanceled();
|
||||
long off = data.getMinAddress().subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
DataType dt = data.getDataType();
|
||||
if (dt instanceof DynamicDataType) {
|
||||
intoListing.createData(dest, dt, data.getLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
LABELS("Labels", List.of()) {
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
SymbolTable intoTable = into.getSymbolTable();
|
||||
for (Symbol label : from.getSymbolTable()
|
||||
.getSymbols(new AddressSet(fromRange), SymbolType.LABEL, true)) {
|
||||
monitor.checkCanceled();
|
||||
if (label.getSource() == SourceType.DEFAULT) {
|
||||
continue;
|
||||
}
|
||||
long off = label.getAddress().subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
Namespace destNs =
|
||||
findOrCopyNamespace(label.getParentNamespace(), intoTable, into);
|
||||
try {
|
||||
intoTable.createLabel(dest, label.getName(), destNs, label.getSource());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Namespace findOrCopyNamespace(Namespace ns, SymbolTable intoTable,
|
||||
Program into) throws Exception {
|
||||
if (ns.isGlobal()) {
|
||||
return into.getGlobalNamespace();
|
||||
}
|
||||
Namespace destParent =
|
||||
findOrCopyNamespace(ns.getParentNamespace(), intoTable, into);
|
||||
return intoTable.getOrCreateNameSpace(destParent, ns.getName(),
|
||||
ns.getSymbol().getSource());
|
||||
}
|
||||
},
|
||||
BREAKPOINTS("Breakpoints (as bookmarks)", List.of()) {
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
for (TraceBreakpoint bpt : from.getTrace()
|
||||
.getBreakpointManager()
|
||||
.getBreakpointsIntersecting(Range.singleton(from.getSnap()), fromRange)) {
|
||||
monitor.checkCanceled();
|
||||
long off = bpt.getMinAddress().subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
ProgramBreakpoint pb =
|
||||
new ProgramBreakpoint(into, dest, bpt.getLength(), bpt.getKinds());
|
||||
if (bpt.isEnabled()) {
|
||||
pb.enable();
|
||||
}
|
||||
else {
|
||||
pb.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
BOOKMARKS("Bookmarks", List.of()) {
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
BookmarkManager intoBookmarks = into.getBookmarkManager();
|
||||
Iterator<Bookmark> bit =
|
||||
from.getBookmarkManager().getBookmarksIterator(fromRange.getMinAddress(), true);
|
||||
while (bit.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
Bookmark bm = bit.next();
|
||||
if (bm.getAddress().compareTo(fromRange.getMaxAddress()) > 0) {
|
||||
break;
|
||||
}
|
||||
BookmarkType type = bm.getType();
|
||||
long off = bm.getAddress().subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
BookmarkType destType = intoBookmarks.getBookmarkType(type.getTypeString());
|
||||
if (destType == null) {
|
||||
destType = intoBookmarks.defineType(type.getTypeString(), type.getIcon(),
|
||||
type.getMarkerColor(), type.getMarkerPriority());
|
||||
}
|
||||
intoBookmarks.setBookmark(dest, destType.getTypeString(), bm.getCategory(),
|
||||
bm.getComment());
|
||||
}
|
||||
}
|
||||
},
|
||||
REFERENCES("References (memory only)", List.of()) {
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
ReferenceManager intoRefs = into.getReferenceManager();
|
||||
for (Reference ref : from.getReferenceManager()
|
||||
.getReferenceIterator(fromRange.getMinAddress())) {
|
||||
monitor.checkCanceled();
|
||||
if (ref.getFromAddress().compareTo(fromRange.getMaxAddress()) > 0) {
|
||||
break;
|
||||
}
|
||||
if (ref.getSource() == SourceType.DEFAULT) {
|
||||
continue;
|
||||
}
|
||||
// TODO: Other kinds of references?
|
||||
if (!ref.isMemoryReference()) {
|
||||
continue;
|
||||
}
|
||||
// Requiring both ends to be in copied range
|
||||
if (!fromRange.contains(ref.getToAddress())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// NB. "from" is overloaded here
|
||||
long offFrom = ref.getFromAddress().subtract(fromRange.getMinAddress());
|
||||
long offTo = ref.getToAddress().subtract(fromRange.getMinAddress());
|
||||
Address destFrom = intoAddress.add(offFrom);
|
||||
Address destTo = intoAddress.add(offTo);
|
||||
intoRefs.addMemoryReference(destFrom, destTo, ref.getReferenceType(),
|
||||
ref.getSource(), ref.getOperandIndex());
|
||||
}
|
||||
}
|
||||
},
|
||||
COMMENTS("Comments", List.of()) {
|
||||
@Override
|
||||
public void copy(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
Listing fromListing = from.getListing();
|
||||
Listing intoListing = into.getListing();
|
||||
for (Address addr : fromListing.getCommentAddressIterator(new AddressSet(fromRange),
|
||||
true)) {
|
||||
monitor.checkCanceled();
|
||||
long off = addr.subtract(fromRange.getMinAddress());
|
||||
Address dest = intoAddress.add(off);
|
||||
// Ugly, but there's not MAX/MIN_COMMENT_TYPE
|
||||
for (int i = CodeUnit.EOL_COMMENT; i <= CodeUnit.REPEATABLE_COMMENT; i++) {
|
||||
String comment = fromListing.getComment(i, addr);
|
||||
if (comment == null) {
|
||||
continue;
|
||||
}
|
||||
intoListing.setComment(dest, i, comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected boolean sameDataOrganization(Program p1, Program p2) {
|
||||
DataOrganization dataOrg1 = p1.getDataTypeManager().getDataOrganization();
|
||||
DataOrganization dataOrg2 = p2.getDataTypeManager().getDataOrganization();
|
||||
return dataOrg1.equals(dataOrg2);
|
||||
}
|
||||
|
||||
public static final List<Copier> VALUES;
|
||||
static {
|
||||
List<AllCopiers> asList = Arrays.asList(values());
|
||||
Collections.sort(asList, Comparator.comparing(AllCopiers::getName));
|
||||
VALUES = Collections.unmodifiableList(asList);
|
||||
}
|
||||
|
||||
final String name;
|
||||
final Collection<Copier> requires;
|
||||
final Collection<Copier> requiredBy = new HashSet<>();
|
||||
|
||||
private AllCopiers(String name, Collection<AllCopiers> requires) {
|
||||
this.name = name;
|
||||
this.requires = Collections.unmodifiableCollection(requires);
|
||||
for (AllCopiers req : requires) {
|
||||
req.requiredBy.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkAvailable(TraceProgramView from, Program into) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(TraceProgramView from, Program into) {
|
||||
return checkAvailable(from, into) &&
|
||||
getRequires().stream().allMatch(c -> c.isAvailable(from, into));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Copier> getRequires() {
|
||||
return requires;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Copier> getRequiredBy() {
|
||||
return requiredBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequiresInitializedMemory() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected final Map<Copier, JCheckBox> checkBoxes = new LinkedHashMap<>();
|
||||
|
||||
public DebuggerCopyPlan() {
|
||||
for (Copier copier : getAllCopiers()) {
|
||||
JCheckBox cb = new JCheckBox(copier.getName());
|
||||
Collection<Copier> requires = copier.getRequires();
|
||||
Collection<Copier> requiredBy = copier.getRequiredBy();
|
||||
if (!requires.isEmpty() || !requiredBy.isEmpty()) {
|
||||
cb.addActionListener(e -> {
|
||||
if (cb.isSelected()) {
|
||||
for (Copier req : requires) {
|
||||
checkBoxes.get(req).setSelected(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Copier dep : requiredBy) {
|
||||
checkBoxes.get(dep).setSelected(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
checkBoxes.put(copier, cb);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Copier> getAllCopiers() {
|
||||
return AllCopiers.VALUES;
|
||||
}
|
||||
|
||||
public JCheckBox getCheckBox(Copier copier) {
|
||||
return checkBoxes.get(copier);
|
||||
}
|
||||
|
||||
public void selectAll() {
|
||||
for (JCheckBox cb : checkBoxes.values()) {
|
||||
cb.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void selectNone() {
|
||||
for (JCheckBox cb : checkBoxes.values()) {
|
||||
cb.setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(TraceProgramView from, AddressRange fromRange, Program into,
|
||||
Address intoAddress, TaskMonitor monitor) throws Exception {
|
||||
for (Copier copier : getAllCopiers()) {
|
||||
if (!copier.isAvailable(from, into)) {
|
||||
continue;
|
||||
}
|
||||
if (!checkBoxes.get(copier).isSelected()) {
|
||||
continue;
|
||||
}
|
||||
copier.copy(from, fromRange, into, intoAddress, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
public void syncCopiersEnabled(TraceProgramView from, Program dest) {
|
||||
for (Map.Entry<Copier, JCheckBox> ent : checkBoxes.entrySet()) {
|
||||
ent.getValue().setEnabled(ent.getKey().isAvailable(from, dest));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequiresInitializedMemory(TraceProgramView from, Program dest) {
|
||||
return checkBoxes.entrySet().stream().anyMatch(ent -> {
|
||||
Copier copier = ent.getKey();
|
||||
return copier.isRequiresInitializedMemory() &&
|
||||
copier.isAvailable(from, dest) && ent.getValue().isSelected();
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-24
@@ -52,7 +52,6 @@ import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
|
||||
import ghidra.app.plugin.core.debug.utils.ProgramLocationUtils;
|
||||
import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
||||
import ghidra.app.plugin.core.exporter.ExporterDialog;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
@@ -72,7 +71,6 @@ import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceVariableSnapProgramView;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
@@ -239,8 +237,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||
protected SyncToStaticListingAction actionSyncToStaticListing;
|
||||
protected FollowsCurrentThreadAction actionFollowsCurrentThread;
|
||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoReadMemory;
|
||||
protected DockingAction actionCaptureSelectedMemory;
|
||||
protected DockingAction actionExportView;
|
||||
protected DockingAction actionReadSelectedMemory;
|
||||
protected DockingAction actionOpenProgram;
|
||||
protected MultiStateDockingAction<LocationTrackingSpec> actionTrackLocation;
|
||||
|
||||
@@ -608,12 +605,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||
actionGoTo = goToTrait.installAction();
|
||||
actionTrackLocation = trackingTrait.installAction();
|
||||
actionAutoReadMemory = readsMemTrait.installAutoReadAction();
|
||||
actionCaptureSelectedMemory = readsMemTrait.installCaptureSelectedAction();
|
||||
|
||||
actionExportView = ExportTraceViewAction.builder(plugin)
|
||||
.enabledWhen(ctx -> current.getView() != null)
|
||||
.onAction(this::activatedExportView)
|
||||
.buildAndInstallLocal(this);
|
||||
actionReadSelectedMemory = readsMemTrait.installReadSelectedAction();
|
||||
|
||||
actionOpenProgram = OpenProgramAction.builder(plugin)
|
||||
.withContext(DebuggerOpenProgramActionContext.class)
|
||||
@@ -623,20 +615,6 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||
contextChanged();
|
||||
}
|
||||
|
||||
private void activatedExportView(ActionContext context) {
|
||||
if (current.getView() == null) {
|
||||
return;
|
||||
}
|
||||
// Avoid odd race conditions by fixing the snap
|
||||
TraceProgramView fixed = current.getView() instanceof TraceVariableSnapProgramView
|
||||
? current.getTrace().getFixedProgramView(current.getSnap())
|
||||
: current.getView();
|
||||
|
||||
ExporterDialog dialog =
|
||||
new ExporterDialog(tool, fixed.getDomainFile(), fixed, getSelection());
|
||||
tool.showDialog(dialog);
|
||||
}
|
||||
|
||||
private void activatedOpenProgram(DebuggerOpenProgramActionContext context) {
|
||||
programManager.openProgram(context.getDomainFile(), DomainFile.DEFAULT_VERSION,
|
||||
ProgramManager.OPEN_CURRENT);
|
||||
|
||||
+2
-2
@@ -148,7 +148,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||
protected DockingAction actionGoTo;
|
||||
protected FollowsCurrentThreadAction actionFollowsCurrentThread;
|
||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoReadMemory;
|
||||
protected DockingAction actionCaptureSelectedMemory;
|
||||
protected DockingAction actionReadSelectedMemory;
|
||||
protected MultiStateDockingAction<LocationTrackingSpec> actionTrackLocation;
|
||||
|
||||
protected ForMemoryBytesGoToTrait goToTrait;
|
||||
@@ -257,7 +257,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||
actionGoTo = goToTrait.installAction();
|
||||
actionTrackLocation = trackingTrait.installAction();
|
||||
actionAutoReadMemory = readsMemTrait.installAutoReadAction();
|
||||
actionCaptureSelectedMemory = readsMemTrait.installCaptureSelectedAction();
|
||||
actionReadSelectedMemory = readsMemTrait.installReadSelectedAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utilities.util.IDHashed;
|
||||
|
||||
interface LogicalBreakpointInternal extends LogicalBreakpoint {
|
||||
public interface LogicalBreakpointInternal extends LogicalBreakpoint {
|
||||
public static class ProgramBreakpoint {
|
||||
public static Set<TraceBreakpointKind> kindsFromBookmark(Bookmark mark) {
|
||||
String[] parts = mark.getCategory().split(";");
|
||||
|
||||
+31
-26
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.service.emulation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.ShiftAndAddressSetView;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
@@ -78,40 +79,44 @@ public class ReadsTargetMemoryPcodeExecutorState
|
||||
DebuggerStaticMappingService mappingService =
|
||||
tool.getService(DebuggerStaticMappingService.class);
|
||||
byte[] data = new byte[4096];
|
||||
for (Entry<Program, ShiftAndAddressSetView> ent : mappingService
|
||||
for (Entry<Program, Collection<MappedAddressRange>> ent : mappingService
|
||||
.getOpenMappedViews(trace, unknown, snap)
|
||||
.entrySet()) {
|
||||
Program program = ent.getKey();
|
||||
ShiftAndAddressSetView shifted = ent.getValue();
|
||||
long shift = shifted.getShift();
|
||||
Memory memory = program.getMemory();
|
||||
AddressSetView initialized = memory.getLoadedAndInitializedAddressSet();
|
||||
AddressSetView toRead = shifted.getAddressSetView().intersect(initialized);
|
||||
Msg.warn(this,
|
||||
"Filling in unknown trace memory in emulator using mapped image: " +
|
||||
program + ": " + toRead);
|
||||
|
||||
for (AddressRange rng : toRead) {
|
||||
long lower = rng.getMinAddress().getOffset();
|
||||
long fullLen = rng.getLength();
|
||||
while (fullLen > 0) {
|
||||
int len = MathUtilities.unsignedMin(data.length, fullLen);
|
||||
try {
|
||||
int read =
|
||||
memory.getBytes(space.getAddress(lower), data, 0, len);
|
||||
if (read < len) {
|
||||
Msg.warn(this,
|
||||
" Partial read of " + rng + ". Got " + read + " bytes");
|
||||
Collection<MappedAddressRange> mappedSet = ent.getValue();
|
||||
for (MappedAddressRange mappedRng : mappedSet) {
|
||||
AddressRange srng = mappedRng.getSourceAddressRange();
|
||||
long shift = mappedRng.getShift();
|
||||
for (AddressRange subsrng : initialized.intersectRange(srng.getMinAddress(),
|
||||
srng.getMaxAddress())) {
|
||||
Msg.warn(this,
|
||||
"Filling in unknown trace memory in emulator using mapped image: " +
|
||||
program + ": " + subsrng);
|
||||
long lower = subsrng.getMinAddress().getOffset();
|
||||
long fullLen = subsrng.getLength();
|
||||
while (fullLen > 0) {
|
||||
int len = MathUtilities.unsignedMin(data.length, fullLen);
|
||||
try {
|
||||
int read =
|
||||
memory.getBytes(space.getAddress(lower), data, 0, len);
|
||||
if (read < len) {
|
||||
Msg.warn(this,
|
||||
" Partial read of " + subsrng + ". Got " + read +
|
||||
" bytes");
|
||||
}
|
||||
cache.putData(lower - shift, data, 0, read);
|
||||
}
|
||||
cache.putData(lower - shift, data, 0, read);
|
||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
lower += len;
|
||||
fullLen -= len;
|
||||
}
|
||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
lower += len;
|
||||
fullLen -= len;
|
||||
result = true;
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
+19
-21
@@ -283,7 +283,6 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
|
||||
private Program program;
|
||||
private AddressRange staticRange;
|
||||
private Long shift; // from static image to trace
|
||||
|
||||
public MappingEntry(TraceStaticMapping mapping) {
|
||||
this.mapping = mapping;
|
||||
@@ -309,8 +308,6 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
Address minAddr = opened.getAddressFactory().getAddress(mapping.getStaticAddress());
|
||||
Address maxAddr = addOrMax(minAddr, mapping.getLength() - 1);
|
||||
this.staticRange = new AddressRangeImpl(minAddr, maxAddr);
|
||||
this.shift = mapping.getMinTraceAddress().getOffset() -
|
||||
staticRange.getMinAddress().getOffset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -320,7 +317,6 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
if (this.program == closed) {
|
||||
this.program = null;
|
||||
this.staticRange = null;
|
||||
this.shift = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -565,7 +561,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
}
|
||||
|
||||
protected void collectOpenMappedPrograms(AddressRange rng, Range<Long> span,
|
||||
Map<Program, ShiftAndAddressSetView> result) {
|
||||
Map<Program, Collection<MappedAddressRange>> result) {
|
||||
TraceAddressSnapRange tatr = new ImmutableTraceAddressSnapRange(rng, span);
|
||||
for (Entry<TraceAddressSnapRange, MappingEntry> out : outbound.entrySet()) {
|
||||
MappingEntry me = out.getValue();
|
||||
@@ -575,16 +571,16 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
if (!out.getKey().intersects(tatr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ShiftAndAddressSetView set = result.computeIfAbsent(me.program,
|
||||
p -> new ShiftAndAddressSetView(-me.shift, new AddressSet()));
|
||||
((AddressSet) set.getAddressSetView()).add(me.mapTraceRangeToProgram(rng));
|
||||
AddressRange srcRng = out.getKey().getRange().intersect(rng);
|
||||
AddressRange dstRng = me.mapTraceRangeToProgram(rng);
|
||||
result.computeIfAbsent(me.program, p -> new TreeSet<>())
|
||||
.add(new MappedAddressRange(srcRng, dstRng));
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Program, ShiftAndAddressSetView> getOpenMappedViews(AddressSetView set,
|
||||
public Map<Program, Collection<MappedAddressRange>> getOpenMappedViews(AddressSetView set,
|
||||
Range<Long> span) {
|
||||
Map<Program, ShiftAndAddressSetView> result = new HashMap<>();
|
||||
Map<Program, Collection<MappedAddressRange>> result = new HashMap<>();
|
||||
for (AddressRange rng : set) {
|
||||
collectOpenMappedPrograms(rng, span, result);
|
||||
}
|
||||
@@ -715,7 +711,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
}
|
||||
|
||||
protected void collectOpenMappedViews(AddressRange rng,
|
||||
Map<TraceSnap, ShiftAndAddressSetView> result) {
|
||||
Map<TraceSnap, Collection<MappedAddressRange>> result) {
|
||||
for (Entry<MappingEntry, Address> inPreceeding : inbound.headMapByValue(
|
||||
rng.getMaxAddress(), true).entrySet()) {
|
||||
Address start = inPreceeding.getValue();
|
||||
@@ -726,14 +722,17 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
if (!me.isInProgramRange(rng)) {
|
||||
continue;
|
||||
}
|
||||
ShiftAndAddressSetView set = result.computeIfAbsent(me.getTraceSnap(),
|
||||
p -> new ShiftAndAddressSetView(me.shift, new AddressSet()));
|
||||
((AddressSet) set.getAddressSetView()).add(me.mapProgramRangeToTrace(rng));
|
||||
|
||||
AddressRange srcRange = me.staticRange.intersect(rng);
|
||||
AddressRange dstRange = me.mapProgramRangeToTrace(rng);
|
||||
result.computeIfAbsent(me.getTraceSnap(), p -> new TreeSet<>())
|
||||
.add(new MappedAddressRange(srcRange, dstRange));
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TraceSnap, ShiftAndAddressSetView> getOpenMappedViews(AddressSetView set) {
|
||||
Map<TraceSnap, ShiftAndAddressSetView> result = new HashMap<>();
|
||||
public Map<TraceSnap, Collection<MappedAddressRange>> getOpenMappedViews(
|
||||
AddressSetView set) {
|
||||
Map<TraceSnap, Collection<MappedAddressRange>> result = new HashMap<>();
|
||||
for (AddressRange rng : set) {
|
||||
collectOpenMappedViews(rng, result);
|
||||
}
|
||||
@@ -1219,9 +1218,8 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Program, ShiftAndAddressSetView> getOpenMappedViews(Trace trace,
|
||||
AddressSetView set,
|
||||
long snap) {
|
||||
public Map<Program, Collection<MappedAddressRange>> getOpenMappedViews(Trace trace,
|
||||
AddressSetView set, long snap) {
|
||||
InfoPerTrace info = requireTrackedInfo(trace);
|
||||
if (info == null) {
|
||||
return null;
|
||||
@@ -1230,7 +1228,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TraceSnap, ShiftAndAddressSetView> getOpenMappedViews(Program program,
|
||||
public Map<TraceSnap, Collection<MappedAddressRange>> getOpenMappedViews(Program program,
|
||||
AddressSetView set) {
|
||||
InfoPerProgram info = requireTrackedInfo(program);
|
||||
if (info == null) {
|
||||
|
||||
+128
-23
@@ -487,27 +487,38 @@ public interface DebuggerStaticMappingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* <<<<<<< HEAD A {@code (shift,view)} pair for describing sets of mapped addresses
|
||||
* A pair for describing sets of mapped addresses
|
||||
*
|
||||
* <p>
|
||||
* Note, the natural order is by the <em>destination</em> address.
|
||||
*/
|
||||
public class ShiftAndAddressSetView {
|
||||
private final long shift;
|
||||
private final AddressSetView view;
|
||||
public class MappedAddressRange implements Comparable<MappedAddressRange> {
|
||||
|
||||
public ShiftAndAddressSetView(long shift, AddressSetView view) {
|
||||
this.shift = shift;
|
||||
this.view = view;
|
||||
private final AddressRange srcRange;
|
||||
private final AddressRange dstRange;
|
||||
private final int hashCode;
|
||||
private final long shift;
|
||||
|
||||
public MappedAddressRange(AddressRange srcRange, AddressRange dstRange) {
|
||||
this.srcRange = srcRange;
|
||||
this.dstRange = dstRange;
|
||||
this.hashCode = Objects.hash(dstRange, srcRange);
|
||||
this.shift = dstRange.getMinAddress().getOffset() -
|
||||
srcRange.getMinAddress().getOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<MappedRange " + srcRange + "::" + dstRange + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shift from the source address set to this address set
|
||||
* Get the shift from the source address range to this address range
|
||||
*
|
||||
* <p>
|
||||
* The meaning depends on what returned this view. If this view is the "static" set, then
|
||||
* The meaning depends on what returned this view. If this view is the "static" range, then
|
||||
* this shift describes what was added to the offset of the "dynamic" address to get a
|
||||
* particular address in this set. Note that since not all addresses from the requested
|
||||
* source set may have been mapped, you cannot simply compare min addresses to obtain this
|
||||
* shift. To "map back" to the source address from a destination address in this set,
|
||||
* <em>subtract</em> this shift.
|
||||
* particular address in the "static" range.
|
||||
*
|
||||
* @return the shift
|
||||
*/
|
||||
@@ -516,12 +527,107 @@ public interface DebuggerStaticMappingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination address set view as mapped from the source address set
|
||||
* Map an address in the source range to the corresponding address in the destination range
|
||||
*
|
||||
* @return the address set
|
||||
* @param saddr the source address (not validated)
|
||||
* @return the destination address
|
||||
*/
|
||||
public AddressSetView getAddressSetView() {
|
||||
return view;
|
||||
public Address mapSourceToDestination(Address saddr) {
|
||||
return dstRange.getAddressSpace().getAddress(saddr.getOffset() + shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map an address in the destination range to the corresponding address in the source range
|
||||
*
|
||||
* @param daddr the destination address (not validated)
|
||||
* @return the source address
|
||||
*/
|
||||
public Address mapDestinationToSource(Address daddr) {
|
||||
return srcRange.getAddressSpace().getAddress(daddr.getOffset() - shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a sub-range of the source to the corresponding sub-range of the destination
|
||||
*
|
||||
* @param srng the source sub-range
|
||||
* @return the destination sub-range
|
||||
*/
|
||||
public AddressRange mapSourceToDestination(AddressRange srng) {
|
||||
try {
|
||||
return new AddressRangeImpl(mapSourceToDestination(srng.getMinAddress()),
|
||||
srng.getLength());
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a sub-range of the destination to the corresponding sub-range of the source
|
||||
*
|
||||
* @param drng the destination sub-range
|
||||
* @return the source sub-range
|
||||
*/
|
||||
public AddressRange mapDestinationToSource(AddressRange drng) {
|
||||
try {
|
||||
return new AddressRangeImpl(mapDestinationToSource(drng.getMinAddress()),
|
||||
drng.getLength());
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source address range
|
||||
*
|
||||
* @return the address range
|
||||
*/
|
||||
public AddressRange getSourceAddressRange() {
|
||||
return srcRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination address range
|
||||
*
|
||||
* @return the address range
|
||||
*/
|
||||
public AddressRange getDestinationAddressRange() {
|
||||
return dstRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MappedAddressRange that) {
|
||||
int c;
|
||||
c = this.dstRange.compareTo(that.dstRange);
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
c = this.srcRange.compareTo(that.srcRange);
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof MappedAddressRange)) {
|
||||
return false;
|
||||
}
|
||||
MappedAddressRange that = (MappedAddressRange) obj;
|
||||
if (!this.dstRange.equals(that.dstRange)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.srcRange.equals(that.srcRange)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,8 +676,7 @@ public interface DebuggerStaticMappingService {
|
||||
boolean truncateExisting) throws TraceConflictedMappingException;
|
||||
|
||||
/**
|
||||
* ======= >>>>>>> d694542c5 (GP-660: Put program filler back in. Need to performance test.) Add
|
||||
* several static mappings (relocations)
|
||||
* Add several static mappings (relocations)
|
||||
*
|
||||
* <p>
|
||||
* This will group the entries by trace and add each's entries in a single transaction. If any
|
||||
@@ -669,9 +774,9 @@ public interface DebuggerStaticMappingService {
|
||||
* @param trace the source trace
|
||||
* @param set the source address set
|
||||
* @param snap the source snap
|
||||
* @return a map of destination programs to corresponding computed destination address sets
|
||||
* @return a map of destination programs to corresponding computed destination address ranges
|
||||
*/
|
||||
Map<Program, ShiftAndAddressSetView> getOpenMappedViews(Trace trace,
|
||||
Map<Program, Collection<MappedAddressRange>> getOpenMappedViews(Trace trace,
|
||||
AddressSetView set, long snap);
|
||||
|
||||
/**
|
||||
@@ -679,9 +784,9 @@ public interface DebuggerStaticMappingService {
|
||||
*
|
||||
* @param program the destination program, from which we are mapping back
|
||||
* @param set the destination address set, from which we are mapping back
|
||||
* @return a map of source traces to corresponding computed source address sets
|
||||
* @return a map of source traces to corresponding computed source address ranges
|
||||
*/
|
||||
Map<TraceSnap, ShiftAndAddressSetView> getOpenMappedViews(Program program,
|
||||
Map<TraceSnap, Collection<MappedAddressRange>> getOpenMappedViews(Program program,
|
||||
AddressSetView set);
|
||||
|
||||
/**
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/* ###
|
||||
* 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.copying;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest.TestDebuggerTargetTraceMapper;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.dbg.model.TestDebuggerModelBuilder;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||
import ghidra.trace.database.module.DBTraceModuleManager;
|
||||
import ghidra.trace.model.DefaultTraceLocation;
|
||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import help.screenshot.GhidraScreenShotGenerator;
|
||||
|
||||
public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenerator {
|
||||
|
||||
ProgramManager programManager;
|
||||
DebuggerTraceManagerService traceManager;
|
||||
DebuggerModelService modelService;
|
||||
DebuggerStaticMappingServicePlugin mappingService;
|
||||
DebuggerListingPlugin listingPlugin;
|
||||
DebuggerListingProvider listingProvider;
|
||||
DebuggerCopyActionsPlugin copyPlugin;
|
||||
TestDebuggerModelBuilder mb;
|
||||
ToyDBTraceBuilder tb;
|
||||
|
||||
@Before
|
||||
public void setUpMine() throws Throwable {
|
||||
programManager = addPlugin(tool, ProgramManagerPlugin.class);
|
||||
traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class);
|
||||
modelService = addPlugin(tool, DebuggerModelServicePlugin.class);
|
||||
mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
|
||||
listingPlugin = addPlugin(tool, DebuggerListingPlugin.class);
|
||||
copyPlugin = addPlugin(tool, DebuggerCopyActionsPlugin.class);
|
||||
|
||||
listingProvider = waitForComponentProvider(DebuggerListingProvider.class);
|
||||
|
||||
mb = new TestDebuggerModelBuilder();
|
||||
mb.createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
tb = new ToyDBTraceBuilder(recorder.getTrace());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownMine() {
|
||||
tb.close();
|
||||
|
||||
if (program != null) {
|
||||
program.release(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaptureDebuggerCopyIntoProgramDialog() throws Throwable {
|
||||
long snap;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
snap = tb.trace.getTimeManager().createSnapshot("First").getKey();
|
||||
DBTraceMemoryManager mem = tb.trace.getMemoryManager();
|
||||
mem.createRegion(".text", snap, tb.range(0x55550000, 0x5555ffff),
|
||||
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE));
|
||||
mem.createRegion(".data", snap, tb.range(0x55560000, 0x5556ffff),
|
||||
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE));
|
||||
mem.createRegion("[stack]", snap, tb.range(0x00100000, 0x001fffff),
|
||||
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE));
|
||||
|
||||
DBTraceModuleManager mods = tb.trace.getModuleManager();
|
||||
|
||||
TraceModule modEcho = mods.addLoadedModule("Modules[/bin/echo]", "/bin/echo",
|
||||
tb.range(0x55550000, 0x5556ffff), snap);
|
||||
modEcho.addSection("Modules[/bin/echo].Sections[.text]", ".text",
|
||||
tb.range(0x55550000, 0x5555ffff));
|
||||
modEcho.addSection("Modules[/bin/echo].Sections[.data]", ".data",
|
||||
tb.range(0x55560000, 0x5556ffff));
|
||||
}
|
||||
|
||||
program = createDefaultProgram("echo", "Toy:BE:64:default", this);
|
||||
AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
|
||||
|
||||
try (UndoableTransaction tid = UndoableTransaction.start(program, "Add memory", true)) {
|
||||
program.setImageBase(tb.addr(stSpace, 0x00400000), true);
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000, (byte) 0,
|
||||
TaskMonitor.DUMMY, false);
|
||||
memory.createInitializedBlock(".data", tb.addr(stSpace, 0x00600000), 0x10000, (byte) 0,
|
||||
TaskMonitor.DUMMY, false);
|
||||
}
|
||||
|
||||
DomainFolder root = tool.getProject().getProjectData().getRootFolder();
|
||||
root.createFile(tb.trace.getName(), tb.trace, TaskMonitor.DUMMY);
|
||||
root.createFile(program.getName(), program, TaskMonitor.DUMMY);
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
mappingService.addMapping(
|
||||
new DefaultTraceLocation(tb.trace, null, Range.atLeast(snap), tb.addr(0x55550000)),
|
||||
new ProgramLocation(program, tb.addr(stSpace, 0x00400000)), 0x10000, true);
|
||||
mappingService.addMapping(
|
||||
new DefaultTraceLocation(tb.trace, null, Range.atLeast(snap), tb.addr(0x55560000)),
|
||||
new ProgramLocation(program, tb.addr(stSpace, 0x00600000)), 0x10000, true);
|
||||
}
|
||||
|
||||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateTrace(tb.trace);
|
||||
|
||||
programManager.openProgram(program);
|
||||
|
||||
listingProvider.requestFocus();
|
||||
waitForSwing();
|
||||
|
||||
listingProvider.setSelection(
|
||||
new ProgramSelection(tb.trace.getMemoryManager().getRegionsAddressSet(snap)));
|
||||
|
||||
waitForCondition(() -> copyPlugin.actionCopyIntoCurrentProgram.isEnabled());
|
||||
performAction(copyPlugin.actionCopyIntoCurrentProgram, false);
|
||||
DebuggerCopyIntoProgramDialog dialog =
|
||||
waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
|
||||
dialog.setRelocate(true);
|
||||
dialog.reset();
|
||||
waitForSwing();
|
||||
|
||||
captureDialog(DebuggerCopyIntoProgramDialog.class, 700, 600);
|
||||
}
|
||||
}
|
||||
+505
File diff suppressed because it is too large
Load Diff
+743
File diff suppressed because it is too large
Load Diff
+12
-12
@@ -983,11 +983,11 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
@Ignore("TODO") // Needs attention, but low priority
|
||||
public void testActionCaptureSelectedMemory() throws Exception {
|
||||
public void testActionReadSelectedMemory() throws Exception {
|
||||
byte[] data = incBlock();
|
||||
byte[] zero = new byte[data.length];
|
||||
ByteBuffer buf = ByteBuffer.allocate(data.length);
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
listingProvider.setAutoReadMemorySpec(readNone);
|
||||
|
||||
// To verify enabled requires live target
|
||||
@@ -1002,12 +1002,12 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
listingProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// Now, simulate the sequence that typically enables the action
|
||||
createTestModel();
|
||||
@@ -1024,12 +1024,12 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
// NOTE: recordTargetContainerAndOpenTrace has already activated the trace
|
||||
// Action is still disabled, because it requires a selection
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
listingProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Now, it should be enabled
|
||||
assertTrue(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertTrue(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// First check nothing captured yet
|
||||
buf.clear();
|
||||
@@ -1038,7 +1038,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
assertArrayEquals(zero, buf.array());
|
||||
|
||||
// Verify that the action performs the expected task
|
||||
performAction(listingProvider.actionCaptureSelectedMemory);
|
||||
performAction(listingProvider.actionReadSelectedMemory);
|
||||
waitForBusyTool(tool);
|
||||
waitForDomainObject(trace);
|
||||
|
||||
@@ -1053,28 +1053,28 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
// Verify that setting the memory inaccessible disables the action
|
||||
mb.testProcess1.memory.setAccessible(false);
|
||||
waitForPass(() -> assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertFalse(listingProvider.actionReadSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that setting it accessible re-enables it (assuming we still have selection)
|
||||
mb.testProcess1.memory.setAccessible(true);
|
||||
waitForPass(() -> assertTrue(listingProvider.actionCaptureSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertTrue(listingProvider.actionReadSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that moving into the past disables the action
|
||||
TraceSnapshot forced = recorder.forceSnapshot();
|
||||
waitForSwing(); // UI Wants to sync with new snap. Wait....
|
||||
traceManager.activateSnap(forced.getKey() - 1);
|
||||
waitForSwing();
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that advancing to the present enables the action (assuming a selection)
|
||||
traceManager.activateSnap(forced.getKey());
|
||||
waitForSwing();
|
||||
assertTrue(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertTrue(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that stopping the recording disables the action
|
||||
recorder.stopRecording();
|
||||
waitForSwing();
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// TODO: When resume recording is implemented, verify action is enabled with selection
|
||||
}
|
||||
|
||||
+13
-13
@@ -742,11 +742,11 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
@Test
|
||||
@Ignore("TODO") // Needs attention, but low priority
|
||||
// Accessibility listener does not seem to work
|
||||
public void testActionCaptureSelectedMemory() throws Exception {
|
||||
public void testActionReadSelectedMemory() throws Exception {
|
||||
byte[] data = incBlock();
|
||||
byte[] zero = new byte[data.length];
|
||||
ByteBuffer buf = ByteBuffer.allocate(data.length);
|
||||
assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
memBytesProvider.setAutoReadMemorySpec(readNone);
|
||||
|
||||
// To verify enabled requires live target
|
||||
@@ -761,12 +761,12 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
memBytesProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// Now, simulate the sequence that typically enables the action
|
||||
createTestModel();
|
||||
@@ -783,21 +783,21 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
|
||||
// NOTE: recordTargetContainerAndOpenTrace has already activated the trace
|
||||
// Action is still disabled, because it requires a selection
|
||||
assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
memBytesProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Now, it should be enabled
|
||||
assertTrue(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// First check nothing captured yet
|
||||
// First check nothing recorded yet
|
||||
buf.clear();
|
||||
assertEquals(data.length,
|
||||
trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf));
|
||||
assertArrayEquals(zero, buf.array());
|
||||
|
||||
// Verify that the action performs the expected task
|
||||
performAction(memBytesProvider.actionCaptureSelectedMemory);
|
||||
performAction(memBytesProvider.actionReadSelectedMemory);
|
||||
waitForBusyTool(tool);
|
||||
waitForDomainObject(trace);
|
||||
|
||||
@@ -812,28 +812,28 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
|
||||
// Verify that setting the memory inaccessible disables the action
|
||||
mb.testProcess1.memory.setAccessible(false);
|
||||
waitForPass(() -> assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that setting it accessible re-enables it (assuming we still have selection)
|
||||
mb.testProcess1.memory.setAccessible(true);
|
||||
waitForPass(() -> assertTrue(memBytesProvider.actionCaptureSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that moving into the past disables the action
|
||||
TraceSnapshot forced = recorder.forceSnapshot();
|
||||
waitForSwing(); // UI Wants to sync with new snap. Wait....
|
||||
traceManager.activateSnap(forced.getKey() - 1);
|
||||
waitForSwing();
|
||||
assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that advancing to the present enables the action (assuming a selection)
|
||||
traceManager.activateSnap(forced.getKey());
|
||||
waitForSwing();
|
||||
assertTrue(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that stopping the recording disables the action
|
||||
recorder.stopRecording();
|
||||
waitForSwing();
|
||||
assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
|
||||
// TODO: When resume recording is implemented, verify action is enabled with selection
|
||||
}
|
||||
|
||||
+37
-32
@@ -27,7 +27,7 @@ import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.ShiftAndAddressSetView;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -339,7 +339,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||
public void testAddMappingThenTranslateTraceViewToStaticEmpty() throws Exception {
|
||||
addMapping();
|
||||
|
||||
Map<Program, ShiftAndAddressSetView> views =
|
||||
Map<Program, Collection<MappedAddressRange>> views =
|
||||
mappingService.getOpenMappedViews(tb.trace, new AddressSet(), 0);
|
||||
assertTrue(views.isEmpty());
|
||||
}
|
||||
@@ -360,18 +360,19 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||
// After
|
||||
set.add(dynSpace.getAddress(0xbadbadbadL), dynSpace.getAddress(0xbadbadbadL + 0xff));
|
||||
|
||||
Map<Program, ShiftAndAddressSetView> views =
|
||||
Map<Program, Collection<MappedAddressRange>> views =
|
||||
mappingService.getOpenMappedViews(tb.trace, set, 0);
|
||||
assertEquals(1, views.size());
|
||||
ShiftAndAddressSetView shifted = views.get(program);
|
||||
assertEquals(0x100000, shifted.getShift());
|
||||
AddressSetView inStatic = shifted.getAddressSetView();
|
||||
assertEquals(3, inStatic.getNumAddressRanges());
|
||||
AddressSet expected = new AddressSet();
|
||||
expected.add(stSpace.getAddress(0x00200000), stSpace.getAddress(0x002000ff));
|
||||
expected.add(stSpace.getAddress(0x00200c0d), stSpace.getAddress(0x00200ccc));
|
||||
expected.add(stSpace.getAddress(0x00201000 - 0x100), stSpace.getAddress(0x00200fff));
|
||||
assertEquals(expected, inStatic);
|
||||
Collection<MappedAddressRange> mappedSet = views.get(program);
|
||||
|
||||
assertEquals(Set.of(
|
||||
new MappedAddressRange(tb.range(0x00100000, 0x001000ff),
|
||||
tb.range(stSpace, 0x00200000, 0x002000ff)),
|
||||
new MappedAddressRange(tb.range(0x00100c0d, 0x00100ccc),
|
||||
tb.range(stSpace, 0x00200c0d, 0x00200ccc)),
|
||||
new MappedAddressRange(tb.range(0x00100f00, 0x00100fff),
|
||||
tb.range(stSpace, 0x00200f00, 0x00200fff))),
|
||||
mappedSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -380,7 +381,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||
copyTrace();
|
||||
add2ndMapping();
|
||||
|
||||
Map<TraceSnap, ShiftAndAddressSetView> views =
|
||||
Map<TraceSnap, Collection<MappedAddressRange>> views =
|
||||
mappingService.getOpenMappedViews(program, new AddressSet());
|
||||
assertTrue(views.isEmpty());
|
||||
}
|
||||
@@ -403,30 +404,34 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||
// After
|
||||
set.add(stSpace.getAddress(0xbadbadbadL), stSpace.getAddress(0xbadbadbadL + 0xff));
|
||||
|
||||
Map<TraceSnap, ShiftAndAddressSetView> views =
|
||||
Map<TraceSnap, Collection<MappedAddressRange>> views =
|
||||
mappingService.getOpenMappedViews(program, set);
|
||||
Msg.info(this, views);
|
||||
assertEquals(2, views.size());
|
||||
ShiftAndAddressSetView shifted1 = views.get(new DefaultTraceSnap(tb.trace, 0));
|
||||
assertEquals(-0x100000, shifted1.getShift());
|
||||
AddressSetView in1st = shifted1.getAddressSetView();
|
||||
assertEquals(5, in1st.getNumAddressRanges());
|
||||
AddressSetView in2nd = views.get(new DefaultTraceSnap(copy, 0)).getAddressSetView();
|
||||
assertEquals(3, in2nd.getNumAddressRanges());
|
||||
Collection<MappedAddressRange> mappedSet1 = views.get(new DefaultTraceSnap(tb.trace, 0));
|
||||
Collection<MappedAddressRange> mappedSet2 = views.get(new DefaultTraceSnap(copy, 0));
|
||||
|
||||
AddressSet expectedIn1st = new AddressSet();
|
||||
AddressSet expectedIn2nd = new AddressSet();
|
||||
expectedIn1st.add(dynSpace.getAddress(0x00100000), dynSpace.getAddress(0x001000ff));
|
||||
expectedIn1st.add(dynSpace.getAddress(0x00100800 - 0x10),
|
||||
dynSpace.getAddress(0x00100800 + 0xf));
|
||||
expectedIn1st.add(dynSpace.getAddress(0x00101000 - 0x100), dynSpace.getAddress(0x00100fff));
|
||||
expectedIn2nd.add(expectedIn1st);
|
||||
assertEquals(Set.of(
|
||||
new MappedAddressRange(tb.range(stSpace, 0x00200000, 0x002000ff),
|
||||
tb.range(0x00100000, 0x001000ff)),
|
||||
new MappedAddressRange(tb.range(stSpace, 0x002007f0, 0x0020080f),
|
||||
tb.range(0x001007f0, 0x0010080f)),
|
||||
new MappedAddressRange(tb.range(stSpace, 0x00200f00, 0x00200fff),
|
||||
tb.range(0x00100f00, 0x00100fff)),
|
||||
new MappedAddressRange(tb.range(stSpace, 0x00200000, 0x002000ff),
|
||||
tb.range(0x00102000, 0x001020ff)),
|
||||
new MappedAddressRange(tb.range(stSpace, 0x002007f0, 0x002007ff),
|
||||
tb.range(0x001027f0, 0x001027ff))),
|
||||
mappedSet1);
|
||||
|
||||
expectedIn1st.add(dynSpace.getAddress(0x00102000), dynSpace.getAddress(0x001020ff));
|
||||
expectedIn1st.add(dynSpace.getAddress(0x00102800 - 0x10), dynSpace.getAddress(0x001027ff));
|
||||
|
||||
assertEquals(expectedIn1st, in1st);
|
||||
assertEquals(expectedIn2nd, in2nd);
|
||||
assertEquals(Set.of(
|
||||
new MappedAddressRange(tb.range(stSpace, 0x00200000, 0x002000ff),
|
||||
tb.range(0x00100000, 0x001000ff)),
|
||||
new MappedAddressRange(tb.range(stSpace, 0x002007f0, 0x0020080f),
|
||||
tb.range(0x001007f0, 0x0010080f)),
|
||||
new MappedAddressRange(tb.range(stSpace, 0x00200f00, 0x00200fff),
|
||||
tb.range(0x00100f00, 0x00100fff))),
|
||||
mappedSet2);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-3
@@ -220,9 +220,7 @@ public class DBTraceDataTypeManager extends DataTypeManagerDB
|
||||
@Override
|
||||
public DataOrganization getDataOrganization() {
|
||||
if (dataOrganization == null) {
|
||||
// TODO: Do I need to have a base compiler spec?
|
||||
dataOrganization =
|
||||
trace.getBaseLanguage().getDefaultCompilerSpec().getDataOrganization();
|
||||
dataOrganization = trace.getBaseCompilerSpec().getDataOrganization();
|
||||
}
|
||||
return dataOrganization;
|
||||
}
|
||||
|
||||
+8
-11
@@ -30,6 +30,7 @@ import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.context.DBTraceRegisterContextManager;
|
||||
import ghidra.trace.database.context.DBTraceRegisterContextSpace;
|
||||
import ghidra.trace.database.language.DBTraceGuestLanguage;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
|
||||
@@ -621,13 +622,12 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
||||
@Override
|
||||
public BigInteger getValue(Register register, boolean signed) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
DBTraceRegisterContextSpace ctxSpace =
|
||||
space.trace.getRegisterContextManager().get(space, false);
|
||||
if (ctxSpace == null) {
|
||||
DBTraceRegisterContextManager manager = space.trace.getRegisterContextManager();
|
||||
RegisterValue rv =
|
||||
manager.getValueWithDefault(getLanguage(), register, getStartSnap(), getAddress());
|
||||
if (rv == null) {
|
||||
return null;
|
||||
}
|
||||
RegisterValue rv =
|
||||
ctxSpace.getValue(getLanguage(), register, getStartSnap(), getAddress());
|
||||
return signed ? rv.getSignedValue() : rv.getUnsignedValue();
|
||||
}
|
||||
}
|
||||
@@ -635,12 +635,9 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
||||
@Override
|
||||
public RegisterValue getRegisterValue(Register register) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
DBTraceRegisterContextSpace ctxSpace =
|
||||
space.trace.getRegisterContextManager().get(space, false);
|
||||
if (ctxSpace == null) {
|
||||
return null;
|
||||
}
|
||||
return ctxSpace.getValue(getLanguage(), register, getStartSnap(), getAddress());
|
||||
DBTraceRegisterContextManager manager = space.trace.getRegisterContextManager();
|
||||
return manager.getValueWithDefault(getLanguage(), register, getStartSnap(),
|
||||
getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-25
@@ -38,6 +38,7 @@ import ghidra.trace.model.listing.TraceInstructionsView;
|
||||
import ghidra.trace.util.OverlappingObjectIterator;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -66,34 +67,9 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
||||
this.conflictCodeUnit = conflictCodeUnit;
|
||||
}
|
||||
|
||||
protected void doSetContexts(Range<Long> lifespan, Address min, Address max,
|
||||
ProcessorContextView context) {
|
||||
Language language = space.baseLanguage;
|
||||
Register contextReg = language.getContextBaseRegister();
|
||||
if (contextReg == null) {
|
||||
return;
|
||||
}
|
||||
RegisterValue newValue = context.getRegisterValue(contextReg);
|
||||
DBTraceRegisterContextManager ctxMgr = space.trace.getRegisterContextManager();
|
||||
if (Objects.equals(ctxMgr.getDefaultValue(language, contextReg, min), newValue)) {
|
||||
DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, false);
|
||||
if (ctxSpace == null) {
|
||||
return;
|
||||
}
|
||||
ctxSpace.setValue(language, null, lifespan, new AddressRangeImpl(min, max));
|
||||
return;
|
||||
}
|
||||
DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, true);
|
||||
// TODO: Do not save non-flowing context beyond???
|
||||
ctxSpace.setValue(language, newValue, lifespan, new AddressRangeImpl(min, max));
|
||||
}
|
||||
|
||||
protected Instruction doCreateInstruction(Range<Long> lifespan, Address address,
|
||||
InstructionPrototype prototype, Instruction protoInstr) {
|
||||
try {
|
||||
doSetContexts(lifespan, address, address.addNoWrap(prototype.getLength() - 1),
|
||||
protoInstr);
|
||||
|
||||
Instruction created = doCreate(lifespan, address, prototype, protoInstr);
|
||||
// copy override settings to replacement instruction
|
||||
if (protoInstr.isFallThroughOverridden()) {
|
||||
@@ -183,6 +159,27 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
||||
super(space, space.instructionMapSpace);
|
||||
}
|
||||
|
||||
protected void doSetContexts(TraceAddressSnapRange tasr, Language language,
|
||||
ProcessorContextView context) {
|
||||
Register contextReg = language.getContextBaseRegister();
|
||||
if (contextReg == null || contextReg == Register.NO_CONTEXT) {
|
||||
return;
|
||||
}
|
||||
RegisterValue newValue = context.getRegisterValue(contextReg);
|
||||
DBTraceRegisterContextManager ctxMgr = space.trace.getRegisterContextManager();
|
||||
if (Objects.equals(ctxMgr.getDefaultValue(language, contextReg, tasr.getX1()), newValue)) {
|
||||
DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, false);
|
||||
if (ctxSpace == null) {
|
||||
return;
|
||||
}
|
||||
ctxSpace.setValue(language, null, tasr.getLifespan(), tasr.getRange());
|
||||
return;
|
||||
}
|
||||
DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, true);
|
||||
// TODO: Do not save non-flowing context beyond???
|
||||
ctxSpace.setValue(language, newValue, tasr.getLifespan(), tasr.getRange());
|
||||
}
|
||||
|
||||
protected DBTraceInstruction doCreate(Range<Long> lifespan, Address address,
|
||||
InstructionPrototype prototype, ProcessorContextView context)
|
||||
throws CodeUnitInsertionException, AddressOverflowException {
|
||||
@@ -214,6 +211,8 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
||||
throw new CodeUnitInsertionException("Code units cannot overlap");
|
||||
}
|
||||
|
||||
doSetContexts(tasr, prototype.getLanguage(), context);
|
||||
|
||||
DBTraceInstruction created = space.instructionMapSpace.put(tasr, null);
|
||||
created.set(prototype, context);
|
||||
|
||||
|
||||
+16
-8
@@ -416,25 +416,33 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||
forward)));
|
||||
}
|
||||
|
||||
protected AddressSetView getCommentAddresses(int commentType, AddressSetView addrSet) {
|
||||
return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
|
||||
s -> program.trace.getCommentAdapter()
|
||||
.getAddressSetView(Range.singleton(s), e -> e.getType() == commentType)));
|
||||
}
|
||||
|
||||
protected AddressSetView getCommentAddresses(AddressSetView addrSet) {
|
||||
return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
|
||||
s -> program.trace.getCommentAdapter()
|
||||
.getAddressSetView(Range.singleton(s))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeUnitIterator getCommentCodeUnitIterator(int commentType, AddressSetView addrSet) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return new WrappingCodeUnitIterator(
|
||||
getCodeUnitIterator(getCommentAddresses(commentType, addrSet), true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressIterator getCommentAddressIterator(int commentType, AddressSetView addrSet,
|
||||
boolean forward) {
|
||||
return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
|
||||
s -> program.trace.getCommentAdapter()
|
||||
.getAddressSetView(Range.singleton(s), e -> e.getType() == commentType)))
|
||||
.getAddresses(forward);
|
||||
return getCommentAddresses(commentType, addrSet).getAddresses(forward);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressIterator getCommentAddressIterator(AddressSetView addrSet, boolean forward) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return getCommentAddresses(addrSet).getAddresses(forward);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
-1
@@ -25,6 +25,7 @@ import javax.help.UnsupportedOperationException;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import generic.NestedIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.Variable;
|
||||
@@ -240,13 +241,22 @@ public abstract class AbstractDBTraceProgramViewReferenceManager implements Refe
|
||||
: (r1, r2) -> -r1.getFromAddress().compareTo(r2.getFromAddress());
|
||||
}
|
||||
|
||||
protected Iterator<Reference> getReferenceIteratorForSnap(long snap, Address startAddr) {
|
||||
AddressIterator addresses =
|
||||
refs.getReferenceSources(Range.singleton(snap)).getAddresses(startAddr, true);
|
||||
return NestedIterator.start(addresses, a -> {
|
||||
return refs.getReferencesFrom(snap, a).iterator();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReferenceIterator getReferenceIterator(Address startAddr) {
|
||||
if (refs(false) == null) {
|
||||
return new ReferenceIteratorAdapter(Collections.emptyIterator());
|
||||
}
|
||||
// TODO: This will fail to occlude on equal (src,dst,opIndex) keys
|
||||
return new ReferenceIteratorAdapter(
|
||||
program.viewport.mergedIterator(s -> refs.getReferencesFrom(s, startAddr).iterator(),
|
||||
program.viewport.mergedIterator(s -> getReferenceIteratorForSnap(s, startAddr),
|
||||
getReferenceFromComparator(true)));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
/**
|
||||
* Constructor for plugin that handles multi-user merge of programs.
|
||||
*
|
||||
* @param tool the tool with the active program to be merged
|
||||
* @param mergeManager the merge manager that will control the merge process
|
||||
* @param program the current program
|
||||
@@ -61,7 +62,8 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
@Override
|
||||
public MergeManagerProvider createProvider() {
|
||||
return new MergeManagerProvider(this, "Merge Programs for " + currentDomainObject.getName());
|
||||
return new MergeManagerProvider(this,
|
||||
"Merge Programs for " + currentDomainObject.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,6 +84,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
/**
|
||||
* Gets the merge manager associated with this plug-in.
|
||||
*
|
||||
* @return the merge manager
|
||||
*/
|
||||
@Override
|
||||
@@ -91,6 +94,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
/**
|
||||
* Defines and displays a component for resolving merge conflicts.
|
||||
*
|
||||
* @param component the component
|
||||
* @param componentID the identifier for this component
|
||||
*/
|
||||
@@ -101,6 +105,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
/**
|
||||
* Sets the merge description at the top of the merge tool.
|
||||
*
|
||||
* @param mergeDescription the new description
|
||||
*/
|
||||
@Override
|
||||
@@ -110,7 +115,9 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
/**
|
||||
* Sets the message below the progress meter in the current phase progress area.
|
||||
* @param progressDescription the new text message to display. If null, then the default message is displayed.
|
||||
*
|
||||
* @param progressDescription the new text message to display. If null, then the default message
|
||||
* is displayed.
|
||||
*/
|
||||
@Override
|
||||
void updateProgressDetails(String progressDescription) {
|
||||
@@ -118,7 +125,9 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the percentage of the progress meter that is filled in for the current phase progress area.
|
||||
* Sets the percentage of the progress meter that is filled in for the current phase progress
|
||||
* area.
|
||||
*
|
||||
* @param currentPercentProgress the percentage of the progress bar to fill in from 0 to 100.
|
||||
*/
|
||||
@Override
|
||||
@@ -135,8 +144,9 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables the Apply button at the bottom of the merge tool.
|
||||
* The Apply button is for applying conflicts.
|
||||
* Enables/disables the Apply button at the bottom of the merge tool. The Apply button is for
|
||||
* applying conflicts.
|
||||
*
|
||||
* @param state true means enable the button. false means disable it.
|
||||
*/
|
||||
@Override
|
||||
@@ -146,6 +156,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
|
||||
/**
|
||||
* Gets the provider for the merge.
|
||||
*
|
||||
* @return the provider
|
||||
*/
|
||||
@Override
|
||||
@@ -153,22 +164,27 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean closeOtherPrograms(boolean ignoreChanges) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean closeAllPrograms(boolean ignoreChanges) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean closeProgram() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean closeProgram(Program program, boolean ignoreChanges) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program[] getAllOpenPrograms() {
|
||||
ProgramMultiUserMergeManager programMergeManager =
|
||||
(ProgramMultiUserMergeManager) mergeManager;
|
||||
@@ -178,10 +194,12 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
programMergeManager.getProgram(MergeConstants.ORIGINAL) };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program getCurrentProgram() {
|
||||
return (Program) currentDomainObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program getProgram(Address addr) {
|
||||
return null;
|
||||
}
|
||||
@@ -190,6 +208,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(Program program) {
|
||||
return false;
|
||||
}
|
||||
@@ -199,6 +218,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program openProgram(DomainFile domainFile) {
|
||||
return null;
|
||||
}
|
||||
@@ -208,29 +228,53 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program openProgram(DomainFile df, int version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program openProgram(DomainFile domainFile, int version, int state) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openProgram(Program program) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openProgram(Program program, boolean current) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openProgram(Program program, int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseProgram(Program program, Object persistentOwner) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram(Program program) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs(Program program) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentProgram(Program p) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPersistentOwner(Program program, Object owner) {
|
||||
return false;
|
||||
}
|
||||
@@ -238,10 +282,12 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
|
||||
public void setSearchPriority(Program p, int priority) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockDown(boolean state) {
|
||||
}
|
||||
}
|
||||
|
||||
+27
-17
@@ -102,8 +102,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||
/**
|
||||
* Method called if the plugin supports this domain file.
|
||||
*
|
||||
* @param data
|
||||
* the data to be used by the running tool
|
||||
* @param data the data to be used by the running tool
|
||||
* @return false if data is not a Program object.
|
||||
*/
|
||||
@Override
|
||||
@@ -447,9 +446,9 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method notifies listening plugins that a programs has been added to
|
||||
* the program manager. This is not used for actually opening a program from
|
||||
* the database and will act strangely if given a closed Program object.
|
||||
* This method notifies listening plugins that a programs has been added to the program manager.
|
||||
* This is not used for actually opening a program from the database and will act strangely if
|
||||
* given a closed Program object.
|
||||
*
|
||||
* @see ghidra.app.services.ProgramManager#openProgram(ghidra.program.model.listing.Program)
|
||||
*/
|
||||
@@ -585,7 +584,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||
/**
|
||||
* Set the string chooser property editor on the property that is a filename.
|
||||
*
|
||||
* @param options property list
|
||||
* @param options property list
|
||||
* @param filePropertyName name of the property that is a filename
|
||||
*/
|
||||
private void setPropertyEditor(Options options, String filePropertyName) {
|
||||
@@ -597,8 +596,8 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a transaction if one has not been started; needed when program
|
||||
* properties are about to change from the options editor.
|
||||
* Start a transaction if one has not been started; needed when program properties are about to
|
||||
* change from the options editor.
|
||||
*/
|
||||
private void startTransaction(Program currentProgram) {
|
||||
if (transactionID < 0) {
|
||||
@@ -685,6 +684,26 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||
return openProgram;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram() {
|
||||
saveProgram(getCurrentProgram());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram(Program program) {
|
||||
Swing.runIfSwingOrRunLater(() -> programSaveMgr.saveProgram(program));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs() {
|
||||
saveProgramAs(getCurrentProgram());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs(Program program) {
|
||||
Swing.runIfSwingOrRunLater(() -> programSaveMgr.saveAs(program));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out my data state.
|
||||
*/
|
||||
@@ -1040,13 +1059,4 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||
public boolean isManaged(Program program) {
|
||||
return programMgr.contains(program);
|
||||
}
|
||||
|
||||
public void saveProgram(Program program) {
|
||||
programSaveMgr.saveProgram(program);
|
||||
}
|
||||
|
||||
public void saveProgramAs(Program program) {
|
||||
programSaveMgr.saveAs(program);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,16 +26,17 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* Service for managing programs. Multiple programs may be open in a tool, but only one is active
|
||||
* at any given time.
|
||||
* Service for managing programs. Multiple programs may be open in a tool, but only one is active at
|
||||
* any given time.
|
||||
*/
|
||||
@ServiceInfo(defaultProvider = ProgramManagerPlugin.class, description = "Get the currently open program")
|
||||
@ServiceInfo(
|
||||
defaultProvider = ProgramManagerPlugin.class,
|
||||
description = "Get the currently open program")
|
||||
public interface ProgramManager {
|
||||
|
||||
/**
|
||||
* Program will be open in a Hidden state if not already open.
|
||||
* This mode is generally used in conjunction with a persistent
|
||||
* program owner.
|
||||
* Program will be open in a Hidden state if not already open. This mode is generally used in
|
||||
* conjunction with a persistent program owner.
|
||||
*/
|
||||
public static final int OPEN_HIDDEN = 0;
|
||||
|
||||
@@ -45,20 +46,21 @@ public interface ProgramManager {
|
||||
public static final int OPEN_CURRENT = 1;
|
||||
|
||||
/**
|
||||
* Program will be open within the tool but no change will be made
|
||||
* to the currently active program. If this is the only program
|
||||
* open, it will become the currently active program.
|
||||
* Program will be open within the tool but no change will be made to the currently active
|
||||
* program. If this is the only program open, it will become the currently active program.
|
||||
*/
|
||||
public static final int OPEN_VISIBLE = 2;
|
||||
|
||||
/**
|
||||
* Return the program that is currently active.
|
||||
*
|
||||
* @return may return null if no program is open
|
||||
*/
|
||||
public Program getCurrentProgram();
|
||||
|
||||
/**
|
||||
* Returns true if the specified program is open and considered visible to the user.
|
||||
*
|
||||
* @param program the program
|
||||
* @return true if the specified program is open and considered visible to the user
|
||||
*/
|
||||
@@ -66,47 +68,51 @@ public interface ProgramManager {
|
||||
|
||||
/**
|
||||
* Closes the currently active program
|
||||
* @return true if the close is successful.
|
||||
* false if the close fails or if there is no program currently active.
|
||||
*
|
||||
* @return true if the close is successful. false if the close fails or if there is no program
|
||||
* currently active.
|
||||
*/
|
||||
public boolean closeProgram();
|
||||
|
||||
/**
|
||||
* Open the program corresponding to the given url.
|
||||
* Open the program corresponding to the given url.
|
||||
*
|
||||
* @param ghidraURL valid server-based program URL
|
||||
* @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE).
|
||||
* The visibility states will be ignored if the program is already open.
|
||||
* @return null if the user canceled the "open" for the new program or an error
|
||||
* occurred and was displayed.
|
||||
* @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE). The visibility
|
||||
* states will be ignored if the program is already open.
|
||||
* @return null if the user canceled the "open" for the new program or an error occurred and was
|
||||
* displayed.
|
||||
* @see GhidraURL
|
||||
*/
|
||||
public Program openProgram(URL ghidraURL, int state);
|
||||
|
||||
/**
|
||||
* Open the program for the given domainFile. Once open it will
|
||||
* become the active program.
|
||||
* Open the program for the given domainFile. Once open it will become the active program.
|
||||
*
|
||||
* @param domainFile domain file that has the program
|
||||
* @return null if the user canceled the "open" for the new program
|
||||
*/
|
||||
public Program openProgram(DomainFile domainFile);
|
||||
|
||||
/**
|
||||
* Open the program for the given domainFile. Once open it will become the active program.
|
||||
* Open the program for the given domainFile. Once open it will become the active program.
|
||||
*
|
||||
* <P>Note: this method functions exactly as {@link #openProgram(DomainFile)}
|
||||
* <P>
|
||||
* Note: this method functions exactly as {@link #openProgram(DomainFile)}
|
||||
*
|
||||
* @param domainFile domain file that has the program
|
||||
* @param dialogParent unused
|
||||
* @return the program
|
||||
* @deprecated deprecated for 10.1; removal for 10.3 or later; use {@link #openProgram(DomainFile)}
|
||||
* @deprecated deprecated for 10.1; removal for 10.3 or later; use
|
||||
* {@link #openProgram(DomainFile)}
|
||||
*/
|
||||
@Deprecated
|
||||
public Program openProgram(DomainFile domainFile, Component dialogParent);
|
||||
|
||||
/**
|
||||
* Opens the specified version of the program represented by the given DomainFile. This
|
||||
* method should be used for shared DomainFiles. The newly opened file will be made the
|
||||
* active program.
|
||||
* Opens the specified version of the program represented by the given DomainFile. This method
|
||||
* should be used for shared DomainFiles. The newly opened file will be made the active program.
|
||||
*
|
||||
* @param df the DomainFile to open
|
||||
* @param version the version of the Program to open
|
||||
* @return the opened program or null if the given version does not exist.
|
||||
@@ -115,29 +121,32 @@ public interface ProgramManager {
|
||||
|
||||
/**
|
||||
* Open the program for the given domainFile
|
||||
*
|
||||
* @param domainFile domain file that has the program
|
||||
* @param version the version of the Program to open. Specify
|
||||
* DomainFile.DEFAULT_VERSION for file update mode.
|
||||
* @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE).
|
||||
* The visibility states will be ignored if the program is already open.
|
||||
* @return null if the user canceled the "open" for the new program or an error
|
||||
* occurred and was displayed.
|
||||
* @param version the version of the Program to open. Specify DomainFile.DEFAULT_VERSION for
|
||||
* file update mode.
|
||||
* @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE). The visibility
|
||||
* states will be ignored if the program is already open.
|
||||
* @return null if the user canceled the "open" for the new program or an error occurred and was
|
||||
* displayed.
|
||||
*/
|
||||
public Program openProgram(DomainFile domainFile, int version, int state);
|
||||
|
||||
/**
|
||||
* Opens the program to the tool. In this case the program is already open, but this tool
|
||||
* may not have it registered as open. The program is made the active program.
|
||||
* Opens the program to the tool. In this case the program is already open, but this tool may
|
||||
* not have it registered as open. The program is made the active program.
|
||||
*
|
||||
* @param program the program to register as open with the tool.
|
||||
*/
|
||||
public void openProgram(Program program);
|
||||
|
||||
/**
|
||||
* Opens the program to the tool. In this case the program is already open, but this tool
|
||||
* may not have it registered as open. The program is made the active program.
|
||||
* Opens the program to the tool. In this case the program is already open, but this tool may
|
||||
* not have it registered as open. The program is made the active program.
|
||||
*
|
||||
* @param program the program to register as open with the tool.
|
||||
* @param current if true, the program is made the current active program. If false, then
|
||||
* the program is made active only if it the first open program in the tool.
|
||||
* @param current if true, the program is made the current active program. If false, then the
|
||||
* program is made active only if it the first open program in the tool.
|
||||
* @deprecated use openProgram(Program program, int state) instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -145,19 +154,45 @@ public interface ProgramManager {
|
||||
|
||||
/**
|
||||
* Open the specified program in the tool.
|
||||
*
|
||||
* @param program the program
|
||||
* @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE).
|
||||
* The visibility states will be ignored if the program is already open.
|
||||
* @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE). The visibility
|
||||
* states will be ignored if the program is already open.
|
||||
*/
|
||||
public void openProgram(Program program, int state);
|
||||
|
||||
/**
|
||||
* Establish a persistent owner on an open program. This will cause the program manager to
|
||||
* imply make a program hidden if it is closed.
|
||||
* Saves the current program, possibly prompting the user for a new name.
|
||||
*/
|
||||
public void saveProgram();
|
||||
|
||||
/**
|
||||
* Saves the specified program, possibly prompting the user for a new name.
|
||||
*
|
||||
* @param program the program
|
||||
*/
|
||||
public void saveProgram(Program program);
|
||||
|
||||
/**
|
||||
* Prompts the user to save the current program to a selected file.
|
||||
*/
|
||||
public void saveProgramAs();
|
||||
|
||||
/**
|
||||
* Prompts the user to save the specified program to a selected file.
|
||||
*
|
||||
* @param program the program
|
||||
*/
|
||||
public void saveProgramAs(Program program);
|
||||
|
||||
/**
|
||||
* Establish a persistent owner on an open program. This will cause the program manager to imply
|
||||
* make a program hidden if it is closed.
|
||||
*
|
||||
* @param program the program
|
||||
* @param owner the owner
|
||||
* @return true if program is open and another object is not already the owner,
|
||||
* or the specified owner is already the owner.
|
||||
* @return true if program is open and another object is not already the owner, or the specified
|
||||
* owner is already the owner.
|
||||
* @see #releaseProgram(Program, Object)
|
||||
*/
|
||||
public boolean setPersistentOwner(Program program, Object owner);
|
||||
@@ -165,62 +200,67 @@ public interface ProgramManager {
|
||||
/**
|
||||
* Release the persistent ownership of a program.
|
||||
* <p>
|
||||
* The program will automatically be closed if it is hidden or was marked as temporary. If
|
||||
* any of these closures corresponds to a program with changes the user will be given an
|
||||
* opportunity to save or keep the program open.
|
||||
* The program will automatically be closed if it is hidden or was marked as temporary. If any
|
||||
* of these closures corresponds to a program with changes the user will be given an opportunity
|
||||
* to save or keep the program open.
|
||||
* <p>
|
||||
* If persistentOwner is not the correct owner, the method will have no affect.
|
||||
*
|
||||
* @param program the program
|
||||
* @param persistentOwner the owner defined by {@link #setPersistentOwner(Program, Object)}
|
||||
*/
|
||||
public void releaseProgram(Program program, Object persistentOwner);
|
||||
|
||||
/**
|
||||
* Closes the given program with the option of saving any changes. The exact behavior of
|
||||
* this method depends on several factors. First of all, if any other tool has this program
|
||||
* open, then the program is closed for this tool only and the user is not prompted to
|
||||
* save the program regardless of the ignoreChanges flag. Otherwise, if ignoreChanges is
|
||||
* false and changes have been made, the user is prompted to save the program.
|
||||
* Closes the given program with the option of saving any changes. The exact behavior of this
|
||||
* method depends on several factors. First of all, if any other tool has this program open,
|
||||
* then the program is closed for this tool only and the user is not prompted to save the
|
||||
* program regardless of the ignoreChanges flag. Otherwise, if ignoreChanges is false and
|
||||
* changes have been made, the user is prompted to save the program.
|
||||
*
|
||||
* @param program the program to close.
|
||||
* @param ignoreChanges if true, the program is closed without saving any changes.
|
||||
* @return true if the program was closed. Returns false if the user canceled the close
|
||||
* while being prompted to save. Also returns false if the program passed in as a parameter
|
||||
* is null.
|
||||
* @return true if the program was closed. Returns false if the user canceled the close while
|
||||
* being prompted to save. Also returns false if the program passed in as a parameter is
|
||||
* null.
|
||||
*/
|
||||
boolean closeProgram(Program program, boolean ignoreChanges);
|
||||
|
||||
/**
|
||||
* Closes all open programs in this tool except the current program.
|
||||
* If this tool is the only tool with a program open and that program has changes,
|
||||
* then the user will be prompted to close each such file.
|
||||
* (Providing the ignoreChanges flag is false)
|
||||
* Closes all open programs in this tool except the current program. If this tool is the only
|
||||
* tool with a program open and that program has changes, then the user will be prompted to
|
||||
* close each such file. (Providing the ignoreChanges flag is false)
|
||||
*
|
||||
* @param ignoreChanges if true, the programs will be closed without saving changes.
|
||||
* @return true if all other programs were closed. Returns false if the user canceled the close
|
||||
* while being prompted to save.
|
||||
* while being prompted to save.
|
||||
*/
|
||||
public boolean closeOtherPrograms(boolean ignoreChanges);
|
||||
|
||||
/**
|
||||
* Closes all open programs in this tool. If this tool is the only tool with a program
|
||||
* open and that program has changes, then the user will be prompted to close each such file.
|
||||
* (Providing the ignoreChanges flag is false)
|
||||
* Closes all open programs in this tool. If this tool is the only tool with a program open and
|
||||
* that program has changes, then the user will be prompted to close each such file. (Providing
|
||||
* the ignoreChanges flag is false)
|
||||
*
|
||||
* @param ignoreChanges if true, the programs will be closed without saving changes.
|
||||
* @return true if all programs were closed. Returns false if the user canceled the close
|
||||
* while being prompted to save.
|
||||
* @return true if all programs were closed. Returns false if the user canceled the close while
|
||||
* being prompted to save.
|
||||
*/
|
||||
public boolean closeAllPrograms(boolean ignoreChanges);
|
||||
|
||||
/**
|
||||
* Sets the given program to be the current active program in the tool.
|
||||
*
|
||||
* @param p the program to make active.
|
||||
*/
|
||||
public void setCurrentProgram(Program p);
|
||||
|
||||
/**
|
||||
* Returns the first program in the list of open programs that contains the given address.
|
||||
* Programs are searched in the order they were opened within a given priority.
|
||||
* Program are initially opened with the PRIORITY_NORMAL priority, but can be set to have
|
||||
* PRIORITY_HIGH or PRIORITY_LOW.
|
||||
* Programs are searched in the order they were opened within a given priority. Program are
|
||||
* initially opened with the PRIORITY_NORMAL priority, but can be set to have PRIORITY_HIGH or
|
||||
* PRIORITY_LOW.
|
||||
*
|
||||
* @param addr the address for which to search.
|
||||
* @return the first program that can be found to contain the given address.
|
||||
*/
|
||||
@@ -228,13 +268,15 @@ public interface ProgramManager {
|
||||
|
||||
/**
|
||||
* Returns a list of all open program.
|
||||
*
|
||||
* @return the programs
|
||||
*/
|
||||
public Program[] getAllOpenPrograms();
|
||||
|
||||
/**
|
||||
* Allows program manager state to be locked/unlocked. While locked, the program manager will
|
||||
* Allows program manager state to be locked/unlocked. While locked, the program manager will
|
||||
* not support opening additional programs.
|
||||
*
|
||||
* @param state locked if true, unlocked if false
|
||||
* @deprecated deprecated for 10.1; removal for 10.3 or later
|
||||
*/
|
||||
@@ -243,6 +285,7 @@ public interface ProgramManager {
|
||||
|
||||
/**
|
||||
* Returns true if program manager is in the locked state
|
||||
*
|
||||
* @return true if program manager is in the locked state
|
||||
* @deprecated deprecated for 10.1; removal for 10.3 or later
|
||||
*/
|
||||
|
||||
+22
-2
@@ -23,8 +23,8 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* A stub of the {@link ProgramManager} interface. This can be used to supply a test program
|
||||
* manager or to spy on system internals by overriding methods as needed.
|
||||
* A stub of the {@link ProgramManager} interface. This can be used to supply a test program manager
|
||||
* or to spy on system internals by overriding methods as needed.
|
||||
*/
|
||||
public class TestDummyProgramManager implements ProgramManager {
|
||||
|
||||
@@ -91,6 +91,26 @@ public class TestDummyProgramManager implements ProgramManager {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram() {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram(Program program) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs() {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs(Program program) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPersistentOwner(Program program, Object owner) {
|
||||
// stub
|
||||
|
||||
+22
-2
@@ -24,8 +24,8 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* A stubbed {@link ProgramManager} that used the 'second program' at the current program. This
|
||||
* is used to secondary views in order to install the right program.
|
||||
* A stubbed {@link ProgramManager} that used the 'second program' at the current program. This is
|
||||
* used to secondary views in order to install the right program.
|
||||
*/
|
||||
public class DiffProgramManager implements ProgramManager {
|
||||
ProgramDiffPlugin programDiffPlugin;
|
||||
@@ -119,6 +119,26 @@ public class DiffProgramManager implements ProgramManager {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram() {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgram(Program program) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs() {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProgramAs(Program program) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentProgram(Program p) {
|
||||
// stub
|
||||
|
||||
+6
-5
@@ -49,7 +49,6 @@ public class SleighAssembler implements Assembler {
|
||||
protected Program program;
|
||||
protected Listing listing;
|
||||
protected Memory memory;
|
||||
protected Disassembler dis;
|
||||
protected AssemblyParser parser;
|
||||
protected AssemblyDefaultContext defaultContext;
|
||||
protected AssemblyContextGraph ctxGraph;
|
||||
@@ -71,8 +70,6 @@ public class SleighAssembler implements Assembler {
|
||||
|
||||
this.listing = program.getListing();
|
||||
this.memory = program.getMemory();
|
||||
this.dis = Disassembler.getDisassembler(program, TaskMonitor.DUMMY,
|
||||
DisassemblerMessageListener.IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,8 +110,12 @@ public class SleighAssembler implements Assembler {
|
||||
Address end = at.add(insbytes.length - 1);
|
||||
listing.clearCodeUnits(at, end, false);
|
||||
memory.setBytes(at, insbytes);
|
||||
dis.disassemble(at, new AddressSet(at));
|
||||
return listing.getInstructions(new AddressSet(at, end), true);
|
||||
AddressSet set = new AddressSet(at, end);
|
||||
// Creating this at construction causes it to assess memory flags too early.
|
||||
Disassembler dis = Disassembler.getDisassembler(program, TaskMonitor.DUMMY,
|
||||
DisassemblerMessageListener.IGNORE);
|
||||
dis.disassemble(at, set);
|
||||
return listing.getInstructions(set, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+34
-25
@@ -46,9 +46,10 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
|
||||
/**
|
||||
* Build a new SLEIGH constructor semantic
|
||||
*
|
||||
* @param cons the SLEIGH constructor
|
||||
* @param indices the indices of RHS non-terminals in the associated production that represent an
|
||||
* operand in the SLEIGH constructor
|
||||
* @param indices the indices of RHS non-terminals in the associated production that represent
|
||||
* an operand in the SLEIGH constructor
|
||||
*/
|
||||
public AssemblyConstructorSemantic(Constructor cons, List<Integer> indices) {
|
||||
this.cons = cons;
|
||||
@@ -73,6 +74,7 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
|
||||
/**
|
||||
* Get the SLEIGH constructor
|
||||
*
|
||||
* @return the constructor
|
||||
*/
|
||||
public Constructor getConstructor() {
|
||||
@@ -81,6 +83,7 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
|
||||
/**
|
||||
* Get the associated encoding patterns for the constructor
|
||||
*
|
||||
* @return the patterns
|
||||
*/
|
||||
public Collection<AssemblyResolvedConstructor> getPatterns() {
|
||||
@@ -92,6 +95,7 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
|
||||
/**
|
||||
* Convert the index of a print piece to its associated operand index
|
||||
*
|
||||
* @param printpos position excluding whitespace and string tokens.
|
||||
* @return the operand index
|
||||
*/
|
||||
@@ -101,6 +105,7 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
|
||||
/**
|
||||
* Get the list of operand indices in print piece order
|
||||
*
|
||||
* @return the list
|
||||
*/
|
||||
public List<Integer> getOperandIndices() {
|
||||
@@ -111,8 +116,9 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
* Get an iterator over the operand indices
|
||||
*
|
||||
* If this iterator is advanced for each non-terminal, while simultaneously iterating over the
|
||||
* RHS of the associated production, then this will identify the corresponding operand index
|
||||
* for each non-terminal
|
||||
* RHS of the associated production, then this will identify the corresponding operand index for
|
||||
* each non-terminal
|
||||
*
|
||||
* @return the iterator
|
||||
*/
|
||||
public Iterator<Integer> getOperandIndexIterator() {
|
||||
@@ -142,17 +148,17 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
* than ("specializes") another, i.e., it matches on more bits than another pattern, the more
|
||||
* specific pattern is chosen. Second, if the two are equally special, then the one that occurs
|
||||
* first in the SLEIGH specification is taken. So, during resolution, if a less-special or
|
||||
* later-occurring constructor is chosen, we must prevent continued resolution from matching
|
||||
* the more-special or earlier-occurring pattern(s).
|
||||
* later-occurring constructor is chosen, we must prevent continued resolution from matching the
|
||||
* more-special or earlier-occurring pattern(s).
|
||||
*
|
||||
* Essentially, this states, "you may choose any value matching my pattern, except those that
|
||||
* match these forbidden patterns."
|
||||
*
|
||||
* This takes a given pattern, and searches the rest of the language for any patterns that
|
||||
* would take precedence, and combines them as forbidden patterns with the given pattern.
|
||||
* This takes a given pattern, and searches the rest of the language for any patterns that would
|
||||
* take precedence, and combines them as forbidden patterns with the given pattern.
|
||||
*
|
||||
* @param pat the given pattern
|
||||
* @return the same pattern with forbidden records added
|
||||
* @return the same pattern with forbidden records added
|
||||
*/
|
||||
protected AssemblyResolvedConstructor withComputedForbids(AssemblyResolvedConstructor pat) {
|
||||
// Forbid anything more specific (or otherwise takes precedence) over me.
|
||||
@@ -194,7 +200,7 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
// OK, they overlap. Let's see if its a strict subset
|
||||
if (comb.bitsEqual(sibpat)) {
|
||||
forbids.add(sibpat.withDescription(
|
||||
cons + " forbids " + sibcons + " by pattern specificity"));
|
||||
sibcons + " forbids " + cons + " by pattern specificity"));
|
||||
return CONTINUE;
|
||||
}
|
||||
else if (comb.bitsEqual(pat)) {
|
||||
@@ -205,7 +211,7 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
// Finally, check the line number
|
||||
if (sibcons.getId() < cons.getId()) {
|
||||
forbids.add(
|
||||
sibpat.withDescription(cons + " forbids " + sibcons + " by rule position"));
|
||||
sibpat.withDescription(sibcons + " forbids " + cons + " by rule position"));
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@@ -219,22 +225,24 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
|
||||
/**
|
||||
* Solve this constructor's context changes
|
||||
*
|
||||
* @param res the combined resolution requirements derived from the subconstructors
|
||||
* @param vals any defined symbols (usually {@code inst_start}, and {@code inst_next})
|
||||
* @param opvals a map from operand index to operand value
|
||||
* @return the resolution with context changes applied in reverse, or an error
|
||||
*
|
||||
* Each value in {@code opvals} must either be a numeric value, e.g., an index from a varnode
|
||||
* list, or another {@link AssemblyResolvedConstructor} for a subconstructor operand.
|
||||
* Each value in {@code opvals} must either be a numeric value, e.g., an index from a
|
||||
* varnode list, or another {@link AssemblyResolvedConstructor} for a subconstructor
|
||||
* operand.
|
||||
*
|
||||
* It's helpful to think of the SLEIGH disassembly process here. Normally, once the appropriate
|
||||
* constructor has been identified (by matching patterns), its context changes are applied, and
|
||||
* then its operands parsed (possibly parsing subconstructor operands). Thus, {@code res} can
|
||||
* be thought of as the intermediate result between applying context changes and parsing
|
||||
* operands, except in reverse. The output of this method corresponds to the state before
|
||||
* context changes were applied, i.e., immediately after selecting the constructor. Thus, in
|
||||
* reverse, the context is solved immediately before applying the selected constructor
|
||||
* patterns.
|
||||
* It's helpful to think of the SLEIGH disassembly process here. Normally, once the
|
||||
* appropriate constructor has been identified (by matching patterns), its context
|
||||
* changes are applied, and then its operands parsed (possibly parsing subconstructor
|
||||
* operands). Thus, {@code res} can be thought of as the intermediate result between
|
||||
* applying context changes and parsing operands, except in reverse. The output of this
|
||||
* method corresponds to the state before context changes were applied, i.e.,
|
||||
* immediately after selecting the constructor. Thus, in reverse, the context is solved
|
||||
* immediately before applying the selected constructor patterns.
|
||||
*
|
||||
* @see AssemblyTreeResolver#resolveSelectedChildren(AssemblyProduction, List, List, Collection)
|
||||
*/
|
||||
@@ -300,10 +308,11 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||
* @param outer the state before context changes
|
||||
* @return the state after context changes
|
||||
*
|
||||
* Unlike the usual disassembly process, this method does not take into account any information
|
||||
* from the instruction encoding. Any context bits that depend on it are set to unknown
|
||||
* ({@code x}) in the output. This method is used to pre-compute a context transition graph in
|
||||
* order to quickly resolve purely-recursive semantics on the root constructor table.
|
||||
* Unlike the usual disassembly process, this method does not take into account any
|
||||
* information from the instruction encoding. Any context bits that depend on it are set
|
||||
* to unknown ({@code x}) in the output. This method is used to pre-compute a context
|
||||
* transition graph in order to quickly resolve purely-recursive semantics on the root
|
||||
* constructor table.
|
||||
*/
|
||||
public AssemblyResolvedConstructor applyForward(AssemblyResolvedConstructor outer) {
|
||||
AssemblyResolvedConstructor res = outer;
|
||||
|
||||
+45
-39
@@ -75,6 +75,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
|
||||
/**
|
||||
* Constructs a new MemoryMapDB
|
||||
*
|
||||
* @param handle the open database handle.
|
||||
* @param addrMap the address map.
|
||||
* @param openMode the open mode for the program.
|
||||
@@ -146,14 +147,16 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the <code>allInitializedAddrSet</code> and <code>initializedLoadedAddrSet</code>
|
||||
* with relevant initialized addresses from the specified memory block. If block is not
|
||||
* a mapped-block and it may be a source to existing mapped-blocks then
|
||||
* <code>scanAllMappedBlocksIfNeeded</code> should be passed as <code>true</code> unless
|
||||
* all mapped blocks will be processed separately.
|
||||
* Update the <code>allInitializedAddrSet</code> and <code>initializedLoadedAddrSet</code> with
|
||||
* relevant initialized addresses from the specified memory block. If block is not a
|
||||
* mapped-block and it may be a source to existing mapped-blocks then
|
||||
* <code>scanAllMappedBlocksIfNeeded</code> should be passed as <code>true</code> unless all
|
||||
* mapped blocks will be processed separately.
|
||||
*
|
||||
* @param block memory block
|
||||
* @param scanAllMappedBlocksIfNeeded if true and block is initialized and not a mapped block all
|
||||
* mapped blocks will be processed for possible introduction of newly initialized mapped regions.
|
||||
* @param scanAllMappedBlocksIfNeeded if true and block is initialized and not a mapped block
|
||||
* all mapped blocks will be processed for possible introduction of newly initialized
|
||||
* mapped regions.
|
||||
*/
|
||||
private void addBlockAddresses(MemoryBlockDB block, boolean scanAllMappedBlocksIfNeeded) {
|
||||
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd());
|
||||
@@ -193,11 +196,12 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update initialized address set for those mapped blocks which map onto the
|
||||
* specified block which has just completed a transition of its' initialized state.
|
||||
* Update initialized address set for those mapped blocks which map onto the specified block
|
||||
* which has just completed a transition of its' initialized state.
|
||||
*
|
||||
* @param block block whose initialized state has changed
|
||||
* @param isInitialized true if block transitioned from uninitialized to initialized,
|
||||
* else transition is from initialized to uninitialized.
|
||||
* @param isInitialized true if block transitioned from uninitialized to initialized, else
|
||||
* transition is from initialized to uninitialized.
|
||||
*/
|
||||
private void updateMappedAddresses(MemoryBlockDB block, boolean isInitialized) {
|
||||
|
||||
@@ -285,6 +289,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
|
||||
/**
|
||||
* Returns the address factory for the program.
|
||||
*
|
||||
* @return program address factory
|
||||
*/
|
||||
AddressFactory getAddressFactory() {
|
||||
@@ -293,6 +298,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
|
||||
/**
|
||||
* Returns the AddressMap from the program.
|
||||
*
|
||||
* @return program address map
|
||||
*/
|
||||
AddressMapDB getAddressMap() {
|
||||
@@ -331,7 +337,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
throw new MemoryAccessException(block.getName() + " does not contain range " +
|
||||
start.toString(true) + "-" + endAddr);
|
||||
}
|
||||
|
||||
|
||||
if (block.isMapped()) {
|
||||
checkMemoryWriteMappedBlock(block, start, endAddr);
|
||||
}
|
||||
@@ -368,7 +374,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
mappedEndAddress =
|
||||
byteMappingScheme.getMappedSourceAddress(mappedRangeMinAddr, endOffset);
|
||||
}
|
||||
|
||||
|
||||
for (MemoryBlockDB b : getBlocks(mappedStartAddress, mappedEndAddress)) {
|
||||
Address minAddr = Address.min(b.getEnd(), mappedEndAddress);
|
||||
Address maxAddr = Address.max(b.getStart(), mappedStartAddress);
|
||||
@@ -381,9 +387,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
throws MemoryAccessException {
|
||||
// TODO: could contain uninitialized region which is illegal to write to although block.isInitialized
|
||||
// may not be of much help since it reflects the first sub-block only - seems like mixing is a bad idea
|
||||
|
||||
|
||||
checkRangeForInstructions(start, endAddr);
|
||||
|
||||
|
||||
// Check all mapped-block address ranges which map onto the range to be modified
|
||||
Collection<MemoryBlockDB> mappedBlocks = nonMappedBlock.getMappedBlocks();
|
||||
if (mappedBlocks != null) {
|
||||
@@ -480,8 +486,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Two blocks have been joined producing newBlock. The block which was
|
||||
* eliminated can be identified using the oldBlockStartAddr.
|
||||
* Two blocks have been joined producing newBlock. The block which was eliminated can be
|
||||
* identified using the oldBlockStartAddr.
|
||||
*
|
||||
* @param newBlock new joined memory block
|
||||
* @param oldBlockStartAddr original start address of affected block
|
||||
*/
|
||||
@@ -798,6 +805,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
|
||||
/**
|
||||
* Check new block name for validity
|
||||
*
|
||||
* @param name new block name
|
||||
* @throws IllegalArgumentException if invalid block name specified
|
||||
*/
|
||||
@@ -1246,25 +1254,19 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the memory contains a sequence of contiguous bytes that match the
|
||||
* given byte array at all bit positions where the mask contains an "on" bit.
|
||||
* The test will be something like
|
||||
* Tests if the memory contains a sequence of contiguous bytes that match the given byte array
|
||||
* at all bit positions where the mask contains an "on" bit. The test will be something like
|
||||
*
|
||||
* for(int i=0;i<bytes.length;i++) {
|
||||
* if (bytes[i] != memory.getByte(addr+i) & masks[i]) {
|
||||
* return false;
|
||||
* }
|
||||
* }
|
||||
* return false;
|
||||
* for(int i=0;i<bytes.length;i++) { if (bytes[i] != memory.getByte(addr+i) & masks[i]) {
|
||||
* return false; } } return false;
|
||||
*
|
||||
* @param addr The beginning address in memory to test against.
|
||||
* @param bytes the array of bytes to test for.
|
||||
* @param masks the array of masks. (One for each byte in the byte array)
|
||||
* @param forward if true, the matching is going forward, otherwise backward
|
||||
*
|
||||
* @return 1 if there is a match
|
||||
* 0 if there is no match
|
||||
* -i if no match is found, this is the number of bytes that can be safely skipped
|
||||
* @return 1 if there is a match 0 if there is no match -i if no match is found, this is the
|
||||
* number of bytes that can be safely skipped
|
||||
*/
|
||||
private int match(Address addr, byte[] bytes, byte[] masks, byte[] data, boolean forward) {
|
||||
try {
|
||||
@@ -1645,10 +1647,11 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
throw new MemoryAccessException(
|
||||
"Address " + addr.toString(true) + " does not exist in memory");
|
||||
}
|
||||
n -= block.getSize() - addr.subtract(block.getStart());
|
||||
if (n <= 0) {
|
||||
long advanced = block.getSize() - addr.subtract(block.getStart());
|
||||
if (advanced >= n) {
|
||||
break;
|
||||
}
|
||||
n -= advanced;
|
||||
try {
|
||||
addr = block.getEnd().addNoWrap(1);
|
||||
}
|
||||
@@ -1879,8 +1882,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the given addressSpace (overlay space) is used by any blocks. If not, it
|
||||
* removes the space.
|
||||
* Tests if the given addressSpace (overlay space) is used by any blocks. If not, it removes the
|
||||
* space.
|
||||
*
|
||||
* @param addressSpace overlay address space to be removed
|
||||
*/
|
||||
private void checkRemoveAddressSpace(AddressSpace addressSpace) {
|
||||
@@ -1930,8 +1934,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the intersected set of addresses between a mapped memory block, and some other
|
||||
* address set.
|
||||
* Gets the intersected set of addresses between a mapped memory block, and some other address
|
||||
* set.
|
||||
*
|
||||
* @param mappedBlock The mapped memory block to use in the intersection.
|
||||
* @param set Some other address set to use in the intersection.
|
||||
@@ -1954,9 +1958,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given address range back from the source range back to the mapped range.
|
||||
* NOTE: It is important that the specified mappedSourceRange is restricted to the
|
||||
* mapped source area of the specified mappedBlock.
|
||||
* Converts the given address range back from the source range back to the mapped range. NOTE:
|
||||
* It is important that the specified mappedSourceRange is restricted to the mapped source area
|
||||
* of the specified mappedBlock.
|
||||
*
|
||||
* @param mappedBlock mapped memory block
|
||||
* @param mappedSourceRange source range which maps into mappedBlock.
|
||||
* @return mapped range or null if source range not mapped to block
|
||||
@@ -2225,9 +2230,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||
|
||||
/**
|
||||
* Returns a list of all memory blocks that contain any addresses in the given range
|
||||
*
|
||||
* @param start the start address
|
||||
* @param end the end address
|
||||
* @return a list of all memory blocks that contain any addresses in the given range
|
||||
* @return a list of all memory blocks that contain any addresses in the given range
|
||||
*/
|
||||
List<MemoryBlockDB> getBlocks(Address start, Address end) {
|
||||
List<MemoryBlockDB> list = new ArrayList<>();
|
||||
|
||||
Reference in New Issue
Block a user