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

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

View file

@ -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

View file

@ -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);
} }
} }

View file

@ -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);
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
} }

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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.");
} }

View file

@ -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();

View file

@ -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);

View file

@ -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() {

View file

@ -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);

View file

@ -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);
} }

View file

@ -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;

View file

@ -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);

View file

@ -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());

View file

@ -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");

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
} }

View file

@ -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();
} }

View file

@ -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();

View file

@ -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");

View file

@ -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;
} }

View file

@ -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

View file

@ -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);
}
}

View file

@ -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;
}
} }

View file

@ -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);
}
} }

View file

@ -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;
} }
} }

View file

@ -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;
}
}

View file

@ -1,126 +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 ByteSourceRange {
protected final Address start;
protected final long size;
protected final long sourceId;
protected final long byteSourceOffset;
protected MemoryBlock block;
public ByteSourceRange(MemoryBlock block, Address start, long size, long sourceId,
long offset) {
this.block = block;
this.start = start;
this.size = size;
this.sourceId = sourceId;
this.byteSourceOffset = offset;
}
public Address getStart() {
return start;
}
public Address getEnd() {
return start.add(size - 1);
}
public long getSize() {
return size;
}
public long getSourceId() {
return sourceId;
}
public long getOffset() {
return byteSourceOffset;
}
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;
}
return new ByteSourceRange(block, start.add(maxOffset - byteSourceOffset),
minEndOffset - maxOffset + 1, sourceId, maxOffset);
}
public MemoryBlock getMemoryBlock() {
return block;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (byteSourceOffset ^ (byteSourceOffset >>> 32));
result = prime * result + (int) (size ^ (size >>> 32));
result = prime * result + (int) (sourceId ^ (sourceId >>> 32));
result = prime * result + ((start == null) ? 0 : start.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ByteSourceRange other = (ByteSourceRange) obj;
if (block == null) {
if (other.block != null) {
return false;
}
}
else if (!block.equals(other.block)) {
return false;
}
if (byteSourceOffset != other.byteSourceOffset) {
return false;
}
if (size != other.size) {
return false;
}
if (sourceId != other.sourceId) {
return false;
}
if (start == null) {
if (other.start != null) {
return false;
}
}
else if (!start.equals(other.start)) {
return false;
}
return true;
}
}

View file

@ -1,220 +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 java.util.*;
import ghidra.program.model.mem.MemoryBlock;
public class ByteSourceRangeList implements Iterable<ByteSourceRange> {
List<ByteSourceRange> ranges;
public ByteSourceRangeList(ByteSourceRange bsRange) {
this();
ranges.add(bsRange);
}
public ByteSourceRangeList() {
ranges = new ArrayList<>();
}
@Override
public Iterator<ByteSourceRange> iterator() {
return ranges.iterator();
}
public void add(ByteSourceRange range) {
if (range != null) {
ranges.add(range);
}
}
public void add(ByteSourceRangeList byteSourceList) {
ranges.addAll(byteSourceList.ranges);
}
public int getRangeCount() {
return ranges.size();
}
public ByteSourceRange get(int i) {
return ranges.get(i);
}
public boolean isEmpty() {
return ranges.isEmpty();
}
public Set<MemoryBlock> getOverlappingBlocks() {
List<BlockRangeEntry> entries = new ArrayList<>();
for (ByteSourceRange range : ranges) {
entries.add(new BlockRangeStart(this, range));
entries.add(new BlockRangeEnd(this, range));
}
Collections.sort(entries);
return findOverlappingBlocks(entries);
}
public ByteSourceRangeList intersect(ByteSourceRangeList rangeList) {
List<BlockRangeEntry> entries = new ArrayList<>();
for (ByteSourceRange range : ranges) {
entries.add(new BlockRangeStart(this, range));
entries.add(new BlockRangeEnd(this, range));
}
for (ByteSourceRange range : rangeList) {
entries.add(new BlockRangeStart(rangeList, range));
entries.add(new BlockRangeEnd(rangeList, range));
}
Collections.sort(entries);
return getIntersectingRanges(entries);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((ranges == null) ? 0 : ranges.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ByteSourceRangeList other = (ByteSourceRangeList) obj;
if (ranges == null) {
if (other.ranges != null) {
return false;
}
}
else if (!ranges.equals(other.ranges)) {
return false;
}
return true;
}
private ByteSourceRangeList getIntersectingRanges(List<BlockRangeEntry> entries) {
ByteSourceRangeList result = new ByteSourceRangeList();
Set<ByteSourceRange> currentSet = new HashSet<>();
for (BlockRangeEntry entry : entries) {
if (entry.isStart()) {
currentSet.add(entry.range);
}
else {
currentSet.remove(entry.range);
addIntersections(result, entry, currentSet);
}
}
return result;
}
private void addIntersections(ByteSourceRangeList set, BlockRangeEntry entry,
Set<ByteSourceRange> currentSet) {
if (currentSet.isEmpty()) {
return;
}
for (ByteSourceRange byteSourceRange : currentSet) {
if (entry.owner == this) {
set.add(entry.range.intersect(byteSourceRange));
}
else {
set.add(byteSourceRange.intersect(entry.range));
}
}
}
private Set<MemoryBlock> findOverlappingBlocks(List<BlockRangeEntry> entries) {
Set<MemoryBlock> overlappingBlocks = new HashSet<>();
Set<ByteSourceRange> currentSet = new HashSet<>();
for (BlockRangeEntry entry : entries) {
if (entry.isStart()) {
currentSet.add(entry.range);
}
else {
currentSet.remove(entry.range);
if (!currentSet.isEmpty()) {
overlappingBlocks.add(entry.range.block);
for (ByteSourceRange byteSourceRange : currentSet) {
overlappingBlocks.add(byteSourceRange.block);
}
}
}
}
return overlappingBlocks;
}
abstract class BlockRangeEntry implements Comparable<BlockRangeEntry> {
private ByteSourceRange range;
private long sourceId;
private long offset;
private ByteSourceRangeList owner;
BlockRangeEntry(ByteSourceRangeList owner, ByteSourceRange range, long offset) {
this.owner = owner;
this.range = range;
this.offset = offset;
this.sourceId = range.getSourceId();
}
abstract boolean isStart();
@Override
public int compareTo(BlockRangeEntry o) {
if (sourceId != o.sourceId) {
return sourceId > o.sourceId ? 1 : -1;
}
if (offset == o.offset) {
return (isStart() == o.isStart()) ? 0 : (isStart() ? -1 : 1);
}
return offset > o.offset ? 1 : -1;
}
}
class BlockRangeStart extends BlockRangeEntry {
BlockRangeStart(ByteSourceRangeList owner, ByteSourceRange range) {
super(owner, range, range.getOffset());
}
@Override
boolean isStart() {
return true;
}
}
class BlockRangeEnd extends BlockRangeEntry {
BlockRangeEnd(ByteSourceRangeList owner, ByteSourceRange range) {
super(owner, range, range.getOffset() + range.size - 1);
}
@Override
boolean isStart() {
return false;
}
}
}

View file

@ -18,8 +18,7 @@ package ghidra.program.database.mem;
import java.io.IOException; import java.io.IOException;
import db.Record; import db.Record;
import ghidra.program.model.address.Address; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.*;
/** /**
* Class for handling {@link FileBytes} memory sub blocks (blocks whose bytes are backed by a FileBytes object * Class for handling {@link FileBytes} memory sub blocks (blocks whose bytes are backed by a FileBytes object
@ -30,8 +29,8 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
FileBytesSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) throws IOException { FileBytesSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) throws IOException {
super(adapter, record); super(adapter, record);
long fileBytesID = record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_ID_COL); long fileBytesID = record.getLongValue(MemoryMapDBAdapter.SUB_INT_DATA1_COL);
fileBytesOffset = record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL); fileBytesOffset = record.getLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL);
fileBytes = adapter.getMemoryMap().getLayeredFileBytes(fileBytesID); fileBytes = adapter.getMemoryMap().getLayeredFileBytes(fileBytesID);
} }
@ -95,11 +94,6 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
return fileBytesOffset; return fileBytesOffset;
} }
@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
@ -109,7 +103,7 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
record.setLongValue(MemoryMapDBAdapter.SUB_LENGTH_COL, subBlockLength); record.setLongValue(MemoryMapDBAdapter.SUB_LENGTH_COL, subBlockLength);
adapter.updateSubBlockRecord(record); adapter.updateSubBlockRecord(record);
int fileBytesID = record.getIntValue(MemoryMapDBAdapter.SUB_SOURCE_ID_COL); int fileBytesID = record.getIntValue(MemoryMapDBAdapter.SUB_INT_DATA1_COL);
Record newSubRecord = adapter.createSubBlockRecord(0, 0, newLength, Record newSubRecord = adapter.createSubBlockRecord(0, 0, newLength,
MemoryMapDBAdapter.SUB_TYPE_FILE_BYTES, fileBytesID, fileBytesOffset + offset); MemoryMapDBAdapter.SUB_TYPE_FILE_BYTES, fileBytesID, fileBytesOffset + offset);
@ -129,14 +123,4 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
return fileBytes.equals(fb); return fileBytes.equals(fb);
} }
@Override
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
long memBlockOffset,
long size) {
long sourceId = fileBytes.getId();
ByteSourceRange bsRange = new ByteSourceRange(block, start, size, sourceId,
fileBytesOffset + memBlockOffset - subBlockOffset);
return new ByteSourceRangeList(bsRange);
}
} }

View file

@ -30,6 +30,7 @@ import ghidra.util.exception.AssertException;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
public class MemoryBlockDB implements MemoryBlock { public class MemoryBlockDB implements MemoryBlock {
private MemoryMapDBAdapter adapter; private MemoryMapDBAdapter adapter;
protected Record record; protected Record record;
private Address startAddress; private Address startAddress;
@ -40,6 +41,8 @@ public class MemoryBlockDB implements MemoryBlock {
private long id; private long id;
private SubMemoryBlock lastSubBlock; private SubMemoryBlock lastSubBlock;
private List<MemoryBlockDB> mappedBlocks; // list of mapped blocks which map onto this block
MemoryBlockDB(MemoryMapDBAdapter adapter, Record record, List<SubMemoryBlock> subBlocks) { MemoryBlockDB(MemoryMapDBAdapter adapter, Record record, List<SubMemoryBlock> subBlocks) {
this.adapter = adapter; this.adapter = adapter;
this.record = record; this.record = record;
@ -74,6 +77,33 @@ public class MemoryBlockDB implements MemoryBlock {
lastSubBlock = null; lastSubBlock = null;
Collections.sort(list); Collections.sort(list);
subBlocks = list; subBlocks = list;
mappedBlocks = null;
}
/**
* Add a block which is mapped onto this block
* @param mappedBlock mapped memory block
*/
void addMappedBlock(MemoryBlockDB mappedBlock) {
if (mappedBlocks == null) {
mappedBlocks = new ArrayList<>();
}
mappedBlocks.add(mappedBlock);
}
/**
* Clear list of blocks mapped onto this block
*/
void clearMappedBlockList() {
mappedBlocks = null;
}
/**
* Get collection of blocks which map onto this block.
* @return collection of blocks which map onto this block or null if none identified
*/
Collection<MemoryBlockDB> getMappedBlocks() {
return mappedBlocks;
} }
@Override @Override
@ -130,8 +160,12 @@ public class MemoryBlockDB implements MemoryBlock {
memMap.lock.acquire(); memMap.lock.acquire();
try { try {
checkValid(); checkValid();
if (oldName.equals(name)) {
return;
}
memMap.checkBlockName(name);
try { try {
if (getStart().getAddressSpace().isOverlaySpace()) { if (isOverlay()) {
memMap.overlayBlockRenamed(oldName, name); memMap.overlayBlockRenamed(oldName, name);
} }
record.setString(MemoryMapDBAdapter.NAME_COL, name); record.setString(MemoryMapDBAdapter.NAME_COL, name);
@ -394,12 +428,14 @@ public class MemoryBlockDB implements MemoryBlock {
@Override @Override
public MemoryBlockType getType() { public MemoryBlockType getType() {
if (startAddress.getAddressSpace().isOverlaySpace()) {
return MemoryBlockType.OVERLAY;
}
return subBlocks.get(0).getType(); return subBlocks.get(0).getType();
} }
@Override
public boolean isOverlay() {
return startAddress.getAddressSpace().isOverlaySpace();
}
public byte getByte(long offset) throws MemoryAccessException { public byte getByte(long offset) throws MemoryAccessException {
SubMemoryBlock subBlock = getSubBlock(offset); SubMemoryBlock subBlock = getSubBlock(offset);
try { try {
@ -585,7 +621,7 @@ public class MemoryBlockDB implements MemoryBlock {
throw new IllegalArgumentException("offset " + offset + " not in this block"); throw new IllegalArgumentException("offset " + offset + " not in this block");
} }
public void initializeBlock(byte initialValue) throws IOException { void initializeBlock(byte initialValue) throws IOException {
lastSubBlock = null; lastSubBlock = null;
for (SubMemoryBlock subBlock : subBlocks) { for (SubMemoryBlock subBlock : subBlocks) {
subBlock.delete(); subBlock.delete();
@ -687,30 +723,4 @@ public class MemoryBlockDB implements MemoryBlock {
return false; return false;
} }
ByteSourceRangeList getByteSourceRangeList(Address address, long size) {
long blockOffset = address.subtract(startAddress);
size = Math.min(size, length - blockOffset);
SubMemoryBlock subBlock = getSubBlock(blockOffset);
long subBlockOffset = blockOffset - subBlock.getStartingOffset();
long available = subBlock.subBlockLength - subBlockOffset;
long subSize = Math.min(size, available);
if (subSize == size) {
return subBlock.getByteSourceRangeList(this, address, blockOffset, size);
}
Address start = address;
ByteSourceRangeList set =
subBlock.getByteSourceRangeList(this, start, blockOffset, subSize);
long total = subSize;
while (total < size) {
subBlock = getSubBlock(blockOffset + total);
subSize = Math.min(size - total, subBlock.subBlockLength);
start = address.add(total);
set.add(subBlock.getByteSourceRangeList(this, start, blockOffset + total, subSize));
total += subSize;
}
return set;
}
} }

View file

@ -35,33 +35,21 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
this.subBlock = subBlock; this.subBlock = subBlock;
} }
/**
* @return
*/
@Override @Override
public long getLength() { public long getLength() {
return subBlock.subBlockLength; return subBlock.subBlockLength;
} }
/**
* @return
*/
@Override @Override
public Address getMinAddress() { public Address getMinAddress() {
return block.getStart().add(subBlock.subBlockOffset); return block.getStart().add(subBlock.subBlockOffset);
} }
/**
* @return
*/
@Override @Override
public Address getMaxAddress() { public Address getMaxAddress() {
return block.getStart().add(subBlock.subBlockOffset + subBlock.subBlockLength - 1); return block.getStart().add(subBlock.subBlockOffset + subBlock.subBlockLength - 1);
} }
/**
* @return
*/
@Override @Override
public String getDescription() { public String getDescription() {
return subBlock.getDescription(); return subBlock.getDescription();
@ -74,9 +62,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
} }
/**
* @return
*/
@Override @Override
public Optional<FileBytes> getFileBytes() { public Optional<FileBytes> getFileBytes() {
if (subBlock instanceof FileBytesSubMemoryBlock) { if (subBlock instanceof FileBytesSubMemoryBlock) {
@ -85,9 +70,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
return Optional.empty(); return Optional.empty();
} }
/**
* @return
*/
@Override @Override
public long getFileBytesOffset() { public long getFileBytesOffset() {
if (subBlock instanceof FileBytesSubMemoryBlock) { if (subBlock instanceof FileBytesSubMemoryBlock) {
@ -96,10 +78,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
return -1; return -1;
} }
/**
* @param address
* @return
*/
@Override @Override
public long getFileBytesOffset(Address address) { public long getFileBytesOffset(Address address) {
if (subBlock instanceof FileBytesSubMemoryBlock && contains(address)) { if (subBlock instanceof FileBytesSubMemoryBlock && contains(address)) {
@ -110,9 +88,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
return -1; return -1;
} }
/**
* @return
*/
@Override @Override
public Optional<AddressRange> getMappedRange() { public Optional<AddressRange> getMappedRange() {
if (subBlock instanceof BitMappedSubMemoryBlock) { if (subBlock instanceof BitMappedSubMemoryBlock) {
@ -126,18 +101,20 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
return Optional.empty(); return Optional.empty();
} }
/** @Override
* @return public Optional<ByteMappingScheme> getByteMappingScheme() {
*/ if (subBlock instanceof ByteMappedSubMemoryBlock) {
ByteMappedSubMemoryBlock byteMapped = (ByteMappedSubMemoryBlock) subBlock;
return Optional.of(byteMapped.getByteMappingScheme());
}
return Optional.empty();
}
@Override @Override
public MemoryBlock getMemoryBlock() { public MemoryBlock getMemoryBlock() {
return block; return block;
} }
/**
* @param address
* @return
*/
@Override @Override
public boolean contains(Address address) { public boolean contains(Address address) {
return address.compareTo(getMinAddress()) >= 0 && address.compareTo(getMaxAddress()) <= 0; return address.compareTo(getMinAddress()) >= 0 && address.compareTo(getMaxAddress()) <= 0;

View file

@ -37,7 +37,6 @@ import ghidra.program.util.ChangeManager;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
/** /**
* The database memory map manager. * The database memory map manager.
@ -67,7 +66,6 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
private final static MemoryBlock NoBlock = new MemoryBlockStub(); // placeholder for no block, not given out private final static MemoryBlock NoBlock = new MemoryBlockStub(); // placeholder for no block, not given out
Lock lock; Lock lock;
private Set<MemoryBlock> potentialOverlappingBlocks;
private static Comparator<Object> BLOCK_ADDRESS_COMPARATOR = (o1, o2) -> { private static Comparator<Object> BLOCK_ADDRESS_COMPARATOR = (o1, o2) -> {
MemoryBlock block = (MemoryBlock) o1; MemoryBlock block = (MemoryBlock) o1;
@ -134,33 +132,97 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
// we have to process the non-mapped blocks first because to process the mapped // we have to process the non-mapped blocks first because to process the mapped
// blocks we need the address sets for the non-mapped blocks to be complete // blocks we need the address sets for the non-mapped blocks to be complete
for (MemoryBlockDB block : blocks) { for (MemoryBlockDB block : blocks) {
block.clearMappedBlockList();
if (!block.isMapped()) { if (!block.isMapped()) {
addBlockAddresses(block); addBlockAddresses(block, false);
} }
} }
// process all mapped blocks after non-mapped-blocks above
for (MemoryBlockDB block : blocks) { for (MemoryBlockDB block : blocks) {
if (block.isMapped()) { if (block.isMapped()) {
addBlockAddresses(block); addBlockAddresses(block, false);
} }
} }
} }
private void addBlockAddresses(MemoryBlockDB block) { /**
* Update the <code>allInitializedAddrSet</code> and <code>initializedLoadedAddrSet</code>
* with relevant initialized addresses from the specified memory block. If block is not
* a mapped-block and it may be a source to existing mapped-blocks then
* <code>scanAllMappedBlocksIfNeeded</code> should be passed as <code>true</code> unless
* all mapped blocks will be processed separately.
* @param block memory block
* @param scanAllMappedBlocksIfNeeded if true and block is initialized and not a mapped block all
* mapped blocks will be processed for possible introduction of newly initialized mapped regions.
*/
private void addBlockAddresses(MemoryBlockDB block, boolean scanAllMappedBlocksIfNeeded) {
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd()); AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd());
addrSet = addrSet.union(blockSet); addrSet = addrSet.union(blockSet);
if (block.isMapped()) { if (block.isMapped()) {
allInitializedAddrSet =
allInitializedAddrSet.union(getMappedIntersection(block, allInitializedAddrSet)); // Identify source-blocks which block maps onto and add as a mapped-block to each of these
AddressRange mappedRange = block.getSourceInfos().get(0).getMappedRange().get();
for (MemoryBlockDB b : getBlocks(mappedRange.getMinAddress(),
mappedRange.getMaxAddress())) {
b.addMappedBlock(block);
}
AddressSet mappedSet = getMappedIntersection(block, allInitializedAddrSet);
allInitializedAddrSet = allInitializedAddrSet.union(mappedSet);
initializedLoadedAddrSet = initializedLoadedAddrSet.union( initializedLoadedAddrSet = initializedLoadedAddrSet.union(
getMappedIntersection(block, initializedLoadedAddrSet)); getMappedIntersection(block, initializedLoadedAddrSet));
} }
else if (block.isInitialized()) { else if (block.isInitialized()) {
allInitializedAddrSet = allInitializedAddrSet.union(blockSet); allInitializedAddrSet = allInitializedAddrSet.union(blockSet);
if (block.isLoaded()) { if (block.isLoaded()) {
initializedLoadedAddrSet = initializedLoadedAddrSet.union(blockSet); initializedLoadedAddrSet = initializedLoadedAddrSet.union(blockSet);
} }
if (scanAllMappedBlocksIfNeeded) {
// If only adding one initialized non-mapped-block we must scan all mapped-blocks
// which may utilize block as a byte source
for (MemoryBlockDB b : blocks) {
b.clearMappedBlockList();
}
for (MemoryBlockDB b : blocks) {
if (b.isMapped()) {
addBlockAddresses(b, false);
}
}
}
}
}
/**
* Update initialized address set for those mapped blocks which map onto the
* specified block which has just completed a transition of its' initialized state.
* @param block block whose initialized state has changed
* @param isInitialized true if block transitioned from uninitialized to initialized,
* else transition is from initialized to uninitialized.
*/
private void updateMappedAddresses(MemoryBlockDB block, boolean isInitialized) {
Collection<MemoryBlockDB> mappedBlocks = block.getMappedBlocks();
if (mappedBlocks == null) {
return;
}
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd());
boolean isLoaded = block.getStart().isLoadedMemoryAddress();
for (MemoryBlockDB mappedBlock : block.getMappedBlocks()) {
AddressSet mappedSet = getMappedIntersection(mappedBlock, blockSet);
if (isInitialized) {
allInitializedAddrSet = allInitializedAddrSet.union(mappedSet);
if (isLoaded) {
initializedLoadedAddrSet = initializedLoadedAddrSet.union(mappedSet);
}
}
else {
allInitializedAddrSet = allInitializedAddrSet.subtract(mappedSet);
if (isLoaded) {
initializedLoadedAddrSet = initializedLoadedAddrSet.union(mappedSet);
}
}
} }
} }
@ -181,9 +243,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
List<MemoryBlockDB> newBlocks = adapter.getMemoryBlocks(); List<MemoryBlockDB> newBlocks = adapter.getMemoryBlocks();
lastBlock = null; lastBlock = null;
blocks = newBlocks; blocks = newBlocks;
addrMap.memoryMapChanged(this);
nameBlockMap = new HashMap<>(); nameBlockMap = new HashMap<>();
executeSet = null; executeSet = null;
addrMap.memoryMapChanged(this);
} }
public void setLanguage(Language newLanguage) { public void setLanguage(Language newLanguage) {
@ -223,6 +285,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/** /**
* Returns the address factory for the program. * Returns the address factory for the program.
* @return program address factory
*/ */
AddressFactory getAddressFactory() { AddressFactory getAddressFactory() {
return addrMap.getAddressFactory(); return addrMap.getAddressFactory();
@ -230,6 +293,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/** /**
* Returns the AddressMap from the program. * Returns the AddressMap from the program.
* @return program address map
*/ */
AddressMapDB getAddressMap() { AddressMapDB getAddressMap() {
return addrMap; return addrMap;
@ -255,34 +319,90 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
void checkMemoryWrite(MemoryBlockDB block, Address start, long length) void checkMemoryWrite(MemoryBlockDB block, Address start, long length)
throws MemoryAccessException { throws MemoryAccessException {
checkRangeForInstructions(start, start.add(length - 1));
Set<MemoryBlock> overlappingBlocks = getPotentialOverlappingBlocks(); if (!block.contains(start)) {
ByteSourceRangeList changeingByteSource = block.getByteSourceRangeList(start, length); throw new MemoryAccessException(
if (overlappingBlocks.contains(block)) { block.getName() + " does not contain address " + start.toString(true));
for (MemoryBlock b : overlappingBlocks) { }
if (b.equals(block)) {
continue; try {
} Address endAddr = start.addNoWrap(length - 1);
ByteSourceRangeList set = if (!block.contains(start)) {
((MemoryBlockDB) b).getByteSourceRangeList(b.getStart(), b.getSize()); throw new MemoryAccessException(block.getName() + " does not contain range " +
ByteSourceRangeList intersect = set.intersect(changeingByteSource); start.toString(true) + "-" + endAddr);
for (ByteSourceRange range : intersect) {
checkRangeForInstructions(range.getStart(), range.getEnd());
}
} }
if (block.isMapped()) {
checkMemoryWriteMappedBlock(block, start, endAddr);
}
else {
checkMemoryWriteNonMappedBlock(block, start, endAddr);
}
}
catch (AddressOverflowException e) {
throw new MemoryAccessException("invalid address range specified for address " +
start.toString(true) + " (length: " + length + ")");
} }
} }
private Set<MemoryBlock> getPotentialOverlappingBlocks() { private void checkMemoryWriteMappedBlock(MemoryBlockDB mappedBlock, Address start,
if (potentialOverlappingBlocks == null) { Address endAddr)
ByteSourceRangeList byteSourceList = new ByteSourceRangeList(); throws AddressOverflowException, MemoryAccessException {
for (MemoryBlockDB block : blocks) { long startOffset = start.subtract(mappedBlock.getStart());
byteSourceList.add(block.getByteSourceRangeList(block.getStart(), block.getSize())); long endOffset = endAddr.subtract(mappedBlock.getStart());
}
potentialOverlappingBlocks = byteSourceList.getOverlappingBlocks(); // determine source block(s) for mapped block
MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0);
AddressRange mappedRange = info.getMappedRange().get();
Address mappedRangeMinAddr = mappedRange.getMinAddress();
Address mappedStartAddress, mappedEndAddress;
if (mappedBlock.getType() == MemoryBlockType.BIT_MAPPED) {
mappedStartAddress = mappedRangeMinAddr.addNoWrap(startOffset / 8);
mappedEndAddress = mappedRangeMinAddr.addNoWrap(endOffset / 8);
}
else { // BYTE_MAPPED
ByteMappingScheme byteMappingScheme = info.getByteMappingScheme().get();
mappedStartAddress =
byteMappingScheme.getMappedSourceAddress(mappedRangeMinAddr, startOffset);
mappedEndAddress =
byteMappingScheme.getMappedSourceAddress(mappedRangeMinAddr, endOffset);
}
for (MemoryBlockDB b : getBlocks(mappedStartAddress, mappedEndAddress)) {
Address minAddr = Address.min(b.getEnd(), mappedEndAddress);
Address maxAddr = Address.max(b.getStart(), mappedStartAddress);
checkMemoryWrite(b, minAddr, maxAddr.subtract(minAddr) + 1);
}
}
private void checkMemoryWriteNonMappedBlock(MemoryBlockDB nonMappedBlock, Address start,
Address endAddr)
throws MemoryAccessException {
// TODO: could contain uninitialized region which is illegal to write to although block.isInitialized
// may not be of much help since it reflects the first sub-block only - seems like mixing is a bad idea
checkRangeForInstructions(start, endAddr);
// Check all mapped-block address ranges which map onto the range to be modified
Collection<MemoryBlockDB> mappedBlocks = nonMappedBlock.getMappedBlocks();
if (mappedBlocks != null) {
for (MemoryBlockDB mappedBlock : mappedBlocks) {
// Determine source intersection with mapped block
MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0);
AddressRange mappedRange = info.getMappedRange().get();
mappedRange = mappedRange.intersectRange(start, endAddr);
if (mappedRange == null) {
continue; // no intersection with range of interest
}
AddressRange range = getMappedRange(mappedBlock, mappedRange);
if (range == null) {
continue; // unexpected
}
checkRangeForInstructions(range.getMinAddress(), range.getMaxAddress());
}
} }
return potentialOverlappingBlocks;
} }
@Override @Override
@ -362,8 +482,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/** /**
* Two blocks have been joined producing newBlock. The block which was * Two blocks have been joined producing newBlock. The block which was
* eliminated can be identified using the oldBlockStartAddr. * eliminated can be identified using the oldBlockStartAddr.
* @param newBlock * @param newBlock new joined memory block
* @param oldBlockStartAddr * @param oldBlockStartAddr original start address of affected block
*/ */
void fireBlocksJoined(MemoryBlock newBlock, Address oldBlockStartAddr) { void fireBlocksJoined(MemoryBlock newBlock, Address oldBlockStartAddr) {
program.setChanged(ChangeManager.DOCR_MEMORY_BLOCKS_JOINED, oldBlockStartAddr, newBlock); program.setChanged(ChangeManager.DOCR_MEMORY_BLOCKS_JOINED, oldBlockStartAddr, newBlock);
@ -477,7 +597,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
public MemoryBlock createInitializedBlock(String name, Address start, InputStream is, public MemoryBlock createInitializedBlock(String name, Address start, InputStream is,
long length, TaskMonitor monitor, boolean overlay) throws MemoryConflictException, long length, TaskMonitor monitor, boolean overlay) throws MemoryConflictException,
AddressOverflowException, CancelledException, LockException, DuplicateNameException { AddressOverflowException, CancelledException, LockException, DuplicateNameException {
Objects.requireNonNull(name); checkBlockName(name);
lock.acquire(); lock.acquire();
try { try {
checkBlockSize(length, true); checkBlockSize(length, true);
@ -496,7 +616,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
MemoryBlockDB newBlock = MemoryBlockDB newBlock =
adapter.createInitializedBlock(name, start, is, length, MemoryBlock.READ); adapter.createInitializedBlock(name, start, is, length, MemoryBlock.READ);
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock); addBlockAddresses(newBlock, !overlay);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -523,7 +643,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
long offset, long length, boolean overlay) throws LockException, DuplicateNameException, long offset, long length, boolean overlay) throws LockException, DuplicateNameException,
MemoryConflictException, AddressOverflowException, IndexOutOfBoundsException { MemoryConflictException, AddressOverflowException, IndexOutOfBoundsException {
Objects.requireNonNull(name); checkBlockName(name);
lock.acquire(); lock.acquire();
try { try {
checkBlockSize(length, true); checkBlockSize(length, true);
@ -540,7 +660,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
MemoryBlockDB newBlock = adapter.createFileBytesBlock(name, start, length, MemoryBlockDB newBlock = adapter.createFileBytesBlock(name, start, length,
fileBytes, offset, MemoryBlock.READ); fileBytes, offset, MemoryBlock.READ);
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock); addBlockAddresses(newBlock, !overlay);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -576,7 +696,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
boolean overlay) throws MemoryConflictException, AddressOverflowException, boolean overlay) throws MemoryConflictException, AddressOverflowException,
LockException, DuplicateNameException { LockException, DuplicateNameException {
Objects.requireNonNull(name); checkBlockName(name);
lock.acquire(); lock.acquire();
try { try {
checkBlockSize(size, false); checkBlockSize(size, false);
@ -591,9 +711,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
try { try {
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.DEFAULT, name, start, MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.DEFAULT, name, start,
size, null, false, MemoryBlock.READ); size, null, false, MemoryBlock.READ, 0);
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock); addBlockAddresses(newBlock, false);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -608,21 +728,27 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
@Override @Override
public MemoryBlock createBitMappedBlock(String name, Address start, Address overlayAddress, public MemoryBlock createBitMappedBlock(String name, Address start, Address mappedAddress,
long length) throws MemoryConflictException, AddressOverflowException, LockException { long length, boolean overlay) throws MemoryConflictException, AddressOverflowException,
LockException, IllegalArgumentException, DuplicateNameException {
Objects.requireNonNull(name); checkBlockName(name);
lock.acquire(); lock.acquire();
try { try {
checkBlockSize(length, false); checkBlockSize(length, false);
program.checkExclusiveAccess(); program.checkExclusiveAccess();
checkRange(start, length); mappedAddress.addNoWrap((length - 1) / 8);// just to check if length fits in address space
overlayAddress.addNoWrap((length - 1) / 8);// just to check if length fits in address space if (overlay) {
start = createOverlaySpace(name, start, length);
}
else {
checkRange(start, length);
}
try { try {
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BIT_MAPPED, name, MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BIT_MAPPED, name,
start, length, overlayAddress, false, MemoryBlock.READ); start, length, mappedAddress, false, MemoryBlock.READ, 0);
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock); addBlockAddresses(newBlock, false);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -637,21 +763,37 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
@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, LockException { long length, ByteMappingScheme byteMappingScheme, boolean overlay)
throws MemoryConflictException, AddressOverflowException, LockException,
DuplicateNameException {
checkBlockName(name);
int mappingScheme = 0; // use for 1:1 mapping
if (byteMappingScheme == null) {
byteMappingScheme = new ByteMappingScheme(mappingScheme); // 1:1 mapping
}
else if (!byteMappingScheme.isOneToOneMapping()) {
mappingScheme = byteMappingScheme.getEncodedMappingScheme();
}
Objects.requireNonNull(name);
lock.acquire(); lock.acquire();
try { try {
checkBlockSize(length, false); checkBlockSize(length, false);
program.checkExclusiveAccess(); program.checkExclusiveAccess();
checkRange(start, length); byteMappingScheme.getMappedSourceAddress(mappedAddress, length - 1); // source fit check
overlayAddress.addNoWrap(length - 1);// just to check if length fits in address space if (overlay) {
start = createOverlaySpace(name, start, length);
}
else {
checkRange(start, length);
}
try { try {
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BYTE_MAPPED, name, MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BYTE_MAPPED, name,
start, length, overlayAddress, false, MemoryBlock.READ); start, length, mappedAddress, false, MemoryBlock.READ, mappingScheme);
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock); addBlockAddresses(newBlock, false);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -665,27 +807,46 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
return null; return null;
} }
/**
* Check new block name for validity
* @param name new block name
* @throws IllegalArgumentException if invalid block name specified
* @throws DuplicateNameException if name conflicts with an address space name
*/
void checkBlockName(
String name)
throws IllegalArgumentException, DuplicateNameException {
if (!Memory.isValidAddressSpaceName(name)) {
throw new IllegalArgumentException("Invalid block name: " + name);
}
if (getAddressFactory().getAddressSpace(name) != null) {
throw new DuplicateNameException(
"Block name conflicts with existing address space: " + name);
}
}
@Override @Override
public MemoryBlock createBlock(MemoryBlock block, String name, Address start, long length) public MemoryBlock createBlock(MemoryBlock block, String name, Address start, long length)
throws MemoryConflictException, AddressOverflowException, LockException { throws MemoryConflictException, AddressOverflowException, LockException,
DuplicateNameException {
Objects.requireNonNull(name); checkBlockName(name);
lock.acquire(); lock.acquire();
try { try {
checkBlockSize(length, block.isInitialized()); checkBlockSize(length, block.isInitialized());
program.checkExclusiveAccess(); program.checkExclusiveAccess();
checkRange(start, length); checkRange(start, length);
try { try {
Address overlayAddr = null; Address mappedAddr = null;
int mappingScheme = 0;
if (block.isMapped()) { if (block.isMapped()) {
MemoryBlockSourceInfo info = block.getSourceInfos().get(0); MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
overlayAddr = info.getMappedRange().get().getMinAddress(); mappingScheme = info.getByteMappingScheme().get().getEncodedMappingScheme();
mappedAddr = info.getMappedRange().get().getMinAddress();
} }
MemoryBlockDB newBlock = adapter.createBlock(block.getType(), name, start, length, MemoryBlockDB newBlock = adapter.createBlock(block.getType(), name, start, length,
overlayAddr, block.isInitialized(), block.getPermissions()); mappedAddr, block.isInitialized(), block.getPermissions(), mappingScheme);
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock); addBlockAddresses(newBlock, !block.isMapped() && block.isInitialized());
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -731,7 +892,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
MemoryBlockDB memBlock = (MemoryBlockDB) block; MemoryBlockDB memBlock = (MemoryBlockDB) block;
Address oldStartAddr = block.getStart(); Address oldStartAddr = block.getStart();
if (block.getType() == MemoryBlockType.OVERLAY) { if (block.isOverlay()) {
throw new IllegalArgumentException("Overlay blocks cannot be moved"); throw new IllegalArgumentException("Overlay blocks cannot be moved");
} }
if (newStartAddr.getAddressSpace().isOverlaySpace()) { if (newStartAddr.getAddressSpace().isOverlaySpace()) {
@ -788,9 +949,21 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
if (addr.equals(memBlock.getStart())) { if (addr.equals(memBlock.getStart())) {
throw new IllegalArgumentException("Split cannot be done on block start address"); throw new IllegalArgumentException("Split cannot be done on block start address");
} }
if (memBlock.getType() == MemoryBlockType.OVERLAY) { if (memBlock.isOverlay()) {
throw new IllegalArgumentException("Split cannot be done on an overlay block"); throw new IllegalArgumentException("Split cannot be done on an overlay block");
} }
if (memBlock.isMapped()) {
if (memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
throw new IllegalArgumentException(
"Split cannot be done on a bit-mapped block");
}
ByteMappingScheme byteMappingScheme =
memBlock.getSourceInfos().get(0).getByteMappingScheme().get();
if (!byteMappingScheme.isOneToOneMapping()) {
throw new IllegalArgumentException(
"Split cannot be done on a byte-mapped block with " + byteMappingScheme);
}
}
if (memBlock.getType() == MemoryBlockType.BIT_MAPPED) { if (memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
throw new IllegalArgumentException("Split cannot be done on a bit mapped block"); throw new IllegalArgumentException("Split cannot be done on a bit mapped block");
} }
@ -850,7 +1023,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
private void checkPreconditionsForJoining(MemoryBlock block1, MemoryBlock block2) private void checkPreconditionsForJoining(MemoryBlock block1, MemoryBlock block2)
throws MemoryBlockException, NotFoundException, LockException { throws MemoryBlockException, LockException {
program.checkExclusiveAccess(); program.checkExclusiveAccess();
if (liveMemory != null) { if (liveMemory != null) {
@ -874,16 +1047,11 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
private void checkBlockForJoining(MemoryBlock block) { private void checkBlockForJoining(MemoryBlock block) {
checkBlock(block); checkBlock(block);
switch (block.getType()) { if (block.isOverlay()) {
case BIT_MAPPED: throw new IllegalArgumentException("Cannot join overlay blocks");
throw new IllegalArgumentException("Cannot join bit mapped blocks"); }
case BYTE_MAPPED: if (block.isMapped()) {
throw new IllegalArgumentException("Cannot join byte mapped blocks"); throw new IllegalArgumentException("Cannot join mapped blocks");
case OVERLAY:
throw new IllegalArgumentException("Cannot join overlay blocks");
case DEFAULT:
default:
// do nothing, these types are ok for joining
} }
} }
@ -909,8 +1077,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Only an Uninitialized Block may be converted to an Initialized Block"); "Only an Uninitialized Block may be converted to an Initialized Block");
} }
MemoryBlockType type = unitializedBlock.getType(); if (unitializedBlock.getType() != MemoryBlockType.DEFAULT) {
if (!((type == MemoryBlockType.DEFAULT) || (type == MemoryBlockType.OVERLAY))) {
throw new IllegalArgumentException("Block is of a type that cannot be initialized"); throw new IllegalArgumentException("Block is of a type that cannot be initialized");
} }
long size = unitializedBlock.getSize(); long size = unitializedBlock.getSize();
@ -922,6 +1089,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
memBlock.initializeBlock(initialValue); memBlock.initializeBlock(initialValue);
allInitializedAddrSet.addRange(memBlock.getStart(), memBlock.getEnd()); allInitializedAddrSet.addRange(memBlock.getStart(), memBlock.getEnd());
initializedLoadedAddrSet.addRange(memBlock.getStart(), memBlock.getEnd()); initializedLoadedAddrSet.addRange(memBlock.getStart(), memBlock.getEnd());
if (!memBlock.isMapped()) {
// update initialized sets for all blocks mapped to memBlock
updateMappedAddresses(memBlock, true);
}
fireBlockChanged(memBlock); fireBlockChanged(memBlock);
fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize()); fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize());
return memBlock; return memBlock;
@ -949,16 +1120,20 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Only an Initialized Block may be converted to an Uninitialized Block"); "Only an Initialized Block may be converted to an Uninitialized Block");
} }
MemoryBlockType type = initializedBlock.getType(); if (initializedBlock.getType() != MemoryBlockType.DEFAULT) {
if (!((type == MemoryBlockType.DEFAULT) || (type == MemoryBlockType.OVERLAY))) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Block is of a type that cannot be uninitialized"); "Block is of a type that cannot be uninitialized");
} }
MemoryBlockDB memBlock = (MemoryBlockDB) initializedBlock; MemoryBlockDB memBlock = (MemoryBlockDB) initializedBlock;
try { try {
// FIXME: clear instructions in initializedBlock or any block which maps to it
memBlock.uninitializeBlock(); memBlock.uninitializeBlock();
allInitializedAddrSet.deleteRange(memBlock.getStart(), memBlock.getEnd()); allInitializedAddrSet.deleteRange(memBlock.getStart(), memBlock.getEnd());
initializedLoadedAddrSet.deleteRange(memBlock.getStart(), memBlock.getEnd()); initializedLoadedAddrSet.deleteRange(memBlock.getStart(), memBlock.getEnd());
if (!memBlock.isMapped()) {
// update initialized sets for all blocks mapped to memBlock
updateMappedAddresses(memBlock, false);
}
fireBlockChanged(memBlock); fireBlockChanged(memBlock);
fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize()); fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize());
return memBlock; return memBlock;
@ -979,7 +1154,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
public Address findBytes(Address addr, byte[] bytes, byte[] masks, boolean forward, public Address findBytes(Address addr, byte[] bytes, byte[] masks, boolean forward,
TaskMonitor monitor) { TaskMonitor monitor) {
if (monitor == null) { if (monitor == null) {
monitor = TaskMonitorAdapter.DUMMY_MONITOR; monitor = TaskMonitor.DUMMY;
} }
AddressIterator it = initializedLoadedAddrSet.getAddresses(addr, forward); AddressIterator it = initializedLoadedAddrSet.getAddresses(addr, forward);
@ -997,6 +1172,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
monitor.incrementProgress(-moffset); monitor.incrementProgress(-moffset);
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
// ignore
} }
continue; continue;
} }
@ -1025,7 +1201,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
public Address findBytes(Address startAddr, Address endAddr, byte[] bytes, byte[] masks, public Address findBytes(Address startAddr, Address endAddr, byte[] bytes, byte[] masks,
boolean forward, TaskMonitor monitor) { boolean forward, TaskMonitor monitor) {
if (monitor == null) { if (monitor == null) {
monitor = TaskMonitorAdapter.DUMMY_MONITOR; monitor = TaskMonitor.DUMMY;
} }
AddressIterator it = allInitializedAddrSet.getAddresses(startAddr, forward); AddressIterator it = allInitializedAddrSet.getAddresses(startAddr, forward);
byte[] b = new byte[bytes.length]; byte[] b = new byte[bytes.length];
@ -1722,7 +1898,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/** /**
* Tests if the given addressSpace (overlay space) is used by any blocks. If not, it * Tests if the given addressSpace (overlay space) is used by any blocks. If not, it
* removes the space. * removes the space.
* @param addressSpace * @param addressSpace overlay address space to be removed
*/ */
private void checkRemoveAddressSpace(AddressSpace addressSpace) { private void checkRemoveAddressSpace(AddressSpace addressSpace) {
lock.acquire(); lock.acquire();
@ -1771,43 +1947,72 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
/** /**
* Gets the intersected set of addresses between a list of mapped memory blocks, and some other * Gets the intersected set of addresses between a mapped memory block, and some other
* address set. * address set.
* *
* @param block The mapped memory block to use in the intersection. * @param mappedBlock The mapped memory block to use in the intersection.
* @param set Some other address set to use in the intersection. * @param set Some other address set to use in the intersection.
* @return The intersected set of addresses between 'mappedMemoryBlock' and other address set * @return The intersected set of addresses between 'mappedMemoryBlock' and other address set
*/ */
private AddressSet getMappedIntersection(MemoryBlock block, AddressSet set) { private AddressSet getMappedIntersection(MemoryBlock mappedBlock, AddressSet set) {
AddressSet mappedIntersection = new AddressSet(); AddressSet mappedIntersection = new AddressSet();
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos(); List<MemoryBlockSourceInfo> sourceInfos = mappedBlock.getSourceInfos();
// mapped blocks can only ever have one sourceInfo // mapped blocks can only ever have one sourceInfo
MemoryBlockSourceInfo info = sourceInfos.get(0); MemoryBlockSourceInfo info = sourceInfos.get(0);
AddressRange range = info.getMappedRange().get(); AddressRange range = info.getMappedRange().get();
AddressSet resolvedIntersection = set.intersect(new AddressSet(range)); AddressSet resolvedIntersection = set.intersect(new AddressSet(range));
for (AddressRange resolvedRange : resolvedIntersection) { for (AddressRange resolvedRange : resolvedIntersection) {
mappedIntersection.add(getMappedRange(block, resolvedRange)); AddressRange mappedRange = getMappedRange(mappedBlock, resolvedRange);
if (mappedRange != null) {
mappedIntersection.add(mappedRange);
}
} }
return mappedIntersection; return mappedIntersection;
} }
/** /**
* Converts the given address range back from the source range back to the mapped range. * Converts the given address range back from the source range back to the mapped range.
* NOTE: It is important that the specified mappedSourceRange is restricted to the
* mapped source area of the specified mappedBlock.
* @param mappedBlock mapped memory block
* @param mappedSourceRange source range which maps into mappedBlock.
* @return mapped range or null if source range not mapped to block
*/ */
private AddressRange getMappedRange(MemoryBlock mappedBlock, AddressRange resolvedRange) { private AddressRange getMappedRange(MemoryBlock mappedBlock, AddressRange mappedSourceRange) {
Address start, end; Address start, end;
MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0); long sourceRangeLength = mappedSourceRange.getLength();
long startOffset = if (sourceRangeLength <= 0) {
resolvedRange.getMinAddress().subtract(info.getMappedRange().get().getMinAddress()); throw new AssertException("invalid mapped source range length");
boolean isBitMapped = mappedBlock.getType() == MemoryBlockType.BIT_MAPPED;
if (isBitMapped) {
start = mappedBlock.getStart().add(startOffset * 8);
end = start.add((resolvedRange.getLength() * 8) - 1);
} }
else { MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0);
start = mappedBlock.getStart().add(startOffset);
end = start.add(resolvedRange.getLength() - 1); long startOffset =
mappedSourceRange.getMinAddress().subtract(info.getMappedRange().get().getMinAddress());
boolean isBitMapped = mappedBlock.getType() == MemoryBlockType.BIT_MAPPED;
try {
if (isBitMapped) {
startOffset *= 8;
start = mappedBlock.getStart().addNoWrap(startOffset);
long endOffset = startOffset + (sourceRangeLength * 8) - 1;
// since end may only partially consume a byte we must limit end address
end = (endOffset < mappedBlock.getSize())
? mappedBlock.getStart().addNoWrap(endOffset)
: mappedBlock.getEnd();
}
else { // Byte mapped
ByteMappingScheme byteMappingScheme = info.getByteMappingScheme().get();
start =
byteMappingScheme.getMappedAddress(mappedBlock, startOffset, false);
long endOffset = startOffset + sourceRangeLength - 1;
end = byteMappingScheme.getMappedAddress(mappedBlock, endOffset, true);
if (start == null || start.compareTo(end) > 0) {
return null; // mappedSourceRange corresponds to non-mapped/skipped bytes
}
}
}
catch (AddressOverflowException e) {
throw new AddressOutOfBoundsException(e.getMessage());
} }
return new AddressRangeImpl(start, end); return new AddressRangeImpl(start, end);
} }

View file

@ -46,8 +46,30 @@ abstract class MemoryMapDBAdapter {
public static final int SUB_TYPE_COL = MemoryMapDBAdapterV3.V3_SUB_TYPE_COL; public static final int SUB_TYPE_COL = MemoryMapDBAdapterV3.V3_SUB_TYPE_COL;
public static final int SUB_LENGTH_COL = MemoryMapDBAdapterV3.V3_SUB_LENGTH_COL; public static final int SUB_LENGTH_COL = MemoryMapDBAdapterV3.V3_SUB_LENGTH_COL;
public static final int SUB_START_OFFSET_COL = MemoryMapDBAdapterV3.V3_SUB_START_OFFSET_COL; public static final int SUB_START_OFFSET_COL = MemoryMapDBAdapterV3.V3_SUB_START_OFFSET_COL;
public static final int SUB_SOURCE_ID_COL = MemoryMapDBAdapterV3.V3_SUB_SOURCE_ID_COL;
public static final int SUB_SOURCE_OFFSET_COL = MemoryMapDBAdapterV3.V3_SUB_SOURCE_OFFSET_COL; /**
* Subblock record int data1 usage:
* <ul>
* <li>{@link BufferSubMemoryBlock} - data buffer ID</li>
* <li>{@link FileBytesSubMemoryBlock} - file bytes layered data buffer ID</li>
* <li>{@link ByteMappedSubMemoryBlock} - encoded byte mapping scheme</li>
* <li>{@link BitMappedSubMemoryBlock} - (not used) 0</li>
* <li>{@link UninitializedSubMemoryBlock} - (not used) 0</li>
* </ul>
*/
public static final int SUB_INT_DATA1_COL = MemoryMapDBAdapterV3.V3_SUB_INT_DATA1_COL;
/**
* Subblock record long data2 usage:
* <ul>
* <li>{@link BufferSubMemoryBlock} - (not used) 0</li>
* <li>{@link FileBytesSubMemoryBlock} - starting byte offset within file bytes buffer</li>
* <li>{@link ByteMappedSubMemoryBlock} - encoded mapped source address</li>
* <li>{@link BitMappedSubMemoryBlock} - encoded mapped source address</li>
* <li>{@link UninitializedSubMemoryBlock} - (not used) 0</li>
* </ul>
*/
public static final int SUB_LONG_DATA2_COL = MemoryMapDBAdapterV3.V3_SUB_LONG_DATA2_COL;
public static final byte SUB_TYPE_BIT_MAPPED = MemoryMapDBAdapterV3.V3_SUB_TYPE_BIT_MAPPED; public static final byte SUB_TYPE_BIT_MAPPED = MemoryMapDBAdapterV3.V3_SUB_TYPE_BIT_MAPPED;
public static final byte SUB_TYPE_BYTE_MAPPED = MemoryMapDBAdapterV3.V3_SUB_TYPE_BYTE_MAPPED; public static final byte SUB_TYPE_BYTE_MAPPED = MemoryMapDBAdapterV3.V3_SUB_TYPE_BYTE_MAPPED;
@ -121,7 +143,7 @@ abstract class MemoryMapDBAdapter {
} }
newBlock = newBlock =
newAdapter.createBlock(block.getType(), block.getName(), block.getStart(), newAdapter.createBlock(block.getType(), block.getName(), block.getStart(),
block.getSize(), mappedAddress, false, block.getPermissions()); block.getSize(), mappedAddress, false, block.getPermissions(), 0);
} }
newBlock.setComment(block.getComment()); newBlock.setComment(block.getComment());
newBlock.setSourceName(block.getSourceName()); newBlock.setSourceName(block.getSourceName());
@ -192,16 +214,19 @@ abstract class MemoryMapDBAdapter {
* @param name the name of the block. * @param name the name of the block.
* @param startAddr the start address of the block * @param startAddr the start address of the block
* @param length the size of the block * @param length the size of the block
* @param mappedAddress the address at which to overlay this block. (If the type is overlay) * @param mappedAddress the starting byte source address at which to map
* @param initializeBytes if true, creates a database buffer for the bytes in the block * the block. (used for bit/byte-mapped blocks only)
* @param initializeBytes if true, creates a database buffer for storing the
* bytes in the block (applies to initialized default blocks only)
* @param permissions the new block permissions * @param permissions the new block permissions
* @param encodedMappingScheme byte mapping scheme (used by byte-mapped blocks only)
* @return new memory block * @return new memory block
* @throws IOException if a database IO error occurs. * @throws IOException if a database IO error occurs.
* @throws AddressOverflowException if block length is too large for the underlying space * @throws AddressOverflowException if block length is too large for the underlying space
*/ */
abstract MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, abstract MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr,
long length, Address mappedAddress, boolean initializeBytes, int permissions) long length, Address mappedAddress, boolean initializeBytes, int permissions,
throws AddressOverflowException, IOException; int encodedMappingScheme) throws AddressOverflowException, IOException;
/** /**
* Deletes the given memory block. * Deletes the given memory block.
@ -253,15 +278,13 @@ abstract class MemoryMapDBAdapter {
* sub block starts * sub block starts
* @param length the length of this sub block * @param length the length of this sub block
* @param subType the type of the subBlock * @param subType the type of the subBlock
* @param sourceID if the type is a buffer, then this is the buffer id. If the type is file bytes, * @param data1 subblock implementation specific integer data
* then this is the FileBytes id. * @param data2 subblock implementation specific long data
* @param sourceOffset if the type is file bytes, then this is the offset into the filebytes. If
* the type is mapped, then this is the encoded mapped address.
* @return the newly created record. * @return the newly created record.
* @throws IOException if a database error occurs * @throws IOException if a database error occurs
*/ */
abstract Record createSubBlockRecord(long memBlockId, long startingOffset, long length, abstract Record createSubBlockRecord(long memBlockId, long startingOffset, long length,
byte subType, int sourceID, long sourceOffset) throws IOException; byte subType, int data1, long data2) throws IOException;
/** /**
* Creates a new memory block. * Creates a new memory block.

View file

@ -156,7 +156,7 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter {
return new ByteMappedSubMemoryBlock(this, record); return new ByteMappedSubMemoryBlock(this, record);
case MemoryMapDBAdapterV2.INITIALIZED: case MemoryMapDBAdapterV2.INITIALIZED:
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BUFFER); record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BUFFER);
record.setLongValue(SUB_SOURCE_OFFSET_COL, bufID); record.setLongValue(SUB_LONG_DATA2_COL, bufID);
return new BufferSubMemoryBlock(this, record); return new BufferSubMemoryBlock(this, record);
case MemoryMapDBAdapterV2.UNINITIALIZED: case MemoryMapDBAdapterV2.UNINITIALIZED:
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_UNITIALIZED); record.setByteValue(SUB_TYPE_COL, SUB_TYPE_UNITIALIZED);
@ -223,7 +223,8 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter {
@Override @Override
MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr,
long length, Address overlayAddr, boolean initializeBytes, int permissions) long length, Address overlayAddr, boolean initializeBytes, int permissions,
int mappingScheme)
throws IOException { throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -253,7 +254,7 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter {
@Override @Override
Record createSubBlockRecord(long memBlockId, long startingOffset, long length, byte subType, Record createSubBlockRecord(long memBlockId, long startingOffset, long length, byte subType,
int sourceID, long sourceOffset) throws IOException { int data1, long data2) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View file

@ -124,15 +124,15 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter {
switch (type) { switch (type) {
case MemoryMapDBAdapterV2.BIT_MAPPED: case MemoryMapDBAdapterV2.BIT_MAPPED:
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BIT_MAPPED); record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BIT_MAPPED);
record.setLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL, overlayAddr); record.setLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL, overlayAddr);
return new BitMappedSubMemoryBlock(this, record); return new BitMappedSubMemoryBlock(this, record);
case MemoryMapDBAdapterV2.BYTE_MAPPED: case MemoryMapDBAdapterV2.BYTE_MAPPED:
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BYTE_MAPPED); record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BYTE_MAPPED);
record.setLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL, overlayAddr); record.setLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL, overlayAddr);
return new ByteMappedSubMemoryBlock(this, record); return new ByteMappedSubMemoryBlock(this, record);
case MemoryMapDBAdapterV2.INITIALIZED: case MemoryMapDBAdapterV2.INITIALIZED:
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BUFFER); record.setByteValue(SUB_TYPE_COL, SUB_TYPE_BUFFER);
record.setIntValue(SUB_SOURCE_ID_COL, bufID); record.setIntValue(SUB_INT_DATA1_COL, bufID);
return new BufferSubMemoryBlock(this, record); return new BufferSubMemoryBlock(this, record);
case MemoryMapDBAdapterV2.UNINITIALIZED: case MemoryMapDBAdapterV2.UNINITIALIZED:
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_UNITIALIZED); record.setByteValue(SUB_TYPE_COL, SUB_TYPE_UNITIALIZED);
@ -161,7 +161,8 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter {
@Override @Override
MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr,
long length, Address mappedAddress, boolean initializeBytes, int permissions) long length, Address mappedAddress, boolean initializeBytes, int permissions,
int mappingScheme)
throws AddressOverflowException, IOException { throws AddressOverflowException, IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -216,7 +217,7 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter {
@Override @Override
Record createSubBlockRecord(long memBlockId, long startingOffset, long length, byte subType, Record createSubBlockRecord(long memBlockId, long startingOffset, long length, byte subType,
int sourceID, long sourceOffset) throws IOException { int data1, long data2) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View file

@ -48,8 +48,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
public static final int V3_SUB_TYPE_COL = 1; public static final int V3_SUB_TYPE_COL = 1;
public static final int V3_SUB_LENGTH_COL = 2; public static final int V3_SUB_LENGTH_COL = 2;
public static final int V3_SUB_START_OFFSET_COL = 3; public static final int V3_SUB_START_OFFSET_COL = 3;
public static final int V3_SUB_SOURCE_ID_COL = 4; public static final int V3_SUB_INT_DATA1_COL = 4;
public static final int V3_SUB_SOURCE_OFFSET_COL = 5; public static final int V3_SUB_LONG_DATA2_COL = 5;
public static final byte V3_SUB_TYPE_BIT_MAPPED = 0; public static final byte V3_SUB_TYPE_BIT_MAPPED = 0;
public static final byte V3_SUB_TYPE_BYTE_MAPPED = 1; public static final byte V3_SUB_TYPE_BYTE_MAPPED = 1;
@ -186,17 +186,19 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
@Override @Override
MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr,
long length, Address mappedAddress, boolean initializeBytes, int permissions) long length, Address mappedAddress, boolean initializeBytes, int permissions,
throws AddressOverflowException, IOException { int encodedMappingScheme) throws AddressOverflowException, IOException {
if (initializeBytes) { if (blockType == MemoryBlockType.BIT_MAPPED) {
return createInitializedBlock(name, startAddr, null, length, permissions);
}
else if (blockType == MemoryBlockType.BIT_MAPPED) {
return createBitMappedBlock(name, startAddr, length, mappedAddress, permissions); return createBitMappedBlock(name, startAddr, length, mappedAddress, permissions);
} }
else if (blockType == MemoryBlockType.BYTE_MAPPED) { if (blockType == MemoryBlockType.BYTE_MAPPED) {
return createByteMappedBlock(name, startAddr, length, mappedAddress, permissions); return createByteMappedBlock(name, startAddr, length, mappedAddress, permissions,
encodedMappingScheme);
}
// DEFAULT block type
if (initializeBytes) {
return createInitializedBlock(name, startAddr, null, length, permissions);
} }
return createUnitializedBlock(name, startAddr, length, permissions); return createUnitializedBlock(name, startAddr, length, permissions);
} }
@ -265,13 +267,14 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
MemoryBlockDB createBitMappedBlock(String name, Address startAddress, long length, MemoryBlockDB createBitMappedBlock(String name, Address startAddress, long length,
Address mappedAddress, int permissions) throws IOException, AddressOverflowException { Address mappedAddress, int permissions) throws IOException, AddressOverflowException {
return createMappedBlock(V3_SUB_TYPE_BIT_MAPPED, name, startAddress, length, mappedAddress, return createMappedBlock(V3_SUB_TYPE_BIT_MAPPED, name, startAddress, length, mappedAddress,
permissions); permissions, 0);
} }
MemoryBlockDB createByteMappedBlock(String name, Address startAddress, long length, MemoryBlockDB createByteMappedBlock(String name, Address startAddress, long length,
Address mappedAddress, int permissions) throws IOException, AddressOverflowException { Address mappedAddress, int permissions, int mappingScheme)
throws IOException, AddressOverflowException {
return createMappedBlock(V3_SUB_TYPE_BYTE_MAPPED, name, startAddress, length, mappedAddress, return createMappedBlock(V3_SUB_TYPE_BYTE_MAPPED, name, startAddress, length, mappedAddress,
permissions); permissions, mappingScheme);
} }
@Override @Override
@ -296,7 +299,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
} }
private MemoryBlockDB createMappedBlock(byte type, String name, Address startAddress, private MemoryBlockDB createMappedBlock(byte type, String name, Address startAddress,
long length, Address mappedAddress, int permissions) long length, Address mappedAddress, int permissions,
int mappingScheme)
throws IOException, AddressOverflowException { throws IOException, AddressOverflowException {
updateAddressMapForAllAddresses(startAddress, length); updateAddressMapForAllAddresses(startAddress, length);
@ -305,7 +309,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
long key = blockRecord.getKey(); long key = blockRecord.getKey();
long encoded = addrMap.getKey(mappedAddress, true); long encoded = addrMap.getKey(mappedAddress, true);
Record subRecord = createSubBlockRecord(key, 0, length, type, 0, encoded); Record subRecord = createSubBlockRecord(key, 0, length, type, mappingScheme, encoded);
subBlocks.add(createSubBlock(subRecord)); subBlocks.add(createSubBlock(subRecord));
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
@ -350,15 +354,15 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
@Override @Override
Record createSubBlockRecord(long parentKey, long startingOffset, long length, byte type, Record createSubBlockRecord(long parentKey, long startingOffset, long length, byte type,
int sourceId, long sourceOffset) throws IOException { int data1, long data2) throws IOException {
Record record = V3_SUB_BLOCK_SCHEMA.createRecord(subBlockTable.getKey()); Record record = V3_SUB_BLOCK_SCHEMA.createRecord(subBlockTable.getKey());
record.setLongValue(V3_SUB_PARENT_ID_COL, parentKey); record.setLongValue(V3_SUB_PARENT_ID_COL, parentKey);
record.setByteValue(V3_SUB_TYPE_COL, type); record.setByteValue(V3_SUB_TYPE_COL, type);
record.setLongValue(V3_SUB_LENGTH_COL, length); record.setLongValue(V3_SUB_LENGTH_COL, length);
record.setLongValue(V3_SUB_START_OFFSET_COL, startingOffset); record.setLongValue(V3_SUB_START_OFFSET_COL, startingOffset);
record.setIntValue(V3_SUB_SOURCE_ID_COL, sourceId); record.setIntValue(V3_SUB_INT_DATA1_COL, data1);
record.setLongValue(V3_SUB_SOURCE_OFFSET_COL, sourceOffset); record.setLongValue(V3_SUB_LONG_DATA2_COL, data2);
subBlockTable.putRecord(record); subBlockTable.putRecord(record);
return record; return record;

View file

@ -18,8 +18,6 @@ package ghidra.program.database.mem;
import java.io.IOException; import java.io.IOException;
import db.Record; import db.Record;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
/** /**
@ -183,11 +181,13 @@ abstract class SubMemoryBlock implements Comparable<SubMemoryBlock> {
} }
/** /**
* Get the {@link MemoryBlockType} for this block: TYPE_DEFAULT, TYPE_OVERLAY, TYPE_BIT_MAPPED, or TYPE_BYTE_MAPPED * Get the {@link MemoryBlockType} for this block: DEFAULT, BIT_MAPPED, or BYTE_MAPPED
* *
* @return the type for this block: TYPE_DEFAULT, TYPE_OVERLAY, TYPE_BIT_MAPPED, or TYPE_BYTE_MAPPED * @return the type for this block: DEFAULT, BIT_MAPPED, or BYTE_MAPPED
*/ */
protected abstract MemoryBlockType getType(); protected MemoryBlockType getType() {
return MemoryBlockType.DEFAULT;
}
/** /**
* Returns the {@link MemoryBlockSourceInfo} object for this SubMemoryBlock * Returns the {@link MemoryBlockSourceInfo} object for this SubMemoryBlock
@ -238,18 +238,6 @@ abstract class SubMemoryBlock implements Comparable<SubMemoryBlock> {
return false; return false;
} }
/**
* Gets the list of BytesSourceRanges from this sub block for the given memBlockOffset and associates
* it with the given {@link AddressRange}
* @param block the {@link MemoryBlock} that generated the BytesSourceSet.
* @param start the program address for which to get a ByteSourceSet
* @param memBlockOffset the offset from the beginning of the containing MemoryBlock.
* @param size the size of region to get byte sources
* @return the set of ByteSourceRanges which maps program addresses to byte source locations.
*/
protected abstract ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
long memBlockOffset, long size);
@Override @Override
public int compareTo(SubMemoryBlock o) { public int compareTo(SubMemoryBlock o) {
long result = getStartingOffset() - o.getStartingOffset(); long result = getStartingOffset() - o.getStartingOffset();

View file

@ -18,8 +18,7 @@ package ghidra.program.database.mem;
import java.io.IOException; import java.io.IOException;
import db.Record; import db.Record;
import ghidra.program.model.address.Address; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.*;
/** /**
* Implementation of SubMemoryBlock for uninitialized blocks. * Implementation of SubMemoryBlock for uninitialized blocks.
@ -28,7 +27,6 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
UninitializedSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) { UninitializedSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) {
super(adapter, record); super(adapter, record);
subBlockOffset = record.getLongValue(MemoryMapDBAdapter.SUB_START_OFFSET_COL);
} }
@Override @Override
@ -53,12 +51,12 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
@Override @Override
public void putByte(long offset, byte b) throws MemoryAccessException { public void putByte(long offset, byte b) throws MemoryAccessException {
throw new MemoryAccessException("Attempted to read from uninitialized block"); throw new MemoryAccessException("Attempted to write to an uninitialized block");
} }
@Override @Override
public int putBytes(long offset, byte[] b, int off, int len) throws MemoryAccessException { public int putBytes(long offset, byte[] b, int off, int len) throws MemoryAccessException {
throw new MemoryAccessException("Attempted to read from uninitialized block"); throw new MemoryAccessException("Attempted to write to an uninitialized block");
} }
@Override @Override
@ -71,11 +69,6 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
return true; return true;
} }
@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
@ -96,11 +89,4 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
return ""; return "";
} }
@Override
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
long memBlockOffset,
long size) {
return new ByteSourceRangeList();
}
} }

View file

@ -406,4 +406,23 @@ public interface Address extends Comparable<Address> {
*/ */
public boolean isExternalAddress(); public boolean isExternalAddress();
/**
* Return the minimum of two addresses using Address.compareTo
* @param a first address
* @param b second address
* @return minimum of two addresses
*/
public static Address min(Address a, Address b) {
return a.compareTo(b) <= 0 ? a : b;
}
/**
* Return the maximum of two addresses using Address.compareTo
* @param a first address
* @param b second address
* @return maximum of two addresses
*/
public static Address max(Address a, Address b) {
return a.compareTo(b) > 0 ? a : b;
}
} }

View file

@ -172,4 +172,9 @@ public class AddressSetViewAdapter implements AddressSetView {
public Address findFirstAddressInCommon(AddressSetView otherSet) { public Address findFirstAddressInCommon(AddressSetView otherSet) {
return set.findFirstAddressInCommon(otherSet); return set.findFirstAddressInCommon(otherSet);
} }
@Override
public String toString() {
return set.toString();
}
} }

View file

@ -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.util.exception.*; import ghidra.util.exception.*;
@ -109,7 +108,8 @@ public interface Memory extends AddressSetView {
/** /**
* Create an initialized memory block and add it to this Memory. * Create an initialized memory block and add it to this Memory.
* @param name block name * @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start start address of the block * @param start start address of the block
* @param is source of the data used to fill the block or null for zero initialization. * @param is source of the data used to fill the block or null for zero initialization.
* @param length the size of the block * @param length the size of the block
@ -124,43 +124,45 @@ public interface Memory extends AddressSetView {
* @throws AddressOverflowException if the start is beyond the * @throws AddressOverflowException if the start is beyond the
* address space * address space
* @throws CancelledException user cancelled operation * @throws CancelledException user cancelled operation
* @throws DuplicateNameException if overlay is true and there is already an overlay address * @throws IllegalArgumentException if invalid block name specified
* space with the same name as this memory block * @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/ */
public MemoryBlock createInitializedBlock(String name, Address start, InputStream is, public MemoryBlock createInitializedBlock(String name, Address start, InputStream is,
long length, TaskMonitor monitor, boolean overlay) long length, TaskMonitor monitor, boolean overlay)
throws LockException, MemoryConflictException, AddressOverflowException, throws LockException, MemoryConflictException, AddressOverflowException,
CancelledException, DuplicateNameException; CancelledException, IllegalArgumentException, DuplicateNameException;
/** /**
* Create an initialized memory block and add it to this Memory. * Create an initialized memory block and add it to this Memory.
* @param name block name * @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start start of the block * @param start start of the block
* @param size block length (positive non-zero value required) * @param size block length (positive non-zero value required)
* @param initialValue initialization value for every byte in the block. * @param initialValue initialization value for every byte in the block.
* @param monitor progress monitor, may be null. * @param monitor progress monitor, may be null.
* @param overlay if true, the block will be created as an OVERLAY which means that a new * @param overlay if true, the block will be created as an OVERLAY which means that a new
* overlay address space will be created and the block will have a starting address at the same * overlay address space will be created and the block will have a starting address at the same
* offset as the given start address paramaeter, but in the new address space. * offset as the given start address parameter, but in the new address space.
* @return new Initialized Memory Block * @return new Initialized Memory Block
* @throws DuplicateNameException if overlay is true and there is already an overlay address
* space with the same name as this memory block
* @throws LockException if exclusive lock not in place (see haveLock()) * @throws LockException if exclusive lock not in place (see haveLock())
* @throws MemoryConflictException if the new block overlaps with a * @throws MemoryConflictException if the new block overlaps with a
* previous block * previous block
* @throws AddressOverflowException if the start is beyond the * @throws AddressOverflowException if the start is beyond the
* address space * address space
* @throws IllegalArgumentException if invalid block name specified
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
* @throws CancelledException user cancelled operation * @throws CancelledException user cancelled operation
*/ */
public MemoryBlock createInitializedBlock(String name, Address start, long size, public MemoryBlock createInitializedBlock(String name, Address start, long size,
byte initialValue, TaskMonitor monitor, boolean overlay) byte initialValue, TaskMonitor monitor, boolean overlay)
throws LockException, DuplicateNameException, MemoryConflictException, throws LockException, IllegalArgumentException, DuplicateNameException,
AddressOverflowException, CancelledException; MemoryConflictException, AddressOverflowException, CancelledException;
/** /**
* Create an initialized memory block using bytes from a {@link FileBytes} object. * Create an initialized memory block using bytes from a {@link FileBytes} object.
* *
* @param name block name * @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start starting address of the block * @param start starting address of the block
* @param fileBytes the {@link FileBytes} object to use as the underlying source of bytes. * @param fileBytes the {@link FileBytes} object to use as the underlying source of bytes.
* @param offset the offset into the FileBytes for the first byte of this memory block. * @param offset the offset into the FileBytes for the first byte of this memory block.
@ -170,86 +172,138 @@ public interface Memory extends AddressSetView {
* offset as the given start address parameter, but in the new address space. * offset as the given start address parameter, but in the new address space.
* @return new Initialized Memory Block * @return new Initialized Memory Block
* @throws LockException if exclusive lock not in place (see haveLock()) * @throws LockException if exclusive lock not in place (see haveLock())
* @throws DuplicateNameException if overlay is true and there is already an overlay address
* space with the same name as this memory block
* @throws MemoryConflictException if the new block overlaps with a * @throws MemoryConflictException if the new block overlaps with a
* previous block * previous block
* @throws AddressOverflowException if the start is beyond the address space * @throws AddressOverflowException if the start is beyond the address space
* @throws IndexOutOfBoundsException if file bytes range specified by offset and size * @throws IndexOutOfBoundsException if file bytes range specified by offset and size
* is out of bounds for the specified fileBytes. * is out of bounds for the specified fileBytes.
* @throws IllegalArgumentException if invalid block name specified
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/ */
public MemoryBlock createInitializedBlock(String name, Address start, FileBytes fileBytes, public MemoryBlock createInitializedBlock(String name, Address start, FileBytes fileBytes,
long offset, long size, boolean overlay) throws LockException, DuplicateNameException, long offset, long size, boolean overlay) throws LockException, IllegalArgumentException,
MemoryConflictException, AddressOverflowException; DuplicateNameException, MemoryConflictException, AddressOverflowException;
/** /**
* Create an uninitialized memory block and add it to this Memory. * Create an uninitialized memory block and add it to this Memory.
* @param name block name * @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start start of the block * @param start start of the block
* @param size block length * @param size block length
* @param overlay if true, the block will be created as an OVERLAY which means that a new * @param overlay if true, the block will be created as an OVERLAY which means that a new
* overlay address space will be created and the block will have a starting address at the same * overlay address space will be created and the block will have a starting address at the same
* offset as the given start address paramaeter, but in the new address space. * offset as the given start address parameter, but in the new address space.
* @return new Uninitialized Memory Block * @return new Uninitialized Memory Block
* @throws LockException if exclusive lock not in place (see haveLock()) * @throws LockException if exclusive lock not in place (see haveLock())
* @throws MemoryConflictException if the new block overlaps with a * @throws MemoryConflictException if the new block overlaps with a
* previous block * previous block
* @throws AddressOverflowException if the start is beyond the * @throws AddressOverflowException if the start is beyond the
* address space * address space
* @throws DuplicateNameException if overlay is true and there is already an overlay address * @throws IllegalArgumentException if invalid block name specified
* space with the same name as this memory block * @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/ */
public MemoryBlock createUninitializedBlock(String name, Address start, long size, public MemoryBlock createUninitializedBlock(String name, Address start, long size,
boolean overlay) throws LockException, DuplicateNameException, MemoryConflictException, boolean overlay) throws LockException, IllegalArgumentException, DuplicateNameException,
AddressOverflowException; MemoryConflictException, AddressOverflowException;
/** /**
* Create a bit overlay memory block and add it to this Memory. * Create a bit overlay memory block and add it to this Memory.
* @param name block name * @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start start of the block * @param start start of the block
* @param mappedAddress start address in the source block for the * @param mappedAddress start address in the source block for the
* beginning of this block * beginning of this block
* @param length block length * @param length block length
* @param overlay if true, the block will be created as an OVERLAY which means that a new
* overlay address space will be created and the block will have a starting address at the same
* offset as the given start address parameter, but in the new address space.
* @return new Bit Memory Block * @return new Bit Memory Block
* @throws LockException if exclusive lock not in place (see haveLock()) * @throws LockException if exclusive lock not in place (see haveLock())
* @throws MemoryConflictException if the new block overlaps with a * @throws MemoryConflictException if the new block overlaps with a
* previous block * previous block
* @throws MemoryConflictException if the new block overlaps with a * @throws MemoryConflictException if the new block overlaps with a
* previous block * previous block
* @throws AddressOverflowException if the start is beyond the * @throws AddressOverflowException if block specification exceeds bounds of address space
* address space * @throws IllegalArgumentException if invalid block name specified
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/ */
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,
IllegalArgumentException, DuplicateNameException;
/** /**
* Create a memory block that uses the bytes located at a different location. * Create a memory block that uses the bytes located at a different location with a 1:1
* @param name block name * byte mapping scheme.
* @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start start of the block * @param start start of the block
* @param mappedAddress start address in the source block for the * @param mappedAddress start address in the source block for the
* beginning of this block * beginning of this block
* @param length block length * @param length block length
* @param byteMappingScheme byte mapping scheme (may be null for 1:1 mapping)
* @param overlay if true, the block will be created as an OVERLAY which means that a new
* overlay address space will be created and the block will have a starting address at the same
* offset as the given start address parameter, but in the new address space.
* @return new Bit Memory Block * @return new Bit Memory Block
* @throws LockException if exclusive lock not in place (see haveLock()) * @throws LockException if exclusive lock not in place (see haveLock())
* @throws MemoryConflictException if the new block overlaps with a * @throws MemoryConflictException if the new block overlaps with a previous block
* previous block * @throws AddressOverflowException if block specification exceeds bounds of address space
* @throws IllegalArgumentException if invalid block name
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/ */
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, DuplicateNameException;
/**
* Create a memory block that uses the bytes located at a different location with a 1:1
* byte mapping scheme.
* @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules)
* @param start start of the block
* @param mappedAddress start address in the source block for the
* beginning of this block
* @param length block length
* @param overlay if true, the block will be created as an OVERLAY which means that a new
* overlay address space will be created and the block will have a starting address at the same
* offset as the given start address parameter, but in the new address space.
* @return new Bit Memory Block
* @throws LockException if exclusive lock not in place (see haveLock())
* @throws MemoryConflictException if the new block overlaps with a previous block
* @throws AddressOverflowException if block specification exceeds bounds of address space
* @throws IllegalArgumentException if invalid block name
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/
default public MemoryBlock createByteMappedBlock(String name, Address start,
Address mappedAddress, long length, boolean overlay) throws LockException,
MemoryConflictException,
AddressOverflowException, IllegalArgumentException, DuplicateNameException {
return createByteMappedBlock(name, start, mappedAddress, length, null, overlay);
}
/** /**
* Creates a MemoryBlock at the given address with the same properties * Creates a MemoryBlock at the given address with the same properties
* as block, and adds it to this Memory. * as block, and adds it to this Memory. Initialized Default blocks will
* have block filled with 0's. Method will only create physical space blocks
* and will not create an overlay block.
* @param block source block * @param block source block
* @param name block name * @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
* naming rules).
* @param start start of the block * @param start start of the block
* @param length the size of the new block. * @param length the size of the new block.
* @return new block
* @throws LockException if exclusive lock not in place (see haveLock()) * @throws LockException if exclusive lock not in place (see haveLock())
* @throws MemoryConflictException if block specification conflicts with an existing block
* @throws AddressOverflowException if the new memory block would extend * @throws AddressOverflowException if the new memory block would extend
* beyond the end of the address space. * beyond the end of the address space.
* @throws IllegalArgumentException if invalid block name specified
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
*/ */
public MemoryBlock createBlock(MemoryBlock block, String name, Address start, long length) public MemoryBlock createBlock(MemoryBlock block, String name, Address start, long length)
throws LockException, MemoryConflictException, AddressOverflowException; throws LockException, IllegalArgumentException, MemoryConflictException,
AddressOverflowException, DuplicateNameException;
/** /**
* Remove the memory block. * Remove the memory block.
@ -760,4 +814,23 @@ public interface Memory extends AddressSetView {
* null if the address is not in memory. * null if the address is not in memory.
*/ */
public AddressSourceInfo getAddressSourceInfo(Address address); public AddressSourceInfo getAddressSourceInfo(Address address);
/**
* Validate the given address space or block name: cannot be null, cannot be an empty string, cannot contain blank
* or reserved characters (e.g., colon).
* @return true if name is valid else false
*/
public static boolean isValidAddressSpaceName(String name) {
if (name == null || name.length() == 0) {
return false;
}
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (c < 0x20 || c >= 0x7f || c == ':') {
return false;
}
}
return true;
}
} }

View file

@ -22,6 +22,7 @@ import java.util.List;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.NamingUtilities;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@ -86,12 +87,15 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
public String getName(); public String getName();
/** /**
* Set the name for this block. * Set the name for this block (See {@link NamingUtilities#isValidName(String)} for
* naming rules). Specified name must not conflict with an address space name.
* @param name the new name for this block. * @param name the new name for this block.
* @throws DuplicateNameException * @throws DuplicateNameException if name conflicts with an address space name
* @throws IllegalArgumentException if invalid name specified
* @throws LockException renaming an Overlay block without exclusive access * @throws LockException renaming an Overlay block without exclusive access
*/ */
public void setName(String name) throws DuplicateNameException, LockException; public void setName(String name)
throws IllegalArgumentException, DuplicateNameException, LockException;
/** /**
* Get the comment associated with this block. * Get the comment associated with this block.
@ -241,7 +245,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
public int putBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException; public int putBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException;
/** /**
* Get the type for this block: TYPE_DEFAULT, TYPE_OVERLAY, TYPE_BIT_MAPPED, or TYPE_BYTE_MAPPED * Get the type for this block: DEFAULT, BIT_MAPPED, or BYTE_MAPPED
*/ */
public MemoryBlockType getType(); public MemoryBlockType getType();
@ -255,6 +259,12 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
*/ */
public boolean isMapped(); public boolean isMapped();
/**
* Returns true if this is an overlay block (i.e., contained within overlay space).
* @return true if this is an overlay block
*/
public boolean isOverlay();
/** /**
* Returns true if this memory block is a real loaded block (i.e. RAM) and not a special block * Returns true if this memory block is a real loaded block (i.e. RAM) and not a special block
* containing file header data such as debug sections. * containing file header data such as debug sections.
@ -285,5 +295,4 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
MemoryBlock block = memory.getBlock(address); MemoryBlock block = memory.getBlock(address);
return block != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName()); return block != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName());
} }
} }

View file

@ -17,6 +17,7 @@ package ghidra.program.model.mem;
import java.util.Optional; import java.util.Optional;
import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.database.mem.FileBytes; import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange; import ghidra.program.model.address.AddressRange;
@ -75,13 +76,20 @@ public interface MemoryBlockSourceInfo {
long getFileBytesOffset(Address address); long getFileBytesOffset(Address address);
/** /**
* Returns an {@link Optional} {@link AddressRange} for the mapped addresses if this is mapped * Returns an {@link Optional} {@link AddressRange} for the mapped addresses if this is a mapped
* memory block (bit mapped or byte mapped). Otherwise, the Optional is empty. * memory block (bit mapped or byte mapped). Otherwise, the Optional is empty.
* @return an {@link Optional} {@link AddressRange} for the mapped addresses if this is mapped * @return an {@link Optional} {@link AddressRange} for the mapped addresses if this is a mapped
* memory block * memory block
*/ */
Optional<AddressRange> getMappedRange(); Optional<AddressRange> getMappedRange();
/**
* Returns an {@link Optional} {@link ByteMappingScheme} employed if this is a byte-mapped
* memory block. Otherwise, the Optional is empty.
* @return an {@link Optional} {@link ByteMappingScheme} employed if this is a byte-mapped memory block.
*/
Optional<ByteMappingScheme> getByteMappingScheme();
/** /**
* Returns the containing Memory Block * Returns the containing Memory Block
* @return the containing Memory Block * @return the containing Memory Block

View file

@ -129,6 +129,11 @@ public class MemoryBlockStub implements MemoryBlock {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean isOverlay() {
throw new UnsupportedOperationException();
}
@Override @Override
public String getSourceName() { public String getSourceName() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View file

@ -20,8 +20,7 @@ public enum MemoryBlockType {
//@formatter:off //@formatter:off
DEFAULT("Default"), DEFAULT("Default"),
BIT_MAPPED("Bit Mapped"), BIT_MAPPED("Bit Mapped"),
BYTE_MAPPED("Byte Mapped"), BYTE_MAPPED("Byte Mapped");
OVERLAY("Overlay");
//@formatter:on //@formatter:on
private String name; private String name;

View file

@ -21,8 +21,7 @@ import java.util.Iterator;
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.util.exception.*; import ghidra.util.exception.*;
@ -235,13 +234,16 @@ public class MemoryStub 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 {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@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 {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View file

@ -1,194 +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 static org.junit.Assert.*;
import java.util.Iterator;
import java.util.Set;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockStub;
public class ByteSourceRangeListTest extends AbstractGenericTest {
private AddressSpace space = new GenericAddressSpace("test", 64, AddressSpace.TYPE_RAM, 0);
private MemoryBlock block = new MemoryBlockStub();
@Test
public void testConstructor() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList(range1);
ByteSourceRangeList list2 = new ByteSourceRangeList();
list2.add(range1);
assertTrue(list1.equals(list2));
}
@Test
public void testAdd() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x10, 2, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList(range1);
ByteSourceRangeList list2 = new ByteSourceRangeList(range2);
list1.add(list2);
assertEquals(2, list1.getRangeCount());
assertEquals(range1, list1.get(0));
assertEquals(range2, list1.get(1));
}
@Test
public void testIsEmpty() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList();
assertTrue(list1.isEmpty());
list1.add(range1);
assertFalse(list1.isEmpty());
}
@Test
public void testAddNullRange() {
ByteSourceRange range = null;
ByteSourceRangeList list1 = new ByteSourceRangeList();
list1.add(range);
assertTrue(list1.isEmpty());
}
@Test
public void testIterator() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x10, 2, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList(range1);
list1.add(range2);
Iterator<ByteSourceRange> it = list1.iterator();
assertTrue(it.hasNext());
assertEquals(range1, it.next());
assertTrue(it.hasNext());
assertEquals(range2, it.next());
assertFalse(it.hasNext());
}
@Test
public void testIntersectSimple() {
ByteSourceRangeList list1 = new ByteSourceRangeList();
list1.add(new ByteSourceRange(block, addr(0), 0x100, 1, 0));
ByteSourceRangeList list2 = new ByteSourceRangeList();
list2.add(new ByteSourceRange(block, addr(0x100), 0x100, 1, 0x10));
// note that list1.intersect(list2) is not equal to list2.intersect(list1).
// The byte sources are the same but the corresponding real addresses are calling
// objects byte sources.
ByteSourceRangeList result = list1.intersect(list2);
assertEquals(1, result.getRangeCount());
ByteSourceRange range = result.get(0);
assertEquals(0xf0, range.getSize());
assertEquals(0x10, range.getOffset());
assertEquals(block, range.getMemoryBlock());
assertEquals(1, range.getSourceId());
assertEquals(addr(0x10), range.getStart());
assertEquals(addr(0xff), range.getEnd());
// now intersect from list2 perspective
result = list2.intersect(list1);
assertEquals(1, result.getRangeCount());
range = result.get(0);
assertEquals(0xf0, range.getSize());
assertEquals(0x10, range.getOffset());
assertEquals(block, range.getMemoryBlock());
assertEquals(1, range.getSourceId());
assertEquals(addr(0x100), range.getStart());
assertEquals(addr(0x1ef), range.getEnd());
}
@Test
public void testGetOverlappingBlocks() {
ByteSourceRange range = new ByteSourceRange(block, addr(0), 0x100, 1, 0x00);
MemoryBlock block1 = new MemoryBlockStub();
ByteSourceRange range1 = new ByteSourceRange(block1, addr(0x100), 0x100, 2, 0x00);
// create a byte source overlap with the first block
MemoryBlock block2 = new MemoryBlockStub();
ByteSourceRange range2 = new ByteSourceRange(block2, addr(0x200), 0x100, 1, 0x50);
ByteSourceRangeList list = new ByteSourceRangeList();
list.add(range);
list.add(range1);
list.add(range2);
Set<MemoryBlock> overlappingBlocks = list.getOverlappingBlocks();
assertEquals(2, overlappingBlocks.size());
assertTrue(overlappingBlocks.contains(block));
assertTrue(overlappingBlocks.contains(block2));
}
@Test
public void testGetOverlappingBlocksBlocksWhereBlocksAreAdjacentButDontOverlap() {
ByteSourceRange range = new ByteSourceRange(block, addr(0), 0x100, 1, 0x00);
MemoryBlock block1 = new MemoryBlockStub();
ByteSourceRange range1 = new ByteSourceRange(block1, addr(0x100), 0x100, 2, 0x00);
// create a byte source overlap with the first block
MemoryBlock block2 = new MemoryBlockStub();
ByteSourceRange range2 = new ByteSourceRange(block2, addr(0x200), 0x100, 1, 0x100);
ByteSourceRangeList list = new ByteSourceRangeList();
list.add(range);
list.add(range1);
list.add(range2);
Set<MemoryBlock> overlappingBlocks = list.getOverlappingBlocks();
assertEquals(0, overlappingBlocks.size());
}
@Test
public void testGetOverlappingBlocksBlocksWhereBlocksOverlapByExactlyOneByte() {
ByteSourceRange range = new ByteSourceRange(block, addr(0), 0x100, 1, 0x00);
MemoryBlock block1 = new MemoryBlockStub();
ByteSourceRange range1 = new ByteSourceRange(block1, addr(0x100), 0x100, 2, 0x00);
// create a byte source overlap with the first block
MemoryBlock block2 = new MemoryBlockStub();
ByteSourceRange range2 = new ByteSourceRange(block2, addr(0x200), 0x100, 1, 0xff);
ByteSourceRangeList list = new ByteSourceRangeList();
list.add(range);
list.add(range1);
list.add(range2);
Set<MemoryBlock> overlappingBlocks = list.getOverlappingBlocks();
assertEquals(2, overlappingBlocks.size());
assertTrue(overlappingBlocks.contains(block));
assertTrue(overlappingBlocks.contains(block2));
}
private Address addr(long value) {
return space.getAddress(value);
}
}

View file

@ -1,119 +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 static org.junit.Assert.*;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockStub;
public class ByteSourceRangeTest extends AbstractGenericTest {
private AddressSpace space = new GenericAddressSpace("test", 64, AddressSpace.TYPE_RAM, 0);
private MemoryBlock block = new MemoryBlockStub();
@Test
public void testIntersectNotSameSource() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x10, 2, 0x50);
assertNull(range1.intersect(range2));
}
@Test
public void testIntersectOneRangeSimpleOverlap() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x20, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x20, 1, 0x60);
ByteSourceRange intersect = range1.intersect(range2);
assertNotNull(intersect);
assertEquals(addr(0x10), intersect.getStart());
assertEquals(addr(0x1f), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x60, intersect.getOffset());
intersect = range2.intersect(range1);
assertNotNull(intersect);
assertEquals(addr(0x100), intersect.getStart());
assertEquals(addr(0x10f), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x60, intersect.getOffset());
}
@Test
public void testIntersectOneRangeButsAgainsAnother() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x20, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x20, 2, 0x70);
assertNull(range1.intersect(range2));
assertNull(range2.intersect(range1));
}
@Test
public void testIntersectOneRangeCompletelyInAnother() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x30, 1, 0x40);
ByteSourceRange intersect = range1.intersect(range2);
assertNotNull(intersect);
assertEquals(addr(0), intersect.getStart());
assertEquals(addr(0xf), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x50, intersect.getOffset());
intersect = range2.intersect(range1);
assertNotNull(intersect);
assertEquals(addr(0x110), intersect.getStart());
assertEquals(addr(0x11f), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x50, intersect.getOffset());
}
@Test
public void testBitMappedIntersect() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new BitMappedByteSourceRange(block, addr(0x100), 1, 0x55, 2);
ByteSourceRange intersect = range1.intersect(range2);
assertNotNull(intersect);
assertEquals(addr(5), intersect.getStart());
assertEquals(addr(6), intersect.getEnd());
assertEquals(2, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x55, intersect.getOffset());
intersect = range2.intersect(range1);
assertNotNull(intersect);
assertEquals(addr(0x100), intersect.getStart());
assertEquals(addr(0x10f), intersect.getEnd());
assertEquals(2, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x55, intersect.getOffset());
}
private Address addr(long value) {
return space.getAddress(value);
}
}

View file

@ -142,7 +142,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
assertEquals(0, block.getStart().getOffset()); assertEquals(0, block.getStart().getOffset());
assertEquals(9, block.getEnd().getOffset()); assertEquals(9, block.getEnd().getOffset());
assertTrue(block.getStart().getAddressSpace().isOverlaySpace()); assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
assertEquals(MemoryBlockType.OVERLAY, block.getType()); assertEquals(MemoryBlockType.DEFAULT, block.getType());
assertTrue(block.isOverlay());
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos(); List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
assertEquals(1, sourceInfos.size()); assertEquals(1, sourceInfos.size());
MemoryBlockSourceInfo info = sourceInfos.get(0); MemoryBlockSourceInfo info = sourceInfos.get(0);
@ -167,7 +168,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
assertEquals(0, block.getStart().getOffset()); assertEquals(0, block.getStart().getOffset());
assertEquals(9, block.getEnd().getOffset()); assertEquals(9, block.getEnd().getOffset());
assertTrue(block.getStart().getAddressSpace().isOverlaySpace()); assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
assertEquals(MemoryBlockType.OVERLAY, block.getType()); assertEquals(MemoryBlockType.DEFAULT, block.getType());
assertTrue(block.isOverlay());
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos(); List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
assertEquals(1, sourceInfos.size()); assertEquals(1, sourceInfos.size());
MemoryBlockSourceInfo info = sourceInfos.get(0); MemoryBlockSourceInfo info = sourceInfos.get(0);
@ -181,7 +183,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testCreateByteMappedBlock() throws Exception { public void testCreateByteMappedBlock() throws Exception {
mem.createInitializedBlock("test1", addr(0), 50, (byte) 1, TaskMonitor.DUMMY, false); mem.createInitializedBlock("test1", addr(0), 50, (byte) 1, TaskMonitor.DUMMY, false);
mem.createUninitializedBlock("test2", addr(50), 50, false); mem.createUninitializedBlock("test2", addr(50), 50, false);
MemoryBlock block = mem.createByteMappedBlock("mapped", addr(1000), addr(40), 20); MemoryBlock block = mem.createByteMappedBlock("mapped", addr(1000), addr(40), 20, false);
assertEquals(20, block.getSize()); assertEquals(20, block.getSize());
assertEquals("mapped", block.getName()); assertEquals("mapped", block.getName());
@ -217,7 +219,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testCreateBitMappedBlock() throws Exception { public void testCreateBitMappedBlock() throws Exception {
mem.createInitializedBlock("test1", addr(0), 50, (byte) 1, TaskMonitor.DUMMY, false); mem.createInitializedBlock("test1", addr(0), 50, (byte) 1, TaskMonitor.DUMMY, false);
mem.createUninitializedBlock("test2", addr(50), 50, false); mem.createUninitializedBlock("test2", addr(50), 50, false);
MemoryBlock block = mem.createBitMappedBlock("mapped", addr(1000), addr(49), 16); MemoryBlock block = mem.createBitMappedBlock("mapped", addr(1000), addr(49), 16, false);
assertEquals(16, block.getSize()); assertEquals(16, block.getSize());
assertEquals("mapped", block.getName()); assertEquals("mapped", block.getName());
@ -570,7 +572,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testByteMappedGetPutByte() throws Exception { public void testByteMappedGetPutByte() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
MemoryBlock block1 = createFileBytesBlock(fileBytes, addr(0), 0, 10); MemoryBlock block1 = createFileBytesBlock(fileBytes, addr(0), 0, 10);
MemoryBlock mappedBlock = mem.createByteMappedBlock("mapped", addr(100), addr(0), 20); MemoryBlock mappedBlock =
mem.createByteMappedBlock("mapped", addr(100), addr(0), 20, false);
assertEquals(5, mappedBlock.getByte(addr(105))); assertEquals(5, mappedBlock.getByte(addr(105)));
assertEquals(5, block1.getByte(addr(5))); assertEquals(5, block1.getByte(addr(5)));
mappedBlock.putByte(addr(105), (byte) 87); mappedBlock.putByte(addr(105), (byte) 87);
@ -581,7 +584,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testByteMappedGetPutBytes() throws Exception { public void testByteMappedGetPutBytes() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
MemoryBlock block1 = createFileBytesBlock(fileBytes, addr(0), 0, 50); MemoryBlock block1 = createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock = mem.createByteMappedBlock("mapped", addr(100), addr(0), 20); MemoryBlock mappedBlock =
mem.createByteMappedBlock("mapped", addr(100), addr(0), 20, false);
byte[] bytes = new byte[10]; byte[] bytes = new byte[10];
mappedBlock.getBytes(addr(100), bytes); mappedBlock.getBytes(addr(100), bytes);
checkBytes(bytes, 0); checkBytes(bytes, 0);
@ -595,8 +599,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testByteMappedJoin() throws Exception { public void testByteMappedJoin() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
createFileBytesBlock(fileBytes, addr(0), 0, 50); createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock1 = mem.createByteMappedBlock("mapped1", addr(100), addr(0), 10); MemoryBlock mappedBlock1 =
MemoryBlock mappedBlock2 = mem.createByteMappedBlock("mapped2", addr(110), addr(10), 10); mem.createByteMappedBlock("mapped1", addr(100), addr(0), 10, false);
MemoryBlock mappedBlock2 =
mem.createByteMappedBlock("mapped2", addr(110), addr(10), 10, false);
try { try {
mem.join(mappedBlock1, mappedBlock2); mem.join(mappedBlock1, mappedBlock2);
fail("Expected exception when joining byte mapped blocks"); fail("Expected exception when joining byte mapped blocks");
@ -610,7 +616,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testByteMappedSplit() throws Exception { public void testByteMappedSplit() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
createFileBytesBlock(fileBytes, addr(0), 0, 50); createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock1 = mem.createByteMappedBlock("mapped1", addr(100), addr(0), 20); MemoryBlock mappedBlock1 =
mem.createByteMappedBlock("mapped1", addr(100), addr(0), 20, false);
mem.split(mappedBlock1, addr(110)); mem.split(mappedBlock1, addr(110));
MemoryBlock[] blocks = mem.getBlocks(); MemoryBlock[] blocks = mem.getBlocks();
assertEquals(3, blocks.length); assertEquals(3, blocks.length);
@ -621,7 +628,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testBitMappedGetPutByte() throws Exception { public void testBitMappedGetPutByte() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
MemoryBlock block = createFileBytesBlock(fileBytes, addr(0), 0, 50); MemoryBlock block = createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock = mem.createBitMappedBlock("mapped1", addr(100), addr(0), 20); MemoryBlock mappedBlock =
mem.createBitMappedBlock("mapped1", addr(100), addr(0), 20, false);
assertEquals(0, mappedBlock.getByte(addr(100))); assertEquals(0, mappedBlock.getByte(addr(100)));
assertEquals(0, mappedBlock.getByte(addr(101))); assertEquals(0, mappedBlock.getByte(addr(101)));
@ -637,7 +645,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testBitMappedGetPutBytes() throws Exception { public void testBitMappedGetPutBytes() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
MemoryBlock block = createFileBytesBlock(fileBytes, addr(0), 0, 50); MemoryBlock block = createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock = mem.createBitMappedBlock("mapped1", addr(100), addr(0), 50); MemoryBlock mappedBlock =
mem.createBitMappedBlock("mapped1", addr(100), addr(0), 50, false);
byte[] bytes = new byte[8]; byte[] bytes = new byte[8];
@ -668,8 +677,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testBitMappedJoin() throws Exception { public void testBitMappedJoin() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
createFileBytesBlock(fileBytes, addr(0), 0, 50); createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock1 = mem.createBitMappedBlock("mapped1", addr(100), addr(0), 16); MemoryBlock mappedBlock1 =
MemoryBlock mappedBlock2 = mem.createBitMappedBlock("mapped2", addr(116), addr(2), 16); mem.createBitMappedBlock("mapped1", addr(100), addr(0), 16, false);
MemoryBlock mappedBlock2 =
mem.createBitMappedBlock("mapped2", addr(116), addr(2), 16, false);
try { try {
mem.join(mappedBlock1, mappedBlock2); mem.join(mappedBlock1, mappedBlock2);
fail("Expected exception when joining bit mapped blocks"); fail("Expected exception when joining bit mapped blocks");
@ -683,7 +694,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testBitMappedSplit() throws Exception { public void testBitMappedSplit() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
createFileBytesBlock(fileBytes, addr(0), 0, 50); createFileBytesBlock(fileBytes, addr(0), 0, 50);
MemoryBlock mappedBlock1 = mem.createBitMappedBlock("mapped1", addr(100), addr(0), 16); MemoryBlock mappedBlock1 =
mem.createBitMappedBlock("mapped1", addr(100), addr(0), 16, false);
try { try {
mem.split(mappedBlock1, addr(108)); mem.split(mappedBlock1, addr(108));
fail("Expected exception when joining bit mapped blocks"); fail("Expected exception when joining bit mapped blocks");
@ -693,200 +705,229 @@ public class MemBlockDBTest extends AbstractGenericTest {
} }
} }
@Test // @Test
public void testGetByteSourceSetForFileBytesBlock() throws Exception { // public void testGetByteSourceSetForFileBytesBlock() throws Exception {
FileBytes fileBytes = createFileBytes(); // FileBytes fileBytes = createFileBytes();
MemoryBlockDB block = (MemoryBlockDB) createFileBytesBlock(fileBytes, addr(0), 10, 50); // MemoryBlockDB block = (MemoryBlockDB) createFileBytesBlock(fileBytes, addr(0), 10, 50);
//
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(5), 10);
//
// // we expect to get a single range ByteSourceSet pointing into the filebytes at offset
// // 15 (10 because block was created at filebytes:10 and 5 because we start at the 5th byte
// // in the block)
//
// assertEquals(1, ranges.getRangeCount());
// assertEquals(10, ranges.get(0).getSize());
// assertEquals(5, ranges.get(0).getStart().getOffset());
// assertEquals(14, ranges.get(0).getEnd().getOffset());
// assertEquals(fileBytes.getId(), ranges.get(0).getSourceId());
// assertEquals(15, ranges.get(0).getOffset());
// }
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(5), 10); // @Test
// public void testGetByteSourceSetForBufferBlock() throws Exception {
// we expect to get a single range ByteSourceSet pointing into the filebytes at offset // MemoryBlockDB block = (MemoryBlockDB) mem.createInitializedBlock("test", addr(0), 30,
// 15 (10 because block was created at filebytes:10 and 5 because we start at the 5th byte // (byte) 1, TaskMonitor.DUMMY, false);
// in the block) //
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10);
assertEquals(1, ranges.getRangeCount()); //
assertEquals(10, ranges.get(0).getSize()); // // We expect to get to ranges because we made the buffer size small (16) so when we
assertEquals(5, ranges.get(0).getStart().getOffset()); // // created a 30 size block, it had to make two separate sub blocks each with its own
assertEquals(14, ranges.get(0).getEnd().getOffset()); // // DBBuffer. The first range should contain the first 6 bytes of the requested range
assertEquals(fileBytes.getId(), ranges.get(0).getSourceId()); // // and the second buffer should contain the last 4 bytes of request range.
assertEquals(15, ranges.get(0).getOffset()); //
} // assertEquals(2, ranges.getRangeCount()); // we have two sublocks so two distinct ranges
// assertEquals(10, ranges.get(0).getSize() + ranges.get(1).getSize());
@Test //
public void testGetByteSourceSetForBufferBlock() throws Exception { // ByteSourceRange range = ranges.get(0);
MemoryBlockDB block = (MemoryBlockDB) mem.createInitializedBlock("test", addr(0), 30, // assertEquals(10, range.getStart().getOffset());
(byte) 1, TaskMonitor.DUMMY, false); // assertEquals(15, range.getEnd().getOffset());
// assertEquals(6, range.getSize());
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10); // assertEquals(10, range.getOffset());
//
// We expect to get to ranges because we made the buffer size small (16) so when we // range = ranges.get(1);
// created a 30 size block, it had to make two separate sub blocks each with its own // assertEquals(16, range.getStart().getOffset());
// DBBuffer. The first range should contain the first 6 bytes of the requested range // assertEquals(19, range.getEnd().getOffset());
// and the second buffer should contain the last 4 bytes of request range. // assertEquals(4, range.getSize());
// assertEquals(0, range.getOffset());
assertEquals(2, ranges.getRangeCount()); // we have two sublocks so two distinct ranges //
assertEquals(10, ranges.get(0).getSize() + ranges.get(1).getSize()); // }
//
ByteSourceRange range = ranges.get(0); // @Test
assertEquals(10, range.getStart().getOffset()); // public void testGetByteSourceForUndefinedBlock() throws Exception {
assertEquals(15, range.getEnd().getOffset()); // MemoryBlockDB block =
assertEquals(6, range.getSize()); // (MemoryBlockDB) mem.createUninitializedBlock("test", addr(0), 30, false);
assertEquals(10, range.getOffset()); // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10);
// // undefined blocks have no source bytes
range = ranges.get(1); // assertTrue(ranges.isEmpty());
assertEquals(16, range.getStart().getOffset()); //
assertEquals(19, range.getEnd().getOffset()); // }
assertEquals(4, range.getSize()); //
assertEquals(0, range.getOffset()); // @Test
// public void testGetByteSourceForByteMappedBlock() throws Exception {
} // mem.createInitializedBlock("test1", addr(0), 15, (byte) 1, TaskMonitor.DUMMY, false);
// mem.createUninitializedBlock("test2", addr(15), 20, false);
@Test // mem.createInitializedBlock("test3", addr(35), 15, (byte) 1, TaskMonitor.DUMMY, false);
public void testGetByteSourceForUndefinedBlock() throws Exception { // MemoryBlockDB block =
MemoryBlockDB block = // (MemoryBlockDB) mem.createByteMappedBlock("mapped", addr(1000), addr(5), 40, false);
(MemoryBlockDB) mem.createUninitializedBlock("test", addr(0), 30, false); //
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10); // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(1005), 30); // 5, 20, 5
// undefined blocks have no source bytes //
assertTrue(ranges.isEmpty()); // // Uninitialized blocks don't contribute, so we should have 10 address (5 from first and last blocks each).
// assertEquals(2, ranges.getRangeCount());
} // assertEquals(10, ranges.get(0).getSize() + ranges.get(1).getSize());
//
@Test // ByteSourceRange range = ranges.get(0);
public void testGetByteSourceForByteMappedBlock() throws Exception { // assertEquals(addr(1005), range.getStart());
mem.createInitializedBlock("test1", addr(0), 15, (byte) 1, TaskMonitor.DUMMY, false); // assertEquals(addr(1009), range.getEnd());
mem.createUninitializedBlock("test2", addr(15), 20, false); // assertEquals(5, range.getSize());
mem.createInitializedBlock("test3", addr(35), 15, (byte) 1, TaskMonitor.DUMMY, false); // assertEquals(10, range.getOffset());
MemoryBlockDB block = //
(MemoryBlockDB) mem.createByteMappedBlock("mapped", addr(1000), addr(5), 40); // range = ranges.get(1);
// assertEquals(addr(1030), range.getStart());
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(1005), 30); // assertEquals(addr(1034), range.getEnd());
// assertEquals(5, range.getSize());
// Uninitialized blocks don't contribute, so we should have 10 address (5 from first and last blocks each). // assertEquals(0, range.getOffset());
assertEquals(2, ranges.getRangeCount()); // }
assertEquals(10, ranges.get(0).getSize() + ranges.get(1).getSize()); //
// @Test
ByteSourceRange range = ranges.get(0); // public void testGetByteSourceForByteMappedBlockWithScheme() throws Exception {
assertEquals(addr(1005), range.getStart()); // mem.createInitializedBlock("test1", addr(0), 15, (byte) 1, TaskMonitor.DUMMY, false); // mapped bytes: 5, 6, .. 9, 10, .. 13, (14
assertEquals(addr(1009), range.getEnd()); // mem.createUninitializedBlock("test2", addr(15), 20, false); // mapped bytes: 17, 18, 21, 22, 25, 26, 29, 30, 33, 34
assertEquals(5, range.getSize()); // mem.createInitializedBlock("test3", addr(35), 15, (byte) 1, TaskMonitor.DUMMY, false); // mapped bytes: .. 37, 38, .. 41, 42), .. 45, 46, .. 49, 50 ...
assertEquals(10, range.getOffset()); // MemoryBlockDB block = (MemoryBlockDB) mem.createByteMappedBlock("mapped", addr(1000),
// addr(5), 40, new ByteMappingScheme(2, 4), false);
range = ranges.get(1); //
assertEquals(addr(1030), range.getStart()); // // NOTE: source range includes skipped bytes within mapped range
assertEquals(addr(1034), range.getEnd()); //
assertEquals(5, range.getSize()); // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(1005), 15);
assertEquals(0, range.getOffset()); //// FIXME XXX Expected something different than previous test !!
} // // Uninitialized blocks don't contribute, so we should have 16 address (1 from first and 4 from last block each, plus 4 skipped bytes in last block).
//// assertEquals(2, ranges.getRangeCount());
@Test //// assertEquals(8, ranges.get(0).getSize() + ranges.get(1).getSize());
public void testGetByteSourceForBitMappedBlock() throws Exception { //
FileBytes fileBytes = createFileBytes(); // ByteSourceRange range = ranges.get(0);
createFileBytesBlock(fileBytes, addr(0), 0, 50); // assertEquals(addr(1005), range.getStart());
// assertEquals(addr(1005), range.getEnd());
MemoryBlockDB block = // assertEquals(1, range.getSize());
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14); // assertEquals(14, range.getOffset());
//
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1000), 0x14); // range = ranges.get(1);
// assertEquals(addr(1016), range.getStart());
assertEquals(1, ranges.getRangeCount()); // assertEquals(addr(1019), range.getEnd());
assertEquals(3, ranges.get(0).getSize()); // assertEquals(5, range.getSize());
// assertEquals(0, range.getOffset());
ByteSourceRange range = ranges.get(0); // }
assertEquals(addr(0x1000), range.getStart()); //
assertEquals(addr(0x1017), range.getEnd()); // @Test
assertEquals(3, range.getSize()); // public void testGetByteSourceForBitMappedBlock() throws Exception {
assertEquals(5, range.getOffset()); // FileBytes fileBytes = createFileBytes();
} // createFileBytesBlock(fileBytes, addr(0), 0, 50);
//
@Test // MemoryBlockDB block =
public void testGetByteSourceForBitMappedBlockOffcutStart() throws Exception { // (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14, false);
FileBytes fileBytes = createFileBytes(); //
createFileBytesBlock(fileBytes, addr(0), 0, 50); // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1000), 0x14);
//
MemoryBlockDB block = // assertEquals(1, ranges.getRangeCount());
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14); // assertEquals(3, ranges.get(0).getSize());
//
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1005), 8); // ByteSourceRange range = ranges.get(0);
// assertEquals(addr(0x1000), range.getStart());
assertEquals(1, ranges.getRangeCount()); // assertEquals(addr(0x1017), range.getEnd());
assertEquals(2, ranges.get(0).getSize()); // assertEquals(3, range.getSize());
// assertEquals(5, range.getOffset());
ByteSourceRange range = ranges.get(0); // }
assertEquals(addr(0x1000), range.getStart()); //
assertEquals(addr(0x100f), range.getEnd()); // @Test
assertEquals(2, range.getSize()); // public void testGetByteSourceForBitMappedBlockOffcutStart() throws Exception {
assertEquals(5, range.getOffset()); // FileBytes fileBytes = createFileBytes();
} // createFileBytesBlock(fileBytes, addr(0), 0, 50);
//
@Test // MemoryBlockDB block =
public void testGetByteSourceForBitMappedBlockOffcutStartNotAtStart() throws Exception { // (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14, false);
FileBytes fileBytes = createFileBytes(); //
createFileBytesBlock(fileBytes, addr(0), 0, 50); // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1005), 8);
//
MemoryBlockDB block = // assertEquals(1, ranges.getRangeCount());
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x44); // assertEquals(2, ranges.get(0).getSize());
//
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1015), 8); // ByteSourceRange range = ranges.get(0);
// assertEquals(addr(0x1000), range.getStart());
assertEquals(1, ranges.getRangeCount()); // assertEquals(addr(0x100f), range.getEnd());
assertEquals(2, ranges.get(0).getSize()); // assertEquals(2, range.getSize());
// assertEquals(5, range.getOffset());
ByteSourceRange range = ranges.get(0); // }
assertEquals(addr(0x1010), range.getStart()); //
assertEquals(addr(0x101f), range.getEnd()); // @Test
assertEquals(2, range.getSize()); // public void testGetByteSourceForBitMappedBlockOffcutStartNotAtStart() throws Exception {
assertEquals(7, range.getOffset()); // FileBytes fileBytes = createFileBytes();
} // createFileBytesBlock(fileBytes, addr(0), 0, 50);
//
@Test // MemoryBlockDB block =
public void testGetByteSourceForBitMappedBlock2() throws Exception { // (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x44, false);
mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false); //
mem.createUninitializedBlock("test2", addr(0x4), 4, false); // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1015), 8);
mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false); //
MemoryBlockDB block = // assertEquals(1, ranges.getRangeCount());
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40); // assertEquals(2, ranges.get(0).getSize());
//
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1008), 0x30); // ByteSourceRange range = ranges.get(0);
// assertEquals(addr(0x1010), range.getStart());
assertEquals(2, ranges.getRangeCount()); // assertEquals(addr(0x101f), range.getEnd());
// assertEquals(2, range.getSize());
ByteSourceRange range = ranges.get(0); // assertEquals(7, range.getOffset());
assertEquals(addr(0x1008), range.getStart()); // }
assertEquals(addr(0x100f), range.getEnd()); //
assertEquals(1, range.getSize()); // @Test
assertEquals(3, range.getOffset()); // public void testGetByteSourceForBitMappedBlock2() throws Exception {
// mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false);
range = ranges.get(1); // mem.createUninitializedBlock("test2", addr(0x4), 4, false);
assertEquals(addr(0x1030), range.getStart()); // mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false);
assertEquals(addr(0x1037), range.getEnd()); // MemoryBlockDB block =
assertEquals(1, range.getSize()); // (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40, false);
assertEquals(0, range.getOffset()); //
} // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1008), 0x30);
//
@Test // assertEquals(2, ranges.getRangeCount());
public void testGetByteSourceForBitMappedBlock2Offcut() throws Exception { //
mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false); // ByteSourceRange range = ranges.get(0);
mem.createUninitializedBlock("test2", addr(0x4), 4, false); // assertEquals(addr(0x1008), range.getStart());
mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false); // assertEquals(addr(0x100f), range.getEnd());
MemoryBlockDB block = // assertEquals(1, range.getSize());
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40); // assertEquals(3, range.getOffset());
//
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1006), 0x34); // range = ranges.get(1);
// assertEquals(addr(0x1030), range.getStart());
assertEquals(2, ranges.getRangeCount()); // assertEquals(addr(0x1037), range.getEnd());
// assertEquals(1, range.getSize());
ByteSourceRange range = ranges.get(0); // assertEquals(0, range.getOffset());
assertEquals(addr(0x1000), range.getStart()); // }
assertEquals(addr(0x100f), range.getEnd()); //
assertEquals(2, range.getSize()); // @Test
assertEquals(2, range.getOffset()); // public void testGetByteSourceForBitMappedBlock2Offcut() throws Exception {
// mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false);
range = ranges.get(1); // mem.createUninitializedBlock("test2", addr(0x4), 4, false);
assertEquals(addr(0x1030), range.getStart()); // mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false);
assertEquals(addr(0x103f), range.getEnd()); // MemoryBlockDB block =
assertEquals(2, range.getSize()); // (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40, false);
assertEquals(0, range.getOffset()); //
} // ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1006), 0x34);
//
// assertEquals(2, ranges.getRangeCount());
//
// ByteSourceRange range = ranges.get(0);
// assertEquals(addr(0x1000), range.getStart());
// assertEquals(addr(0x100f), range.getEnd());
// assertEquals(2, range.getSize());
// assertEquals(2, range.getOffset());
//
// range = ranges.get(1);
// assertEquals(addr(0x1030), range.getStart());
// assertEquals(addr(0x103f), range.getEnd());
// assertEquals(2, range.getSize());
// assertEquals(0, range.getOffset());
// }
@Test @Test
public void testAddressSourceInfoForFileBytesBlock() throws Exception { public void testAddressSourceInfoForFileBytesBlock() throws Exception {
@ -934,7 +975,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
public void testAddressSourceInfoForMappedBlock() throws Exception { public void testAddressSourceInfoForMappedBlock() throws Exception {
FileBytes fileBytes = createFileBytes(); FileBytes fileBytes = createFileBytes();
mem.createInitializedBlock("block", addr(0), fileBytes, 10, 50, false); mem.createInitializedBlock("block", addr(0), fileBytes, 10, 50, false);
mem.createByteMappedBlock("mapped", addr(1000), addr(0), 20); mem.createByteMappedBlock("mapped", addr(1000), addr(0), 20, false);
AddressSourceInfo info = mem.getAddressSourceInfo(addr(1000)); AddressSourceInfo info = mem.getAddressSourceInfo(addr(1000));
assertEquals(addr(1000), info.getAddress()); assertEquals(addr(1000), info.getAddress());

View file

@ -45,7 +45,7 @@ public class MemoryMapPluginScreenShots extends GhidraScreenShotGenerator {
moveProviderToItsOwnWindow(provider); moveProviderToItsOwnWindow(provider);
JComponent component = getDockableComponent(provider); JComponent component = getDockableComponent(provider);
captureIsolatedComponent(component, 650, 225); captureIsolatedComponent(component, 800, 225);
} }
@Test @Test

View file

@ -279,14 +279,16 @@
<ul class="medium"> <ul class="medium">
<li>The Memory Map</li> <li>The Memory Map</li>
<li>Allows users to add, delete, move, split, merge, or expand memory blocks in their program.</li> <li>Allows users to add, delete, move, split, merge, or expand memory blocks in their program.</li>
<li>Memory Blocks can be byte-mapped, bit-mapped (if supported by processor) or overlays</li> <li>Default memory blocks may be uninitialized or initialized using specified data</li>
<li>Other memory block types include byte-mapped and bit-mapped</li>
<li>Any memory block may be created as an overlay</li>
<li>Allows users to rename memory blocks</li> <li>Allows users to rename memory blocks</li>
<li>Allows users to change the image base of their program</li> <li>Allows users to change the image base of their program</li>
<li>Allows users to edit settings on individual memory blocks</li> <li>Allows users to edit settings on individual memory blocks</li>
<ul> <ul>
<li>Read/Write/Execute</li> <li>Read/Write/Execute</li>
<li>Volatile/non-volatile</li> <li>Volatile/non-volatile</li>
<li>Initialized/non-initialized</li> <li>Initialized/non-initialized (default blocks only)</li>
</ul> </ul>
</ul> </ul>
<div role="note"> <div role="note">

View file

@ -528,7 +528,7 @@ be installed in a pre-existing Eclipse installation.</p>
lookups. lookups.
</li> </li>
<li> <li>
Image base can not be changed if overlays have been defined. Image base may not be changed to an address which falls within an existing memory block.
</li> </li>
<li> <li>
Language versioning and migration does not handle complex changes in the use of the context Language versioning and migration does not handle complex changes in the use of the context