Modified Memory API for creating Overlay blocks allow for

byte/bit-mapped overlays.  Added ByteMappingScheme for byte-mapped
blocks.
This commit is contained in:
ghidra1
2020-04-29 15:27:35 -04:00
parent 1df6fa79da
commit 6ff98a4098
76 changed files with 2351 additions and 1618 deletions
@@ -238,8 +238,8 @@
<LI><B>Search Only in Accessible Memory Blocks</B> - if checked, searches only in memory <LI><B>Search Only in Accessible Memory Blocks</B> - if checked, searches only in memory
blocks that have at least one of the Read (R), Write (W), or Execute (X) permissions set blocks that have at least one of the Read (R), Write (W), or Execute (X) permissions set
to true. Enabling this option ensures strings are not created in areas such as overlays to true. Enabling this option ensures strings are not created in areas such as non-loaded
or debug sections.</LI> overlays or debug sections.</LI>
<LI><B>String End Alignment</B> - specifies the byte alignment requirement for the end of <LI><B>String End Alignment</B> - specifies the byte alignment requirement for the end of
the string. An alignment of 1 means the string can end at any address. Alignments greater the string. An alignment of 1 means the string can end at any address. Alignments greater
@@ -898,7 +898,11 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
<H2><A name="Overlay"></A>Overlay</H2> <H2><A name="Overlay"></A>Overlay</H2>
<BLOCKQUOTE> <BLOCKQUOTE>
<P>A memory block that occupies the same memory address range as some other block.</P> <P>A memory block which corresponds to a physical memory space address within a corresponding
overlay address space identified by the block name. This allows multiple memory blocks to be defined which correspond
to the same physical address region. While the use of overlay blocks are useful to
represent a memory range its' use has significant limitations for the decompiler and
analysis which may be unable to determine when an overlay should be referenced.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
@@ -374,7 +374,7 @@
<H4>Overlay</H4> <H4>Overlay</H4>
<BLOCKQUOTE> <BLOCKQUOTE>
<P>If selected, the bytes will be loaded as an overlay. A new overlay space will be <P>If selected, the bytes will be loaded as an initiailized overlay block. A new overlay space will be
created with the same name as the Block Name.</P> created with the same name as the Block Name.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
@@ -20,40 +20,54 @@
<P>The <I>Memory Map</I> window displays a list of memory blocks that make up the memory <P>The <I>Memory Map</I> window displays a list of memory blocks that make up the memory
structure of the current program.&nbsp; The component provides actions for adding, renaming, structure of the current program.&nbsp; The component provides actions for adding, renaming,
moving, splitting, extending, joining, and deleting memory blocks.</P> moving, splitting, extending, joining, and deleting memory blocks.</P>
<P><IMG src="../../shared/note.png" border="0">When working with a versioned program within a
shared project an exclusive checkout of the program project file is required to perform any
modifications to the memory map.</P>
<P>Ghidra supports four different block types through the Memory Map window:</P> <P>Ghidra supports three different block types through the Memory Map window:</P>
<OL> <OL>
<LI> <LI>
<A name="DefaultType"></A><I><B>Default</B> -</I> The normal block type that can be <A name="DefaultType"></A><I><B>Default</B> -</I> The normal block type that can be
<I>initialized</I> or <I>uninitialized</I>. <I>Initialized</I>, <I>File Bytes</I> or <I>Uninitialized</I>.
<UL> <UL>
<LI><A name="InitializeBlockType"></A><I>Initialized</I> - The block has an initial value <LI><A name="InitializedBlock"></A><I>Initialized</I> - The block has an initial value
specified for the bytes</LI> specified for all bytes</LI>
<LI><A name="FileBytesBlock"></A><I>File Bytes</I> - An initialized block whose data corresponds
to a specified range within an existing loaded File Bytes instance.</LI>
<LI><A name="UninitializedBlockType"></A><I>Uninitialized</I> - The block has no initial <LI><A name="UninitializedBlock"></A><I>Uninitialized</I> - The block has no initial
value specified for the bytes</LI> value specified for the bytes</LI>
</UL> </UL>
</LI> </LI>
<LI><A name="BitMappedType"></A><I><B>Bit Mapped</B></I> - The block provides a <LI><A name="BitMappedType"></A><I><B>Bit Mapped</B></I> - The block provides a
bit-addressable map onto other blocks. This is useful when a processor can access some or all bit-addressable map onto other blocks. This is useful when a processor can indirectly access
of the bits in memory directly using an alternative addressing space.</LI> individual bits within memory using an alternative byte address. Such blocks have a fixed
mapping of 8-bytes to 1-source-byte..</LI>
<LI><A name="ByteMappedType"></A><I><B>Byte Mapped</B></I> - The block provides a <LI><A name="ByteMappedType"></A><I><B>Byte Mapped</B></I> - The block provides a
byte-addressable map onto other blocks.&nbsp; This can be useful when the same bytes can be byte-addressable map onto other blocks.&nbsp; This can be useful when a range of
accessed via two or more addresses.</LI> bytes can be accessed via an alternative address range. While the default mapping
is 1-byte to 1-source-byte (1:1), other decimations are permitted specified using a
<LI><A name="OverlayType"></A><I><B>Overlay</B></I> - The block is created in a new mapping ratio (e.g., 2:4).</LI>
<I>overlay</I> address space. Overlay blocks can be <I>initialized</I> or
<I>unitialized</I>.&nbsp;Using Overlays is a way to get around the problem where the program
is too large to fit completely in the target system's memory.&nbsp; Overlay blocks contain
code that would get swapped in when the program needs to execute it.&nbsp;&nbsp; Note that
Overlay blocks are fixed and may not be moved, split or expanded.&nbsp; In addition, Overlays
do not relocate with image base changes.<BR>
</LI>
</OL> </OL>
<P><IMG src="../../shared/note.png" border="0"><I>File Bytes</I> are currently only created
by importers. At this point in time there is no capability provided by the Memory Map provider to create a
new File Bytes instance.</P>
<P><B>Overlay</B> - Each of the above memory block types may optionally be specified as an <I>Overlay</I> at the
time of creation. If this option is selected, the block is created in a new
overlay address space.&nbsp; Overlay blocks can serve various
purposes where a memory range may contain different data/code or map to different areas of memory
at any given point in time or processor state. &nbsp; Note that
overlay blocks are fixed and may not be moved, split, merged or expanded.&nbsp; In addition, Overlays
do not relocate with image base changes and have significant limitations in conjunction with
decompilation and analysis.</P>
<P>To view the <I>Memory Map</I>, select <B>Window<IMG src="../../shared/arrow.gif" border="0"> <P>To view the <I>Memory Map</I>, select <B>Window<IMG src="../../shared/arrow.gif" border="0">
Memory Map</B> from the main tool menu, or click on the&nbsp; <IMG src="images/memory16.gif" Memory Map</B> from the main tool menu, or click on the&nbsp; <IMG src="images/memory16.gif"
@@ -86,16 +100,14 @@
<P><I><B>W -</B></I> Indicates write permission.</P> <P><I><B>W -</B></I> Indicates write permission.</P>
<P><I><B>X -</B></I> Indicates execute permission.<BR> <P><I><B>X -</B></I> Indicates execute permission.</P>
</P>
<P><B>Volatile</B> - Indicates a region of volatile I/O Memory.</P>
<P><SPAN style="font-weight: bold;">Volatile</SPAN> - Indicates a region of volatile I/O <P><I><B>Overlay -</B></I> Indicates if block is defined as a memory overlay.</P>
Memory.<BR>
</P>
<P><I><B>Type -</B></I> Indicates whether the block is a <A href="#DefaultType">Default</A>, <P><I><B>Type -</B></I> Indicates whether the block is a <A href="#DefaultType">Default</A>,
<A href="#BitMappedType">Bit Mapped</A>, <A href="#ByteMappedType">Byte Mapped</A> or <A <A href="#BitMappedType">Bit Mapped</A> or <A href="#ByteMappedType">Byte Mapped</A> type of block.</P>
href="#OverlayType">Overlay</A> type of block.</P>
<P><I><B>Initialized -</B></I> Indicates whether the block has been initialized with values; <P><I><B>Initialized -</B></I> Indicates whether the block has been initialized with values;
this property applies to Default and Overlay blocks.</P> this property applies to Default and Overlay blocks.</P>
@@ -107,10 +119,7 @@
sources. In that case, source information about the first several regions will be d sources. In that case, source information about the first several regions will be d
displayed.</P> displayed.</P>
<P><I><B>Source -</B></I> The name of the file that produced the bytes that make up this <P><I><B>Source -</B></I> Description of block origination.</P>
block as set by the file importer; for <A href="#BitMappedType">Bit Mapped</A> or <A href=
"#ByteMappedType">Byte Mapped</A> blocks, the <I>Source</I> shows the mapped source
address.</P>
<P><I><B>Comment -</B></I> User added comment about this memory block.</P> <P><I><B>Comment -</B></I> User added comment about this memory block.</P>
@@ -221,15 +230,14 @@
<P><I><B>Write</B></I> - Sets the write permission.</P> <P><I><B>Write</B></I> - Sets the write permission.</P>
<P><B><I>Execute</I></B> - Sets the execute permission.<BR> <P><B><I>Execute</I></B> - Sets the execute permission.</P>
</P>
<P><SPAN style="font-weight: bold;">Volatile</SPAN> - Marks this block as volatile I/O <P><B>Volatile</B> - Marks this block as volatile I/O memory.</P>
memory.<BR>
</P> <P><B>Overlay</B> - Creates the block as an overlay within a corresponding overlay address space.</P>
<P><B><I>Block Types</I></B> - Select the block type from the combo box: <I><B>Default, Bit <P><B><I>Block Types</I></B> - Select the block type from the combo box: <I><B>Default, Bit
Mapped, Byte Mapped, or Overlay</B></I>.</P> Mapped or Byte Mapped</B></I>.</P>
<BLOCKQUOTE> <BLOCKQUOTE>
<UL> <UL>
@@ -245,15 +253,7 @@
<P><I><IMG src="../../shared/note.png" border="0"> You can use the "Add To Program" <P><I><IMG src="../../shared/note.png" border="0"> You can use the "Add To Program"
using "Binary Import" to create new FileBytes that you can use here.</I></P> using "Binary Import" to create new FileBytes that you can use here.</I></P>
</UL> </UL>
<LI><B><I>Overlay -</I></B> An overlay block is used to give an alternative set of <LI><B><I>Bit Mapped -</I></B> This is a block that allows bit addressing of a section
bytes (and related information) for a range in memory.&nbsp; This is achieved by
creating a new address space related to the actual processor address space and placing
the block in the new space at the same offsets as the start address in the processor
space.&nbsp; Overlay blocks can be either initialized or uninitialized. If you select
<I>Initialized</I> you can enter a byte value that will be used to fill all the bytes
in the new memory block.</LI>
<LI><B><I>Bit Mapped -</I></B> This is a block that allow bit addressing of a section
of bytes in memory.&nbsp; For example, the first bit of the byte at memory location of bytes in memory.&nbsp; For example, the first bit of the byte at memory location
0x1000 might also be addressed as BIT:0. The second bit at the same byte would then be 0x1000 might also be addressed as BIT:0. The second bit at the same byte would then be
addressed as BIT:1 and so on.</LI> addressed as BIT:1 and so on.</LI>
@@ -261,10 +261,9 @@
<LI style="list-style: none"> <LI style="list-style: none">
<P>The illustration below depicts a Bit Mapped block of <I>Length</I> 16 with a <P>The illustration below depicts a Bit Mapped block of <I>Length</I> 16 with a
<I>Start Addr</I> of (BIT:) 0000, and a <I>Source Address</I> of 00008100.&nbsp; Note <I>Start Addr</I> of (BIT:) 0000, and a <I>Source Address</I> of 00008100.&nbsp; Note
that Bit Overlay addresses are assigned from least significant bit to most that bit-mapped addresses are assigned from least significant bit to most
significant bit.</P> significant bit.</P>
</LI>
</UL>
<TABLE x-use-null-cells="" width="100%"> <TABLE x-use-null-cells="" width="100%">
<TBODY> <TBODY>
@@ -274,16 +273,21 @@
</TR> </TR>
</TBODY> </TBODY>
</TABLE> </TABLE>
<UL> <BR>This is used to model certain processors that allow this sort of addressing such as
<LI>This is used to model certain processors that allow this sort of addressing such as
the INTEL 8051. When a Bit Mapped block is created you must specify the byte address on the INTEL 8051. When a Bit Mapped block is created you must specify the byte address on
which the bit addressing will be based.</LI> which the bit addressing will be based.</LI>
</UL>
<UL>
<LI>&nbsp;<B><I>Byte Mapped</I></B> - This is a block that allows access to a range of <LI>&nbsp;<B><I>Byte Mapped</I></B> - This is a block that allows access to a range of
bytes in memory using an alternative address.&nbsp; In other words, it allows the same bytes in memory using an alternative address.&nbsp; A <I>Source Address</I> must
set of bytes to be accessed by two different logical addresses. A source address must be specified which corresponds to the source of the actual bytes for this block, although all or part of the
be specified that contains the actual bytes for this block.</LI> mapping may correspond to an uninitialized block or no block at all. The default mapping ratio
is 1-byte to 1-source-byte (1:1), although other decimations may be specified using a mapping ratio. When specifying a <I>Mapping
Ratio</I> both values must be in the range 1..127 where the right (source-byte count) value must be greater-than-or-equal
to the left value (e.g., 2:4).</LI>
</UL> </UL>
</BLOCKQUOTE> </BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
@@ -517,9 +521,9 @@
be created.&nbsp; Disregarding the warning may cause Ghidra to fail with an "out of memory" be created.&nbsp; Disregarding the warning may cause Ghidra to fail with an "out of memory"
error.</P> error.</P>
<P><I><IMG src="../../shared/note.png" border="0"></I> Only blocks of the same type can be <P><I><IMG src="../../shared/note.png" border="0"></I> Only adjacent <I>Default</I> blocks of the same
merged. For example, <A href="#DefaultType">default</A> blocks can only be merged with initialization state can be merged.</P>
another default block.&nbsp;</P> <P><I><IMG src="../../shared/note.png" border="0"></I>Overlay type blocks cannot be merged.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@@ -40,9 +40,11 @@ abstract class AbstractAddMemoryBlockCmd implements Command {
protected final boolean write; protected final boolean write;
protected final boolean execute; protected final boolean execute;
protected final boolean isVolatile; protected final boolean isVolatile;
protected final boolean isOverlay;
AbstractAddMemoryBlockCmd(String name, String comment, String source, Address start, AbstractAddMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile) { long length, boolean read, boolean write, boolean execute, boolean isVolatile,
boolean isOverlay) {
this.name = name; this.name = name;
this.comment = comment; this.comment = comment;
this.source = source; this.source = source;
@@ -52,6 +54,7 @@ abstract class AbstractAddMemoryBlockCmd implements Command {
this.write = write; this.write = write;
this.execute = execute; this.execute = execute;
this.isVolatile = isVolatile; this.isVolatile = isVolatile;
this.isOverlay = isOverlay;
} }
@Override @Override
@@ -19,9 +19,13 @@ import ghidra.framework.store.LockException;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException; import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.util.exception.DuplicateNameException;
/** /**
* Command for adding Bit-mapped memory blocks * Command for adding Bit-mapped memory blocks.
* The resulting mapped block will derive its' byte values (1 or 0) from the mapped source bits.
* Example: 8 bytes in the resulting block will be derived from 1-byte
* in the underlying source region.
*/ */
public class AddBitMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd { public class AddBitMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
@@ -33,25 +37,27 @@ public class AddBitMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
* @param comment the comment for the block * @param comment the comment for the block
* @param source indicates what is creating the block * @param source indicates what is creating the block
* @param start the start address for the the block * @param start the start address for the the block
* @param length the length of the new block * @param length the length of the new block in number of bits to be mapped
* @param read sets the block's read permission flag * @param read sets the block's read permission flag
* @param write sets the block's write permission flag * @param write sets the block's write permission flag
* @param execute sets the block's execute permission flag * @param execute sets the block's execute permission flag
* @param isVolatile sets the block's volatile flag * @param isVolatile sets the block's volatile flag
* @param mappedAddress the address in memory that will serve as the bytes source for the block * @param mappedAddress the address in memory that will serve as the bytes source for the block
* @param isOverlay if true, the block will be created in a new overlay address space.
*/ */
public AddBitMappedMemoryBlockCmd(String name, String comment, String source, Address start, public AddBitMappedMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile, long length, boolean read, boolean write, boolean execute, boolean isVolatile,
Address mappedAddress) { Address mappedAddress, boolean isOverlay) {
super(name, comment, source, start, length, read, write, execute, isVolatile); super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
this.mappedAddress = mappedAddress; this.mappedAddress = mappedAddress;
} }
@Override @Override
protected MemoryBlock createMemoryBlock(Memory memory) protected MemoryBlock createMemoryBlock(Memory memory)
throws LockException, MemoryConflictException, AddressOverflowException { throws LockException, MemoryConflictException, AddressOverflowException,
return memory.createBitMappedBlock(name, start, mappedAddress, length); IllegalArgumentException, DuplicateNameException {
return memory.createBitMappedBlock(name, start, mappedAddress, length, isOverlay);
} }
} }
@@ -16,9 +16,11 @@
package ghidra.app.cmd.memory; package ghidra.app.cmd.memory;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException; import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.util.exception.DuplicateNameException;
/** /**
* Command for adding byte-mapped memory blocks * Command for adding byte-mapped memory blocks
@@ -26,9 +28,16 @@ import ghidra.program.model.mem.*;
public class AddByteMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd { public class AddByteMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
private final Address mappedAddress; private final Address mappedAddress;
private final ByteMappingScheme byteMappingScheme;
/** /**
* Create a new AddByteMappedMemoryBlockCmd * Create a new AddByteMappedMemoryBlockCmd with a specified byte mapping scheme.
* Byte mapping scheme is specified by two values schemeDestByteCount and schemeSrcByteCount which
* may be viewed as a ratio of number of destination bytes to number of mapped source bytes.
* When the destination consumes bytes from the mapped source it consume schemeDestByteCount bytes then
* skips (schemeSrcByteCount - schemeDestByteCount) bytes before repeating the mapping sequence over
* the extent of the destination block. The block start address and source mappedAddress must
* be chosen carefully as they relate to the mapping scheme when it is anything other than 1:1.
* @param name the name for the new memory block. * @param name the name for the new memory block.
* @param comment the comment for the block * @param comment the comment for the block
* @param source indicates what is creating the block * @param source indicates what is creating the block
@@ -39,19 +48,45 @@ public class AddByteMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
* @param execute sets the block's execute permission flag * @param execute sets the block's execute permission flag
* @param isVolatile sets the block's volatile flag * @param isVolatile sets the block's volatile flag
* @param mappedAddress the address in memory that will serve as the bytes source for the block * @param mappedAddress the address in memory that will serve as the bytes source for the block
* @param byteMappingScheme byte mapping scheme (may be null for 1:1 mapping)
* @param isOverlay if true, the block will be created in a new overlay address space.
*/ */
public AddByteMappedMemoryBlockCmd(String name, String comment, String source, Address start, public AddByteMappedMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile, long length, boolean read, boolean write, boolean execute, boolean isVolatile,
Address mappedAddress) { Address mappedAddress, ByteMappingScheme byteMappingScheme, boolean isOverlay) {
super(name, comment, source, start, length, read, write, execute, isVolatile); super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
this.mappedAddress = mappedAddress; this.mappedAddress = mappedAddress;
this.byteMappingScheme = byteMappingScheme;
}
/**
* Create a new AddByteMappedMemoryBlockCmd with 1:1 byte mapping scheme
* @param name the name for the new memory block.
* @param comment the comment for the block
* @param source indicates what is creating the block
* @param start the start address for the the block
* @param length the length of the new block
* @param read sets the block's read permission flag
* @param write sets the block's write permission flag
* @param execute sets the block's execute permission flag
* @param isVolatile sets the block's volatile flag
* @param mappedAddress the address in memory that will serve as the bytes source for the block
* @param isOverlay if true, the block will be created in a new overlay address space.
*/
public AddByteMappedMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile,
Address mappedAddress, boolean isOverlay) {
this(name, comment, source, start, length, read, write, execute, isVolatile, mappedAddress,
null, isOverlay);
} }
@Override @Override
protected MemoryBlock createMemoryBlock(Memory memory) protected MemoryBlock createMemoryBlock(Memory memory)
throws LockException, MemoryConflictException, AddressOverflowException { throws LockException, MemoryConflictException, AddressOverflowException,
return memory.createByteMappedBlock(name, start, mappedAddress, length); IllegalArgumentException, DuplicateNameException {
return memory.createByteMappedBlock(name, start, mappedAddress, length,
byteMappingScheme,
isOverlay);
} }
} }
@@ -29,7 +29,6 @@ public class AddFileBytesMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
private final FileBytes fileBytes; private final FileBytes fileBytes;
private final long offset; private final long offset;
private final boolean isOverlay;
/** /**
* Create a new AddFileBytesMemoryBlockCmd * Create a new AddFileBytesMemoryBlockCmd
@@ -49,10 +48,9 @@ public class AddFileBytesMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
public AddFileBytesMemoryBlockCmd(String name, String comment, String source, Address start, public AddFileBytesMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile, long length, boolean read, boolean write, boolean execute, boolean isVolatile,
FileBytes fileBytes, long offset, boolean isOverlay) { FileBytes fileBytes, long offset, boolean isOverlay) {
super(name, comment, source, start, length, read, write, execute, isVolatile); super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
this.fileBytes = fileBytes; this.fileBytes = fileBytes;
this.offset = offset; this.offset = offset;
this.isOverlay = isOverlay;
} }
@Override @Override
@@ -28,7 +28,6 @@ import ghidra.util.exception.DuplicateNameException;
public class AddInitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd { public class AddInitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
private final byte initialValue; private final byte initialValue;
private final boolean isOverlay;
/** /**
* Create a new AddFileBytesMemoryBlockCmd * Create a new AddFileBytesMemoryBlockCmd
@@ -47,10 +46,9 @@ public class AddInitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
public AddInitializedMemoryBlockCmd(String name, String comment, String source, Address start, public AddInitializedMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile, long length, boolean read, boolean write, boolean execute, boolean isVolatile,
byte initialValue, boolean isOverlay) { byte initialValue, boolean isOverlay) {
super(name, comment, source, start, length, read, write, execute, isVolatile); super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
this.initialValue = initialValue; this.initialValue = initialValue;
this.isOverlay = isOverlay;
} }
@Override @Override
@@ -26,8 +26,6 @@ import ghidra.util.exception.DuplicateNameException;
*/ */
public class AddUninitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd { public class AddUninitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
private final boolean isOverlay;
/** /**
* Create a new AddUninitializedMemoryBlockCmd * Create a new AddUninitializedMemoryBlockCmd
* @param name the name for the new memory block. * @param name the name for the new memory block.
@@ -44,9 +42,7 @@ public class AddUninitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
public AddUninitializedMemoryBlockCmd(String name, String comment, String source, Address start, public AddUninitializedMemoryBlockCmd(String name, String comment, String source, Address start,
long length, boolean read, boolean write, boolean execute, boolean isVolatile, long length, boolean read, boolean write, boolean execute, boolean isVolatile,
boolean isOverlay) { boolean isOverlay) {
super(name, comment, source, start, length, read, write, execute, isVolatile); super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
this.isOverlay = isOverlay;
} }
@Override @Override
@@ -27,6 +27,7 @@ import docking.widgets.checkbox.GCheckBox;
import docking.widgets.combobox.GhidraComboBox; import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import docking.widgets.textfield.IntegerTextField;
import ghidra.app.plugin.core.memory.AddBlockModel.InitializedType; import ghidra.app.plugin.core.memory.AddBlockModel.InitializedType;
import ghidra.app.plugin.core.misc.RegisterField; import ghidra.app.plugin.core.misc.RegisterField;
import ghidra.app.util.*; import ghidra.app.util.*;
@@ -63,11 +64,14 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
private JCheckBox writeCB; private JCheckBox writeCB;
private JCheckBox executeCB; private JCheckBox executeCB;
private JCheckBox volatileCB; private JCheckBox volatileCB;
private JCheckBox overlayCB;
private RegisterField initialValueField; private RegisterField initialValueField;
private JLabel initialValueLabel; private JLabel initialValueLabel;
private AddressFactory addrFactory; private AddressFactory addrFactory;
private AddressInput baseAddrField; // used for BitMemoryBlocks private AddressInput baseAddrField; // used for Bit and Byte mapped blocks
private Address baseAddress; private IntegerTextField schemeDestByteCountField; // used for Byte mapped blocks
private IntegerTextField schemeSrcByteCountField; // used for Byte mapped blocks
private AddBlockModel model; private AddBlockModel model;
private GhidraComboBox<MemoryBlockType> comboBox; private GhidraComboBox<MemoryBlockType> comboBox;
private boolean updatingInitializedRB; private boolean updatingInitializedRB;
@@ -103,6 +107,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
writeCB.setSelected(model.isWrite()); writeCB.setSelected(model.isWrite());
executeCB.setSelected(model.isExecute()); executeCB.setSelected(model.isExecute());
volatileCB.setSelected(model.isVolatile()); volatileCB.setSelected(model.isVolatile());
overlayCB.setSelected(model.isOverlay());
} }
/** /**
@@ -163,12 +168,18 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
volatileCB.setSelected(model.isVolatile()); volatileCB.setSelected(model.isVolatile());
volatileCB.addActionListener(e -> model.setVolatile(volatileCB.isSelected())); volatileCB.addActionListener(e -> model.setVolatile(volatileCB.isSelected()));
overlayCB = new GCheckBox("Overlay");
overlayCB.setName("Overlay");
overlayCB.setSelected(model.isOverlay());
overlayCB.addActionListener(e -> model.setOverlay(overlayCB.isSelected()));
JPanel panel = new JPanel(new HorizontalLayout(10)); JPanel panel = new JPanel(new HorizontalLayout(10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 30, 20, 30)); panel.setBorder(BorderFactory.createEmptyBorder(10, 30, 20, 30));
panel.add(readCB); panel.add(readCB);
panel.add(writeCB); panel.add(writeCB);
panel.add(executeCB); panel.add(executeCB);
panel.add(volatileCB); panel.add(volatileCB);
panel.add(overlayCB);
return panel; return panel;
} }
@@ -178,7 +189,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
panel.setBorder(BorderFactory.createTitledBorder("Block Types")); panel.setBorder(BorderFactory.createTitledBorder("Block Types"));
MemoryBlockType[] items = new MemoryBlockType[] { MemoryBlockType.DEFAULT, MemoryBlockType[] items = new MemoryBlockType[] { MemoryBlockType.DEFAULT,
MemoryBlockType.OVERLAY, MemoryBlockType.BIT_MAPPED, MemoryBlockType.BYTE_MAPPED }; MemoryBlockType.BIT_MAPPED, MemoryBlockType.BYTE_MAPPED };
comboBox = new GhidraComboBox<>(items); comboBox = new GhidraComboBox<>(items);
comboBox.addItemListener(e -> blockTypeSelected()); comboBox.addItemListener(e -> blockTypeSelected());
@@ -308,6 +319,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
writeCB.setSelected(model.isWrite()); writeCB.setSelected(model.isWrite());
executeCB.setSelected(model.isExecute()); executeCB.setSelected(model.isExecute());
volatileCB.setSelected(model.isVolatile()); volatileCB.setSelected(model.isVolatile());
overlayCB.setSelected(model.isOverlay());
setOkEnabled(false); setOkEnabled(false);
tool.showDialog(this, tool.getComponentProvider(PluginConstants.MEMORY_MAP)); tool.showDialog(this, tool.getComponentProvider(PluginConstants.MEMORY_MAP));
@@ -406,29 +418,66 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
} }
private void baseAddressChanged() { private void baseAddressChanged() {
baseAddress = baseAddrField.getAddress(); Address baseAddress = baseAddrField.getAddress();
model.setBaseAddress(baseAddress); model.setBaseAddress(baseAddress);
} }
private void schemeSrcByteCountChanged() {
int value = schemeSrcByteCountField.getIntValue();
model.setSchemeSrcByteCount(value);
}
private void schemeDestByteCountChanged() {
int value = schemeDestByteCountField.getIntValue();
model.setSchemeDestByteCount(value);
}
private void blockTypeSelected() { private void blockTypeSelected() {
MemoryBlockType blockType = (MemoryBlockType) comboBox.getSelectedItem(); MemoryBlockType blockType = (MemoryBlockType) comboBox.getSelectedItem();
model.setBlockType(blockType); model.setBlockType(blockType);
if (blockType == MemoryBlockType.DEFAULT || blockType == MemoryBlockType.OVERLAY) { if (blockType == MemoryBlockType.DEFAULT) {
typeCardLayout.show(viewPanel, UNMAPPED); typeCardLayout.show(viewPanel, UNMAPPED);
} }
else { else {
enableByteMappingSchemeControls(blockType == MemoryBlockType.BYTE_MAPPED);
schemeDestByteCountField.setValue(model.getSchemeDestByteCount());
schemeSrcByteCountField.setValue(model.getSchemeSrcByteCount());
typeCardLayout.show(viewPanel, MAPPED); typeCardLayout.show(viewPanel, MAPPED);
} }
} }
private void enableByteMappingSchemeControls(boolean b) {
schemeDestByteCountField.setValue(1);
schemeDestByteCountField.setEnabled(b);
schemeSrcByteCountField.setValue(1);
schemeSrcByteCountField.setEnabled(b);
}
private JPanel buildMappedPanel() { private JPanel buildMappedPanel() {
JPanel panel = new JPanel(new PairLayout()); JPanel panel = new JPanel(new PairLayout());
baseAddrField = new AddressInput(); baseAddrField = new AddressInput();
baseAddrField.setAddressFactory(addrFactory); baseAddrField.setAddressFactory(addrFactory);
baseAddrField.setName("Source Addr"); baseAddrField.setName("Source Addr");
baseAddrField.addChangeListener(ev -> baseAddressChanged()); baseAddrField.addChangeListener(ev -> baseAddressChanged());
JPanel schemePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
schemeDestByteCountField = new IntegerTextField(4, 1);
schemeDestByteCountField.setAllowNegativeValues(false);
schemeDestByteCountField.setAllowsHexPrefix(false);
schemeDestByteCountField.setDecimalMode();
schemeDestByteCountField.addChangeListener(ev -> schemeDestByteCountChanged());
schemeSrcByteCountField = new IntegerTextField(4, 1);
schemeSrcByteCountField.setAllowNegativeValues(false);
schemeSrcByteCountField.setAllowsHexPrefix(false);
schemeSrcByteCountField.setDecimalMode();
schemeSrcByteCountField.addChangeListener(ev -> schemeSrcByteCountChanged());
schemePanel.add(schemeDestByteCountField.getComponent());
schemePanel.add(new GLabel(" : "));
schemePanel.add(schemeSrcByteCountField.getComponent());
Program program = model.getProgram(); Program program = model.getProgram();
Address minAddr = program.getMinAddress(); Address minAddr = program.getMinAddress();
@@ -437,8 +486,12 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
} }
baseAddrField.setAddress(minAddr); baseAddrField.setAddress(minAddr);
model.setBaseAddress(minAddr); model.setBaseAddress(minAddr);
panel.add(new GLabel("Source Addr:")); panel.add(new GLabel("Source Address:"));
panel.add(baseAddrField); panel.add(baseAddrField);
panel.add(new GLabel("Mapping Ratio:"));
panel.add(schemePanel);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
return panel; return panel;
} }
@@ -20,6 +20,7 @@ import javax.swing.event.ChangeListener;
import ghidra.app.cmd.memory.*; import ghidra.app.cmd.memory.*;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.database.mem.FileBytes; import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
@@ -42,8 +43,11 @@ class AddBlockModel {
private String blockName; private String blockName;
private Address startAddr; private Address startAddr;
private Address baseAddr; private Address baseAddr;
private int schemeDestByteCount;
private int schemeSrcByteCount;
private long length; private long length;
private MemoryBlockType blockType; private MemoryBlockType blockType;
private boolean isOverlay;
private int initialValue; private int initialValue;
private String message; private String message;
private ChangeListener listener; private ChangeListener listener;
@@ -121,6 +125,9 @@ class AddBlockModel {
isWrite = true; isWrite = true;
isExecute = false; isExecute = false;
isVolatile = false; isVolatile = false;
isOverlay = false;
schemeDestByteCount = blockType == MemoryBlockType.BIT_MAPPED ? 8 : 1;
schemeSrcByteCount = 1;
initializedType = InitializedType.UNITIALIZED; initializedType = InitializedType.UNITIALIZED;
validateInfo(); validateInfo();
listener.stateChanged(null); listener.stateChanged(null);
@@ -142,6 +149,10 @@ class AddBlockModel {
this.isVolatile = b; this.isVolatile = b;
} }
void setOverlay(boolean b) {
this.isOverlay = b;
}
void setInitializedType(InitializedType type) { void setInitializedType(InitializedType type) {
this.initializedType = type; this.initializedType = type;
validateInfo(); validateInfo();
@@ -154,6 +165,26 @@ class AddBlockModel {
listener.stateChanged(null); listener.stateChanged(null);
} }
void setSchemeSrcByteCount(int value) {
this.schemeSrcByteCount = value;
validateInfo();
listener.stateChanged(null);
}
int getSchemeSrcByteCount() {
return schemeSrcByteCount;
}
void setSchemeDestByteCount(int value) {
this.schemeDestByteCount = value;
validateInfo();
listener.stateChanged(null);
}
int getSchemeDestByteCount() {
return schemeDestByteCount;
}
Address getStartAddress() { Address getStartAddress() {
return startAddr; return startAddr;
} }
@@ -194,6 +225,10 @@ class AddBlockModel {
return isVolatile; return isVolatile;
} }
boolean isOverlay() {
return isOverlay;
}
InitializedType getInitializedType() { InitializedType getInitializedType() {
return initializedType; return initializedType;
} }
@@ -217,21 +252,21 @@ class AddBlockModel {
switch (blockType) { switch (blockType) {
case BIT_MAPPED: case BIT_MAPPED:
return new AddBitMappedMemoryBlockCmd(blockName, comment, source, startAddr, length, return new AddBitMappedMemoryBlockCmd(blockName, comment, source, startAddr, length,
isRead, isWrite, isExecute, isVolatile, baseAddr); isRead, isWrite, isExecute, isVolatile, baseAddr, isOverlay);
case BYTE_MAPPED: case BYTE_MAPPED:
ByteMappingScheme byteMappingScheme =
new ByteMappingScheme(schemeDestByteCount, schemeSrcByteCount);
return new AddByteMappedMemoryBlockCmd(blockName, comment, source, startAddr, return new AddByteMappedMemoryBlockCmd(blockName, comment, source, startAddr,
length, isRead, isWrite, isExecute, isVolatile, baseAddr); length, isRead, isWrite, isExecute, isVolatile, baseAddr, byteMappingScheme,
isOverlay);
case DEFAULT: case DEFAULT:
return createNonMappedMemoryBlock(source, false); return createNonMappedMemoryBlock(source);
case OVERLAY:
return createNonMappedMemoryBlock(source, true);
default: default:
throw new AssertException("Encountered unexpected block type: " + blockType); throw new AssertException("Encountered unexpected block type: " + blockType);
} }
} }
private Command createNonMappedMemoryBlock(String source, boolean isOverlay) { private Command createNonMappedMemoryBlock(String source) {
switch (initializedType) { switch (initializedType) {
case INITIALIZED_FROM_FILE_BYTES: case INITIALIZED_FROM_FILE_BYTES:
return new AddFileBytesMemoryBlockCmd(blockName, comment, source, startAddr, length, return new AddFileBytesMemoryBlockCmd(blockName, comment, source, startAddr, length,
@@ -299,7 +334,7 @@ class AddBlockModel {
} }
private boolean hasUniqueNameIfOverlay() { private boolean hasUniqueNameIfOverlay() {
if (blockType != MemoryBlockType.OVERLAY) { if (!isOverlay) {
return true; return true;
} }
AddressFactory factory = program.getAddressFactory(); AddressFactory factory = program.getAddressFactory();
@@ -315,7 +350,7 @@ class AddBlockModel {
private boolean isOverlayIfOtherSpace() { private boolean isOverlayIfOtherSpace() {
if (startAddr.getAddressSpace().equals(AddressSpace.OTHER_SPACE)) { if (startAddr.getAddressSpace().equals(AddressSpace.OTHER_SPACE)) {
if (blockType != MemoryBlockType.OVERLAY) { if (!isOverlay) {
message = "Blocks defined in the " + AddressSpace.OTHER_SPACE.getName() + message = "Blocks defined in the " + AddressSpace.OTHER_SPACE.getName() +
" space must be overlay blocks"; " space must be overlay blocks";
return false; return false;
@@ -327,16 +362,27 @@ class AddBlockModel {
private boolean hasMappedAddressIfNeeded() { private boolean hasMappedAddressIfNeeded() {
if (blockType == MemoryBlockType.BIT_MAPPED || blockType == MemoryBlockType.BYTE_MAPPED) { if (blockType == MemoryBlockType.BIT_MAPPED || blockType == MemoryBlockType.BYTE_MAPPED) {
if (baseAddr == null) { if (baseAddr == null) {
String blockTypeStr = (blockType == MemoryBlockType.BIT_MAPPED) ? "bit" : "overlay"; String blockTypeStr =
(blockType == MemoryBlockType.BIT_MAPPED) ? "bit-mapped" : "byte-mapped";
message = "Please enter a source address for the " + blockTypeStr + " block"; message = "Please enter a source address for the " + blockTypeStr + " block";
return false; return false;
} }
if (schemeDestByteCount <= 0 || schemeDestByteCount > Byte.MAX_VALUE ||
schemeSrcByteCount <= 0 || schemeSrcByteCount > Byte.MAX_VALUE) {
message = "Mapping ratio values must be within range: 1 to 127";
return false;
}
if (schemeDestByteCount > schemeSrcByteCount) {
message =
"Mapping ratio destination byte count (left-value) must be less than or equal the source byte count (right-value)";
return false;
}
} }
return true; return true;
} }
private boolean hasNoMemoryConflicts() { private boolean hasNoMemoryConflicts() {
if (blockType == MemoryBlockType.OVERLAY) { if (isOverlay) {
return true; return true;
} }
Address endAddr = startAddr.add(length - 1); Address endAddr = startAddr.add(length - 1);
@@ -81,11 +81,11 @@ class MemoryMapManager {
Listing listing = program.getListing(); Listing listing = program.getListing();
String[] treeNames = listing.getTreeNames(); String[] treeNames = listing.getTreeNames();
for (int i = 0; i < treeNames.length; i++) { for (String treeName : treeNames) {
boolean duplicate = false; boolean duplicate = false;
int index = 0; int index = 0;
ProgramFragment frag = listing.getFragment(treeNames[i], start); ProgramFragment frag = listing.getFragment(treeName, start);
do { do {
try { try {
frag.setName("Frag" + index + "-" + name); frag.setName("Frag" + index + "-" + name);
@@ -121,6 +121,11 @@ class MemoryMapManager {
// make sure that the block after the first block is the second block // make sure that the block after the first block is the second block
Address nextStart = blockA.getEnd(); Address nextStart = blockA.getEnd();
AddressSpace space = nextStart.getAddressSpace(); AddressSpace space = nextStart.getAddressSpace();
if (space.isOverlaySpace()) {
Msg.showError(this, plugin.getMemoryMapProvider().getComponent(),
"Merge Blocks Failed", "Can't merge overlay blocks");
return false;
}
Address blockBstart = blockB.getStart(); Address blockBstart = blockB.getStart();
if (!space.isSuccessor(nextStart, blockBstart)) { if (!space.isSuccessor(nextStart, blockBstart)) {
@@ -171,19 +176,9 @@ class MemoryMapManager {
return true; return true;
} }
boolean isValidBlockName(String name) { boolean isDuplicateName(String name) {
if (name == null || name.length() == 0) { // block names may not duplicate existing address spaces (includes overlay blocks)
return false; return program.getAddressFactory().getAddressSpace(name) != null;
}
Memory memory = program.getMemory();
MemoryBlock[] blocks = memory.getBlocks();
for (int i = 0; i < blocks.length; i++) {
if (blocks[i].getName().equals(name)) {
return false;
}
}
return true;
} }
void setProgram(Program program) { void setProgram(Program program) {
@@ -332,8 +327,7 @@ class MemoryMapManager {
return false; return false;
} }
for (int i = 0; i < blocks.size(); i++) { for (MemoryBlock nextBlock : blocks) {
MemoryBlock nextBlock = blocks.get(i);
if (min == null || nextBlock.getStart().compareTo(min) < 0) { if (min == null || nextBlock.getStart().compareTo(min) < 0) {
min = nextBlock.getStart(); min = nextBlock.getStart();
} }
@@ -412,8 +406,8 @@ class MemoryMapManager {
private boolean allBlocksInSameSpace() { private boolean allBlocksInSameSpace() {
AddressSpace lastSpace = null; AddressSpace lastSpace = null;
for (int i = 0; i < blocks.size(); i++) { for (MemoryBlock block : blocks) {
Address start = blocks.get(i).getStart(); Address start = block.getStart();
AddressSpace space = start.getAddressSpace(); AddressSpace space = start.getAddressSpace();
if (lastSpace != null && !lastSpace.equals(space)) { if (lastSpace != null && !lastSpace.equals(space)) {
return false; return false;
@@ -37,7 +37,6 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.NamingUtilities;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> { class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
@@ -50,11 +49,12 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
final static byte WRITE = 5; final static byte WRITE = 5;
final static byte EXECUTE = 6; final static byte EXECUTE = 6;
final static byte VOLATILE = 7; final static byte VOLATILE = 7;
final static byte BLOCK_TYPE = 8; final static byte OVERLAY = 8;
final static byte INIT = 9; final static byte BLOCK_TYPE = 9;
final static byte BYTE_SOURCE = 10; final static byte INIT = 10;
final static byte SOURCE = 11; final static byte BYTE_SOURCE = 11;
final static byte COMMENT = 12; final static byte SOURCE = 12;
final static byte COMMENT = 13;
final static String NAME_COL = "Name"; final static String NAME_COL = "Name";
final static String START_COL = "Start"; final static String START_COL = "Start";
@@ -64,6 +64,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
final static String WRITE_COL = "W"; final static String WRITE_COL = "W";
final static String EXECUTE_COL = "X"; final static String EXECUTE_COL = "X";
final static String VOLATILE_COL = "Volatile"; final static String VOLATILE_COL = "Volatile";
final static String OVERLAY_COL = "Overlay";
final static String BLOCK_TYPE_COL = "Type"; final static String BLOCK_TYPE_COL = "Type";
final static String INIT_COL = "Initialized"; final static String INIT_COL = "Initialized";
final static String BYTE_SOURCE_COL = "Byte Source"; final static String BYTE_SOURCE_COL = "Byte Source";
@@ -77,7 +78,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
private final static String COLUMN_NAMES[] = private final static String COLUMN_NAMES[] =
{ NAME_COL, START_COL, END_COL, LENGTH_COL, READ_COL, WRITE_COL, EXECUTE_COL, VOLATILE_COL, { NAME_COL, START_COL, END_COL, LENGTH_COL, READ_COL, WRITE_COL, EXECUTE_COL, VOLATILE_COL,
BLOCK_TYPE_COL, INIT_COL, BYTE_SOURCE_COL, SOURCE_COL, COMMENT_COL }; OVERLAY_COL, BLOCK_TYPE_COL, INIT_COL, BYTE_SOURCE_COL, SOURCE_COL, COMMENT_COL };
MemoryMapModel(MemoryMapProvider provider, Program program) { MemoryMapModel(MemoryMapProvider provider, Program program) {
super(START); super(START);
@@ -115,7 +116,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
@Override @Override
public boolean isSortable(int columnIndex) { public boolean isSortable(int columnIndex) {
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE || if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
columnIndex == VOLATILE || columnIndex == INIT) { columnIndex == VOLATILE || columnIndex == OVERLAY || columnIndex == INIT) {
return false; return false;
} }
return true; return true;
@@ -163,7 +164,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
@Override @Override
public Class<?> getColumnClass(int columnIndex) { public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE || if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
columnIndex == VOLATILE || columnIndex == INIT) { columnIndex == VOLATILE || columnIndex == OVERLAY || columnIndex == INIT) {
return Boolean.class; return Boolean.class;
} }
return String.class; return String.class;
@@ -263,17 +264,17 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
"Please enter a label name."); "Please enter a label name.");
break; break;
} }
if (!NamingUtilities.isValidName(name)) { if (name.equals(block.getName())) {
break;
}
if (Memory.isValidAddressSpaceName(name)) {
Msg.showError(this, provider.getComponent(), "Invalid Name", Msg.showError(this, provider.getComponent(), "Invalid Name",
"Invalid Memory Block Name: " + name); "Invalid Memory Block Name: " + name);
break; break;
} }
if (name.equals(block.getName())) { if (provider.getMemoryMapManager().isDuplicateName(name)) {
break;
}
if (!provider.getMemoryMapManager().isValidBlockName(name)) {
Msg.showError(this, provider.getComponent(), "Duplicate Name", Msg.showError(this, provider.getComponent(), "Duplicate Name",
"Block named " + name + " already exists."); "Address space/overlay named " + name + " already exists.");
break; break;
} }
if (!name.equals(block.getName())) { if (!name.equals(block.getName())) {
@@ -417,7 +418,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
} }
private boolean verifyRenameAllowed(MemoryBlock block, String newName) { private boolean verifyRenameAllowed(MemoryBlock block, String newName) {
if ((block.getType() != MemoryBlockType.OVERLAY) || block.getName().equals(newName)) { if (!block.isOverlay() || block.getName().equals(newName)) {
return true; return true;
} }
if (!program.hasExclusiveAccess()) { if (!program.hasExclusiveAccess()) {
@@ -492,6 +493,8 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return block.isExecute() ? Boolean.TRUE : Boolean.FALSE; return block.isExecute() ? Boolean.TRUE : Boolean.FALSE;
case VOLATILE: case VOLATILE:
return block.isVolatile() ? Boolean.TRUE : Boolean.FALSE; return block.isVolatile() ? Boolean.TRUE : Boolean.FALSE;
case OVERLAY:
return block.isOverlay() ? Boolean.TRUE : Boolean.FALSE;
case INIT: case INIT:
MemoryBlockType blockType = block.getType(); MemoryBlockType blockType = block.getType();
if (blockType == MemoryBlockType.BIT_MAPPED) { if (blockType == MemoryBlockType.BIT_MAPPED) {
@@ -581,6 +584,10 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
int b1v = (b1.isVolatile() ? 1 : -1); int b1v = (b1.isVolatile() ? 1 : -1);
int b2v = (b2.isVolatile() ? 1 : -1); int b2v = (b2.isVolatile() ? 1 : -1);
return (b1v - b2v); return (b1v - b2v);
case OVERLAY:
int b1o = (b1.isOverlay() ? 1 : -1);
int b2o = (b2.isOverlay() ? 1 : -1);
return (b1o - b2o);
case INIT: case INIT:
int b1init = (b1.isInitialized() ? 1 : -1); int b1init = (b1.isInitialized() ? 1 : -1);
int b2init = (b2.isInitialized() ? 1 : -1); int b2init = (b2.isInitialized() ? 1 : -1);
@@ -150,6 +150,8 @@ class MemoryMapProvider extends ComponentProviderAdapter {
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL); column = memTable.getColumn(MemoryMapModel.VOLATILE_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL);
column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.INIT_COL); column = memTable.getColumn(MemoryMapModel.INIT_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
@@ -435,13 +437,22 @@ class MemoryMapProvider extends ComponentProviderAdapter {
column.setResizable(false); column.setResizable(false);
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL); column = memTable.getColumn(MemoryMapModel.VOLATILE_COL);
column.setMaxWidth(50); column.setMaxWidth(57);
column.setMinWidth(50); column.setMinWidth(57);
column.setResizable(false); column.setResizable(false);
column = memTable.getColumn(MemoryMapModel.INIT_COL); column = memTable.getColumn(MemoryMapModel.OVERLAY_COL);
column.setMaxWidth(60); column.setMaxWidth(55);
column.setMinWidth(55);
column.setResizable(false);
column = memTable.getColumn(MemoryMapModel.BLOCK_TYPE_COL);
column.setMinWidth(60); column.setMinWidth(60);
// column.setResizable(true);
column = memTable.getColumn(MemoryMapModel.INIT_COL);
column.setMaxWidth(68);
column.setMinWidth(68);
column.setResizable(false); column.setResizable(false);
} }
@@ -539,7 +550,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
if (block == null) { if (block == null) {
return; return;
} }
if (block.getType() == MemoryBlockType.OVERLAY) { if (block.isOverlay()) {
Msg.showInfo(getClass(), getComponent(), "Expand Overlay Block Not Allowed", Msg.showInfo(getClass(), getComponent(), "Expand Overlay Block Not Allowed",
"Overlay blocks cannot be expanded."); "Overlay blocks cannot be expanded.");
} }
@@ -558,7 +569,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return; return;
} }
if (block.getType() == MemoryBlockType.OVERLAY) { if (block.isOverlay()) {
Msg.showInfo(getClass(), getComponent(), "Move Overlay Block Not Allowed", Msg.showInfo(getClass(), getComponent(), "Move Overlay Block Not Allowed",
"Overlay blocks cannot be moved."); "Overlay blocks cannot be moved.");
} }
@@ -575,7 +586,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
if (block == null) { if (block == null) {
return; return;
} }
if (block.getType() == MemoryBlockType.OVERLAY) { if (block.isOverlay()) {
Msg.showInfo(getClass(), getComponent(), "Split Overlay Block Not Allowed", Msg.showInfo(getClass(), getComponent(), "Split Overlay Block Not Allowed",
"Overlay blocks cannot be split."); "Overlay blocks cannot be split.");
} }
@@ -29,9 +29,9 @@ import ghidra.app.plugin.core.misc.RegisterField;
import ghidra.app.util.AddressInput; import ghidra.app.util.AddressInput;
import ghidra.app.util.HelpTopics; import ghidra.app.util.HelpTopics;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.NamingUtilities;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
import ghidra.util.layout.PairLayout; import ghidra.util.layout.PairLayout;
@@ -85,15 +85,14 @@ class SplitBlockDialog extends DialogComponentProvider {
newBlockName = block.getName() + ".split"; newBlockName = block.getName() + ".split";
blockTwoNameField.setText(newBlockName); blockTwoNameField.setText(newBlockName);
} }
if (!plugin.getMemoryMapManager().isValidBlockName(newBlockName)) { if (!Memory.isValidAddressSpaceName(newBlockName)) {
setStatusText("Block name already exists");
return;
}
if (!NamingUtilities.isValidName(newBlockName)) {
setStatusText("Invalid Block Name: " + newBlockName); setStatusText("Invalid Block Name: " + newBlockName);
return; return;
} }
if (plugin.getMemoryMapManager().isDuplicateName(newBlockName)) {
setStatusText("Address space/overlay named " + newBlockName + " already exists.");
return;
}
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
plugin.getMemoryMapManager().splitBlock(block, blockTwoStart.getAddress(), newBlockName); plugin.getMemoryMapManager().splitBlock(block, blockTwoStart.getAddress(), newBlockName);
close(); close();
@@ -121,17 +121,18 @@ public class MemoryBlockUtils {
* @param r the read permission for the new block. * @param r the read permission for the new block.
* @param w the write permission for the new block. * @param w the write permission for the new block.
* @param x the execute permission for the new block. * @param x the execute permission for the new block.
* @param overlay create overlay block if true otherwise a normal mapped block will be created
* @param log a {@link StringBuffer} for appending error messages * @param log a {@link StringBuffer} for appending error messages
* @return the new created block * @return the new created block
*/ */
public static MemoryBlock createBitMappedBlock(Program program, String name, Address start, public static MemoryBlock createBitMappedBlock(Program program, String name, Address start,
Address base, int length, String comment, String source, boolean r, boolean w, Address base, int length, String comment, String source, boolean r, boolean w,
boolean x, MessageLog log) { boolean x, boolean overlay, MessageLog log) {
Memory memory = program.getMemory(); Memory memory = program.getMemory();
try { try {
MemoryBlock block = memory.createBitMappedBlock(name, start, base, length); MemoryBlock block = memory.createBitMappedBlock(name, start, base, length, overlay);
setBlockAttributes(block, comment, source, r, w, x); setBlockAttributes(block, comment, source, r, w, x);
adjustFragment(program, start, name); adjustFragment(program, start, name);
@@ -148,7 +149,8 @@ public class MemoryBlockUtils {
} }
/** /**
* Creates a new byte mapped memory block. (A byte mapped block is a block where each byte value * Creates a new byte mapped memory block with a 1:1 byte mapping scheme.
* (A byte mapped block is a block where each byte value
* is taken from a byte at some other address in memory) * is taken from a byte at some other address in memory)
* *
* @param program the program in which to create the block. * @param program the program in which to create the block.
@@ -161,17 +163,18 @@ public class MemoryBlockUtils {
* @param r the read permission for the new block. * @param r the read permission for the new block.
* @param w the write permission for the new block. * @param w the write permission for the new block.
* @param x the execute permission for the new block. * @param x the execute permission for the new block.
* @param overlay create overlay block if true otherwise a normal mapped block will be created
* @param log a {@link MessageLog} for appending error messages * @param log a {@link MessageLog} for appending error messages
* @return the new created block * @return the new created block
*/ */
public static MemoryBlock createByteMappedBlock(Program program, String name, Address start, public static MemoryBlock createByteMappedBlock(Program program, String name, Address start,
Address base, int length, String comment, String source, boolean r, boolean w, Address base, int length, String comment, String source, boolean r, boolean w,
boolean x, MessageLog log) { boolean x, boolean overlay, MessageLog log) {
Memory memory = program.getMemory(); Memory memory = program.getMemory();
try { try {
MemoryBlock block = memory.createByteMappedBlock(name, start, base, length); MemoryBlock block = memory.createByteMappedBlock(name, start, base, length, overlay);
setBlockAttributes(block, comment, source, r, w, x); setBlockAttributes(block, comment, source, r, w, x);
adjustFragment(program, start, name); adjustFragment(program, start, name);
@@ -31,7 +31,8 @@ public class CommentFieldMouseHandler implements FieldMouseHandlerExtension {
private final static Class<?>[] SUPPORTED_CLASSES = private final static Class<?>[] SUPPORTED_CLASSES =
new Class[] { CommentFieldLocation.class, EolCommentFieldLocation.class, new Class[] { CommentFieldLocation.class, EolCommentFieldLocation.class,
PlateFieldLocation.class, AutomaticCommentFieldLocation.class }; PlateFieldLocation.class, AutomaticCommentFieldLocation.class,
MemoryBlockStartFieldLocation.class };
@Override @Override
public Class<?>[] getSupportedProgramLocations() { public Class<?>[] getSupportedProgramLocations() {
@@ -111,8 +111,15 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
return null; return null;
} }
CodeUnit cu = (CodeUnit) proxyObject; CodeUnit cu = (CodeUnit) proxyObject;
List<AttributedString> attributedStrings = createBlockStartText(cu);
String[] comments = new String[attributedStrings.size()];
for (int i = 0; i < comments.length; i++) {
comments[i] = attributedStrings.get(i).getText();
}
return new MemoryBlockStartFieldLocation(cu.getProgram(), cu.getMinAddress(), null, row, return new MemoryBlockStartFieldLocation(cu.getProgram(), cu.getMinAddress(), null, row,
col, null, 0); col, comments, 0);
} }
/** /**
@@ -199,11 +206,20 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
return null; return null;
} }
String type = block.getType() == MemoryBlockType.DEFAULT ? "" : "(" + block.getType() + ")"; MemoryBlockType blockType = block.getType();
String type = "";
if (blockType != MemoryBlockType.DEFAULT) {
if (block.isMapped()) {
type = "(" + block.getSourceInfos().get(0).getDescription() + ")";
}
else {
type = "(" + blockType + ")";
}
}
String line1 = block.getName() + " " + type; String line1 = block.getName() + " " + type;
String line2 = block.getComment(); String line2 = block.getComment();
String line3 = cu.getMemory().getMinAddress().getAddressSpace().toString() + " " + String line3 = block.getStart().toString(true) + "-" + block.getEnd().toString(true);
block.getStart() + "-" + block.getEnd();
AttributedString borderAS = new AttributedString("//", color, getMetrics()); AttributedString borderAS = new AttributedString("//", color, getMetrics());
lines.add(borderAS); lines.add(borderAS);
@@ -149,7 +149,7 @@ class MemoryMapXmlMgr {
Address sourceAddr = factory.getAddress(element.getAttribute("SOURCE_ADDRESS")); Address sourceAddr = factory.getAddress(element.getAttribute("SOURCE_ADDRESS"));
MemoryBlock block = MemoryBlockUtils.createBitMappedBlock(program, overlayName, MemoryBlock block = MemoryBlockUtils.createBitMappedBlock(program, overlayName,
addr, sourceAddr, length, comment, comment, r, w, x, log); addr, sourceAddr, length, comment, comment, r, w, x, false, log);
if (block != null) { if (block != null) {
block.setVolatile(isVolatile); block.setVolatile(isVolatile);
} }
@@ -159,7 +159,7 @@ class MemoryMapXmlMgr {
Address sourceAddr = factory.getAddress(element.getAttribute("SOURCE_ADDRESS")); Address sourceAddr = factory.getAddress(element.getAttribute("SOURCE_ADDRESS"));
MemoryBlock block = MemoryBlockUtils.createByteMappedBlock(program, overlayName, MemoryBlock block = MemoryBlockUtils.createByteMappedBlock(program, overlayName,
addr, sourceAddr, length, comment, comment, r, w, x, log); addr, sourceAddr, length, comment, comment, r, w, x, false, log);
if (block != null) { if (block != null) {
block.setVolatile(isVolatile); block.setVolatile(isVolatile);
} }
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,6 +15,8 @@
*/ */
package ghidra.program.util; package ghidra.program.util;
import java.util.ArrayList;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
@@ -26,8 +27,6 @@ import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.NotFoundException; import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import java.util.ArrayList;
/** /**
* <CODE>MemoryDiff</CODE> determines where the memory differs between two programs as well as the * <CODE>MemoryDiff</CODE> determines where the memory differs between two programs as well as the
* types of differences. * types of differences.
@@ -179,12 +178,12 @@ public class MemoryDiff {
*/ */
public AddressRange[] getDifferentAddressRanges() { public AddressRange[] getDifferentAddressRanges() {
ArrayList<AddressRange> rangeDiffs = new ArrayList<AddressRange>(); ArrayList<AddressRange> rangeDiffs = new ArrayList<AddressRange>();
for (int i = 0; i < ranges.length; i++) { for (AddressRange range : ranges) {
Address addr = ranges[i].getMinAddress(); Address addr = range.getMinAddress();
MemoryBlock block1 = memory1.getBlock(addr); MemoryBlock block1 = memory1.getBlock(addr);
MemoryBlock block2 = memory2.getBlock(addr); MemoryBlock block2 = memory2.getBlock(addr);
if (!sameMemoryBlock(block1, block2)) { if (!sameMemoryBlock(block1, block2)) {
rangeDiffs.add(ranges[i]); rangeDiffs.add(range);
} }
} }
return rangeDiffs.toArray(new AddressRange[rangeDiffs.size()]); return rangeDiffs.toArray(new AddressRange[rangeDiffs.size()]);
@@ -271,15 +270,8 @@ public class MemoryDiff {
memory1.join(firstBlock, secondBlock); memory1.join(firstBlock, secondBlock);
} }
return true; return true;
} catch (MemoryBlockException e) { }
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); catch (Exception e) {
} catch (LockException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
} catch (MemoryConflictException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
} catch (AddressOverflowException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
} catch (NotFoundException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
} }
return false; return false;
@@ -225,7 +225,7 @@ public class ProgramMemoryUtil {
AddressSet addrSet = new AddressSet(); AddressSet addrSet = new AddressSet();
MemoryBlock[] memBlocks = program.getMemory().getBlocks(); MemoryBlock[] memBlocks = program.getMemory().getBlocks();
for (MemoryBlock memoryBlock : memBlocks) { for (MemoryBlock memoryBlock : memBlocks) {
if (memoryBlock.getType() == MemoryBlockType.OVERLAY) { if (memoryBlock.isOverlay()) {
AddressRange addressRange = AddressRange addressRange =
new AddressRangeImpl(memoryBlock.getStart(), memoryBlock.getEnd()); new AddressRangeImpl(memoryBlock.getStart(), memoryBlock.getEnd());
addrSet.add(addressRange); addrSet.add(addressRange);
@@ -143,7 +143,10 @@ public class AddBlockModelTest extends AbstractGhidraHeadedIntegrationTest
model.setLength(100); model.setLength(100);
assertTrue(model.isValidInfo()); assertTrue(model.isValidInfo());
model.setBlockType(MemoryBlockType.OVERLAY); model.setBlockType(MemoryBlockType.DEFAULT);
assertTrue(model.isValidInfo());
model.setOverlay(true);
assertTrue(model.isValidInfo()); assertTrue(model.isValidInfo());
model.setBaseAddress(getAddr(0x2000)); model.setBaseAddress(getAddr(0x2000));
@@ -181,7 +184,8 @@ public class AddBlockModelTest extends AbstractGhidraHeadedIntegrationTest
model.setBlockName(".test"); model.setBlockName(".test");
model.setStartAddress(getAddr(0x100)); model.setStartAddress(getAddr(0x100));
model.setLength(100); model.setLength(100);
model.setBlockType(MemoryBlockType.OVERLAY); model.setBlockType(MemoryBlockType.DEFAULT);
model.setOverlay(true);
model.setInitializedType(InitializedType.INITIALIZED_FROM_VALUE); model.setInitializedType(InitializedType.INITIALIZED_FROM_VALUE);
model.setInitialValue(0xa); model.setInitialValue(0xa);
assertTrue(model.execute()); assertTrue(model.execute());
@@ -206,7 +210,8 @@ public class AddBlockModelTest extends AbstractGhidraHeadedIntegrationTest
model.setBlockName(".test"); model.setBlockName(".test");
model.setStartAddress(getAddr(0x01001000)); model.setStartAddress(getAddr(0x01001000));
model.setLength(100); model.setLength(100);
model.setBlockType(MemoryBlockType.OVERLAY); model.setBlockType(MemoryBlockType.DEFAULT);
model.setOverlay(true);
model.setInitializedType(InitializedType.INITIALIZED_FROM_VALUE); model.setInitializedType(InitializedType.INITIALIZED_FROM_VALUE);
model.setInitialValue(0xa); model.setInitialValue(0xa);
assertTrue(model.execute()); assertTrue(model.execute());
@@ -482,7 +482,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
// add a bit overlay block, live block, and an unitialized block // add a bit overlay block, live block, and an unitialized block
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100); memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100, false);
memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false); memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false);
program.endTransaction(transactionID, true); program.endTransaction(transactionID, true);
@@ -508,7 +508,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
public void testSortBlockTypeDescending() throws Exception { public void testSortBlockTypeDescending() throws Exception {
// add a bit overlay block, live block, and an unitialized block // add a bit overlay block, live block, and an unitialized block
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100); memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100, false);
memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false); memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false);
program.endTransaction(transactionID, true); program.endTransaction(transactionID, true);
@@ -540,7 +540,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
// //
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
MemoryBlock block = MemoryBlock block =
memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100); memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100, false);
block.setSourceName("this is a test"); block.setSourceName("this is a test");
block = memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false); block = memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false);
block.setSourceName("other source"); block.setSourceName("other source");
@@ -581,7 +581,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
// //
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
MemoryBlock block = MemoryBlock block =
memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100); memory.createBitMappedBlock(".Bit", getAddr(0), getAddr(0x01001000), 0x100, false);
block.setSourceName("this is a test"); block.setSourceName("this is a test");
block = memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false); block = memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false);
block.setSourceName("other source"); block.setSourceName("other source");
@@ -215,6 +215,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.EXECUTE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.EXECUTE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE)); assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT));
assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE)); assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE));
@@ -292,6 +293,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.EXECUTE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.EXECUTE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE)); assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT));
assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE)); assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE));
@@ -578,6 +580,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE)); assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE)); assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT)); assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT));
assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE)); assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE));
@@ -611,6 +614,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
final JCheckBox readCB = (JCheckBox) findComponentByName(d.getComponent(), "Read"); final JCheckBox readCB = (JCheckBox) findComponentByName(d.getComponent(), "Read");
final JCheckBox writeCB = (JCheckBox) findComponentByName(d.getComponent(), "Write"); final JCheckBox writeCB = (JCheckBox) findComponentByName(d.getComponent(), "Write");
final JCheckBox executeCB = (JCheckBox) findComponentByName(d.getComponent(), "Execute"); final JCheckBox executeCB = (JCheckBox) findComponentByName(d.getComponent(), "Execute");
final JCheckBox overlayCB = (JCheckBox) findComponentByName(d.getComponent(), "Overlay");
final JRadioButton initializedRB = final JRadioButton initializedRB =
(JRadioButton) findComponentByName(d.getComponent(), "Initialized"); (JRadioButton) findComponentByName(d.getComponent(), "Initialized");
final RegisterField initialValue = final RegisterField initialValue =
@@ -623,11 +627,16 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
final JButton okButton = findButton(d.getComponent(), "OK"); final JButton okButton = findButton(d.getComponent(), "OK");
SwingUtilities.invokeAndWait(() -> { SwingUtilities.invokeAndWait(() -> {
comboBox.setSelectedItem(MemoryBlockType.OVERLAY); comboBox.setSelectedItem(MemoryBlockType.DEFAULT);
overlayCB.setSelected(true);
overlayCB.getActionListeners()[0].actionPerformed(null);
nameField.setText(".test"); nameField.setText(".test");
lengthField.setText("0x100"); lengthField.setText("0x100");
commentField.setText("this is a block test"); commentField.setText("this is a block test");
initialValue.setText("0xa"); initialValue.setText("0xa");
});
SwingUtilities.invokeAndWait(() -> {
pressButton(executeCB); pressButton(executeCB);
}); });
@@ -666,7 +675,9 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.WRITE));
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.EXECUTE)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.EXECUTE));
assertEquals(MemoryBlockType.OVERLAY.toString(), assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.OVERLAY));
assertEquals(
MemoryBlockType.DEFAULT.toString(),
model.getValueAt(row, MemoryMapModel.BLOCK_TYPE)); model.getValueAt(row, MemoryMapModel.BLOCK_TYPE));
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.INIT)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.INIT));
assertEquals("", model.getValueAt(row, MemoryMapModel.SOURCE)); assertEquals("", model.getValueAt(row, MemoryMapModel.SOURCE));
@@ -693,6 +704,8 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
final JCheckBox readCB = (JCheckBox) findComponentByName(d.getComponent(), "Read"); final JCheckBox readCB = (JCheckBox) findComponentByName(d.getComponent(), "Read");
final JCheckBox writeCB = (JCheckBox) findComponentByName(d.getComponent(), "Write"); final JCheckBox writeCB = (JCheckBox) findComponentByName(d.getComponent(), "Write");
final JCheckBox executeCB = (JCheckBox) findComponentByName(d.getComponent(), "Execute"); final JCheckBox executeCB = (JCheckBox) findComponentByName(d.getComponent(), "Execute");
final JCheckBox overlayCB = (JCheckBox) findComponentByName(d.getComponent(), "Overlay");
final JRadioButton uninitRB = final JRadioButton uninitRB =
(JRadioButton) findComponentByName(d.getComponent(), "Uninitialized"); (JRadioButton) findComponentByName(d.getComponent(), "Uninitialized");
final AddressInput addrField = final AddressInput addrField =
@@ -703,7 +716,9 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
final JButton okButton = findButton(d.getComponent(), "OK"); final JButton okButton = findButton(d.getComponent(), "OK");
SwingUtilities.invokeAndWait(() -> { SwingUtilities.invokeAndWait(() -> {
comboBox.setSelectedItem(MemoryBlockType.OVERLAY); comboBox.setSelectedItem(MemoryBlockType.DEFAULT);
overlayCB.setSelected(true);
overlayCB.getActionListeners()[0].actionPerformed(null);
nameField.setText(".test"); nameField.setText(".test");
lengthField.setText("0x100"); lengthField.setText("0x100");
commentField.setText("this is a block test"); commentField.setText("this is a block test");
@@ -743,7 +758,9 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.WRITE));
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.EXECUTE)); assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.EXECUTE));
assertEquals(MemoryBlockType.OVERLAY.toString(), assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.OVERLAY));
assertEquals(
MemoryBlockType.DEFAULT.toString(),
model.getValueAt(row, MemoryMapModel.BLOCK_TYPE)); model.getValueAt(row, MemoryMapModel.BLOCK_TYPE));
assertEquals(Boolean.FALSE, model.getValueAt(row, MemoryMapModel.INIT)); assertEquals(Boolean.FALSE, model.getValueAt(row, MemoryMapModel.INIT));
assertEquals("", model.getValueAt(row, MemoryMapModel.SOURCE)); assertEquals("", model.getValueAt(row, MemoryMapModel.SOURCE));
@@ -822,6 +839,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE)); assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
assertEquals("Bit Mapped", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE)); assertEquals("Bit Mapped", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
assertNull(model.getValueAt(0, MemoryMapModel.INIT)); assertNull(model.getValueAt(0, MemoryMapModel.INIT));
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE)); assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE));
@@ -900,6 +918,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE)); assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE)); assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
assertEquals("Byte Mapped", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE)); assertEquals("Byte Mapped", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT)); assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT));
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE)); assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE));
@@ -15,8 +15,7 @@
*/ */
package ghidra.program.database.map; package ghidra.program.database.map;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import org.junit.*; import org.junit.*;
@@ -62,7 +61,7 @@ public class AddressIndexPrimaryKeyIteratorTest extends AbstractGhidraHeadedInte
// Create fragmented memory // Create fragmented memory
memMap.createInitializedBlock("Block1", addr(0x8000), 0x10, (byte) 0, null, false);// startKey: 0x0 memMap.createInitializedBlock("Block1", addr(0x8000), 0x10, (byte) 0, null, false);// startKey: 0x0
memMap.createUninitializedBlock("Block2", addr(0x5000), 0x10, false);// startKey: 0x10000 memMap.createUninitializedBlock("Block2", addr(0x5000), 0x10, false);// startKey: 0x10000
memMap.createBitMappedBlock("Block3", addr(0x9000), addr(0x5000), 0x10);// startKey: 0x20000 memMap.createBitMappedBlock("Block3", addr(0x9000), addr(0x5000), 0x10, false);// startKey: 0x20000
memMap.createUninitializedBlock("Block4", addr(0x3000), 0x10, false);// startKey: 0x30000 memMap.createUninitializedBlock("Block4", addr(0x3000), 0x10, false);// startKey: 0x30000
// Create table with indexed address column // Create table with indexed address column
@@ -15,8 +15,7 @@
*/ */
package ghidra.program.database.map; package ghidra.program.database.map;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -65,7 +64,7 @@ public class AddressKeyIteratorTest extends AbstractGhidraHeadedIntegrationTest
// Create fragmented memory // Create fragmented memory
memMap.createInitializedBlock("Block1", addr(0x8000), 0x10, (byte) 0, null, false);// startKey: 0x0 memMap.createInitializedBlock("Block1", addr(0x8000), 0x10, (byte) 0, null, false);// startKey: 0x0
memMap.createUninitializedBlock("Block2", addr(0x5000), 0x10, false);// startKey: 0x10000 memMap.createUninitializedBlock("Block2", addr(0x5000), 0x10, false);// startKey: 0x10000
memMap.createBitMappedBlock("Block3", addr(0x9000), addr(0x5000), 0x10);// startKey: 0x20000 memMap.createBitMappedBlock("Block3", addr(0x9000), addr(0x5000), 0x10, false);// startKey: 0x20000
memMap.createUninitializedBlock("Block4", addr(0x3000), 0x10, false);// startKey: 0x30000 memMap.createUninitializedBlock("Block4", addr(0x3000), 0x10, false);// startKey: 0x30000
// Create table keyed on address // Create table keyed on address
@@ -15,8 +15,7 @@
*/ */
package ghidra.program.database.mem; package ghidra.program.database.mem;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import org.junit.*; import org.junit.*;
@@ -31,7 +30,7 @@ import ghidra.util.task.TaskMonitorAdapter;
/** /**
* Test for the BitMemoryBlock for the database implementation. * Test for the BitMemoryBlock for the database implementation.
*/ */
public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest { public class BitMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
private AddressSpace byteSpace; private AddressSpace byteSpace;
private AddressSpace bitSpace; private AddressSpace bitSpace;
private MemoryBlock block; private MemoryBlock block;
@@ -43,7 +42,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
* Constructor for BitMemoryBlockTest. * Constructor for BitMemoryBlockTest.
* @param name * @param name
*/ */
public BitMemoryBlockTest() { public BitMappedMemoryBlockTest() {
super(); super();
} }
@@ -74,11 +73,12 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testCreateNewBlock() throws Exception { public void testCreateNewBlock() throws Exception {
memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0), bitSpace.getAddress(0x20), memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0), bitSpace.getAddress(0x20),
0x20); 0x20, false);
Address newStart = bitSpace.getAddress(0x40); Address newStart = bitSpace.getAddress(0x40);
MemoryBlock newblock = MemoryBlock newblock =
memory.createBitMappedBlock("BitTest", newStart, bitSpace.getAddress(0x20), 0x50); memory.createBitMappedBlock("BitTest", newStart, bitSpace.getAddress(0x20), 0x50,
false);
assertNotNull(newblock); assertNotNull(newblock);
assertEquals(newStart, newblock.getStart()); assertEquals(newStart, newblock.getStart());
} }
@@ -86,7 +86,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testNoUnderlyingMemory() throws Exception { public void testNoUnderlyingMemory() throws Exception {
MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0), MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0),
bitSpace.getAddress(0x20), 0x20); bitSpace.getAddress(0x20), 0x20, false);
Address addr = bitSpace.getAddress(0x40); Address addr = bitSpace.getAddress(0x40);
MemoryBlock newblock = memory.createBlock(bitBlock, "BitTest", addr, 0x50); MemoryBlock newblock = memory.createBlock(bitBlock, "BitTest", addr, 0x50);
@@ -101,7 +101,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testGetByte() throws Exception { public void testGetByte() throws Exception {
MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0), MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0),
byteSpace.getAddress(0x20), 256); byteSpace.getAddress(0x20), 256, false);
for (int i = 0; i < 256; i += 2) { for (int i = 0; i < 256; i += 2) {
assertEquals(0, bitBlock.getByte(bitSpace.getAddress(i))); assertEquals(0, bitBlock.getByte(bitSpace.getAddress(i)));
@@ -113,7 +113,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testPutByte() throws Exception { public void testPutByte() throws Exception {
MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0), MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0),
byteSpace.getAddress(0x20), 256); byteSpace.getAddress(0x20), 256, false);
for (int i = 0; i < 256; i += 2) { for (int i = 0; i < 256; i += 2) {
bitBlock.putByte(bitSpace.getAddress(i), (byte) 1); bitBlock.putByte(bitSpace.getAddress(i), (byte) 1);
bitBlock.putByte(bitSpace.getAddress(i + 1), (byte) 0); bitBlock.putByte(bitSpace.getAddress(i + 1), (byte) 0);
@@ -0,0 +1,354 @@
/* ###
* 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.program.database.mem;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.task.TaskMonitor;
public class ByteMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
private AddressSpace space;
private MemoryBlock block;
private Memory memory;
private Program program;
private int transactionID;
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_LE, this);
memory = program.getMemory();
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) i;
}
space = program.getAddressFactory().getDefaultAddressSpace();
transactionID = program.startTransaction("Test");
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
memory.setBytes(block.getStart(), bytes);
}
@After
public void tearDown() {
program.endTransaction(transactionID, true);
program.release(this);
}
private Address addr(long offset) {
return space.getAddress(offset);
}
@Test
public void testCreateNewBlock1to1() throws Exception {
MemoryBlock byteMappedBlock =
memory.createByteMappedBlock("test", addr(0x1000), addr(0x80), 0x100, false);
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(addr(0x1000), byteMappedBlock.getStart());
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(addr(0x1000), addr(0x107F));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(1, scheme.getMappedByteCount());
assertEquals(1, scheme.getMappedSourceByteCount());
assertEquals(addr(0x80), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x80; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + i, b & 0xff);
}
try {
byteMappedBlock.getByte(addr(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length,
(byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(addr(0x1080), addr(0x10FF));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x80; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + i, b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(addr(0x1080 + i));
assertEquals(~i & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3 };
byteMappedBlock.putBytes(addr(0x1080), data1);
byte[] data2 = new byte[3];
assertEquals(3, byteMappedBlock.getBytes(addr(0x1080), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(3, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(data1, data2));
}
@Test
public void testCreateNewBlock1to2() throws Exception {
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(1, 2), false);
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(addr(0x1000), byteMappedBlock.getStart());
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(addr(0x1000), addr(0x103F));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(1, scheme.getMappedByteCount());
assertEquals(2, scheme.getMappedSourceByteCount());
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + (2 * i), b & 0xff);
}
try {
byteMappedBlock.getByte(addr(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(addr(0x1040), addr(0x10BF));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + (2 * i), b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(addr(0x1040 + i));
assertEquals(~(2 * i) & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3, 4 };
byteMappedBlock.putBytes(addr(0x1040), data1);
byte[] data2 = new byte[4];
assertEquals(4, byteMappedBlock.getBytes(addr(0x1040), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(4, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(new byte[] { 1, -2, 2, -4 }, data2));
}
@Test
public void testCreateNewBlock2to4() throws Exception {
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), false);
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(addr(0x1000), byteMappedBlock.getStart());
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(addr(0x1000), addr(0x103E));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(2, scheme.getMappedByteCount());
assertEquals(4, scheme.getMappedSourceByteCount());
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
try {
byteMappedBlock.getByte(addr(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(addr(0x103F), addr(0x10BE));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(addr(0x1040 + i));
int val = ~(4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3, 4 };
byteMappedBlock.putBytes(addr(0x1040), data1);
byte[] data2 = new byte[4];
assertEquals(4, byteMappedBlock.getBytes(addr(0x1040), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(4, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(new byte[] { 1, 2, -3, -4 }, data2));
}
@Test
public void testCreateNewBlock2to4Overlay() throws Exception {
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), true);
assertTrue(byteMappedBlock.isOverlay());
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
assertNotNull(testSpace);
assertEquals(space, testSpace.getPhysicalSpace());
assertEquals(testSpace.getAddress(0x1000), testSpace.getMinAddress());
assertEquals(testSpace.getAddress(0x10FF), testSpace.getMaxAddress());
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(testSpace.getAddress(0x1000), byteMappedBlock.getStart());
assertEquals(testSpace.getAddress(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(testSpace.getAddress(0x1000), testSpace.getAddress(0x103E));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(2, scheme.getMappedByteCount());
assertEquals(4, scheme.getMappedSourceByteCount());
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
try {
byteMappedBlock.getByte(testSpace.getAddress(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(testSpace.getAddress(0x103F), testSpace.getAddress(0x10BE));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(testSpace.getAddress(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1040 + i));
int val = ~(4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3, 4 };
byteMappedBlock.putBytes(testSpace.getAddress(0x1040), data1);
byte[] data2 = new byte[4];
assertEquals(4, byteMappedBlock.getBytes(testSpace.getAddress(0x1040), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(4, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(new byte[] { 1, 2, -3, -4 }, data2));
}
}
@@ -15,51 +15,20 @@
*/ */
package ghidra.program.database.mem; package ghidra.program.database.mem;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Iterator; import java.util.Iterator;
import org.junit.After; import org.junit.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.plugin.core.memory.UninitializedBlockCmd; import ghidra.app.plugin.core.memory.UninitializedBlockCmd;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressOverflowException; import ghidra.program.model.data.*;
import ghidra.program.model.address.AddressRange; import ghidra.program.model.listing.*;
import ghidra.program.model.address.AddressRangeImpl; import ghidra.program.model.mem.*;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.symbol.*;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.ByteDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.ProgramFragment;
import ghidra.program.model.listing.ProgramModule;
import ghidra.program.model.mem.LiveMemoryHandler;
import ghidra.program.model.mem.LiveMemoryListener;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockException;
import ghidra.program.model.mem.MemoryBlockSourceInfo;
import ghidra.program.model.mem.MemoryBlockStub;
import ghidra.program.model.mem.MemoryBlockType;
import ghidra.program.model.mem.MemoryConflictException;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceManager;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.ToyProgramBuilder; import ghidra.test.ToyProgramBuilder;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@@ -255,7 +224,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
public void testCreateBitBlock() throws Exception { public void testCreateBitBlock() throws Exception {
createBlock("Test", addr(0), 100); createBlock("Test", addr(0), 100);
createBlock("Test", addr(500), 100); createBlock("Test", addr(500), 100);
MemoryBlock bitBlock = mem.createBitMappedBlock("BitBlock", addr(600), addr(30), 20); MemoryBlock bitBlock = mem.createBitMappedBlock("BitBlock", addr(600), addr(30), 20, false);
MemoryBlock block = mem.getBlock(addr(610)); MemoryBlock block = mem.getBlock(addr(610));
assertNotNull(block); assertNotNull(block);
assertEquals(bitBlock, block); assertEquals(bitBlock, block);
@@ -321,7 +290,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
MemoryBlock block2 = createBlock("Test2", addr(500), 100); MemoryBlock block2 = createBlock("Test2", addr(500), 100);
MemoryBlock block3 = mem.createUninitializedBlock("Test3", addr(1500), 200, false); MemoryBlock block3 = mem.createUninitializedBlock("Test3", addr(1500), 200, false);
MemoryBlock block4 = mem.createUninitializedBlock("Test4", addr(2500), 100, false); MemoryBlock block4 = mem.createUninitializedBlock("Test4", addr(2500), 100, false);
mem.createBitMappedBlock("BitBlock", addr(3000), addr(550), 2000); mem.createBitMappedBlock("BitBlock", addr(3000), addr(550), 2000, false);
MemoryBlock[] blocks = mem.getBlocks(); MemoryBlock[] blocks = mem.getBlocks();
assertEquals(5, blocks.length); assertEquals(5, blocks.length);
@@ -487,7 +456,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
MemoryBlock block2 = createBlock("Test2", addr(500), 100); MemoryBlock block2 = createBlock("Test2", addr(500), 100);
MemoryBlock block3 = mem.createUninitializedBlock("Test3", addr(1500), 200, false); MemoryBlock block3 = mem.createUninitializedBlock("Test3", addr(1500), 200, false);
mem.createUninitializedBlock("Test4", addr(2500), 100, false); mem.createUninitializedBlock("Test4", addr(2500), 100, false);
MemoryBlock block5 = mem.createBitMappedBlock("BitBlock", addr(3000), addr(550), 20); MemoryBlock block5 = mem.createBitMappedBlock("BitBlock", addr(3000), addr(550), 20, false);
block1.setComment("Hello!"); block1.setComment("Hello!");
block2.setName("NewTest2"); block2.setName("NewTest2");
block3.setWrite(false); block3.setWrite(false);
@@ -670,7 +639,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
public void testMoveBitBlock() throws Exception { public void testMoveBitBlock() throws Exception {
createBlock("Test", addr(0), 100); createBlock("Test", addr(0), 100);
MemoryBlock bitBlock = mem.createBitMappedBlock("BitBlock", addr(200), addr(50), 20); MemoryBlock bitBlock = mem.createBitMappedBlock("BitBlock", addr(200), addr(50), 20, false);
assertEquals(0, bitBlock.getByte(addr(200))); assertEquals(0, bitBlock.getByte(addr(200)));
bitBlock.putByte(addr(200), (byte) 5); bitBlock.putByte(addr(200), (byte) 5);
assertEquals(1, bitBlock.getByte(addr(200))); assertEquals(1, bitBlock.getByte(addr(200)));
@@ -1034,13 +1003,15 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
public void testCreateOverlayBlock() throws Exception { public void testCreateOverlayBlock() throws Exception {
MemoryBlock block = mem.createInitializedBlock(".overlay", addr(0), 0x1000, (byte) 0xa, MemoryBlock block = mem.createInitializedBlock(".overlay", addr(0), 0x1000, (byte) 0xa,
TaskMonitor.DUMMY, true); TaskMonitor.DUMMY, true);
assertEquals(MemoryBlockType.OVERLAY, block.getType()); assertEquals(MemoryBlockType.DEFAULT, block.getType());
assertTrue(block.isOverlay());
} }
@Test @Test
public void testCreateBitMappedBlock() throws Exception { public void testCreateBitMappedBlock() throws Exception {
mem.createInitializedBlock("mem", addr(0), 0x1000, (byte) 0xa, TaskMonitor.DUMMY, false); mem.createInitializedBlock("mem", addr(0), 0x1000, (byte) 0xa, TaskMonitor.DUMMY, false);
MemoryBlock bitBlock = mem.createBitMappedBlock("bit", addr(0x2000), addr(0xf00), 0x1000); MemoryBlock bitBlock =
mem.createBitMappedBlock("bit", addr(0x2000), addr(0xf00), 0x1000, false);
assertEquals(MemoryBlockType.BIT_MAPPED, bitBlock.getType()); assertEquals(MemoryBlockType.BIT_MAPPED, bitBlock.getType());
@@ -1056,7 +1027,8 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testCreateByteMappedBlock() throws Exception { public void testCreateByteMappedBlock() throws Exception {
mem.createInitializedBlock("mem", addr(0), 0x1000, (byte) 0xa, TaskMonitor.DUMMY, false); mem.createInitializedBlock("mem", addr(0), 0x1000, (byte) 0xa, TaskMonitor.DUMMY, false);
MemoryBlock byteBlock = mem.createByteMappedBlock("byte", addr(0x2000), addr(0xf00), 0x200); MemoryBlock byteBlock =
mem.createByteMappedBlock("byte", addr(0x2000), addr(0xf00), 0x200, false);
assertEquals(MemoryBlockType.BYTE_MAPPED, byteBlock.getType()); assertEquals(MemoryBlockType.BYTE_MAPPED, byteBlock.getType());
@@ -1066,14 +1038,14 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
expectedInitializedSet.add(addr(0), addr(0xfff)); expectedInitializedSet.add(addr(0), addr(0xfff));
expectedInitializedSet.add(addr(0x2000), addr(0x20ff)); expectedInitializedSet.add(addr(0x2000), addr(0x20ff));
assertEquals(expectedInitializedSet, mem.getAllInitializedAddressSet()); assertEquals(expectedInitializedSet, mem.getAllInitializedAddressSet());
} }
@Test @Test
public void testCreateRemoveCreateOverlayBlock() throws Exception { public void testCreateRemoveCreateOverlayBlock() throws Exception {
MemoryBlock block = mem.createInitializedBlock(".overlay", addr(0), 0x1000, (byte) 0xa, MemoryBlock block = mem.createInitializedBlock(".overlay", addr(0), 0x1000, (byte) 0xa,
TaskMonitor.DUMMY, true); TaskMonitor.DUMMY, true);
assertEquals(MemoryBlockType.OVERLAY, block.getType()); assertEquals(MemoryBlockType.DEFAULT, block.getType());
assertTrue(block.isOverlay());
mem.removeBlock(block, TaskMonitor.DUMMY); mem.removeBlock(block, TaskMonitor.DUMMY);
block = block =
mem.createInitializedBlock("ov2", addr(0), 0x2000, (byte) 0xa, TaskMonitor.DUMMY, true); mem.createInitializedBlock("ov2", addr(0), 0x2000, (byte) 0xa, TaskMonitor.DUMMY, true);
@@ -0,0 +1,193 @@
/* ###
* 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.program.database.mem;
import static org.junit.Assert.*;
import org.junit.*;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.task.TaskMonitor;
public class MemoryWriteCheckTest extends AbstractGhidraHeadedIntegrationTest {
private AddressSpace space;
private MemoryBlock block;
private Memory memory;
private Program program;
private int transactionID;
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_LE, this);
memory = program.getMemory();
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) i;
}
space = program.getAddressFactory().getDefaultAddressSpace();
transactionID = program.startTransaction("Test");
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0), bytes.length,
(byte) 0, TaskMonitor.DUMMY, false);
memory.setBytes(block.getStart(), bytes);
}
@After
public void tearDown() {
program.endTransaction(transactionID, true);
program.release(this);
}
private Address addr(long offset) {
return space.getAddress(offset);
}
@Test
public void testByteMappedMemoryCheck() throws Exception {
AddressSet set = new AddressSet(addr(0), addr(0xd7));
DisassembleCommand cmd = new DisassembleCommand(set, set);
cmd.applyTo(program); // range 0x0000 to 0x00d7 disassembled
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), true);
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
try {
byteMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000080", e.getMessage());
}
try {
byteMappedBlock.putBytes(testSpace.getAddress(0x1002), new byte[] { 1, 2 });
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000084", e.getMessage());
}
program.getListing().clearCodeUnits(addr(0), addr(0xd7), true);
byteMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
assertEquals(1, byteMappedBlock.getByte(testSpace.getAddress(0x1000)));
byteMappedBlock.putBytes(testSpace.getAddress(0x1002), new byte[] { 1, 2 });
byte[] data = new byte[2];
assertEquals(2, byteMappedBlock.getBytes(testSpace.getAddress(0x1002), data));
assertArrayEquals(new byte[] { 1, 2 }, data);
}
@Test
public void testByteMappedMemoryCheck1() throws Exception {
// NOTE: disassembling in a 2:4 byte-mapped block is rather inappropriate and may be disallowed in the future
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), true);
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
AddressSet set = new AddressSet(testSpace.getAddress(0x1000), testSpace.getAddress(0x1011));
DisassembleCommand cmd = new DisassembleCommand(set, set);
cmd.applyTo(program); // range test:0x1000 to test::0x1011 disassembled
try {
block.putByte(addr(0x80), (byte) 1);
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at test::00001000",
e.getMessage());
}
// small modification within filler byte region for mapped block allowed
block.putBytes(addr(0x82), new byte[] { 1, 2 });
byte[] data = new byte[2];
assertEquals(2, block.getBytes(addr(0x82), data));
assertArrayEquals(new byte[] { 1, 2 }, data);
try {
block.putBytes(addr(0x84), new byte[] { 1, 2 });
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at test::00001002",
e.getMessage());
}
program.getListing().clearCodeUnits(set.getMinAddress(), set.getMaxAddress(), true);
block.putByte(addr(0x80), (byte) 1);
assertEquals(1, byteMappedBlock.getByte(testSpace.getAddress(0x1000)));
block.putBytes(addr(0x84), new byte[] { 1, 2 });
assertEquals(2, byteMappedBlock.getBytes(testSpace.getAddress(0x1002), data));
assertArrayEquals(new byte[] { 1, 2 }, data);
}
@Test
public void testBitMappedMemoryCheck() throws Exception {
AddressSet set = new AddressSet(addr(0), addr(0xd7));
DisassembleCommand cmd = new DisassembleCommand(set, set);
cmd.applyTo(program); // range 0x0000 to 0x00d7 disassembled
MemoryBlock bitMappedBlock =
memory.createBitMappedBlock("test", addr(0x1000), addr(0x80), 0x100, true);
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
try {
bitMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000080", e.getMessage());
}
try {
bitMappedBlock.putBytes(testSpace.getAddress(0x1010), new byte[] { 1, 0, 1, 0 });
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000082", e.getMessage());
}
program.getListing().clearCodeUnits(addr(0), addr(0xd7), true);
bitMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
assertEquals(1, bitMappedBlock.getByte(testSpace.getAddress(0x1000)));
bitMappedBlock.putBytes(testSpace.getAddress(0x1010), new byte[] { 1, 0, 1, 0 });
byte[] data = new byte[4];
assertEquals(4, bitMappedBlock.getBytes(testSpace.getAddress(0x1010), data));
assertArrayEquals(new byte[] { 1, 0, 1, 0 }, data);
}
}
@@ -22,7 +22,8 @@ import org.junit.*;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.Address; import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.util.exception.RollbackException; import ghidra.util.exception.RollbackException;
@@ -47,7 +48,7 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
notepad = notepadBuilder.getProgram(); notepad = notepadBuilder.getProgram();
ProgramBuilder x08Builder = new ProgramBuilder("x08", ProgramBuilder._8051); ProgramBuilder x08Builder = new ProgramBuilder("x08", ProgramBuilder._8051);
x08Builder.createMemory("test1", "0x0", 1); x08Builder.createMemory("test1", "0x0", 400);
x08 = x08Builder.getProgram(); x08 = x08Builder.getProgram();
} }
@@ -59,6 +60,8 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
assertTrue(applyCmd(notepad, command)); assertTrue(applyCmd(notepad, command));
MemoryBlock block = notepad.getMemory().getBlock(getNotepadAddr(0x100)); MemoryBlock block = notepad.getMemory().getBlock(getNotepadAddr(0x100));
assertNotNull(block); assertNotNull(block);
assertEquals(MemoryBlockType.DEFAULT, block.getType());
assertFalse(block.isOverlay());
byte b = block.getByte(getNotepadAddr(0x100)); byte b = block.getByte(getNotepadAddr(0x100));
assertEquals((byte) 0xa, b); assertEquals((byte) 0xa, b);
@@ -103,29 +106,139 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
public void testAddBitBlock() { public void testAddBitBlock() {
Address addr = getX08Addr(0x3000); Address addr = getX08Addr(0x3000);
command = new AddBitMappedMemoryBlockCmd(".testBit", "A Test", "new block", addr, 100, true, command = new AddBitMappedMemoryBlockCmd(".testBit", "A Test", "new block", addr, 100, true,
true, true, false, getX08Addr(0)); true, true, false, getX08Addr(0), false);
assertTrue(applyCmd(x08, command));
// map 100 byte block from source of 12-bytes (96 bits) + partial byte (4 bits)
MemoryBlock block = x08.getMemory().getBlock(addr);
assertNotNull(block);
assertEquals(100, block.getSize());
assertEquals(getX08Addr(0x3000), block.getStart());
assertEquals(getX08Addr(0x3063), block.getEnd());
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
AddressRange mappedRange = info.getMappedRange().get();
assertEquals(13, mappedRange.getLength());
assertEquals(getX08Addr(0), mappedRange.getMinAddress());
assertEquals(getX08Addr(12), mappedRange.getMaxAddress());
assertEquals(MemoryBlockType.BIT_MAPPED, block.getType());
assertFalse(block.isOverlay());
}
@Test
public void testAddBitOverlayBlock() {
Address addr = getX08Addr(0x3000);
command = new AddBitMappedMemoryBlockCmd(".testBit", "A Test", "new block", addr, 100, true,
true, true, false, getX08Addr(0), true);
assertTrue(applyCmd(x08, command)); assertTrue(applyCmd(x08, command));
MemoryBlock block = x08.getMemory().getBlock(addr); MemoryBlock block = x08.getMemory().getBlock(addr);
assertNull(block);
block = x08.getMemory().getBlock(".testBit");
assertNotNull(block); assertNotNull(block);
assertEquals(100, block.getSize());
AddressSpace space = x08.getAddressFactory().getAddressSpace(".testBit");
assertNotNull(space);
assertTrue(space.isOverlaySpace());
assertEquals(space.getAddress(0x3000), block.getStart());
assertEquals(space.getAddress(0x3063), block.getEnd());
assertEquals(block.getStart(), space.getMinAddress());
assertEquals(block.getEnd(), space.getMaxAddress());
MemoryBlockSourceInfo info = block.getSourceInfos().get(0); MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress()); AddressRange mappedRange = info.getMappedRange().get();
assertEquals(13, mappedRange.getLength());
assertEquals(getX08Addr(0), mappedRange.getMinAddress());
assertEquals(getX08Addr(12), mappedRange.getMaxAddress());
assertEquals(MemoryBlockType.BIT_MAPPED, block.getType()); assertEquals(MemoryBlockType.BIT_MAPPED, block.getType());
assertTrue(block.isOverlay());
} }
@Test @Test
public void testAddByteBlock() { public void testAddByteBlock() {
Address addr = getX08Addr(0x3000); Address addr = getX08Addr(0x3000);
command = new AddByteMappedMemoryBlockCmd(".testByte", "A Test", "new block", addr, 100, command = new AddByteMappedMemoryBlockCmd(".testByte", "A Test", "new block", addr, 100,
true, true, true, false, getX08Addr(0)); true, true, true, false, getX08Addr(0), false);
assertTrue(applyCmd(x08, command)); assertTrue(applyCmd(x08, command));
MemoryBlock block = x08.getMemory().getBlock(addr); MemoryBlock block = x08.getMemory().getBlock(addr);
assertNotNull(block); assertNotNull(block);
assertEquals(100, block.getSize());
MemoryBlockSourceInfo info = block.getSourceInfos().get(0); MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress()); assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress());
assertEquals(getX08Addr(99), info.getMappedRange().get().getMaxAddress());
assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType()); assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType());
assertFalse(block.isOverlay());
}
@Test
public void testAddByteBlockWithScheme() {
Address addr = getX08Addr(0x3000);
command = new AddByteMappedMemoryBlockCmd(".testByte", "A Test", "new block", addr, 100,
true, true, true, false, getX08Addr(0), new ByteMappingScheme(2, 4), false);
assertTrue(applyCmd(x08, command));
MemoryBlock block = x08.getMemory().getBlock(addr);
assertNotNull(block);
assertEquals(100, block.getSize());
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress());
assertEquals(getX08Addr(197), info.getMappedRange().get().getMaxAddress());
assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType());
assertFalse(block.isOverlay());
}
@Test
public void testAddByteOverlayBlock() {
Address addr = getX08Addr(0x3000);
command = new AddByteMappedMemoryBlockCmd(".testByte", "A Test", "new block", addr, 100,
true, true, true, false, getX08Addr(0), true);
assertTrue(applyCmd(x08, command));
MemoryBlock block = x08.getMemory().getBlock(addr);
assertNull(block);
block = x08.getMemory().getBlock(".testByte");
assertNotNull(block);
assertEquals(100, block.getSize());
AddressSpace space = x08.getAddressFactory().getAddressSpace(".testByte");
assertNotNull(space);
assertTrue(space.isOverlaySpace());
assertEquals(space.getAddress(0x3000), block.getStart());
assertEquals(space.getAddress(0x3063), block.getEnd());
assertEquals(block.getStart(), space.getMinAddress());
assertEquals(block.getEnd(), space.getMaxAddress());
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
AddressRange mappedRange = info.getMappedRange().get();
assertEquals(100, mappedRange.getLength());
assertEquals(getX08Addr(0), mappedRange.getMinAddress());
assertEquals(getX08Addr(99), mappedRange.getMaxAddress());
assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType());
assertTrue(block.isOverlay());
}
@Test
public void testAddByteOverlayBlockWithScheme() {
Address addr = getX08Addr(0x3000);
command = new AddByteMappedMemoryBlockCmd(".testByte", "A Test", "new block", addr, 100,
true, true, true, false, getX08Addr(0), new ByteMappingScheme(2, 4), true);
assertTrue(applyCmd(x08, command));
MemoryBlock block = x08.getMemory().getBlock(addr);
assertNull(block);
block = x08.getMemory().getBlock(".testByte");
assertNotNull(block);
assertEquals(100, block.getSize());
AddressSpace space = x08.getAddressFactory().getAddressSpace(".testByte");
assertNotNull(space);
assertTrue(space.isOverlaySpace());
assertEquals(space.getAddress(0x3000), block.getStart());
assertEquals(space.getAddress(0x3063), block.getEnd());
assertEquals(block.getStart(), space.getMinAddress());
assertEquals(block.getEnd(), space.getMaxAddress());
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
AddressRange mappedRange = info.getMappedRange().get();
assertEquals(198, mappedRange.getLength());
assertEquals(getX08Addr(0), mappedRange.getMinAddress());
assertEquals(getX08Addr(197), mappedRange.getMaxAddress());
assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType());
assertTrue(block.isOverlay());
} }
@Test @Test
@@ -144,7 +257,8 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
} }
} }
assertNotNull(block); assertNotNull(block);
assertEquals(MemoryBlockType.OVERLAY, block.getType()); assertEquals(MemoryBlockType.DEFAULT, block.getType());
assertTrue(block.isOverlay());
byte b = block.getByte(block.getStart().getNewAddress(0x3000)); byte b = block.getByte(block.getStart().getNewAddress(0x3000));
assertEquals((byte) 0xa, b); assertEquals((byte) 0xa, b);
} }
@@ -20,8 +20,7 @@ import java.io.InputStream;
import java.util.List; import java.util.List;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.database.mem.AddressSourceInfo; import ghidra.program.database.mem.*;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
@@ -103,13 +102,15 @@ class MyTestMemory extends AddressSet implements Memory {
@Override @Override
public MemoryBlock createBitMappedBlock(String name, Address start, Address overlayAddress, public MemoryBlock createBitMappedBlock(String name, Address start, Address overlayAddress,
long length) throws MemoryConflictException, AddressOverflowException { long length, boolean overlay) throws MemoryConflictException, AddressOverflowException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public MemoryBlock createByteMappedBlock(String name, Address start, Address overlayAddress, public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress,
long length) throws MemoryConflictException, AddressOverflowException { long length, ByteMappingScheme byteMappingScheme, boolean overlay)
throws LockException,
MemoryConflictException, AddressOverflowException, IllegalArgumentException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -170,6 +170,11 @@ class MyTestMemoryBlock implements MemoryBlock {
return MemoryBlockType.DEFAULT; return MemoryBlockType.DEFAULT;
} }
@Override
public boolean isOverlay() {
return false;
}
@Override @Override
public int compareTo(MemoryBlock block) { public int compareTo(MemoryBlock block) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@@ -19,6 +19,7 @@ import java.math.BigInteger;
import ghidra.app.plugin.core.format.ByteBlock; import ghidra.app.plugin.core.format.ByteBlock;
import ghidra.app.plugin.core.format.ByteBlockAccessException; import ghidra.app.plugin.core.format.ByteBlockAccessException;
import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
@@ -139,9 +140,7 @@ public class MemoryByteBlock implements ByteBlock {
@Override @Override
public boolean hasValue(BigInteger index) { public boolean hasValue(BigInteger index) {
Address addr = getAddress(index); Address addr = getAddress(index);
MemoryBlock memBlock = memory.getBlock(addr); return memory.getAllInitializedAddressSet().contains(addr);
return (memBlock != null) && memBlock.isInitialized();
} }
/** /**
@@ -260,6 +259,23 @@ public class MemoryByteBlock implements ByteBlock {
return (int) (start.getOffset() % radix); return (int) (start.getOffset() % radix);
} }
private Address getMappedAddress(Address addr) {
MemoryBlock memBlock = memory.getBlock(addr);
if (memBlock != null && memBlock.getType() == MemoryBlockType.BYTE_MAPPED) {
try {
MemoryBlockSourceInfo info = memBlock.getSourceInfos().get(0);
AddressRange mappedRange = info.getMappedRange().get();
ByteMappingScheme byteMappingScheme = info.getByteMappingScheme().get();
addr = byteMappingScheme.getMappedSourceAddress(mappedRange.getMinAddress(),
addr.subtract(memBlock.getStart()));
}
catch (AddressOverflowException e) {
// ignore
}
}
return addr;
}
/** /**
* Get the address based on the index. * Get the address based on the index.
*/ */
@@ -268,7 +284,6 @@ public class MemoryByteBlock implements ByteBlock {
mAddr = start; mAddr = start;
mAddr = mAddr.addNoWrap(index); mAddr = mAddr.addNoWrap(index);
return mAddr; return mAddr;
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
throw new IndexOutOfBoundsException("Index " + index + " is not in this block"); throw new IndexOutOfBoundsException("Index " + index + " is not in this block");
@@ -20,8 +20,7 @@ import java.io.InputStream;
import java.util.List; import java.util.List;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.database.mem.AddressSourceInfo; import ghidra.program.database.mem.*;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
@@ -48,7 +47,8 @@ public class MemoryTestDummy extends AddressSet implements Memory {
@Override @Override
public MemoryBlock createBitMappedBlock(String name, Address start, Address mappedAddress, public MemoryBlock createBitMappedBlock(String name, Address start, Address mappedAddress,
long length) throws LockException, MemoryConflictException, AddressOverflowException { long length, boolean overlay)
throws LockException, MemoryConflictException, AddressOverflowException {
return null; return null;
} }
@@ -60,7 +60,9 @@ public class MemoryTestDummy extends AddressSet implements Memory {
@Override @Override
public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress, public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress,
long length) throws LockException, MemoryConflictException, AddressOverflowException { long length, ByteMappingScheme byteMappingScheme, boolean overlay)
throws LockException, MemoryConflictException, AddressOverflowException,
IllegalArgumentException {
return null; return null;
} }
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,7 +22,7 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.util.XmlProgramUtilities; import ghidra.util.XmlProgramUtilities;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.task.TaskMonitor;
import ghidra.util.xml.XmlAttributeException; import ghidra.util.xml.XmlAttributeException;
import ghidra.util.xml.XmlUtilities; import ghidra.util.xml.XmlUtilities;
import ghidra.xml.XmlElement; import ghidra.xml.XmlElement;
@@ -92,13 +91,13 @@ public class MemoryBlockDefinition {
if (bitMappedAddress != null) { if (bitMappedAddress != null) {
Address mappedAddr = Address mappedAddr =
XmlProgramUtilities.parseAddress(program.getAddressFactory(), bitMappedAddress); XmlProgramUtilities.parseAddress(program.getAddressFactory(), bitMappedAddress);
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length); block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length, false);
} }
else if (initialized) { else if (initialized) {
try { try {
block = block =
mem.createInitializedBlock(blockName, addr, length, (byte) 0, mem.createInitializedBlock(blockName, addr, length, (byte) 0,
TaskMonitorAdapter.DUMMY_MONITOR, false); TaskMonitor.DUMMY, false);
} }
catch (CancelledException e) { catch (CancelledException e) {
throw new AssertException(e); // unexpected throw new AssertException(e); // unexpected
@@ -1,49 +0,0 @@
/* ###
* 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.program.database.mem;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemoryBlock;
public class BitMappedByteSourceRange extends ByteSourceRange {
public BitMappedByteSourceRange(MemoryBlock block, Address start, long sourceId, long offset,
long size) {
super(block, start, size, sourceId, offset);
}
@Override
public Address getEnd() {
return getStart().add(size * 8 - 1);
}
@Override
public ByteSourceRange intersect(ByteSourceRange range) {
if (sourceId != range.sourceId) {
return null;
}
long maxOffset = Math.max(byteSourceOffset, range.byteSourceOffset);
long minEndOffset =
Math.min(byteSourceOffset + size - 1, range.byteSourceOffset + range.size - 1);
if (maxOffset > minEndOffset) {
return null;
}
long sourceSize = minEndOffset - maxOffset + 1;
return new BitMappedByteSourceRange(block, start.add((maxOffset - byteSourceOffset) / 8),
sourceId, maxOffset, sourceSize);
}
}
@@ -16,12 +16,12 @@
package ghidra.program.database.mem; package ghidra.program.database.mem;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import db.Record; import db.Record;
import ghidra.program.database.map.AddressMapDB; import ghidra.program.database.map.AddressMapDB;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlockType;
/** /**
* Class for handling bit mapped memory sub blocks * Class for handling bit mapped memory sub blocks
@@ -36,7 +36,7 @@ class BitMappedSubMemoryBlock extends SubMemoryBlock {
this.memMap = adapter.getMemoryMap(); this.memMap = adapter.getMemoryMap();
AddressMapDB addressMap = memMap.getAddressMap(); AddressMapDB addressMap = memMap.getAddressMap();
mappedAddress = addressMap.decodeAddress( mappedAddress = addressMap.decodeAddress(
record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL), false); record.getLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL), false);
} }
@Override @Override
@@ -62,7 +62,7 @@ class BitMappedSubMemoryBlock extends SubMemoryBlock {
} }
} }
public AddressRange getMappedRange() { AddressRange getMappedRange() {
Address endMappedAddress = mappedAddress.add((subBlockLength - 1) / 8); Address endMappedAddress = mappedAddress.add((subBlockLength - 1) / 8);
return new AddressRangeImpl(mappedAddress, endMappedAddress); return new AddressRangeImpl(mappedAddress, endMappedAddress);
} }
@@ -182,55 +182,4 @@ class BitMappedSubMemoryBlock extends SubMemoryBlock {
return "Bit Mapped: " + mappedAddress; return "Bit Mapped: " + mappedAddress;
} }
@Override
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
long memBlockOffset,
long size) {
ByteSourceRangeList result = new ByteSourceRangeList();
// Since mapped blocks are mapped onto other memory blocks, find those blocks and
// handle each one separately
// converts to byte space since 8 bytes in this block's space maps to 1 byte in real memory
Address startMappedAddress = mappedAddress.add(memBlockOffset / 8);
Address endMappedAddress = mappedAddress.add((memBlockOffset + size - 1) / 8);
List<MemoryBlockDB> blocks = memMap.getBlocks(startMappedAddress, endMappedAddress);
// for each block, get its ByteSourceSet and then translate that set back into this block's
// addresses
for (MemoryBlockDB mappedBlock : blocks) {
Address startInBlock = max(mappedBlock.getStart(), startMappedAddress);
Address endInBlock = min(mappedBlock.getEnd(), endMappedAddress);
long blockSize = endInBlock.subtract(startInBlock) + 1;
ByteSourceRangeList ranges =
mappedBlock.getByteSourceRangeList(startInBlock, blockSize);
for (ByteSourceRange bsRange : ranges) {
result.add(translate(block, bsRange, start, memBlockOffset, size));
}
}
return result;
}
// translates the ByteSourceRange back to addresse
private ByteSourceRange translate(MemoryBlock block, ByteSourceRange bsRange, Address start,
long offset,
long bitLength) {
Address startMappedAddress = mappedAddress.add(offset / 8);
Address normalizedStart = start.subtract(offset % 8);
long mappedOffsetFromStart = bsRange.getStart().subtract(startMappedAddress);
long offsetFromStart = mappedOffsetFromStart * 8;
Address startAddress = normalizedStart.add(offsetFromStart);
return new BitMappedByteSourceRange(block, startAddress, bsRange.getSourceId(),
bsRange.getOffset(), bsRange.getSize());
}
Address min(Address a1, Address a2) {
return a1.compareTo(a2) <= 0 ? a1 : a2;
}
Address max(Address a1, Address a2) {
return a1.compareTo(a2) >= 0 ? a1 : a2;
}
} }
@@ -19,8 +19,7 @@ import java.io.IOException;
import db.DBBuffer; import db.DBBuffer;
import db.Record; import db.Record;
import ghidra.program.model.address.Address; import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.*;
/** /**
* Implementation of SubMemoryBlock for blocks that store bytes in their own private database * Implementation of SubMemoryBlock for blocks that store bytes in their own private database
@@ -31,7 +30,7 @@ class BufferSubMemoryBlock extends SubMemoryBlock {
BufferSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) throws IOException { BufferSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) throws IOException {
super(adapter, record); super(adapter, record);
int bufferID = record.getIntValue(MemoryMapDBAdapter.SUB_SOURCE_ID_COL); int bufferID = record.getIntValue(MemoryMapDBAdapter.SUB_INT_DATA1_COL);
buf = adapter.getBuffer(bufferID); buf = adapter.getBuffer(bufferID);
} }
@@ -95,11 +94,6 @@ class BufferSubMemoryBlock extends SubMemoryBlock {
return record.getKey(); return record.getKey();
} }
@Override
protected MemoryBlockType getType() {
return MemoryBlockType.DEFAULT;
}
@Override @Override
protected SubMemoryBlock split(long memBlockOffset) throws IOException { protected SubMemoryBlock split(long memBlockOffset) throws IOException {
// convert from offset in block to offset in this sub block // convert from offset in block to offset in this sub block
@@ -121,14 +115,4 @@ class BufferSubMemoryBlock extends SubMemoryBlock {
protected String getDescription() { protected String getDescription() {
return ""; return "";
} }
@Override
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
long memBlockOffset,
long size) {
long sourceId = -buf.getId(); // buffers use negative id values; FileBytes use positive id values.
ByteSourceRange bsRange =
new ByteSourceRange(block, start, size, sourceId, memBlockOffset - subBlockOffset);
return new ByteSourceRangeList(bsRange);
}
} }
@@ -16,12 +16,12 @@
package ghidra.program.database.mem; package ghidra.program.database.mem;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import db.Record; import db.Record;
import ghidra.program.database.map.AddressMapDB; import ghidra.program.database.map.AddressMapDB;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlockType;
/** /**
* Class for handling byte mapped memory sub blocks * Class for handling byte mapped memory sub blocks
@@ -30,14 +30,23 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
private final MemoryMapDB memMap; private final MemoryMapDB memMap;
private final Address mappedAddress; private final Address mappedAddress;
private final ByteMappingScheme byteMappingScheme;
private boolean ioPending; private boolean ioPending;
ByteMappedSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) { ByteMappedSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) {
super(adapter, record); super(adapter, record);
this.memMap = adapter.getMemoryMap(); this.memMap = adapter.getMemoryMap();
AddressMapDB addressMap = memMap.getAddressMap(); AddressMapDB addressMap = memMap.getAddressMap();
// TODO: ensure that mappedAddress is aligned with addressMask (trailing 0's of mask should be 0 in mappedAddress)
mappedAddress = addressMap.decodeAddress( mappedAddress = addressMap.decodeAddress(
record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL), false); record.getLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL), false);
int encodedMappingScheme = record.getIntValue(MemoryMapDBAdapter.SUB_INT_DATA1_COL);
byteMappingScheme = new ByteMappingScheme(encodedMappingScheme);
}
ByteMappingScheme getByteMappingScheme() {
return byteMappingScheme;
} }
@Override @Override
@@ -53,7 +62,9 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
} }
try { try {
ioPending = true; ioPending = true;
return memMap.getByte(mappedAddress.addNoWrap(offsetInSubBlock)); Address sourceAddr =
byteMappingScheme.getMappedSourceAddress(mappedAddress, offsetInSubBlock);
return memMap.getByte(sourceAddr);
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
throw new MemoryAccessException("No memory at address"); throw new MemoryAccessException("No memory at address");
@@ -68,13 +79,14 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
throws MemoryAccessException, IOException { throws MemoryAccessException, IOException {
long offsetInSubBlock = offsetInMemBlock - subBlockOffset; long offsetInSubBlock = offsetInMemBlock - subBlockOffset;
long available = subBlockLength - offsetInSubBlock; long available = subBlockLength - offsetInSubBlock;
// TODO: should array length be considered?
len = (int) Math.min(len, available); len = (int) Math.min(len, available);
if (ioPending) { if (ioPending) {
new MemoryAccessException("Cyclic Access"); new MemoryAccessException("Cyclic Access");
} }
try { try {
ioPending = true; ioPending = true;
return memMap.getBytes(mappedAddress.addNoWrap(offsetInSubBlock), b, off, len); return byteMappingScheme.getBytes(memMap, mappedAddress, offsetInSubBlock, b, off, len);
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
throw new MemoryAccessException("No memory at address"); throw new MemoryAccessException("No memory at address");
@@ -92,7 +104,9 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
new MemoryAccessException("Cyclic Access"); new MemoryAccessException("Cyclic Access");
} }
ioPending = true; ioPending = true;
memMap.setByte(mappedAddress.addNoWrap(offsetInSubBlock), b); Address sourceAddr =
byteMappingScheme.getMappedSourceAddress(mappedAddress, offsetInSubBlock);
memMap.setByte(sourceAddr, b);
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
throw new MemoryAccessException("No memory at address"); throw new MemoryAccessException("No memory at address");
@@ -114,8 +128,7 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
new MemoryAccessException("Cyclic Access"); new MemoryAccessException("Cyclic Access");
} }
ioPending = true; ioPending = true;
memMap.setBytes(mappedAddress.addNoWrap(offsetInSubBlock), b, off, byteMappingScheme.setBytes(memMap, mappedAddress, offsetInSubBlock, b, off, len);
len);
return len; return len;
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
@@ -126,8 +139,16 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
} }
} }
public AddressRange getMappedRange() { AddressRange getMappedRange() {
Address endMappedAddress = mappedAddress.add(subBlockLength - 1); Address endMappedAddress;
try {
endMappedAddress =
byteMappingScheme.getMappedSourceAddress(mappedAddress, subBlockLength - 1);
}
catch (AddressOverflowException e) {
// keep things happy
endMappedAddress = mappedAddress.getAddressSpace().getMaxAddress();
}
return new AddressRangeImpl(mappedAddress, endMappedAddress); return new AddressRangeImpl(mappedAddress, endMappedAddress);
} }
@@ -148,6 +169,17 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
@Override @Override
protected SubMemoryBlock split(long memBlockOffset) throws IOException { protected SubMemoryBlock split(long memBlockOffset) throws IOException {
// NOTE - GUI does not support any split of any byte-mapped blocks although API does.
// Not sure we really need to support it for byte-mapped block.
if (!byteMappingScheme.isOneToOneMapping()) {
// byte-mapping scheme alignment restrictions would apply to split
// boundary if we were to support
throw new UnsupportedOperationException(
"split not supported for byte-mapped block with " + byteMappingScheme);
}
// convert from offset in block to offset in this sub block // convert from offset in block to offset in this sub block
int offset = (int) (memBlockOffset - subBlockOffset); int offset = (int) (memBlockOffset - subBlockOffset);
long newLength = subBlockLength - offset; long newLength = subBlockLength - offset;
@@ -167,45 +199,7 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
@Override @Override
protected String getDescription() { protected String getDescription() {
return "Byte Mapped: " + mappedAddress; return "Byte Mapped: " + mappedAddress + ", " + byteMappingScheme;
}
@Override
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
long offset, long size) {
ByteSourceRangeList result = new ByteSourceRangeList();
long relativeOffset = offset - subBlockOffset;
Address startAddress = mappedAddress.add(relativeOffset);
Address endAddress = startAddress.add(size - 1);
List<MemoryBlockDB> blocks = memMap.getBlocks(startAddress, endAddress);
for (MemoryBlockDB mappedBlock : blocks) {
Address startInBlock = max(mappedBlock.getStart(), startAddress);
Address endInBlock = min(mappedBlock.getEnd(), endAddress);
AddressRange blockRange = new AddressRangeImpl(startInBlock, endInBlock);
ByteSourceRangeList ranges =
mappedBlock.getByteSourceRangeList(startInBlock, blockRange.getLength());
for (ByteSourceRange bsRange : ranges) {
result.add(translate(block, bsRange, start, relativeOffset));
}
}
return result;
}
private ByteSourceRange translate(MemoryBlock block, ByteSourceRange bsRange, Address addr,
long relativeOffset) {
Address mappedStart = bsRange.getStart();
long offset = mappedStart.subtract(mappedAddress);
Address start = addr.add(offset - relativeOffset);
return new ByteSourceRange(block, start, bsRange.getSize(), bsRange.getSourceId(),
bsRange.getOffset());
}
Address min(Address a1, Address a2) {
return a1.compareTo(a2) <= 0 ? a1 : a2;
}
Address max(Address a1, Address a2) {
return a1.compareTo(a2) >= 0 ? a1 : a2;
} }
} }
@@ -0,0 +1,329 @@
/* ###
* 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.program.database.mem;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.mem.*;
/**
* <code>ByteMappingScheme</code> facilitate byte mapping/decimation scheme for a mapped sub-block to
* an underlying source memory region.
*/
public class ByteMappingScheme {
// Repeating byte mapping pattern defined by number of source bytes mapped (mappedByteCount) followed
// by number of non-mapped source bytes (nonMappedByteCount). The sum of these two values is
// mappedSourceByteCount. The first byte of this block must correspond to the first mapped
// byte of this mapping sequence.
private final int mappedByteCount;
private final int nonMappedByteCount;
private final int mappedSourceByteCount;
/**
* Construct byte mapping scheme from an encoded mappingScheme value.
* @param encodedMappingScheme encoded mapping scheme value or 0 for a 1:1 default mapping.
* A zero value is accepted to ensure backward compatibility with pre-existing byte-mapped blocks
* where a 1:1 mapping was employed.
* @throws IllegalArgumentException if packed mapping scheme produces an invalid mapping ratio
*/
ByteMappingScheme(int encodedMappingScheme) throws IllegalArgumentException {
if (encodedMappingScheme == 0) {
// default mode implies 1:1 mapping
mappedByteCount = 1;
mappedSourceByteCount = 1;
nonMappedByteCount = 0;
}
else {
mappedByteCount = getMappedByteCount(encodedMappingScheme);
mappedSourceByteCount = getMappedSourceByteCount(encodedMappingScheme);
nonMappedByteCount = mappedSourceByteCount - mappedByteCount;
validateMappingScheme(mappedByteCount, mappedSourceByteCount);
}
}
/**
* Construct byte mapping scheme specified as a ratio of mapped bytes to source bytes.
* @param mappedByteCount number of mapped bytes per mappedSourcebyteCount (1..127). This
* value must be less-than or equal to schemeSrcByteCount.
* @param mappedSourceByteCount number of source bytes for mapping ratio (1..127)
* @throws IllegalArgumentException if invalid mapping scheme specified
*/
public ByteMappingScheme(int mappedByteCount, int mappedSourceByteCount) {
validateMappingScheme(mappedByteCount, mappedSourceByteCount);
this.mappedByteCount = mappedByteCount;
this.mappedSourceByteCount = mappedSourceByteCount;
this.nonMappedByteCount = mappedSourceByteCount - mappedByteCount;
}
@Override
public String toString() {
String ratioStr = "1:1";
if (!isOneToOneMapping()) {
ratioStr = mappedByteCount + ":" + mappedSourceByteCount;
}
return ratioStr + " mapping";
}
/**
* Get byte mapping scheme as single 14-bit packed value for storage and reconstruction use.
* @return mapping scheme as single 14-bit integer value
*/
int getEncodedMappingScheme() {
if (isOneToOneMapping()) {
// for legacy reasons continue to use 0 to indicate 1:1 default mapping
return 0;
}
return getEncodedMappingScheme(mappedByteCount, mappedSourceByteCount);
}
/**
* Determine this scheme corresponds to a 1:1 byte mapping
* @return true if 1:1 mapping else false
*/
public boolean isOneToOneMapping() {
return mappedSourceByteCount <= 1;
}
/**
* Get the mapped-byte-count (left-hand value in mapping ratio)
* @return mapped-byte-count
*/
public int getMappedByteCount() {
if (isOneToOneMapping()) {
return 1;
}
return mappedByteCount;
}
/**
* Get the mapped-source-byte-count (right-hand value in mapping ratio)
* @return mapped-source-byte-count
*/
public int getMappedSourceByteCount() {
if (isOneToOneMapping()) {
return 1;
}
return mappedSourceByteCount;
}
/**
* Calculate the mapped source address for a specified offset with the mapped sub-block.
* @param mappedSourceBaseAddress mapped source base address for sub-block
* @param offsetInSubBlock byte offset within sub-block to be mapped into source
* @return mapped source address
* @throws AddressOverflowException if offset in sub-block produces a wrap condition in
* the mapped source address space.
*/
public Address getMappedSourceAddress(Address mappedSourceBaseAddress,
long offsetInSubBlock)
throws AddressOverflowException {
if (offsetInSubBlock < 0) {
throw new IllegalArgumentException("negative offset");
}
long sourceOffset = offsetInSubBlock;
if (!isOneToOneMapping()) {
sourceOffset = (mappedSourceByteCount * (offsetInSubBlock / mappedByteCount)) +
(offsetInSubBlock % mappedByteCount);
}
return mappedSourceBaseAddress.addNoWrap(sourceOffset);
}
/**
* Calculate the address within a mapped block for a specified mapped source offset.
* If the specified mappedSourceOffset corresponds to a non-mapped (i.e., skipped) byte
* the address returned will correspond to the last mapped byte. Care must be used
* when using this method.
* @param mappedBlock mapped block
* @param mappedSourceOffset byte offset within mapped source relative to mapped base source address.
* @param skipBack controls return address when mappedSourceOffset corresponds to a non-mapped/skipped byte.
* If true the returned address will correspond to the previous mapped address, if false the next mapped
* address will be returned.
* @return mapped address within block or null if skipBack is false and unable to map within block limits
* @throws AddressOverflowException thrown for 1:1 mapping when mappedSourceOffset exceeds length of mappedBlock
*/
Address getMappedAddress(MemoryBlock mappedBlock, long mappedSourceOffset, boolean skipBack)
throws AddressOverflowException {
if (mappedSourceOffset < 0) {
throw new IllegalArgumentException("negative source offset");
}
long mappedOffset = mappedSourceOffset;
if (!isOneToOneMapping()) {
mappedOffset = (mappedByteCount * (mappedSourceOffset / mappedSourceByteCount));
long offsetLimit = mappedBlock.getSize() - 1;
long mod = mappedSourceOffset % mappedSourceByteCount;
if (mod < mappedByteCount) {
mappedOffset += mod;
}
else if (!skipBack) {
mappedOffset += mappedByteCount;
if (mappedOffset > offsetLimit) {
return null;
}
}
}
return mappedBlock.getStart().addNoWrap(mappedOffset);
}
/**
* Read bytes into an array from memory utilizing this mapping scheme.
* @param memory program memory
* @param mappedSourceBaseAddress base source memory address for byte-mapped subblock
* @param offsetInSubBlock byte offset from start of subblock where reading should begin
* @param b byte array to be filled
* @param off offset within byte array b where filling should start
* @param len number of bytes to be read
* @return actual number of bytes read
* @throws MemoryAccessException if read of uninitialized or non-existing memory occurs
* @throws AddressOverflowException if address computation error occurs
*/
int getBytes(Memory memory, Address mappedSourceBaseAddress, long offsetInSubBlock, byte[] b,
int off, int len) throws MemoryAccessException, AddressOverflowException {
if (isOneToOneMapping()) {
return memory.getBytes(mappedSourceBaseAddress.addNoWrap(offsetInSubBlock), b, off,
len);
}
// NOTE: approach avoids incremental reading by including unmapped bytes in
// bulk read and filters as needed based upon mapping scheme ratio
long patternCount = offsetInSubBlock / mappedByteCount;
int partialByteCount = (int) (offsetInSubBlock % mappedByteCount);
long mappedOffset = (mappedSourceByteCount * patternCount) + partialByteCount;
int bufSize = mappedSourceByteCount * ((len / mappedByteCount) + 1);
byte[] buf = new byte[bufSize];
int bufCnt = memory.getBytes(mappedSourceBaseAddress.addNoWrap(mappedOffset), buf);
int bufIndex = 0;
int cnt = 0;
int index = off;
int i = mappedByteCount - partialByteCount;
boolean skip = false;
while (bufIndex < bufCnt && cnt < len) {
if (!skip) {
b[index++] = buf[bufIndex];
++cnt;
if (--i == 0) {
skip = true;
i = nonMappedByteCount;
}
}
else if (--i == 0) {
skip = false;
i = mappedByteCount;
}
++bufIndex;
}
return cnt;
}
/**
* Write an array of bytes to memory utilizing this mapping scheme.
* @param memory program memory
* @param mappedSourceBaseAddress base source memory address for byte-mapped subblock
* @param offsetInSubBlock byte offset from start of subblock where writing should begin
* @param b an array to get bytes from
* @param off start source index within byte array b where bytes should be read
* @param len number of bytes to be written
* @throws MemoryAccessException if write of uninitialized or non-existing memory occurs
* @throws AddressOverflowException if address computation error occurs
*/
void setBytes(Memory memory, Address mappedSourceBaseAddress, long offsetInSubBlock,
byte[] b,
int off, int len) throws MemoryAccessException, AddressOverflowException {
if (isOneToOneMapping()) {
memory.setBytes(mappedSourceBaseAddress.addNoWrap(offsetInSubBlock), b, off, len);
return;
}
long patternCount = offsetInSubBlock / mappedByteCount;
int partialByteCount = (int) (offsetInSubBlock % mappedByteCount);
long mappedOffset = (mappedSourceByteCount * patternCount) + partialByteCount;
Address destAddr = mappedSourceBaseAddress.addNoWrap(mappedOffset);
int index = off;
int cnt = 0;
int i = mappedByteCount - partialByteCount;
while (cnt < len) {
memory.setBytes(destAddr, b, index, i);
index += i;
cnt += i;
destAddr = destAddr.addNoWrap(i + nonMappedByteCount);
i = mappedByteCount;
}
}
/**
* Validate mapping scheme. This scheme is specified as a ratio of mapped bytes to source bytes.
* @param schemeDestByteCount number of mapped bytes per mappedSourcebyteCount (1..127). This
* value must be less-than or equal to schemeSrcByteCount.
* @param schemeSrcByteCount number of source bytes for mapping ratio (1..127)
* @throws IllegalArgumentException if invalid mapping scheme specified
*/
static void validateMappingScheme(int schemeDestByteCount, int schemeSrcByteCount) {
if (schemeDestByteCount <= 0 || schemeDestByteCount > 0x7F || schemeSrcByteCount <= 0 ||
schemeSrcByteCount > 0x7F ||
schemeDestByteCount > schemeSrcByteCount) {
throw new IllegalArgumentException(
"invalid byte mapping ratio: " + schemeDestByteCount + ":" + schemeSrcByteCount);
}
}
/**
* Get encoded mapping scheme as a single value for storage purposes. This scheme value
* identifies the ratio of mapped bytes to source bytes. Value is encoded as two 7-bit
* values corresponding to the destination and source byte counts.
* @param schemeDestByteCount number of mapped bytes per mappedSourcebyteCount (1..127). This
* value must be less-than or equal to schemeSrcByteCount.
* @param schemeSrcByteCount number of source bytes for mapping ratio (1..127)
* @return mapping scheme value
* @throws IllegalArgumentException if invalid mapping scheme specified
*/
static int getEncodedMappingScheme(int schemeDestByteCount, int schemeSrcByteCount) {
validateMappingScheme(schemeDestByteCount, schemeSrcByteCount);
return (schemeDestByteCount << 7) | (schemeSrcByteCount & 0x7F);
}
/**
* Extract the mapping scheme mapped-byte-count from a mappingScheme value.
* @param mappingScheme mapping scheme
* @return mapped-byte-count (aka schemeDestByteCount)
*/
static int getMappedByteCount(int mappingScheme) {
int mappedByteCount = 1;
if (mappingScheme != 0) {
mappedByteCount = (mappingScheme >> 7) & 0x7F;
}
return mappedByteCount;
}
/**
* Extract the mapping ratio mapped-source-byte-count from a mappingScheme value.
* @param mappingScheme mapping scheme
* @return mapped-source-byte-count (aka schemeSrcByteCount)
*/
static int getMappedSourceByteCount(int mappingScheme) {
int mappedSourceByteCount = 1;
if (mappingScheme != 0) {
mappedSourceByteCount = mappingScheme & 0x7F;
}
return mappedSourceByteCount;
}
}

Some files were not shown because too many files have changed in this diff Show More