Modified Memory API for creating Overlay blocks allow for
byte/bit-mapped overlays. Added ByteMappingScheme for byte-mapped blocks.
|
@ -238,8 +238,8 @@
|
|||
|
||||
<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
|
||||
to true. Enabling this option ensures strings are not created in areas such as overlays
|
||||
or debug sections.</LI>
|
||||
to true. Enabling this option ensures strings are not created in areas such as non-loaded
|
||||
overlays or debug sections.</LI>
|
||||
|
||||
<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
|
||||
|
|
|
@ -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>
|
||||
|
||||
<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>
|
||||
|
||||
|
|
|
@ -374,7 +374,7 @@
|
|||
<H4>Overlay</H4>
|
||||
|
||||
<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>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
|
@ -20,40 +20,54 @@
|
|||
<P>The <I>Memory Map</I> window displays a list of memory blocks that make up the memory
|
||||
structure of the current program. The component provides actions for adding, renaming,
|
||||
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>
|
||||
<LI>
|
||||
<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>
|
||||
<LI><A name="InitializeBlockType"></A><I>Initialized</I> - The block has an initial value
|
||||
specified for the bytes</LI>
|
||||
<LI><A name="InitializedBlock"></A><I>Initialized</I> - The block has an initial value
|
||||
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>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<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
|
||||
of the bits in memory directly using an alternative addressing space.</LI>
|
||||
bit-addressable map onto other blocks. This is useful when a processor can indirectly access
|
||||
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
|
||||
byte-addressable map onto other blocks. This can be useful when the same bytes can be
|
||||
accessed via two or more addresses.</LI>
|
||||
|
||||
<LI><A name="OverlayType"></A><I><B>Overlay</B></I> - The block is created in a new
|
||||
<I>overlay</I> address space. Overlay blocks can be <I>initialized</I> or
|
||||
<I>unitialized</I>. 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. Overlay blocks contain
|
||||
code that would get swapped in when the program needs to execute it. Note that
|
||||
Overlay blocks are fixed and may not be moved, split or expanded. In addition, Overlays
|
||||
do not relocate with image base changes.<BR>
|
||||
</LI>
|
||||
byte-addressable map onto other blocks. This can be useful when a range of
|
||||
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
|
||||
mapping ratio (e.g., 2:4).</LI>
|
||||
</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. 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. Note that
|
||||
overlay blocks are fixed and may not be moved, split, merged or expanded. 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">
|
||||
Memory Map</B> from the main tool menu, or click on the <IMG src="images/memory16.gif"
|
||||
|
@ -86,16 +100,14 @@
|
|||
|
||||
<P><I><B>W -</B></I> Indicates write permission.</P>
|
||||
|
||||
<P><I><B>X -</B></I> Indicates execute permission.<BR>
|
||||
</P>
|
||||
<P><I><B>X -</B></I> Indicates execute permission.</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
|
||||
Memory.<BR>
|
||||
</P>
|
||||
<P><I><B>Overlay -</B></I> Indicates if block is defined as a memory overlay.</P>
|
||||
|
||||
<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
|
||||
href="#OverlayType">Overlay</A> type of block.</P>
|
||||
<A href="#BitMappedType">Bit Mapped</A> or <A href="#ByteMappedType">Byte Mapped</A> type of block.</P>
|
||||
|
||||
<P><I><B>Initialized -</B></I> Indicates whether the block has been initialized with values;
|
||||
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
|
||||
displayed.</P>
|
||||
|
||||
<P><I><B>Source -</B></I> The name of the file that produced the bytes that make up this
|
||||
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>Source -</B></I> Description of block origination.</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><B><I>Execute</I></B> - Sets the execute permission.<BR>
|
||||
</P>
|
||||
<P><B><I>Execute</I></B> - Sets the execute permission.</P>
|
||||
|
||||
<P><SPAN style="font-weight: bold;">Volatile</SPAN> - Marks this block as volatile I/O
|
||||
memory.<BR>
|
||||
</P>
|
||||
<P><B>Volatile</B> - Marks this block as volatile I/O memory.</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
|
||||
Mapped, Byte Mapped, or Overlay</B></I>.</P>
|
||||
Mapped or Byte Mapped</B></I>.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<UL>
|
||||
|
@ -245,15 +253,7 @@
|
|||
<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>
|
||||
</UL>
|
||||
<LI><B><I>Overlay -</I></B> An overlay block is used to give an alternative set of
|
||||
bytes (and related information) for a range in memory. 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. 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
|
||||
<LI><B><I>Bit Mapped -</I></B> This is a block that allows bit addressing of a section
|
||||
of bytes in memory. 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
|
||||
addressed as BIT:1 and so on.</LI>
|
||||
|
@ -261,10 +261,9 @@
|
|||
<LI style="list-style: none">
|
||||
<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. 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>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
|
||||
<TABLE x-use-null-cells="" width="100%">
|
||||
<TBODY>
|
||||
|
@ -274,16 +273,21 @@
|
|||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
|
||||
<UL>
|
||||
<LI>This is used to model certain processors that allow this sort of addressing such as
|
||||
|
||||
<BR>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
|
||||
which the bit addressing will be based.</LI>
|
||||
</UL>
|
||||
|
||||
<UL>
|
||||
|
||||
<LI> <B><I>Byte Mapped</I></B> - This is a block that allows access to a range of
|
||||
bytes in memory using an alternative address. In other words, it allows the same
|
||||
set of bytes to be accessed by two different logical addresses. A source address must
|
||||
be specified that contains the actual bytes for this block.</LI>
|
||||
bytes in memory using an alternative address. A <I>Source Address</I> must
|
||||
be specified which corresponds to the source of the actual bytes for this block, although all or part of the
|
||||
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>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
@ -517,9 +521,9 @@
|
|||
be created. Disregarding the warning may cause Ghidra to fail with an "out of memory"
|
||||
error.</P>
|
||||
|
||||
<P><I><IMG src="../../shared/note.png" border="0"></I> Only blocks of the same type can be
|
||||
merged. For example, <A href="#DefaultType">default</A> blocks can only be merged with
|
||||
another default block. </P>
|
||||
<P><I><IMG src="../../shared/note.png" border="0"></I> Only adjacent <I>Default</I> blocks of the same
|
||||
initialization state can be merged.</P>
|
||||
<P><I><IMG src="../../shared/note.png" border="0"></I>Overlay type blocks cannot be merged.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
@ -40,9 +40,11 @@ abstract class AbstractAddMemoryBlockCmd implements Command {
|
|||
protected final boolean write;
|
||||
protected final boolean execute;
|
||||
protected final boolean isVolatile;
|
||||
protected final boolean isOverlay;
|
||||
|
||||
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.comment = comment;
|
||||
this.source = source;
|
||||
|
@ -52,6 +54,7 @@ abstract class AbstractAddMemoryBlockCmd implements Command {
|
|||
this.write = write;
|
||||
this.execute = execute;
|
||||
this.isVolatile = isVolatile;
|
||||
this.isOverlay = isOverlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,9 +19,13 @@ import ghidra.framework.store.LockException;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
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 {
|
||||
|
||||
|
@ -33,25 +37,27 @@ public class AddBitMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
|||
* @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 length the length of the new block in number of bits to be mapped
|
||||
* @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 AddBitMappedMemoryBlockCmd(String name, String comment, String source, Address start,
|
||||
long length, boolean read, boolean write, boolean execute, boolean isVolatile,
|
||||
Address mappedAddress) {
|
||||
super(name, comment, source, start, length, read, write, execute, isVolatile);
|
||||
Address mappedAddress, boolean isOverlay) {
|
||||
super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
|
||||
this.mappedAddress = mappedAddress;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryBlock createMemoryBlock(Memory memory)
|
||||
throws LockException, MemoryConflictException, AddressOverflowException {
|
||||
return memory.createBitMappedBlock(name, start, mappedAddress, length);
|
||||
throws LockException, MemoryConflictException, AddressOverflowException,
|
||||
IllegalArgumentException, DuplicateNameException {
|
||||
return memory.createBitMappedBlock(name, start, mappedAddress, length, isOverlay);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
package ghidra.app.cmd.memory;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.mem.ByteMappingScheme;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Command for adding byte-mapped memory blocks
|
||||
|
@ -26,9 +28,16 @@ import ghidra.program.model.mem.*;
|
|||
public class AddByteMappedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
||||
|
||||
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 comment the comment for 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 isVolatile sets the block's volatile flag
|
||||
* @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,
|
||||
long length, boolean read, boolean write, boolean execute, boolean isVolatile,
|
||||
Address mappedAddress) {
|
||||
super(name, comment, source, start, length, read, write, execute, isVolatile);
|
||||
Address mappedAddress, ByteMappingScheme byteMappingScheme, boolean isOverlay) {
|
||||
super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
|
||||
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
|
||||
protected MemoryBlock createMemoryBlock(Memory memory)
|
||||
throws LockException, MemoryConflictException, AddressOverflowException {
|
||||
return memory.createByteMappedBlock(name, start, mappedAddress, length);
|
||||
throws LockException, MemoryConflictException, AddressOverflowException,
|
||||
IllegalArgumentException, DuplicateNameException {
|
||||
return memory.createByteMappedBlock(name, start, mappedAddress, length,
|
||||
byteMappingScheme,
|
||||
isOverlay);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ public class AddFileBytesMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
|||
|
||||
private final FileBytes fileBytes;
|
||||
private final long offset;
|
||||
private final boolean isOverlay;
|
||||
|
||||
/**
|
||||
* Create a new AddFileBytesMemoryBlockCmd
|
||||
|
@ -49,10 +48,9 @@ public class AddFileBytesMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
|||
public AddFileBytesMemoryBlockCmd(String name, String comment, String source, Address start,
|
||||
long length, boolean read, boolean write, boolean execute, boolean isVolatile,
|
||||
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.offset = offset;
|
||||
this.isOverlay = isOverlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,7 +28,6 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
public class AddInitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
||||
|
||||
private final byte initialValue;
|
||||
private final boolean isOverlay;
|
||||
|
||||
/**
|
||||
* Create a new AddFileBytesMemoryBlockCmd
|
||||
|
@ -47,10 +46,9 @@ public class AddInitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
|||
public AddInitializedMemoryBlockCmd(String name, String comment, String source, Address start,
|
||||
long length, boolean read, boolean write, boolean execute, boolean isVolatile,
|
||||
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.isOverlay = isOverlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,8 +26,6 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
*/
|
||||
public class AddUninitializedMemoryBlockCmd extends AbstractAddMemoryBlockCmd {
|
||||
|
||||
private final boolean isOverlay;
|
||||
|
||||
/**
|
||||
* Create a new AddUninitializedMemoryBlockCmd
|
||||
* @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,
|
||||
long length, boolean read, boolean write, boolean execute, boolean isVolatile,
|
||||
boolean isOverlay) {
|
||||
super(name, comment, source, start, length, read, write, execute, isVolatile);
|
||||
|
||||
this.isOverlay = isOverlay;
|
||||
super(name, comment, source, start, length, read, write, execute, isVolatile, isOverlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import docking.widgets.checkbox.GCheckBox;
|
|||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.label.GLabel;
|
||||
import docking.widgets.textfield.IntegerTextField;
|
||||
import ghidra.app.plugin.core.memory.AddBlockModel.InitializedType;
|
||||
import ghidra.app.plugin.core.misc.RegisterField;
|
||||
import ghidra.app.util.*;
|
||||
|
@ -63,11 +64,14 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
private JCheckBox writeCB;
|
||||
private JCheckBox executeCB;
|
||||
private JCheckBox volatileCB;
|
||||
private JCheckBox overlayCB;
|
||||
private RegisterField initialValueField;
|
||||
private JLabel initialValueLabel;
|
||||
private AddressFactory addrFactory;
|
||||
private AddressInput baseAddrField; // used for BitMemoryBlocks
|
||||
private Address baseAddress;
|
||||
private AddressInput baseAddrField; // used for Bit and Byte mapped blocks
|
||||
private IntegerTextField schemeDestByteCountField; // used for Byte mapped blocks
|
||||
private IntegerTextField schemeSrcByteCountField; // used for Byte mapped blocks
|
||||
|
||||
private AddBlockModel model;
|
||||
private GhidraComboBox<MemoryBlockType> comboBox;
|
||||
private boolean updatingInitializedRB;
|
||||
|
@ -103,6 +107,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
writeCB.setSelected(model.isWrite());
|
||||
executeCB.setSelected(model.isExecute());
|
||||
volatileCB.setSelected(model.isVolatile());
|
||||
overlayCB.setSelected(model.isOverlay());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,12 +168,18 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
volatileCB.setSelected(model.isVolatile());
|
||||
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));
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 30, 20, 30));
|
||||
panel.add(readCB);
|
||||
panel.add(writeCB);
|
||||
panel.add(executeCB);
|
||||
panel.add(volatileCB);
|
||||
panel.add(overlayCB);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
@ -178,7 +189,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
panel.setBorder(BorderFactory.createTitledBorder("Block Types"));
|
||||
|
||||
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.addItemListener(e -> blockTypeSelected());
|
||||
|
@ -308,6 +319,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
writeCB.setSelected(model.isWrite());
|
||||
executeCB.setSelected(model.isExecute());
|
||||
volatileCB.setSelected(model.isVolatile());
|
||||
overlayCB.setSelected(model.isOverlay());
|
||||
|
||||
setOkEnabled(false);
|
||||
tool.showDialog(this, tool.getComponentProvider(PluginConstants.MEMORY_MAP));
|
||||
|
@ -406,29 +418,66 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
}
|
||||
|
||||
private void baseAddressChanged() {
|
||||
baseAddress = baseAddrField.getAddress();
|
||||
Address baseAddress = baseAddrField.getAddress();
|
||||
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() {
|
||||
MemoryBlockType blockType = (MemoryBlockType) comboBox.getSelectedItem();
|
||||
model.setBlockType(blockType);
|
||||
if (blockType == MemoryBlockType.DEFAULT || blockType == MemoryBlockType.OVERLAY) {
|
||||
if (blockType == MemoryBlockType.DEFAULT) {
|
||||
typeCardLayout.show(viewPanel, UNMAPPED);
|
||||
}
|
||||
else {
|
||||
enableByteMappingSchemeControls(blockType == MemoryBlockType.BYTE_MAPPED);
|
||||
schemeDestByteCountField.setValue(model.getSchemeDestByteCount());
|
||||
schemeSrcByteCountField.setValue(model.getSchemeSrcByteCount());
|
||||
typeCardLayout.show(viewPanel, MAPPED);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableByteMappingSchemeControls(boolean b) {
|
||||
schemeDestByteCountField.setValue(1);
|
||||
schemeDestByteCountField.setEnabled(b);
|
||||
schemeSrcByteCountField.setValue(1);
|
||||
schemeSrcByteCountField.setEnabled(b);
|
||||
}
|
||||
|
||||
private JPanel buildMappedPanel() {
|
||||
JPanel panel = new JPanel(new PairLayout());
|
||||
|
||||
baseAddrField = new AddressInput();
|
||||
baseAddrField.setAddressFactory(addrFactory);
|
||||
baseAddrField.setName("Source Addr");
|
||||
|
||||
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();
|
||||
Address minAddr = program.getMinAddress();
|
||||
|
@ -437,8 +486,12 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
}
|
||||
baseAddrField.setAddress(minAddr);
|
||||
model.setBaseAddress(minAddr);
|
||||
panel.add(new GLabel("Source Addr:"));
|
||||
panel.add(new GLabel("Source Address:"));
|
||||
panel.add(baseAddrField);
|
||||
|
||||
panel.add(new GLabel("Mapping Ratio:"));
|
||||
panel.add(schemePanel);
|
||||
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
return panel;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import javax.swing.event.ChangeListener;
|
|||
import ghidra.app.cmd.memory.*;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.mem.ByteMappingScheme;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
@ -42,8 +43,11 @@ class AddBlockModel {
|
|||
private String blockName;
|
||||
private Address startAddr;
|
||||
private Address baseAddr;
|
||||
private int schemeDestByteCount;
|
||||
private int schemeSrcByteCount;
|
||||
private long length;
|
||||
private MemoryBlockType blockType;
|
||||
private boolean isOverlay;
|
||||
private int initialValue;
|
||||
private String message;
|
||||
private ChangeListener listener;
|
||||
|
@ -121,6 +125,9 @@ class AddBlockModel {
|
|||
isWrite = true;
|
||||
isExecute = false;
|
||||
isVolatile = false;
|
||||
isOverlay = false;
|
||||
schemeDestByteCount = blockType == MemoryBlockType.BIT_MAPPED ? 8 : 1;
|
||||
schemeSrcByteCount = 1;
|
||||
initializedType = InitializedType.UNITIALIZED;
|
||||
validateInfo();
|
||||
listener.stateChanged(null);
|
||||
|
@ -142,6 +149,10 @@ class AddBlockModel {
|
|||
this.isVolatile = b;
|
||||
}
|
||||
|
||||
void setOverlay(boolean b) {
|
||||
this.isOverlay = b;
|
||||
}
|
||||
|
||||
void setInitializedType(InitializedType type) {
|
||||
this.initializedType = type;
|
||||
validateInfo();
|
||||
|
@ -154,6 +165,26 @@ class AddBlockModel {
|
|||
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() {
|
||||
return startAddr;
|
||||
}
|
||||
|
@ -194,6 +225,10 @@ class AddBlockModel {
|
|||
return isVolatile;
|
||||
}
|
||||
|
||||
boolean isOverlay() {
|
||||
return isOverlay;
|
||||
}
|
||||
|
||||
InitializedType getInitializedType() {
|
||||
return initializedType;
|
||||
}
|
||||
|
@ -217,21 +252,21 @@ class AddBlockModel {
|
|||
switch (blockType) {
|
||||
case BIT_MAPPED:
|
||||
return new AddBitMappedMemoryBlockCmd(blockName, comment, source, startAddr, length,
|
||||
isRead, isWrite, isExecute, isVolatile, baseAddr);
|
||||
isRead, isWrite, isExecute, isVolatile, baseAddr, isOverlay);
|
||||
case BYTE_MAPPED:
|
||||
ByteMappingScheme byteMappingScheme =
|
||||
new ByteMappingScheme(schemeDestByteCount, schemeSrcByteCount);
|
||||
return new AddByteMappedMemoryBlockCmd(blockName, comment, source, startAddr,
|
||||
length, isRead, isWrite, isExecute, isVolatile, baseAddr);
|
||||
length, isRead, isWrite, isExecute, isVolatile, baseAddr, byteMappingScheme,
|
||||
isOverlay);
|
||||
case DEFAULT:
|
||||
return createNonMappedMemoryBlock(source, false);
|
||||
case OVERLAY:
|
||||
return createNonMappedMemoryBlock(source, true);
|
||||
return createNonMappedMemoryBlock(source);
|
||||
default:
|
||||
throw new AssertException("Encountered unexpected block type: " + blockType);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Command createNonMappedMemoryBlock(String source, boolean isOverlay) {
|
||||
private Command createNonMappedMemoryBlock(String source) {
|
||||
switch (initializedType) {
|
||||
case INITIALIZED_FROM_FILE_BYTES:
|
||||
return new AddFileBytesMemoryBlockCmd(blockName, comment, source, startAddr, length,
|
||||
|
@ -299,7 +334,7 @@ class AddBlockModel {
|
|||
}
|
||||
|
||||
private boolean hasUniqueNameIfOverlay() {
|
||||
if (blockType != MemoryBlockType.OVERLAY) {
|
||||
if (!isOverlay) {
|
||||
return true;
|
||||
}
|
||||
AddressFactory factory = program.getAddressFactory();
|
||||
|
@ -315,7 +350,7 @@ class AddBlockModel {
|
|||
|
||||
private boolean isOverlayIfOtherSpace() {
|
||||
if (startAddr.getAddressSpace().equals(AddressSpace.OTHER_SPACE)) {
|
||||
if (blockType != MemoryBlockType.OVERLAY) {
|
||||
if (!isOverlay) {
|
||||
message = "Blocks defined in the " + AddressSpace.OTHER_SPACE.getName() +
|
||||
" space must be overlay blocks";
|
||||
return false;
|
||||
|
@ -327,16 +362,27 @@ class AddBlockModel {
|
|||
private boolean hasMappedAddressIfNeeded() {
|
||||
if (blockType == MemoryBlockType.BIT_MAPPED || blockType == MemoryBlockType.BYTE_MAPPED) {
|
||||
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";
|
||||
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;
|
||||
}
|
||||
|
||||
private boolean hasNoMemoryConflicts() {
|
||||
if (blockType == MemoryBlockType.OVERLAY) {
|
||||
if (isOverlay) {
|
||||
return true;
|
||||
}
|
||||
Address endAddr = startAddr.add(length - 1);
|
||||
|
|
|
@ -81,11 +81,11 @@ class MemoryMapManager {
|
|||
|
||||
Listing listing = program.getListing();
|
||||
String[] treeNames = listing.getTreeNames();
|
||||
for (int i = 0; i < treeNames.length; i++) {
|
||||
for (String treeName : treeNames) {
|
||||
boolean duplicate = false;
|
||||
int index = 0;
|
||||
|
||||
ProgramFragment frag = listing.getFragment(treeNames[i], start);
|
||||
ProgramFragment frag = listing.getFragment(treeName, start);
|
||||
do {
|
||||
try {
|
||||
frag.setName("Frag" + index + "-" + name);
|
||||
|
@ -121,6 +121,11 @@ class MemoryMapManager {
|
|||
// make sure that the block after the first block is the second block
|
||||
Address nextStart = blockA.getEnd();
|
||||
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();
|
||||
if (!space.isSuccessor(nextStart, blockBstart)) {
|
||||
|
@ -171,19 +176,9 @@ class MemoryMapManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean isValidBlockName(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
boolean isDuplicateName(String name) {
|
||||
// block names may not duplicate existing address spaces (includes overlay blocks)
|
||||
return program.getAddressFactory().getAddressSpace(name) != null;
|
||||
}
|
||||
|
||||
void setProgram(Program program) {
|
||||
|
@ -332,8 +327,7 @@ class MemoryMapManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks.size(); i++) {
|
||||
MemoryBlock nextBlock = blocks.get(i);
|
||||
for (MemoryBlock nextBlock : blocks) {
|
||||
if (min == null || nextBlock.getStart().compareTo(min) < 0) {
|
||||
min = nextBlock.getStart();
|
||||
}
|
||||
|
@ -412,8 +406,8 @@ class MemoryMapManager {
|
|||
|
||||
private boolean allBlocksInSameSpace() {
|
||||
AddressSpace lastSpace = null;
|
||||
for (int i = 0; i < blocks.size(); i++) {
|
||||
Address start = blocks.get(i).getStart();
|
||||
for (MemoryBlock block : blocks) {
|
||||
Address start = block.getStart();
|
||||
AddressSpace space = start.getAddressSpace();
|
||||
if (lastSpace != null && !lastSpace.equals(space)) {
|
||||
return false;
|
||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.NamingUtilities;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
||||
|
@ -50,11 +49,12 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
final static byte WRITE = 5;
|
||||
final static byte EXECUTE = 6;
|
||||
final static byte VOLATILE = 7;
|
||||
final static byte BLOCK_TYPE = 8;
|
||||
final static byte INIT = 9;
|
||||
final static byte BYTE_SOURCE = 10;
|
||||
final static byte SOURCE = 11;
|
||||
final static byte COMMENT = 12;
|
||||
final static byte OVERLAY = 8;
|
||||
final static byte BLOCK_TYPE = 9;
|
||||
final static byte INIT = 10;
|
||||
final static byte BYTE_SOURCE = 11;
|
||||
final static byte SOURCE = 12;
|
||||
final static byte COMMENT = 13;
|
||||
|
||||
final static String NAME_COL = "Name";
|
||||
final static String START_COL = "Start";
|
||||
|
@ -64,6 +64,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
final static String WRITE_COL = "W";
|
||||
final static String EXECUTE_COL = "X";
|
||||
final static String VOLATILE_COL = "Volatile";
|
||||
final static String OVERLAY_COL = "Overlay";
|
||||
final static String BLOCK_TYPE_COL = "Type";
|
||||
final static String INIT_COL = "Initialized";
|
||||
final static String BYTE_SOURCE_COL = "Byte Source";
|
||||
|
@ -77,7 +78,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
|
||||
private final static String COLUMN_NAMES[] =
|
||||
{ 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) {
|
||||
super(START);
|
||||
|
@ -115,7 +116,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
|
||||
columnIndex == VOLATILE || columnIndex == INIT) {
|
||||
columnIndex == VOLATILE || columnIndex == OVERLAY || columnIndex == INIT) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -163,7 +164,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
|
||||
columnIndex == VOLATILE || columnIndex == INIT) {
|
||||
columnIndex == VOLATILE || columnIndex == OVERLAY || columnIndex == INIT) {
|
||||
return Boolean.class;
|
||||
}
|
||||
return String.class;
|
||||
|
@ -263,17 +264,17 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
"Please enter a label name.");
|
||||
break;
|
||||
}
|
||||
if (!NamingUtilities.isValidName(name)) {
|
||||
if (name.equals(block.getName())) {
|
||||
break;
|
||||
}
|
||||
if (Memory.isValidAddressSpaceName(name)) {
|
||||
Msg.showError(this, provider.getComponent(), "Invalid Name",
|
||||
"Invalid Memory Block Name: " + name);
|
||||
break;
|
||||
}
|
||||
if (name.equals(block.getName())) {
|
||||
break;
|
||||
}
|
||||
if (!provider.getMemoryMapManager().isValidBlockName(name)) {
|
||||
if (provider.getMemoryMapManager().isDuplicateName(name)) {
|
||||
Msg.showError(this, provider.getComponent(), "Duplicate Name",
|
||||
"Block named " + name + " already exists.");
|
||||
"Address space/overlay named " + name + " already exists.");
|
||||
break;
|
||||
}
|
||||
if (!name.equals(block.getName())) {
|
||||
|
@ -417,7 +418,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (!program.hasExclusiveAccess()) {
|
||||
|
@ -492,6 +493,8 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
return block.isExecute() ? Boolean.TRUE : Boolean.FALSE;
|
||||
case VOLATILE:
|
||||
return block.isVolatile() ? Boolean.TRUE : Boolean.FALSE;
|
||||
case OVERLAY:
|
||||
return block.isOverlay() ? Boolean.TRUE : Boolean.FALSE;
|
||||
case INIT:
|
||||
MemoryBlockType blockType = block.getType();
|
||||
if (blockType == MemoryBlockType.BIT_MAPPED) {
|
||||
|
@ -581,6 +584,10 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
|||
int b1v = (b1.isVolatile() ? 1 : -1);
|
||||
int b2v = (b2.isVolatile() ? 1 : -1);
|
||||
return (b1v - b2v);
|
||||
case OVERLAY:
|
||||
int b1o = (b1.isOverlay() ? 1 : -1);
|
||||
int b2o = (b2.isOverlay() ? 1 : -1);
|
||||
return (b1o - b2o);
|
||||
case INIT:
|
||||
int b1init = (b1.isInitialized() ? 1 : -1);
|
||||
int b2init = (b2.isInitialized() ? 1 : -1);
|
||||
|
|
|
@ -150,6 +150,8 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL);
|
||||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL);
|
||||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
column = memTable.getColumn(MemoryMapModel.INIT_COL);
|
||||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
|
||||
|
@ -435,13 +437,22 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
column.setResizable(false);
|
||||
|
||||
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL);
|
||||
column.setMaxWidth(50);
|
||||
column.setMinWidth(50);
|
||||
column.setMaxWidth(57);
|
||||
column.setMinWidth(57);
|
||||
column.setResizable(false);
|
||||
|
||||
column = memTable.getColumn(MemoryMapModel.INIT_COL);
|
||||
column.setMaxWidth(60);
|
||||
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL);
|
||||
column.setMaxWidth(55);
|
||||
column.setMinWidth(55);
|
||||
column.setResizable(false);
|
||||
|
||||
column = memTable.getColumn(MemoryMapModel.BLOCK_TYPE_COL);
|
||||
column.setMinWidth(60);
|
||||
// column.setResizable(true);
|
||||
|
||||
column = memTable.getColumn(MemoryMapModel.INIT_COL);
|
||||
column.setMaxWidth(68);
|
||||
column.setMinWidth(68);
|
||||
column.setResizable(false);
|
||||
}
|
||||
|
||||
|
@ -539,7 +550,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
if (block.getType() == MemoryBlockType.OVERLAY) {
|
||||
if (block.isOverlay()) {
|
||||
Msg.showInfo(getClass(), getComponent(), "Expand Overlay Block Not Allowed",
|
||||
"Overlay blocks cannot be expanded.");
|
||||
}
|
||||
|
@ -558,7 +569,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
return;
|
||||
}
|
||||
|
||||
if (block.getType() == MemoryBlockType.OVERLAY) {
|
||||
if (block.isOverlay()) {
|
||||
Msg.showInfo(getClass(), getComponent(), "Move Overlay Block Not Allowed",
|
||||
"Overlay blocks cannot be moved.");
|
||||
}
|
||||
|
@ -575,7 +586,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
if (block.getType() == MemoryBlockType.OVERLAY) {
|
||||
if (block.isOverlay()) {
|
||||
Msg.showInfo(getClass(), getComponent(), "Split Overlay Block Not Allowed",
|
||||
"Overlay blocks cannot be split.");
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ import ghidra.app.plugin.core.misc.RegisterField;
|
|||
import ghidra.app.util.AddressInput;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.NamingUtilities;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
|
@ -85,15 +85,14 @@ class SplitBlockDialog extends DialogComponentProvider {
|
|||
newBlockName = block.getName() + ".split";
|
||||
blockTwoNameField.setText(newBlockName);
|
||||
}
|
||||
if (!plugin.getMemoryMapManager().isValidBlockName(newBlockName)) {
|
||||
setStatusText("Block name already exists");
|
||||
return;
|
||||
}
|
||||
if (!NamingUtilities.isValidName(newBlockName)) {
|
||||
if (!Memory.isValidAddressSpaceName(newBlockName)) {
|
||||
setStatusText("Invalid Block Name: " + newBlockName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getMemoryMapManager().isDuplicateName(newBlockName)) {
|
||||
setStatusText("Address space/overlay named " + newBlockName + " already exists.");
|
||||
return;
|
||||
}
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
plugin.getMemoryMapManager().splitBlock(block, blockTwoStart.getAddress(), newBlockName);
|
||||
close();
|
||||
|
|
|
@ -121,17 +121,18 @@ public class MemoryBlockUtils {
|
|||
* @param r the read permission for the new block.
|
||||
* @param w the write 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
|
||||
* @return the new created block
|
||||
*/
|
||||
public static MemoryBlock createBitMappedBlock(Program program, String name, Address start,
|
||||
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();
|
||||
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);
|
||||
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)
|
||||
*
|
||||
* @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 w the write 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
|
||||
* @return the new created block
|
||||
*/
|
||||
public static MemoryBlock createByteMappedBlock(Program program, String name, Address start,
|
||||
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();
|
||||
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);
|
||||
adjustFragment(program, start, name);
|
||||
|
|
|
@ -31,7 +31,8 @@ public class CommentFieldMouseHandler implements FieldMouseHandlerExtension {
|
|||
|
||||
private final static Class<?>[] SUPPORTED_CLASSES =
|
||||
new Class[] { CommentFieldLocation.class, EolCommentFieldLocation.class,
|
||||
PlateFieldLocation.class, AutomaticCommentFieldLocation.class };
|
||||
PlateFieldLocation.class, AutomaticCommentFieldLocation.class,
|
||||
MemoryBlockStartFieldLocation.class };
|
||||
|
||||
@Override
|
||||
public Class<?>[] getSupportedProgramLocations() {
|
||||
|
|
|
@ -111,8 +111,15 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
|
|||
return null;
|
||||
}
|
||||
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,
|
||||
col, null, 0);
|
||||
col, comments, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,11 +206,20 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
|
|||
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 line2 = block.getComment();
|
||||
String line3 = cu.getMemory().getMinAddress().getAddressSpace().toString() + " " +
|
||||
block.getStart() + "-" + block.getEnd();
|
||||
String line3 = block.getStart().toString(true) + "-" + block.getEnd().toString(true);
|
||||
|
||||
AttributedString borderAS = new AttributedString("//", color, getMetrics());
|
||||
lines.add(borderAS);
|
||||
|
|
|
@ -149,7 +149,7 @@ class MemoryMapXmlMgr {
|
|||
Address sourceAddr = factory.getAddress(element.getAttribute("SOURCE_ADDRESS"));
|
||||
|
||||
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) {
|
||||
block.setVolatile(isVolatile);
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ class MemoryMapXmlMgr {
|
|||
Address sourceAddr = factory.getAddress(element.getAttribute("SOURCE_ADDRESS"));
|
||||
|
||||
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) {
|
||||
block.setVolatile(isVolatile);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
@ -26,8 +27,6 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
import ghidra.util.exception.NotFoundException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* <CODE>MemoryDiff</CODE> determines where the memory differs between two programs as well as the
|
||||
* types of differences.
|
||||
|
@ -179,12 +178,12 @@ public class MemoryDiff {
|
|||
*/
|
||||
public AddressRange[] getDifferentAddressRanges() {
|
||||
ArrayList<AddressRange> rangeDiffs = new ArrayList<AddressRange>();
|
||||
for (int i = 0; i < ranges.length; i++) {
|
||||
Address addr = ranges[i].getMinAddress();
|
||||
for (AddressRange range : ranges) {
|
||||
Address addr = range.getMinAddress();
|
||||
MemoryBlock block1 = memory1.getBlock(addr);
|
||||
MemoryBlock block2 = memory2.getBlock(addr);
|
||||
if (!sameMemoryBlock(block1, block2)) {
|
||||
rangeDiffs.add(ranges[i]);
|
||||
rangeDiffs.add(range);
|
||||
}
|
||||
}
|
||||
return rangeDiffs.toArray(new AddressRange[rangeDiffs.size()]);
|
||||
|
@ -271,15 +270,8 @@ public class MemoryDiff {
|
|||
memory1.join(firstBlock, secondBlock);
|
||||
}
|
||||
return true;
|
||||
} catch (MemoryBlockException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), 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) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -225,7 +225,7 @@ public class ProgramMemoryUtil {
|
|||
AddressSet addrSet = new AddressSet();
|
||||
MemoryBlock[] memBlocks = program.getMemory().getBlocks();
|
||||
for (MemoryBlock memoryBlock : memBlocks) {
|
||||
if (memoryBlock.getType() == MemoryBlockType.OVERLAY) {
|
||||
if (memoryBlock.isOverlay()) {
|
||||
AddressRange addressRange =
|
||||
new AddressRangeImpl(memoryBlock.getStart(), memoryBlock.getEnd());
|
||||
addrSet.add(addressRange);
|
||||
|
|
|
@ -143,7 +143,10 @@ public class AddBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
|||
model.setLength(100);
|
||||
assertTrue(model.isValidInfo());
|
||||
|
||||
model.setBlockType(MemoryBlockType.OVERLAY);
|
||||
model.setBlockType(MemoryBlockType.DEFAULT);
|
||||
assertTrue(model.isValidInfo());
|
||||
|
||||
model.setOverlay(true);
|
||||
assertTrue(model.isValidInfo());
|
||||
|
||||
model.setBaseAddress(getAddr(0x2000));
|
||||
|
@ -181,7 +184,8 @@ public class AddBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
|||
model.setBlockName(".test");
|
||||
model.setStartAddress(getAddr(0x100));
|
||||
model.setLength(100);
|
||||
model.setBlockType(MemoryBlockType.OVERLAY);
|
||||
model.setBlockType(MemoryBlockType.DEFAULT);
|
||||
model.setOverlay(true);
|
||||
model.setInitializedType(InitializedType.INITIALIZED_FROM_VALUE);
|
||||
model.setInitialValue(0xa);
|
||||
assertTrue(model.execute());
|
||||
|
@ -206,7 +210,8 @@ public class AddBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
|||
model.setBlockName(".test");
|
||||
model.setStartAddress(getAddr(0x01001000));
|
||||
model.setLength(100);
|
||||
model.setBlockType(MemoryBlockType.OVERLAY);
|
||||
model.setBlockType(MemoryBlockType.DEFAULT);
|
||||
model.setOverlay(true);
|
||||
model.setInitializedType(InitializedType.INITIALIZED_FROM_VALUE);
|
||||
model.setInitialValue(0xa);
|
||||
assertTrue(model.execute());
|
||||
|
|
|
@ -482,7 +482,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
|||
|
||||
// add a bit overlay block, live block, and an unitialized block
|
||||
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);
|
||||
program.endTransaction(transactionID, true);
|
||||
|
||||
|
@ -508,7 +508,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
|||
public void testSortBlockTypeDescending() throws Exception {
|
||||
// add a bit overlay block, live block, and an unitialized block
|
||||
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);
|
||||
program.endTransaction(transactionID, true);
|
||||
|
||||
|
@ -540,7 +540,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
|||
//
|
||||
int transactionID = program.startTransaction("test");
|
||||
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 = memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false);
|
||||
block.setSourceName("other source");
|
||||
|
@ -581,7 +581,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
|||
//
|
||||
int transactionID = program.startTransaction("test");
|
||||
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 = memory.createUninitializedBlock(".Uninit", getAddr(0x3000), 0x200, false);
|
||||
block.setSourceName("other source");
|
||||
|
|
|
@ -215,6 +215,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
|
||||
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(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
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.WRITE));
|
||||
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(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
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.WRITE));
|
||||
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(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
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 writeCB = (JCheckBox) findComponentByName(d.getComponent(), "Write");
|
||||
final JCheckBox executeCB = (JCheckBox) findComponentByName(d.getComponent(), "Execute");
|
||||
final JCheckBox overlayCB = (JCheckBox) findComponentByName(d.getComponent(), "Overlay");
|
||||
final JRadioButton initializedRB =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "Initialized");
|
||||
final RegisterField initialValue =
|
||||
|
@ -623,11 +627,16 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
final JButton okButton = findButton(d.getComponent(), "OK");
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
comboBox.setSelectedItem(MemoryBlockType.OVERLAY);
|
||||
comboBox.setSelectedItem(MemoryBlockType.DEFAULT);
|
||||
overlayCB.setSelected(true);
|
||||
overlayCB.getActionListeners()[0].actionPerformed(null);
|
||||
nameField.setText(".test");
|
||||
lengthField.setText("0x100");
|
||||
commentField.setText("this is a block test");
|
||||
initialValue.setText("0xa");
|
||||
});
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
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.WRITE));
|
||||
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));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.INIT));
|
||||
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 writeCB = (JCheckBox) findComponentByName(d.getComponent(), "Write");
|
||||
final JCheckBox executeCB = (JCheckBox) findComponentByName(d.getComponent(), "Execute");
|
||||
final JCheckBox overlayCB = (JCheckBox) findComponentByName(d.getComponent(), "Overlay");
|
||||
|
||||
final JRadioButton uninitRB =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "Uninitialized");
|
||||
final AddressInput addrField =
|
||||
|
@ -703,7 +716,9 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
final JButton okButton = findButton(d.getComponent(), "OK");
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
comboBox.setSelectedItem(MemoryBlockType.OVERLAY);
|
||||
comboBox.setSelectedItem(MemoryBlockType.DEFAULT);
|
||||
overlayCB.setSelected(true);
|
||||
overlayCB.getActionListeners()[0].actionPerformed(null);
|
||||
nameField.setText(".test");
|
||||
lengthField.setText("0x100");
|
||||
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.WRITE));
|
||||
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));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(row, MemoryMapModel.INIT));
|
||||
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.WRITE));
|
||||
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));
|
||||
assertNull(model.getValueAt(0, MemoryMapModel.INIT));
|
||||
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.WRITE));
|
||||
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(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE));
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
|
@ -62,7 +61,7 @@ public class AddressIndexPrimaryKeyIteratorTest extends AbstractGhidraHeadedInte
|
|||
// Create fragmented memory
|
||||
memMap.createInitializedBlock("Block1", addr(0x8000), 0x10, (byte) 0, null, false);// startKey: 0x0
|
||||
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
|
||||
|
||||
// Create table with indexed address column
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
@ -65,7 +64,7 @@ public class AddressKeyIteratorTest extends AbstractGhidraHeadedIntegrationTest
|
|||
// Create fragmented memory
|
||||
memMap.createInitializedBlock("Block1", addr(0x8000), 0x10, (byte) 0, null, false);// startKey: 0x0
|
||||
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
|
||||
|
||||
// Create table keyed on address
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.mem;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
|
@ -31,7 +30,7 @@ import ghidra.util.task.TaskMonitorAdapter;
|
|||
/**
|
||||
* Test for the BitMemoryBlock for the database implementation.
|
||||
*/
|
||||
public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
public class BitMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private AddressSpace byteSpace;
|
||||
private AddressSpace bitSpace;
|
||||
private MemoryBlock block;
|
||||
|
@ -43,7 +42,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
* Constructor for BitMemoryBlockTest.
|
||||
* @param name
|
||||
*/
|
||||
public BitMemoryBlockTest() {
|
||||
public BitMappedMemoryBlockTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
@ -74,11 +73,12 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testCreateNewBlock() throws Exception {
|
||||
memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0), bitSpace.getAddress(0x20),
|
||||
0x20);
|
||||
0x20, false);
|
||||
Address newStart = bitSpace.getAddress(0x40);
|
||||
|
||||
MemoryBlock newblock =
|
||||
memory.createBitMappedBlock("BitTest", newStart, bitSpace.getAddress(0x20), 0x50);
|
||||
memory.createBitMappedBlock("BitTest", newStart, bitSpace.getAddress(0x20), 0x50,
|
||||
false);
|
||||
assertNotNull(newblock);
|
||||
assertEquals(newStart, newblock.getStart());
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testNoUnderlyingMemory() throws Exception {
|
||||
MemoryBlock bitBlock = memory.createBitMappedBlock("BIT_BLOCK", bitSpace.getAddress(0),
|
||||
bitSpace.getAddress(0x20), 0x20);
|
||||
bitSpace.getAddress(0x20), 0x20, false);
|
||||
|
||||
Address addr = bitSpace.getAddress(0x40);
|
||||
MemoryBlock newblock = memory.createBlock(bitBlock, "BitTest", addr, 0x50);
|
||||
|
@ -101,7 +101,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testGetByte() throws Exception {
|
||||
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) {
|
||||
assertEquals(0, bitBlock.getByte(bitSpace.getAddress(i)));
|
||||
|
@ -113,7 +113,7 @@ public class BitMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testPutByte() throws Exception {
|
||||
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) {
|
||||
bitBlock.putByte(bitSpace.getAddress(i), (byte) 1);
|
||||
bitBlock.putByte(bitSpace.getAddress(i + 1), (byte) 0);
|
|
@ -0,0 +1,354 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.database.mem;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class ByteMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private AddressSpace space;
|
||||
private MemoryBlock block;
|
||||
private Memory memory;
|
||||
private Program program;
|
||||
private int transactionID;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_LE, this);
|
||||
memory = program.getMemory();
|
||||
|
||||
byte[] bytes = new byte[0x100];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) i;
|
||||
}
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
transactionID = program.startTransaction("Test");
|
||||
|
||||
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0),
|
||||
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
memory.setBytes(block.getStart(), bytes);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
program.endTransaction(transactionID, true);
|
||||
program.release(this);
|
||||
}
|
||||
|
||||
private Address addr(long offset) {
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewBlock1to1() throws Exception {
|
||||
MemoryBlock byteMappedBlock =
|
||||
memory.createByteMappedBlock("test", addr(0x1000), addr(0x80), 0x100, false);
|
||||
assertEquals(0x100, byteMappedBlock.getSize());
|
||||
assertEquals(addr(0x1000), byteMappedBlock.getStart());
|
||||
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
|
||||
|
||||
AddressSet set = new AddressSet(addr(0), addr(0xFF));
|
||||
set.add(addr(0x1000), addr(0x107F));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
|
||||
ByteMappingScheme scheme = info.getByteMappingScheme().get();
|
||||
assertEquals(1, scheme.getMappedByteCount());
|
||||
assertEquals(1, scheme.getMappedSourceByteCount());
|
||||
assertEquals(addr(0x80), scheme.getMappedSourceAddress(addr(0), 0x80));
|
||||
|
||||
for (int i = 0; i < 0x80; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
|
||||
assertEquals(0x80 + i, b & 0xff);
|
||||
}
|
||||
|
||||
try {
|
||||
byteMappedBlock.getByte(addr(0x1100));
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[0x100];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) ~i;
|
||||
}
|
||||
|
||||
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
|
||||
bytes.length,
|
||||
(byte) 0, TaskMonitor.DUMMY, false);
|
||||
|
||||
set.add(addr(0x100), addr(0x1FF));
|
||||
set.add(addr(0x1080), addr(0x10FF));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
|
||||
|
||||
memory.setBytes(block2.getStart(), bytes);
|
||||
|
||||
for (int i = 0; i < 0x80; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
|
||||
assertEquals(0x80 + i, b & 0xff);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x7F; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1080 + i));
|
||||
assertEquals(~i & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
byte[] data1 = new byte[] { 1, 2, 3 };
|
||||
byteMappedBlock.putBytes(addr(0x1080), data1);
|
||||
|
||||
byte[] data2 = new byte[3];
|
||||
assertEquals(3, byteMappedBlock.getBytes(addr(0x1080), data2));
|
||||
assertTrue(Arrays.equals(data1, data2));
|
||||
assertEquals(3, block2.getBytes(addr(0x100), data2));
|
||||
assertTrue(Arrays.equals(data1, data2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewBlock1to2() throws Exception {
|
||||
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
|
||||
0x100, new ByteMappingScheme(1, 2), false);
|
||||
assertEquals(0x100, byteMappedBlock.getSize());
|
||||
assertEquals(addr(0x1000), byteMappedBlock.getStart());
|
||||
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
|
||||
|
||||
AddressSet set = new AddressSet(addr(0), addr(0xFF));
|
||||
set.add(addr(0x1000), addr(0x103F));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
|
||||
ByteMappingScheme scheme = info.getByteMappingScheme().get();
|
||||
assertEquals(1, scheme.getMappedByteCount());
|
||||
assertEquals(2, scheme.getMappedSourceByteCount());
|
||||
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
|
||||
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
|
||||
assertEquals(0x80 + (2 * i), b & 0xff);
|
||||
}
|
||||
|
||||
try {
|
||||
byteMappedBlock.getByte(addr(0x1100));
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[0x100];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) ~i;
|
||||
}
|
||||
|
||||
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
|
||||
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
|
||||
set.add(addr(0x100), addr(0x1FF));
|
||||
set.add(addr(0x1040), addr(0x10BF));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
|
||||
|
||||
memory.setBytes(block2.getStart(), bytes);
|
||||
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
|
||||
assertEquals(0x80 + (2 * i), b & 0xff);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x7F; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1040 + i));
|
||||
assertEquals(~(2 * i) & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
byte[] data1 = new byte[] { 1, 2, 3, 4 };
|
||||
byteMappedBlock.putBytes(addr(0x1040), data1);
|
||||
|
||||
byte[] data2 = new byte[4];
|
||||
assertEquals(4, byteMappedBlock.getBytes(addr(0x1040), data2));
|
||||
assertTrue(Arrays.equals(data1, data2));
|
||||
assertEquals(4, block2.getBytes(addr(0x100), data2));
|
||||
assertTrue(Arrays.equals(new byte[] { 1, -2, 2, -4 }, data2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewBlock2to4() throws Exception {
|
||||
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
|
||||
0x100, new ByteMappingScheme(2, 4), false);
|
||||
assertEquals(0x100, byteMappedBlock.getSize());
|
||||
assertEquals(addr(0x1000), byteMappedBlock.getStart());
|
||||
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
|
||||
|
||||
AddressSet set = new AddressSet(addr(0), addr(0xFF));
|
||||
set.add(addr(0x1000), addr(0x103E));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
|
||||
ByteMappingScheme scheme = info.getByteMappingScheme().get();
|
||||
assertEquals(2, scheme.getMappedByteCount());
|
||||
assertEquals(4, scheme.getMappedSourceByteCount());
|
||||
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
|
||||
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
|
||||
int val = 0x80 + (4 * (i / 2) + (i % 2));
|
||||
assertEquals(val & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
try {
|
||||
byteMappedBlock.getByte(addr(0x1100));
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[0x100];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) ~i;
|
||||
}
|
||||
|
||||
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
|
||||
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
|
||||
set.add(addr(0x100), addr(0x1FF));
|
||||
set.add(addr(0x103F), addr(0x10BE));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
|
||||
|
||||
memory.setBytes(block2.getStart(), bytes);
|
||||
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
|
||||
int val = 0x80 + (4 * (i / 2) + (i % 2));
|
||||
assertEquals(val & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x7F; i++) {
|
||||
byte b = byteMappedBlock.getByte(addr(0x1040 + i));
|
||||
int val = ~(4 * (i / 2) + (i % 2));
|
||||
assertEquals(val & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
byte[] data1 = new byte[] { 1, 2, 3, 4 };
|
||||
byteMappedBlock.putBytes(addr(0x1040), data1);
|
||||
|
||||
byte[] data2 = new byte[4];
|
||||
assertEquals(4, byteMappedBlock.getBytes(addr(0x1040), data2));
|
||||
assertTrue(Arrays.equals(data1, data2));
|
||||
assertEquals(4, block2.getBytes(addr(0x100), data2));
|
||||
assertTrue(Arrays.equals(new byte[] { 1, 2, -3, -4 }, data2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewBlock2to4Overlay() throws Exception {
|
||||
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
|
||||
0x100, new ByteMappingScheme(2, 4), true);
|
||||
assertTrue(byteMappedBlock.isOverlay());
|
||||
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
|
||||
assertNotNull(testSpace);
|
||||
assertEquals(space, testSpace.getPhysicalSpace());
|
||||
assertEquals(testSpace.getAddress(0x1000), testSpace.getMinAddress());
|
||||
assertEquals(testSpace.getAddress(0x10FF), testSpace.getMaxAddress());
|
||||
assertEquals(0x100, byteMappedBlock.getSize());
|
||||
assertEquals(testSpace.getAddress(0x1000), byteMappedBlock.getStart());
|
||||
assertEquals(testSpace.getAddress(0x10FF), byteMappedBlock.getEnd());
|
||||
|
||||
AddressSet set = new AddressSet(addr(0), addr(0xFF));
|
||||
set.add(testSpace.getAddress(0x1000), testSpace.getAddress(0x103E));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
|
||||
ByteMappingScheme scheme = info.getByteMappingScheme().get();
|
||||
assertEquals(2, scheme.getMappedByteCount());
|
||||
assertEquals(4, scheme.getMappedSourceByteCount());
|
||||
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
|
||||
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1000 + i));
|
||||
int val = 0x80 + (4 * (i / 2) + (i % 2));
|
||||
assertEquals(val & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
try {
|
||||
byteMappedBlock.getByte(testSpace.getAddress(0x1100));
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[0x100];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) ~i;
|
||||
}
|
||||
|
||||
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
|
||||
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
|
||||
set.add(addr(0x100), addr(0x1FF));
|
||||
set.add(testSpace.getAddress(0x103F), testSpace.getAddress(0x10BE));
|
||||
assertEquals(set, memory.getAllInitializedAddressSet());
|
||||
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
|
||||
|
||||
assertEquals(0, byteMappedBlock.getByte(testSpace.getAddress(0x1080)));
|
||||
|
||||
memory.setBytes(block2.getStart(), bytes);
|
||||
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1000 + i));
|
||||
int val = 0x80 + (4 * (i / 2) + (i % 2));
|
||||
assertEquals(val & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x7F; i++) {
|
||||
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1040 + i));
|
||||
int val = ~(4 * (i / 2) + (i % 2));
|
||||
assertEquals(val & 0xff, b & 0xff);
|
||||
}
|
||||
|
||||
byte[] data1 = new byte[] { 1, 2, 3, 4 };
|
||||
byteMappedBlock.putBytes(testSpace.getAddress(0x1040), data1);
|
||||
|
||||
byte[] data2 = new byte[4];
|
||||
assertEquals(4, byteMappedBlock.getBytes(testSpace.getAddress(0x1040), data2));
|
||||
assertTrue(Arrays.equals(data1, data2));
|
||||
assertEquals(4, block2.getBytes(addr(0x100), data2));
|
||||
assertTrue(Arrays.equals(new byte[] { 1, 2, -3, -4 }, data2));
|
||||
}
|
||||
}
|
|
@ -15,51 +15,20 @@
|
|||
*/
|
||||
package ghidra.program.database.mem;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.app.plugin.core.memory.UninitializedBlockCmd;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.AddressRangeImpl;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
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.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -255,7 +224,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testCreateBitBlock() throws Exception {
|
||||
createBlock("Test", addr(0), 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));
|
||||
assertNotNull(block);
|
||||
assertEquals(bitBlock, block);
|
||||
|
@ -321,7 +290,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
MemoryBlock block2 = createBlock("Test2", addr(500), 100);
|
||||
MemoryBlock block3 = mem.createUninitializedBlock("Test3", addr(1500), 200, 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();
|
||||
assertEquals(5, blocks.length);
|
||||
|
@ -487,7 +456,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
MemoryBlock block2 = createBlock("Test2", addr(500), 100);
|
||||
MemoryBlock block3 = mem.createUninitializedBlock("Test3", addr(1500), 200, 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!");
|
||||
block2.setName("NewTest2");
|
||||
block3.setWrite(false);
|
||||
|
@ -670,7 +639,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testMoveBitBlock() throws Exception {
|
||||
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)));
|
||||
bitBlock.putByte(addr(200), (byte) 5);
|
||||
assertEquals(1, bitBlock.getByte(addr(200)));
|
||||
|
@ -1034,13 +1003,15 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testCreateOverlayBlock() throws Exception {
|
||||
MemoryBlock block = mem.createInitializedBlock(".overlay", addr(0), 0x1000, (byte) 0xa,
|
||||
TaskMonitor.DUMMY, true);
|
||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||
assertTrue(block.isOverlay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateBitMappedBlock() throws Exception {
|
||||
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());
|
||||
|
||||
|
@ -1056,7 +1027,8 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testCreateByteMappedBlock() throws Exception {
|
||||
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());
|
||||
|
||||
|
@ -1066,14 +1038,14 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
expectedInitializedSet.add(addr(0), addr(0xfff));
|
||||
expectedInitializedSet.add(addr(0x2000), addr(0x20ff));
|
||||
assertEquals(expectedInitializedSet, mem.getAllInitializedAddressSet());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRemoveCreateOverlayBlock() throws Exception {
|
||||
MemoryBlock block = mem.createInitializedBlock(".overlay", addr(0), 0x1000, (byte) 0xa,
|
||||
TaskMonitor.DUMMY, true);
|
||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||
assertTrue(block.isOverlay());
|
||||
mem.removeBlock(block, TaskMonitor.DUMMY);
|
||||
block =
|
||||
mem.createInitializedBlock("ov2", addr(0), 0x2000, (byte) 0xa, TaskMonitor.DUMMY, true);
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.database.mem;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class MemoryWriteCheckTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private AddressSpace space;
|
||||
private MemoryBlock block;
|
||||
private Memory memory;
|
||||
private Program program;
|
||||
private int transactionID;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_LE, this);
|
||||
memory = program.getMemory();
|
||||
|
||||
byte[] bytes = new byte[0x100];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) i;
|
||||
}
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
transactionID = program.startTransaction("Test");
|
||||
|
||||
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0), bytes.length,
|
||||
(byte) 0, TaskMonitor.DUMMY, false);
|
||||
memory.setBytes(block.getStart(), bytes);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
program.endTransaction(transactionID, true);
|
||||
program.release(this);
|
||||
}
|
||||
|
||||
private Address addr(long offset) {
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteMappedMemoryCheck() throws Exception {
|
||||
|
||||
AddressSet set = new AddressSet(addr(0), addr(0xd7));
|
||||
DisassembleCommand cmd = new DisassembleCommand(set, set);
|
||||
cmd.applyTo(program); // range 0x0000 to 0x00d7 disassembled
|
||||
|
||||
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
|
||||
0x100, new ByteMappingScheme(2, 4), true);
|
||||
|
||||
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
|
||||
|
||||
try {
|
||||
byteMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
assertEquals("Memory change conflicts with instruction at 00000080", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
byteMappedBlock.putBytes(testSpace.getAddress(0x1002), new byte[] { 1, 2 });
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
assertEquals("Memory change conflicts with instruction at 00000084", e.getMessage());
|
||||
}
|
||||
|
||||
program.getListing().clearCodeUnits(addr(0), addr(0xd7), true);
|
||||
|
||||
byteMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
|
||||
assertEquals(1, byteMappedBlock.getByte(testSpace.getAddress(0x1000)));
|
||||
|
||||
byteMappedBlock.putBytes(testSpace.getAddress(0x1002), new byte[] { 1, 2 });
|
||||
byte[] data = new byte[2];
|
||||
assertEquals(2, byteMappedBlock.getBytes(testSpace.getAddress(0x1002), data));
|
||||
assertArrayEquals(new byte[] { 1, 2 }, data);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteMappedMemoryCheck1() throws Exception {
|
||||
|
||||
// NOTE: disassembling in a 2:4 byte-mapped block is rather inappropriate and may be disallowed in the future
|
||||
|
||||
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
|
||||
0x100, new ByteMappingScheme(2, 4), true);
|
||||
|
||||
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
|
||||
|
||||
AddressSet set = new AddressSet(testSpace.getAddress(0x1000), testSpace.getAddress(0x1011));
|
||||
DisassembleCommand cmd = new DisassembleCommand(set, set);
|
||||
cmd.applyTo(program); // range test:0x1000 to test::0x1011 disassembled
|
||||
|
||||
try {
|
||||
block.putByte(addr(0x80), (byte) 1);
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
assertEquals("Memory change conflicts with instruction at test::00001000",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
// small modification within filler byte region for mapped block allowed
|
||||
block.putBytes(addr(0x82), new byte[] { 1, 2 });
|
||||
byte[] data = new byte[2];
|
||||
assertEquals(2, block.getBytes(addr(0x82), data));
|
||||
assertArrayEquals(new byte[] { 1, 2 }, data);
|
||||
|
||||
try {
|
||||
block.putBytes(addr(0x84), new byte[] { 1, 2 });
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
assertEquals("Memory change conflicts with instruction at test::00001002",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
program.getListing().clearCodeUnits(set.getMinAddress(), set.getMaxAddress(), true);
|
||||
|
||||
block.putByte(addr(0x80), (byte) 1);
|
||||
assertEquals(1, byteMappedBlock.getByte(testSpace.getAddress(0x1000)));
|
||||
|
||||
block.putBytes(addr(0x84), new byte[] { 1, 2 });
|
||||
assertEquals(2, byteMappedBlock.getBytes(testSpace.getAddress(0x1002), data));
|
||||
assertArrayEquals(new byte[] { 1, 2 }, data);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBitMappedMemoryCheck() throws Exception {
|
||||
|
||||
AddressSet set = new AddressSet(addr(0), addr(0xd7));
|
||||
DisassembleCommand cmd = new DisassembleCommand(set, set);
|
||||
cmd.applyTo(program); // range 0x0000 to 0x00d7 disassembled
|
||||
|
||||
MemoryBlock bitMappedBlock =
|
||||
memory.createBitMappedBlock("test", addr(0x1000), addr(0x80), 0x100, true);
|
||||
|
||||
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
|
||||
|
||||
try {
|
||||
bitMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
assertEquals("Memory change conflicts with instruction at 00000080", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
bitMappedBlock.putBytes(testSpace.getAddress(0x1010), new byte[] { 1, 0, 1, 0 });
|
||||
fail("expected MemoryAccessException");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
assertEquals("Memory change conflicts with instruction at 00000082", e.getMessage());
|
||||
}
|
||||
|
||||
program.getListing().clearCodeUnits(addr(0), addr(0xd7), true);
|
||||
|
||||
bitMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
|
||||
assertEquals(1, bitMappedBlock.getByte(testSpace.getAddress(0x1000)));
|
||||
|
||||
bitMappedBlock.putBytes(testSpace.getAddress(0x1010), new byte[] { 1, 0, 1, 0 });
|
||||
byte[] data = new byte[4];
|
||||
assertEquals(4, bitMappedBlock.getBytes(testSpace.getAddress(0x1010), data));
|
||||
assertArrayEquals(new byte[] { 1, 0, 1, 0 }, data);
|
||||
|
||||
}
|
||||
}
|
|
@ -22,7 +22,8 @@ import org.junit.*;
|
|||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.framework.cmd.Command;
|
||||
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.mem.*;
|
||||
import ghidra.util.exception.RollbackException;
|
||||
|
@ -47,7 +48,7 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
notepad = notepadBuilder.getProgram();
|
||||
|
||||
ProgramBuilder x08Builder = new ProgramBuilder("x08", ProgramBuilder._8051);
|
||||
x08Builder.createMemory("test1", "0x0", 1);
|
||||
x08Builder.createMemory("test1", "0x0", 400);
|
||||
|
||||
x08 = x08Builder.getProgram();
|
||||
}
|
||||
|
@ -59,6 +60,8 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
assertTrue(applyCmd(notepad, command));
|
||||
MemoryBlock block = notepad.getMemory().getBlock(getNotepadAddr(0x100));
|
||||
assertNotNull(block);
|
||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||
assertFalse(block.isOverlay());
|
||||
byte b = block.getByte(getNotepadAddr(0x100));
|
||||
assertEquals((byte) 0xa, b);
|
||||
|
||||
|
@ -103,29 +106,139 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
public void testAddBitBlock() {
|
||||
Address addr = getX08Addr(0x3000);
|
||||
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));
|
||||
|
||||
MemoryBlock block = x08.getMemory().getBlock(addr);
|
||||
assertNull(block);
|
||||
block = x08.getMemory().getBlock(".testBit");
|
||||
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);
|
||||
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());
|
||||
assertTrue(block.isOverlay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddByteBlock() {
|
||||
Address addr = getX08Addr(0x3000);
|
||||
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));
|
||||
|
||||
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(99), info.getMappedRange().get().getMaxAddress());
|
||||
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
|
||||
|
@ -144,7 +257,8 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
}
|
||||
}
|
||||
assertNotNull(block);
|
||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||
assertTrue(block.isOverlay());
|
||||
byte b = block.getByte(block.getStart().getNewAddress(0x3000));
|
||||
assertEquals((byte) 0xa, b);
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ import java.io.InputStream;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.mem.AddressSourceInfo;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.database.mem.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
@ -103,13 +102,15 @@ class MyTestMemory extends AddressSet implements Memory {
|
|||
|
||||
@Override
|
||||
public MemoryBlock createBitMappedBlock(String name, Address start, Address overlayAddress,
|
||||
long length) throws MemoryConflictException, AddressOverflowException {
|
||||
long length, boolean overlay) throws MemoryConflictException, AddressOverflowException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryBlock createByteMappedBlock(String name, Address start, Address overlayAddress,
|
||||
long length) throws MemoryConflictException, AddressOverflowException {
|
||||
public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress,
|
||||
long length, ByteMappingScheme byteMappingScheme, boolean overlay)
|
||||
throws LockException,
|
||||
MemoryConflictException, AddressOverflowException, IllegalArgumentException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,11 @@ class MyTestMemoryBlock implements MemoryBlock {
|
|||
return MemoryBlockType.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverlay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MemoryBlock block) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.math.BigInteger;
|
|||
|
||||
import ghidra.app.plugin.core.format.ByteBlock;
|
||||
import ghidra.app.plugin.core.format.ByteBlockAccessException;
|
||||
import ghidra.program.database.mem.ByteMappingScheme;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
@ -139,9 +140,7 @@ public class MemoryByteBlock implements ByteBlock {
|
|||
@Override
|
||||
public boolean hasValue(BigInteger index) {
|
||||
Address addr = getAddress(index);
|
||||
MemoryBlock memBlock = memory.getBlock(addr);
|
||||
|
||||
return (memBlock != null) && memBlock.isInitialized();
|
||||
return memory.getAllInitializedAddressSet().contains(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -260,6 +259,23 @@ public class MemoryByteBlock implements ByteBlock {
|
|||
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.
|
||||
*/
|
||||
|
@ -268,7 +284,6 @@ public class MemoryByteBlock implements ByteBlock {
|
|||
mAddr = start;
|
||||
mAddr = mAddr.addNoWrap(index);
|
||||
return mAddr;
|
||||
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new IndexOutOfBoundsException("Index " + index + " is not in this block");
|
||||
|
|
|
@ -20,8 +20,7 @@ import java.io.InputStream;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.mem.AddressSourceInfo;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.database.mem.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
@ -48,7 +47,8 @@ public class MemoryTestDummy extends AddressSet implements Memory {
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,9 @@ public class MemoryTestDummy extends AddressSet implements Memory {
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.util.XmlProgramUtilities;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlAttributeException;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
import ghidra.xml.XmlElement;
|
||||
|
@ -92,13 +91,13 @@ public class MemoryBlockDefinition {
|
|||
if (bitMappedAddress != null) {
|
||||
Address mappedAddr =
|
||||
XmlProgramUtilities.parseAddress(program.getAddressFactory(), bitMappedAddress);
|
||||
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length);
|
||||
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length, false);
|
||||
}
|
||||
else if (initialized) {
|
||||
try {
|
||||
block =
|
||||
mem.createInitializedBlock(blockName, addr, length, (byte) 0,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
||||
TaskMonitor.DUMMY, false);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.database.mem;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
|
||||
public class BitMappedByteSourceRange extends ByteSourceRange {
|
||||
|
||||
public BitMappedByteSourceRange(MemoryBlock block, Address start, long sourceId, long offset,
|
||||
long size) {
|
||||
|
||||
super(block, start, size, sourceId, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getEnd() {
|
||||
return getStart().add(size * 8 - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteSourceRange intersect(ByteSourceRange range) {
|
||||
if (sourceId != range.sourceId) {
|
||||
return null;
|
||||
}
|
||||
long maxOffset = Math.max(byteSourceOffset, range.byteSourceOffset);
|
||||
long minEndOffset =
|
||||
Math.min(byteSourceOffset + size - 1, range.byteSourceOffset + range.size - 1);
|
||||
if (maxOffset > minEndOffset) {
|
||||
return null;
|
||||
}
|
||||
long sourceSize = minEndOffset - maxOffset + 1;
|
||||
return new BitMappedByteSourceRange(block, start.add((maxOffset - byteSourceOffset) / 8),
|
||||
sourceId, maxOffset, sourceSize);
|
||||
}
|
||||
}
|
|
@ -16,12 +16,12 @@
|
|||
package ghidra.program.database.mem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.program.database.map.AddressMapDB;
|
||||
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
|
||||
|
@ -36,7 +36,7 @@ class BitMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
this.memMap = adapter.getMemoryMap();
|
||||
AddressMapDB addressMap = memMap.getAddressMap();
|
||||
mappedAddress = addressMap.decodeAddress(
|
||||
record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL), false);
|
||||
record.getLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +62,7 @@ class BitMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
}
|
||||
}
|
||||
|
||||
public AddressRange getMappedRange() {
|
||||
AddressRange getMappedRange() {
|
||||
Address endMappedAddress = mappedAddress.add((subBlockLength - 1) / 8);
|
||||
return new AddressRangeImpl(mappedAddress, endMappedAddress);
|
||||
}
|
||||
|
@ -182,55 +182,4 @@ class BitMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
return "Bit Mapped: " + mappedAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
|
||||
long memBlockOffset,
|
||||
long size) {
|
||||
ByteSourceRangeList result = new ByteSourceRangeList();
|
||||
|
||||
// Since mapped blocks are mapped onto other memory blocks, find those blocks and
|
||||
// handle each one separately
|
||||
|
||||
// converts to byte space since 8 bytes in this block's space maps to 1 byte in real memory
|
||||
Address startMappedAddress = mappedAddress.add(memBlockOffset / 8);
|
||||
Address endMappedAddress = mappedAddress.add((memBlockOffset + size - 1) / 8);
|
||||
List<MemoryBlockDB> blocks = memMap.getBlocks(startMappedAddress, endMappedAddress);
|
||||
|
||||
// for each block, get its ByteSourceSet and then translate that set back into this block's
|
||||
// addresses
|
||||
for (MemoryBlockDB mappedBlock : blocks) {
|
||||
Address startInBlock = max(mappedBlock.getStart(), startMappedAddress);
|
||||
Address endInBlock = min(mappedBlock.getEnd(), endMappedAddress);
|
||||
long blockSize = endInBlock.subtract(startInBlock) + 1;
|
||||
ByteSourceRangeList ranges =
|
||||
mappedBlock.getByteSourceRangeList(startInBlock, blockSize);
|
||||
for (ByteSourceRange bsRange : ranges) {
|
||||
result.add(translate(block, bsRange, start, memBlockOffset, size));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// translates the ByteSourceRange back to addresse
|
||||
private ByteSourceRange translate(MemoryBlock block, ByteSourceRange bsRange, Address start,
|
||||
long offset,
|
||||
long bitLength) {
|
||||
Address startMappedAddress = mappedAddress.add(offset / 8);
|
||||
Address normalizedStart = start.subtract(offset % 8);
|
||||
long mappedOffsetFromStart = bsRange.getStart().subtract(startMappedAddress);
|
||||
long offsetFromStart = mappedOffsetFromStart * 8;
|
||||
Address startAddress = normalizedStart.add(offsetFromStart);
|
||||
|
||||
return new BitMappedByteSourceRange(block, startAddress, bsRange.getSourceId(),
|
||||
bsRange.getOffset(), bsRange.getSize());
|
||||
}
|
||||
|
||||
Address min(Address a1, Address a2) {
|
||||
return a1.compareTo(a2) <= 0 ? a1 : a2;
|
||||
}
|
||||
|
||||
Address max(Address a1, Address a2) {
|
||||
return a1.compareTo(a2) >= 0 ? a1 : a2;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ import java.io.IOException;
|
|||
|
||||
import db.DBBuffer;
|
||||
import db.Record;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -95,11 +94,6 @@ class BufferSubMemoryBlock extends SubMemoryBlock {
|
|||
return record.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryBlockType getType() {
|
||||
return MemoryBlockType.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SubMemoryBlock split(long memBlockOffset) throws IOException {
|
||||
// convert from offset in block to offset in this sub block
|
||||
|
@ -121,14 +115,4 @@ class BufferSubMemoryBlock extends SubMemoryBlock {
|
|||
protected String getDescription() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
|
||||
long memBlockOffset,
|
||||
long size) {
|
||||
long sourceId = -buf.getId(); // buffers use negative id values; FileBytes use positive id values.
|
||||
ByteSourceRange bsRange =
|
||||
new ByteSourceRange(block, start, size, sourceId, memBlockOffset - subBlockOffset);
|
||||
return new ByteSourceRangeList(bsRange);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
package ghidra.program.database.mem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.program.database.map.AddressMapDB;
|
||||
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
|
||||
|
@ -30,14 +30,23 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
|
||||
private final MemoryMapDB memMap;
|
||||
private final Address mappedAddress;
|
||||
private final ByteMappingScheme byteMappingScheme;
|
||||
|
||||
private boolean ioPending;
|
||||
|
||||
ByteMappedSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) {
|
||||
super(adapter, record);
|
||||
this.memMap = adapter.getMemoryMap();
|
||||
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(
|
||||
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
|
||||
|
@ -53,7 +62,9 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
}
|
||||
try {
|
||||
ioPending = true;
|
||||
return memMap.getByte(mappedAddress.addNoWrap(offsetInSubBlock));
|
||||
Address sourceAddr =
|
||||
byteMappingScheme.getMappedSourceAddress(mappedAddress, offsetInSubBlock);
|
||||
return memMap.getByte(sourceAddr);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new MemoryAccessException("No memory at address");
|
||||
|
@ -68,13 +79,14 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
throws MemoryAccessException, IOException {
|
||||
long offsetInSubBlock = offsetInMemBlock - subBlockOffset;
|
||||
long available = subBlockLength - offsetInSubBlock;
|
||||
// TODO: should array length be considered?
|
||||
len = (int) Math.min(len, available);
|
||||
if (ioPending) {
|
||||
new MemoryAccessException("Cyclic Access");
|
||||
}
|
||||
try {
|
||||
ioPending = true;
|
||||
return memMap.getBytes(mappedAddress.addNoWrap(offsetInSubBlock), b, off, len);
|
||||
return byteMappingScheme.getBytes(memMap, mappedAddress, offsetInSubBlock, b, off, len);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new MemoryAccessException("No memory at address");
|
||||
|
@ -92,7 +104,9 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
new MemoryAccessException("Cyclic Access");
|
||||
}
|
||||
ioPending = true;
|
||||
memMap.setByte(mappedAddress.addNoWrap(offsetInSubBlock), b);
|
||||
Address sourceAddr =
|
||||
byteMappingScheme.getMappedSourceAddress(mappedAddress, offsetInSubBlock);
|
||||
memMap.setByte(sourceAddr, b);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new MemoryAccessException("No memory at address");
|
||||
|
@ -114,8 +128,7 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
new MemoryAccessException("Cyclic Access");
|
||||
}
|
||||
ioPending = true;
|
||||
memMap.setBytes(mappedAddress.addNoWrap(offsetInSubBlock), b, off,
|
||||
len);
|
||||
byteMappingScheme.setBytes(memMap, mappedAddress, offsetInSubBlock, b, off, len);
|
||||
return len;
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
|
@ -126,8 +139,16 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
}
|
||||
}
|
||||
|
||||
public AddressRange getMappedRange() {
|
||||
Address endMappedAddress = mappedAddress.add(subBlockLength - 1);
|
||||
AddressRange getMappedRange() {
|
||||
Address endMappedAddress;
|
||||
try {
|
||||
endMappedAddress =
|
||||
byteMappingScheme.getMappedSourceAddress(mappedAddress, subBlockLength - 1);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
// keep things happy
|
||||
endMappedAddress = mappedAddress.getAddressSpace().getMaxAddress();
|
||||
}
|
||||
return new AddressRangeImpl(mappedAddress, endMappedAddress);
|
||||
}
|
||||
|
||||
|
@ -148,6 +169,17 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
|
||||
@Override
|
||||
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
|
||||
int offset = (int) (memBlockOffset - subBlockOffset);
|
||||
long newLength = subBlockLength - offset;
|
||||
|
@ -167,45 +199,7 @@ class ByteMappedSubMemoryBlock extends SubMemoryBlock {
|
|||
|
||||
@Override
|
||||
protected String getDescription() {
|
||||
return "Byte Mapped: " + mappedAddress;
|
||||
}
|
||||
|
||||
@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;
|
||||
return "Byte Mapped: " + mappedAddress + ", " + byteMappingScheme;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -18,8 +18,7 @@ package ghidra.program.database.mem;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
super(adapter, record);
|
||||
long fileBytesID = record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_ID_COL);
|
||||
fileBytesOffset = record.getLongValue(MemoryMapDBAdapter.SUB_SOURCE_OFFSET_COL);
|
||||
long fileBytesID = record.getLongValue(MemoryMapDBAdapter.SUB_INT_DATA1_COL);
|
||||
fileBytesOffset = record.getLongValue(MemoryMapDBAdapter.SUB_LONG_DATA2_COL);
|
||||
fileBytes = adapter.getMemoryMap().getLayeredFileBytes(fileBytesID);
|
||||
}
|
||||
|
||||
|
@ -95,11 +94,6 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
|
|||
return fileBytesOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryBlockType getType() {
|
||||
return MemoryBlockType.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SubMemoryBlock split(long memBlockOffset) throws IOException {
|
||||
// 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);
|
||||
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,
|
||||
MemoryMapDBAdapter.SUB_TYPE_FILE_BYTES, fileBytesID, fileBytesOffset + offset);
|
||||
|
||||
|
@ -129,14 +123,4 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import ghidra.util.exception.AssertException;
|
|||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class MemoryBlockDB implements MemoryBlock {
|
||||
|
||||
private MemoryMapDBAdapter adapter;
|
||||
protected Record record;
|
||||
private Address startAddress;
|
||||
|
@ -40,6 +41,8 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
private long id;
|
||||
private SubMemoryBlock lastSubBlock;
|
||||
|
||||
private List<MemoryBlockDB> mappedBlocks; // list of mapped blocks which map onto this block
|
||||
|
||||
MemoryBlockDB(MemoryMapDBAdapter adapter, Record record, List<SubMemoryBlock> subBlocks) {
|
||||
this.adapter = adapter;
|
||||
this.record = record;
|
||||
|
@ -74,6 +77,33 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
lastSubBlock = null;
|
||||
Collections.sort(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
|
||||
|
@ -130,8 +160,12 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
memMap.lock.acquire();
|
||||
try {
|
||||
checkValid();
|
||||
if (oldName.equals(name)) {
|
||||
return;
|
||||
}
|
||||
memMap.checkBlockName(name);
|
||||
try {
|
||||
if (getStart().getAddressSpace().isOverlaySpace()) {
|
||||
if (isOverlay()) {
|
||||
memMap.overlayBlockRenamed(oldName, name);
|
||||
}
|
||||
record.setString(MemoryMapDBAdapter.NAME_COL, name);
|
||||
|
@ -394,12 +428,14 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
|
||||
@Override
|
||||
public MemoryBlockType getType() {
|
||||
if (startAddress.getAddressSpace().isOverlaySpace()) {
|
||||
return MemoryBlockType.OVERLAY;
|
||||
}
|
||||
return subBlocks.get(0).getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverlay() {
|
||||
return startAddress.getAddressSpace().isOverlaySpace();
|
||||
}
|
||||
|
||||
public byte getByte(long offset) throws MemoryAccessException {
|
||||
SubMemoryBlock subBlock = getSubBlock(offset);
|
||||
try {
|
||||
|
@ -585,7 +621,7 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
throw new IllegalArgumentException("offset " + offset + " not in this block");
|
||||
}
|
||||
|
||||
public void initializeBlock(byte initialValue) throws IOException {
|
||||
void initializeBlock(byte initialValue) throws IOException {
|
||||
lastSubBlock = null;
|
||||
for (SubMemoryBlock subBlock : subBlocks) {
|
||||
subBlock.delete();
|
||||
|
@ -687,30 +723,4 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,33 +35,21 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
|
|||
this.subBlock = subBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public long getLength() {
|
||||
return subBlock.subBlockLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Address getMinAddress() {
|
||||
return block.getStart().add(subBlock.subBlockOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Address getMaxAddress() {
|
||||
return block.getStart().add(subBlock.subBlockOffset + subBlock.subBlockLength - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return subBlock.getDescription();
|
||||
|
@ -74,9 +62,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Optional<FileBytes> getFileBytes() {
|
||||
if (subBlock instanceof FileBytesSubMemoryBlock) {
|
||||
|
@ -85,9 +70,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public long getFileBytesOffset() {
|
||||
if (subBlock instanceof FileBytesSubMemoryBlock) {
|
||||
|
@ -96,10 +78,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public long getFileBytesOffset(Address address) {
|
||||
if (subBlock instanceof FileBytesSubMemoryBlock && contains(address)) {
|
||||
|
@ -110,9 +88,6 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Optional<AddressRange> getMappedRange() {
|
||||
if (subBlock instanceof BitMappedSubMemoryBlock) {
|
||||
|
@ -126,18 +101,20 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Optional<ByteMappingScheme> getByteMappingScheme() {
|
||||
if (subBlock instanceof ByteMappedSubMemoryBlock) {
|
||||
ByteMappedSubMemoryBlock byteMapped = (ByteMappedSubMemoryBlock) subBlock;
|
||||
return Optional.of(byteMapped.getByteMappingScheme());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryBlock getMemoryBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(Address address) {
|
||||
return address.compareTo(getMinAddress()) >= 0 && address.compareTo(getMaxAddress()) <= 0;
|
||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.program.util.ChangeManager;
|
|||
import ghidra.util.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
Lock lock;
|
||||
private Set<MemoryBlock> potentialOverlappingBlocks;
|
||||
|
||||
private static Comparator<Object> BLOCK_ADDRESS_COMPARATOR = (o1, o2) -> {
|
||||
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
|
||||
// blocks we need the address sets for the non-mapped blocks to be complete
|
||||
for (MemoryBlockDB block : blocks) {
|
||||
block.clearMappedBlockList();
|
||||
if (!block.isMapped()) {
|
||||
addBlockAddresses(block);
|
||||
addBlockAddresses(block, false);
|
||||
}
|
||||
}
|
||||
// process all mapped blocks after non-mapped-blocks above
|
||||
for (MemoryBlockDB block : blocks) {
|
||||
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());
|
||||
addrSet = addrSet.union(blockSet);
|
||||
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(
|
||||
getMappedIntersection(block, initializedLoadedAddrSet));
|
||||
|
||||
}
|
||||
else if (block.isInitialized()) {
|
||||
allInitializedAddrSet = allInitializedAddrSet.union(blockSet);
|
||||
if (block.isLoaded()) {
|
||||
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();
|
||||
lastBlock = null;
|
||||
blocks = newBlocks;
|
||||
addrMap.memoryMapChanged(this);
|
||||
nameBlockMap = new HashMap<>();
|
||||
executeSet = null;
|
||||
addrMap.memoryMapChanged(this);
|
||||
}
|
||||
|
||||
public void setLanguage(Language newLanguage) {
|
||||
|
@ -223,6 +285,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
/**
|
||||
* Returns the address factory for the program.
|
||||
* @return program address factory
|
||||
*/
|
||||
AddressFactory getAddressFactory() {
|
||||
return addrMap.getAddressFactory();
|
||||
|
@ -230,6 +293,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
/**
|
||||
* Returns the AddressMap from the program.
|
||||
* @return program address map
|
||||
*/
|
||||
AddressMapDB getAddressMap() {
|
||||
return addrMap;
|
||||
|
@ -255,34 +319,90 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
void checkMemoryWrite(MemoryBlockDB block, Address start, long length)
|
||||
throws MemoryAccessException {
|
||||
checkRangeForInstructions(start, start.add(length - 1));
|
||||
|
||||
Set<MemoryBlock> overlappingBlocks = getPotentialOverlappingBlocks();
|
||||
ByteSourceRangeList changeingByteSource = block.getByteSourceRangeList(start, length);
|
||||
if (overlappingBlocks.contains(block)) {
|
||||
for (MemoryBlock b : overlappingBlocks) {
|
||||
if (b.equals(block)) {
|
||||
continue;
|
||||
}
|
||||
ByteSourceRangeList set =
|
||||
((MemoryBlockDB) b).getByteSourceRangeList(b.getStart(), b.getSize());
|
||||
ByteSourceRangeList intersect = set.intersect(changeingByteSource);
|
||||
for (ByteSourceRange range : intersect) {
|
||||
checkRangeForInstructions(range.getStart(), range.getEnd());
|
||||
}
|
||||
if (!block.contains(start)) {
|
||||
throw new MemoryAccessException(
|
||||
block.getName() + " does not contain address " + start.toString(true));
|
||||
}
|
||||
|
||||
try {
|
||||
Address endAddr = start.addNoWrap(length - 1);
|
||||
if (!block.contains(start)) {
|
||||
throw new MemoryAccessException(block.getName() + " does not contain range " +
|
||||
start.toString(true) + "-" + endAddr);
|
||||
}
|
||||
|
||||
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() {
|
||||
if (potentialOverlappingBlocks == null) {
|
||||
ByteSourceRangeList byteSourceList = new ByteSourceRangeList();
|
||||
for (MemoryBlockDB block : blocks) {
|
||||
byteSourceList.add(block.getByteSourceRangeList(block.getStart(), block.getSize()));
|
||||
}
|
||||
potentialOverlappingBlocks = byteSourceList.getOverlappingBlocks();
|
||||
private void checkMemoryWriteMappedBlock(MemoryBlockDB mappedBlock, Address start,
|
||||
Address endAddr)
|
||||
throws AddressOverflowException, MemoryAccessException {
|
||||
long startOffset = start.subtract(mappedBlock.getStart());
|
||||
long endOffset = endAddr.subtract(mappedBlock.getStart());
|
||||
|
||||
// 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
|
||||
|
@ -362,8 +482,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
/**
|
||||
* Two blocks have been joined producing newBlock. The block which was
|
||||
* eliminated can be identified using the oldBlockStartAddr.
|
||||
* @param newBlock
|
||||
* @param oldBlockStartAddr
|
||||
* @param newBlock new joined memory block
|
||||
* @param oldBlockStartAddr original start address of affected block
|
||||
*/
|
||||
void fireBlocksJoined(MemoryBlock newBlock, Address oldBlockStartAddr) {
|
||||
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,
|
||||
long length, TaskMonitor monitor, boolean overlay) throws MemoryConflictException,
|
||||
AddressOverflowException, CancelledException, LockException, DuplicateNameException {
|
||||
Objects.requireNonNull(name);
|
||||
checkBlockName(name);
|
||||
lock.acquire();
|
||||
try {
|
||||
checkBlockSize(length, true);
|
||||
|
@ -496,7 +616,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
MemoryBlockDB newBlock =
|
||||
adapter.createInitializedBlock(name, start, is, length, MemoryBlock.READ);
|
||||
initializeBlocks();
|
||||
addBlockAddresses(newBlock);
|
||||
addBlockAddresses(newBlock, !overlay);
|
||||
fireBlockAdded(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
@ -523,7 +643,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
long offset, long length, boolean overlay) throws LockException, DuplicateNameException,
|
||||
MemoryConflictException, AddressOverflowException, IndexOutOfBoundsException {
|
||||
|
||||
Objects.requireNonNull(name);
|
||||
checkBlockName(name);
|
||||
lock.acquire();
|
||||
try {
|
||||
checkBlockSize(length, true);
|
||||
|
@ -540,7 +660,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
MemoryBlockDB newBlock = adapter.createFileBytesBlock(name, start, length,
|
||||
fileBytes, offset, MemoryBlock.READ);
|
||||
initializeBlocks();
|
||||
addBlockAddresses(newBlock);
|
||||
addBlockAddresses(newBlock, !overlay);
|
||||
fireBlockAdded(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
@ -576,7 +696,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
boolean overlay) throws MemoryConflictException, AddressOverflowException,
|
||||
LockException, DuplicateNameException {
|
||||
|
||||
Objects.requireNonNull(name);
|
||||
checkBlockName(name);
|
||||
lock.acquire();
|
||||
try {
|
||||
checkBlockSize(size, false);
|
||||
|
@ -591,9 +711,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
try {
|
||||
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.DEFAULT, name, start,
|
||||
size, null, false, MemoryBlock.READ);
|
||||
size, null, false, MemoryBlock.READ, 0);
|
||||
initializeBlocks();
|
||||
addBlockAddresses(newBlock);
|
||||
addBlockAddresses(newBlock, false);
|
||||
fireBlockAdded(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
@ -608,21 +728,27 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MemoryBlock createBitMappedBlock(String name, Address start, Address overlayAddress,
|
||||
long length) throws MemoryConflictException, AddressOverflowException, LockException {
|
||||
public MemoryBlock createBitMappedBlock(String name, Address start, Address mappedAddress,
|
||||
long length, boolean overlay) throws MemoryConflictException, AddressOverflowException,
|
||||
LockException, IllegalArgumentException, DuplicateNameException {
|
||||
|
||||
Objects.requireNonNull(name);
|
||||
checkBlockName(name);
|
||||
lock.acquire();
|
||||
try {
|
||||
checkBlockSize(length, false);
|
||||
program.checkExclusiveAccess();
|
||||
checkRange(start, length);
|
||||
overlayAddress.addNoWrap((length - 1) / 8);// just to check if length fits in address space
|
||||
mappedAddress.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 {
|
||||
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BIT_MAPPED, name,
|
||||
start, length, overlayAddress, false, MemoryBlock.READ);
|
||||
start, length, mappedAddress, false, MemoryBlock.READ, 0);
|
||||
initializeBlocks();
|
||||
addBlockAddresses(newBlock);
|
||||
addBlockAddresses(newBlock, false);
|
||||
fireBlockAdded(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
@ -637,21 +763,37 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MemoryBlock createByteMappedBlock(String name, Address start, Address overlayAddress,
|
||||
long length) throws MemoryConflictException, AddressOverflowException, LockException {
|
||||
public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress,
|
||||
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();
|
||||
try {
|
||||
checkBlockSize(length, false);
|
||||
program.checkExclusiveAccess();
|
||||
checkRange(start, length);
|
||||
overlayAddress.addNoWrap(length - 1);// just to check if length fits in address space
|
||||
byteMappingScheme.getMappedSourceAddress(mappedAddress, length - 1); // source fit check
|
||||
if (overlay) {
|
||||
start = createOverlaySpace(name, start, length);
|
||||
}
|
||||
else {
|
||||
checkRange(start, length);
|
||||
}
|
||||
try {
|
||||
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BYTE_MAPPED, name,
|
||||
start, length, overlayAddress, false, MemoryBlock.READ);
|
||||
start, length, mappedAddress, false, MemoryBlock.READ, mappingScheme);
|
||||
initializeBlocks();
|
||||
addBlockAddresses(newBlock);
|
||||
addBlockAddresses(newBlock, false);
|
||||
fireBlockAdded(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
@ -665,27 +807,46 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
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
|
||||
public MemoryBlock createBlock(MemoryBlock block, String name, Address start, long length)
|
||||
throws MemoryConflictException, AddressOverflowException, LockException {
|
||||
|
||||
Objects.requireNonNull(name);
|
||||
throws MemoryConflictException, AddressOverflowException, LockException,
|
||||
DuplicateNameException {
|
||||
checkBlockName(name);
|
||||
lock.acquire();
|
||||
try {
|
||||
checkBlockSize(length, block.isInitialized());
|
||||
program.checkExclusiveAccess();
|
||||
checkRange(start, length);
|
||||
|
||||
try {
|
||||
Address overlayAddr = null;
|
||||
Address mappedAddr = null;
|
||||
int mappingScheme = 0;
|
||||
if (block.isMapped()) {
|
||||
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,
|
||||
overlayAddr, block.isInitialized(), block.getPermissions());
|
||||
mappedAddr, block.isInitialized(), block.getPermissions(), mappingScheme);
|
||||
initializeBlocks();
|
||||
addBlockAddresses(newBlock);
|
||||
addBlockAddresses(newBlock, !block.isMapped() && block.isInitialized());
|
||||
fireBlockAdded(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
@ -731,7 +892,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
MemoryBlockDB memBlock = (MemoryBlockDB) block;
|
||||
|
||||
Address oldStartAddr = block.getStart();
|
||||
if (block.getType() == MemoryBlockType.OVERLAY) {
|
||||
if (block.isOverlay()) {
|
||||
throw new IllegalArgumentException("Overlay blocks cannot be moved");
|
||||
}
|
||||
if (newStartAddr.getAddressSpace().isOverlaySpace()) {
|
||||
|
@ -788,9 +949,21 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
if (addr.equals(memBlock.getStart())) {
|
||||
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");
|
||||
}
|
||||
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) {
|
||||
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)
|
||||
throws MemoryBlockException, NotFoundException, LockException {
|
||||
throws MemoryBlockException, LockException {
|
||||
|
||||
program.checkExclusiveAccess();
|
||||
if (liveMemory != null) {
|
||||
|
@ -874,16 +1047,11 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
private void checkBlockForJoining(MemoryBlock block) {
|
||||
checkBlock(block);
|
||||
switch (block.getType()) {
|
||||
case BIT_MAPPED:
|
||||
throw new IllegalArgumentException("Cannot join bit mapped blocks");
|
||||
case BYTE_MAPPED:
|
||||
throw new IllegalArgumentException("Cannot join byte mapped blocks");
|
||||
case OVERLAY:
|
||||
throw new IllegalArgumentException("Cannot join overlay blocks");
|
||||
case DEFAULT:
|
||||
default:
|
||||
// do nothing, these types are ok for joining
|
||||
if (block.isOverlay()) {
|
||||
throw new IllegalArgumentException("Cannot join overlay blocks");
|
||||
}
|
||||
if (block.isMapped()) {
|
||||
throw new IllegalArgumentException("Cannot join mapped blocks");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -909,8 +1077,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
throw new IllegalArgumentException(
|
||||
"Only an Uninitialized Block may be converted to an Initialized Block");
|
||||
}
|
||||
MemoryBlockType type = unitializedBlock.getType();
|
||||
if (!((type == MemoryBlockType.DEFAULT) || (type == MemoryBlockType.OVERLAY))) {
|
||||
if (unitializedBlock.getType() != MemoryBlockType.DEFAULT) {
|
||||
throw new IllegalArgumentException("Block is of a type that cannot be initialized");
|
||||
}
|
||||
long size = unitializedBlock.getSize();
|
||||
|
@ -922,6 +1089,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
memBlock.initializeBlock(initialValue);
|
||||
allInitializedAddrSet.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);
|
||||
fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize());
|
||||
return memBlock;
|
||||
|
@ -949,16 +1120,20 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
throw new IllegalArgumentException(
|
||||
"Only an Initialized Block may be converted to an Uninitialized Block");
|
||||
}
|
||||
MemoryBlockType type = initializedBlock.getType();
|
||||
if (!((type == MemoryBlockType.DEFAULT) || (type == MemoryBlockType.OVERLAY))) {
|
||||
if (initializedBlock.getType() != MemoryBlockType.DEFAULT) {
|
||||
throw new IllegalArgumentException(
|
||||
"Block is of a type that cannot be uninitialized");
|
||||
}
|
||||
MemoryBlockDB memBlock = (MemoryBlockDB) initializedBlock;
|
||||
try {
|
||||
// FIXME: clear instructions in initializedBlock or any block which maps to it
|
||||
memBlock.uninitializeBlock();
|
||||
allInitializedAddrSet.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);
|
||||
fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize());
|
||||
return memBlock;
|
||||
|
@ -979,7 +1154,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
public Address findBytes(Address addr, byte[] bytes, byte[] masks, boolean forward,
|
||||
TaskMonitor monitor) {
|
||||
if (monitor == null) {
|
||||
monitor = TaskMonitorAdapter.DUMMY_MONITOR;
|
||||
monitor = TaskMonitor.DUMMY;
|
||||
}
|
||||
|
||||
AddressIterator it = initializedLoadedAddrSet.getAddresses(addr, forward);
|
||||
|
@ -997,6 +1172,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
monitor.incrementProgress(-moffset);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
// ignore
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1025,7 +1201,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
public Address findBytes(Address startAddr, Address endAddr, byte[] bytes, byte[] masks,
|
||||
boolean forward, TaskMonitor monitor) {
|
||||
if (monitor == null) {
|
||||
monitor = TaskMonitorAdapter.DUMMY_MONITOR;
|
||||
monitor = TaskMonitor.DUMMY;
|
||||
}
|
||||
AddressIterator it = allInitializedAddrSet.getAddresses(startAddr, forward);
|
||||
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
|
||||
* removes the space.
|
||||
* @param addressSpace
|
||||
* @param addressSpace overlay address space to be removed
|
||||
*/
|
||||
private void checkRemoveAddressSpace(AddressSpace addressSpace) {
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
* @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();
|
||||
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||
List<MemoryBlockSourceInfo> sourceInfos = mappedBlock.getSourceInfos();
|
||||
// mapped blocks can only ever have one sourceInfo
|
||||
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||
AddressRange range = info.getMappedRange().get();
|
||||
AddressSet resolvedIntersection = set.intersect(new AddressSet(range));
|
||||
for (AddressRange resolvedRange : resolvedIntersection) {
|
||||
mappedIntersection.add(getMappedRange(block, resolvedRange));
|
||||
AddressRange mappedRange = getMappedRange(mappedBlock, resolvedRange);
|
||||
if (mappedRange != null) {
|
||||
mappedIntersection.add(mappedRange);
|
||||
}
|
||||
}
|
||||
return mappedIntersection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0);
|
||||
long startOffset =
|
||||
resolvedRange.getMinAddress().subtract(info.getMappedRange().get().getMinAddress());
|
||||
boolean isBitMapped = mappedBlock.getType() == MemoryBlockType.BIT_MAPPED;
|
||||
if (isBitMapped) {
|
||||
start = mappedBlock.getStart().add(startOffset * 8);
|
||||
end = start.add((resolvedRange.getLength() * 8) - 1);
|
||||
long sourceRangeLength = mappedSourceRange.getLength();
|
||||
if (sourceRangeLength <= 0) {
|
||||
throw new AssertException("invalid mapped source range length");
|
||||
}
|
||||
else {
|
||||
start = mappedBlock.getStart().add(startOffset);
|
||||
end = start.add(resolvedRange.getLength() - 1);
|
||||
MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -46,8 +46,30 @@ abstract class MemoryMapDBAdapter {
|
|||
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_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_BYTE_MAPPED = MemoryMapDBAdapterV3.V3_SUB_TYPE_BYTE_MAPPED;
|
||||
|
@ -121,7 +143,7 @@ abstract class MemoryMapDBAdapter {
|
|||
}
|
||||
newBlock =
|
||||
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.setSourceName(block.getSourceName());
|
||||
|
@ -192,16 +214,19 @@ abstract class MemoryMapDBAdapter {
|
|||
* @param name the name of the block.
|
||||
* @param startAddr the start address 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 initializeBytes if true, creates a database buffer for the bytes in the block
|
||||
* @param mappedAddress the starting byte source address at which to map
|
||||
* 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 encodedMappingScheme byte mapping scheme (used by byte-mapped blocks only)
|
||||
* @return new memory block
|
||||
* @throws IOException if a database IO error occurs.
|
||||
* @throws AddressOverflowException if block length is too large for the underlying space
|
||||
*/
|
||||
abstract MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr,
|
||||
long length, Address mappedAddress, boolean initializeBytes, int permissions)
|
||||
throws AddressOverflowException, IOException;
|
||||
long length, Address mappedAddress, boolean initializeBytes, int permissions,
|
||||
int encodedMappingScheme) throws AddressOverflowException, IOException;
|
||||
|
||||
/**
|
||||
* Deletes the given memory block.
|
||||
|
@ -253,15 +278,13 @@ abstract class MemoryMapDBAdapter {
|
|||
* sub block starts
|
||||
* @param length the length of this sub block
|
||||
* @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,
|
||||
* then this is the FileBytes id.
|
||||
* @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.
|
||||
* @param data1 subblock implementation specific integer data
|
||||
* @param data2 subblock implementation specific long data
|
||||
* @return the newly created record.
|
||||
* @throws IOException if a database error occurs
|
||||
*/
|
||||
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.
|
||||
|
|
|
@ -156,7 +156,7 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter {
|
|||
return new ByteMappedSubMemoryBlock(this, record);
|
||||
case MemoryMapDBAdapterV2.INITIALIZED:
|
||||
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);
|
||||
case MemoryMapDBAdapterV2.UNINITIALIZED:
|
||||
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_UNITIALIZED);
|
||||
|
@ -223,7 +223,8 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter {
|
|||
|
||||
@Override
|
||||
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 {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -253,7 +254,7 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter {
|
|||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -124,15 +124,15 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter {
|
|||
switch (type) {
|
||||
case MemoryMapDBAdapterV2.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);
|
||||
case MemoryMapDBAdapterV2.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);
|
||||
case MemoryMapDBAdapterV2.INITIALIZED:
|
||||
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);
|
||||
case MemoryMapDBAdapterV2.UNINITIALIZED:
|
||||
record.setByteValue(SUB_TYPE_COL, SUB_TYPE_UNITIALIZED);
|
||||
|
@ -161,7 +161,8 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter {
|
|||
|
||||
@Override
|
||||
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 {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -216,7 +217,7 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter {
|
|||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
|
|||
public static final int V3_SUB_TYPE_COL = 1;
|
||||
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_SOURCE_ID_COL = 4;
|
||||
public static final int V3_SUB_SOURCE_OFFSET_COL = 5;
|
||||
public static final int V3_SUB_INT_DATA1_COL = 4;
|
||||
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_BYTE_MAPPED = 1;
|
||||
|
@ -186,17 +186,19 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
|
|||
|
||||
@Override
|
||||
MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr,
|
||||
long length, Address mappedAddress, boolean initializeBytes, int permissions)
|
||||
throws AddressOverflowException, IOException {
|
||||
long length, Address mappedAddress, boolean initializeBytes, int permissions,
|
||||
int encodedMappingScheme) throws AddressOverflowException, IOException {
|
||||
|
||||
if (initializeBytes) {
|
||||
return createInitializedBlock(name, startAddr, null, length, permissions);
|
||||
}
|
||||
else if (blockType == MemoryBlockType.BIT_MAPPED) {
|
||||
if (blockType == MemoryBlockType.BIT_MAPPED) {
|
||||
return createBitMappedBlock(name, startAddr, length, mappedAddress, permissions);
|
||||
}
|
||||
else if (blockType == MemoryBlockType.BYTE_MAPPED) {
|
||||
return createByteMappedBlock(name, startAddr, length, mappedAddress, permissions);
|
||||
if (blockType == MemoryBlockType.BYTE_MAPPED) {
|
||||
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);
|
||||
}
|
||||
|
@ -265,13 +267,14 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
|
|||
MemoryBlockDB createBitMappedBlock(String name, Address startAddress, long length,
|
||||
Address mappedAddress, int permissions) throws IOException, AddressOverflowException {
|
||||
return createMappedBlock(V3_SUB_TYPE_BIT_MAPPED, name, startAddress, length, mappedAddress,
|
||||
permissions);
|
||||
permissions, 0);
|
||||
}
|
||||
|
||||
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,
|
||||
permissions);
|
||||
permissions, mappingScheme);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -296,7 +299,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
|
|||
}
|
||||
|
||||
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 {
|
||||
updateAddressMapForAllAddresses(startAddress, length);
|
||||
|
||||
|
@ -305,7 +309,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
|
|||
long key = blockRecord.getKey();
|
||||
|
||||
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));
|
||||
|
||||
memBlockTable.putRecord(blockRecord);
|
||||
|
@ -350,15 +354,15 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
|
|||
|
||||
@Override
|
||||
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.setLongValue(V3_SUB_PARENT_ID_COL, parentKey);
|
||||
record.setByteValue(V3_SUB_TYPE_COL, type);
|
||||
record.setLongValue(V3_SUB_LENGTH_COL, length);
|
||||
record.setLongValue(V3_SUB_START_OFFSET_COL, startingOffset);
|
||||
record.setIntValue(V3_SUB_SOURCE_ID_COL, sourceId);
|
||||
record.setLongValue(V3_SUB_SOURCE_OFFSET_COL, sourceOffset);
|
||||
record.setIntValue(V3_SUB_INT_DATA1_COL, data1);
|
||||
record.setLongValue(V3_SUB_LONG_DATA2_COL, data2);
|
||||
subBlockTable.putRecord(record);
|
||||
|
||||
return record;
|
||||
|
|
|
@ -18,8 +18,6 @@ package ghidra.program.database.mem;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
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
|
||||
|
@ -238,18 +238,6 @@ abstract class SubMemoryBlock implements Comparable<SubMemoryBlock> {
|
|||
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
|
||||
public int compareTo(SubMemoryBlock o) {
|
||||
long result = getStartingOffset() - o.getStartingOffset();
|
||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.program.database.mem;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
/**
|
||||
* Implementation of SubMemoryBlock for uninitialized blocks.
|
||||
|
@ -28,7 +27,6 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
|
|||
|
||||
UninitializedSubMemoryBlock(MemoryMapDBAdapter adapter, Record record) {
|
||||
super(adapter, record);
|
||||
subBlockOffset = record.getLongValue(MemoryMapDBAdapter.SUB_START_OFFSET_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,12 +51,12 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
|
|||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
|
@ -71,11 +69,6 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryBlockType getType() {
|
||||
return MemoryBlockType.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SubMemoryBlock split(long memBlockOffset) throws IOException {
|
||||
// convert from offset in block to offset in this sub block
|
||||
|
@ -96,11 +89,4 @@ class UninitializedSubMemoryBlock extends SubMemoryBlock {
|
|||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteSourceRangeList getByteSourceRangeList(MemoryBlock block, Address start,
|
||||
long memBlockOffset,
|
||||
long size) {
|
||||
return new ByteSourceRangeList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -406,4 +406,23 @@ public interface Address extends Comparable<Address> {
|
|||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,4 +172,9 @@ public class AddressSetViewAdapter implements AddressSetView {
|
|||
public Address findFirstAddressInCommon(AddressSetView otherSet) {
|
||||
return set.findFirstAddressInCommon(otherSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return set.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ import java.io.InputStream;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.mem.AddressSourceInfo;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.database.mem.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.*;
|
||||
|
@ -109,7 +108,8 @@ public interface Memory extends AddressSetView {
|
|||
|
||||
/**
|
||||
* 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 is source of the data used to fill the block or null for zero initialization.
|
||||
* @param length the size of the block
|
||||
|
@ -124,43 +124,45 @@ public interface Memory extends AddressSetView {
|
|||
* @throws AddressOverflowException if the start is beyond the
|
||||
* address space
|
||||
* @throws CancelledException user cancelled operation
|
||||
* @throws DuplicateNameException if overlay is true and there is already an overlay address
|
||||
* space with the same name as this memory block
|
||||
* @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, InputStream is,
|
||||
long length, TaskMonitor monitor, boolean overlay)
|
||||
throws LockException, MemoryConflictException, AddressOverflowException,
|
||||
CancelledException, DuplicateNameException;
|
||||
CancelledException, IllegalArgumentException, DuplicateNameException;
|
||||
|
||||
/**
|
||||
* 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 size block length (positive non-zero value required)
|
||||
* @param initialValue initialization value for every byte in the block.
|
||||
* @param monitor progress monitor, may be null.
|
||||
* @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 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
|
||||
* @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 MemoryConflictException if the new block overlaps with a
|
||||
* previous block
|
||||
* @throws AddressOverflowException if the start is beyond the
|
||||
* 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
|
||||
*/
|
||||
public MemoryBlock createInitializedBlock(String name, Address start, long size,
|
||||
byte initialValue, TaskMonitor monitor, boolean overlay)
|
||||
throws LockException, DuplicateNameException, MemoryConflictException,
|
||||
AddressOverflowException, CancelledException;
|
||||
throws LockException, IllegalArgumentException, DuplicateNameException,
|
||||
MemoryConflictException, AddressOverflowException, CancelledException;
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
|
@ -170,86 +172,138 @@ public interface Memory extends AddressSetView {
|
|||
* offset as the given start address parameter, but in the new address space.
|
||||
* @return new Initialized Memory Block
|
||||
* @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
|
||||
* previous block
|
||||
* @throws AddressOverflowException if the start is beyond the address space
|
||||
* @throws IndexOutOfBoundsException if file bytes range specified by offset and size
|
||||
* 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,
|
||||
long offset, long size, boolean overlay) throws LockException, DuplicateNameException,
|
||||
MemoryConflictException, AddressOverflowException;
|
||||
long offset, long size, boolean overlay) throws LockException, IllegalArgumentException,
|
||||
DuplicateNameException, MemoryConflictException, AddressOverflowException;
|
||||
|
||||
/**
|
||||
* 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 size 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 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
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
* previous block
|
||||
* @throws AddressOverflowException if the start is beyond the
|
||||
* address space
|
||||
* @throws DuplicateNameException if overlay is true and there is already an overlay address
|
||||
* space with the same name as this memory block
|
||||
* @throws IllegalArgumentException if invalid block name specified
|
||||
* @throws DuplicateNameException if name conflicts with an existing address space/overlay name
|
||||
*/
|
||||
public MemoryBlock createUninitializedBlock(String name, Address start, long size,
|
||||
boolean overlay) throws LockException, DuplicateNameException, MemoryConflictException,
|
||||
AddressOverflowException;
|
||||
boolean overlay) throws LockException, IllegalArgumentException, DuplicateNameException,
|
||||
MemoryConflictException, AddressOverflowException;
|
||||
|
||||
/**
|
||||
* 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 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 MemoryConflictException if the new block overlaps with a
|
||||
* previous block
|
||||
* @throws AddressOverflowException if the start is beyond the
|
||||
* address space
|
||||
* @throws AddressOverflowException if block specification exceeds bounds of 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,
|
||||
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.
|
||||
* @param name block name
|
||||
* 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 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
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
* previous block
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* 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 name block name
|
||||
* @param name block name (See {@link Memory#isValidAddressSpaceName(String)} for
|
||||
* naming rules).
|
||||
* @param start start of the block
|
||||
* @param length the size of the new block.
|
||||
* @return new block
|
||||
* @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
|
||||
* 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)
|
||||
throws LockException, MemoryConflictException, AddressOverflowException;
|
||||
throws LockException, IllegalArgumentException, MemoryConflictException,
|
||||
AddressOverflowException, DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Remove the memory block.
|
||||
|
@ -760,4 +814,23 @@ public interface Memory extends AddressSetView {
|
|||
* null if the address is not in memory.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.NamingUtilities;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
|
@ -86,12 +87,15 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
|||
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.
|
||||
* @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
|
||||
*/
|
||||
public void setName(String name) throws DuplicateNameException, LockException;
|
||||
public void setName(String name)
|
||||
throws IllegalArgumentException, DuplicateNameException, LockException;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
|
@ -255,6 +259,12 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
|||
*/
|
||||
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
|
||||
* containing file header data such as debug sections.
|
||||
|
@ -285,5 +295,4 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
|||
MemoryBlock block = memory.getBlock(address);
|
||||
return block != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.program.model.mem;
|
|||
|
||||
import java.util.Optional;
|
||||
|
||||
import ghidra.program.database.mem.ByteMappingScheme;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
|
@ -75,13 +76,20 @@ public interface MemoryBlockSourceInfo {
|
|||
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.
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* @return the containing Memory Block
|
||||
|
|
|
@ -129,6 +129,11 @@ public class MemoryBlockStub implements MemoryBlock {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverlay() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -20,8 +20,7 @@ public enum MemoryBlockType {
|
|||
//@formatter:off
|
||||
DEFAULT("Default"),
|
||||
BIT_MAPPED("Bit Mapped"),
|
||||
BYTE_MAPPED("Byte Mapped"),
|
||||
OVERLAY("Overlay");
|
||||
BYTE_MAPPED("Byte Mapped");
|
||||
//@formatter:on
|
||||
|
||||
private String name;
|
||||
|
|
|
@ -21,8 +21,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.mem.AddressSourceInfo;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.database.mem.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.*;
|
||||
|
@ -235,13 +234,16 @@ public class MemoryStub implements Memory {
|
|||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -142,7 +142,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
assertEquals(0, block.getStart().getOffset());
|
||||
assertEquals(9, block.getEnd().getOffset());
|
||||
assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
|
||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||
assertTrue(block.isOverlay());
|
||||
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||
assertEquals(1, sourceInfos.size());
|
||||
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||
|
@ -167,7 +168,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
assertEquals(0, block.getStart().getOffset());
|
||||
assertEquals(9, block.getEnd().getOffset());
|
||||
assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
|
||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||
assertTrue(block.isOverlay());
|
||||
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||
assertEquals(1, sourceInfos.size());
|
||||
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||
|
@ -181,7 +183,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testCreateByteMappedBlock() throws Exception {
|
||||
mem.createInitializedBlock("test1", addr(0), 50, (byte) 1, TaskMonitor.DUMMY, 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("mapped", block.getName());
|
||||
|
@ -217,7 +219,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testCreateBitMappedBlock() throws Exception {
|
||||
mem.createInitializedBlock("test1", addr(0), 50, (byte) 1, TaskMonitor.DUMMY, 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("mapped", block.getName());
|
||||
|
@ -570,7 +572,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testByteMappedGetPutByte() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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, block1.getByte(addr(5)));
|
||||
mappedBlock.putByte(addr(105), (byte) 87);
|
||||
|
@ -581,7 +584,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testByteMappedGetPutBytes() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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];
|
||||
mappedBlock.getBytes(addr(100), bytes);
|
||||
checkBytes(bytes, 0);
|
||||
|
@ -595,8 +599,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testByteMappedJoin() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
MemoryBlock mappedBlock1 = mem.createByteMappedBlock("mapped1", addr(100), addr(0), 10);
|
||||
MemoryBlock mappedBlock2 = mem.createByteMappedBlock("mapped2", addr(110), addr(10), 10);
|
||||
MemoryBlock mappedBlock1 =
|
||||
mem.createByteMappedBlock("mapped1", addr(100), addr(0), 10, false);
|
||||
MemoryBlock mappedBlock2 =
|
||||
mem.createByteMappedBlock("mapped2", addr(110), addr(10), 10, false);
|
||||
try {
|
||||
mem.join(mappedBlock1, mappedBlock2);
|
||||
fail("Expected exception when joining byte mapped blocks");
|
||||
|
@ -610,7 +616,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testByteMappedSplit() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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));
|
||||
MemoryBlock[] blocks = mem.getBlocks();
|
||||
assertEquals(3, blocks.length);
|
||||
|
@ -621,7 +628,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testBitMappedGetPutByte() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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(101)));
|
||||
|
@ -637,7 +645,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testBitMappedGetPutBytes() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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];
|
||||
|
||||
|
@ -668,8 +677,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testBitMappedJoin() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
MemoryBlock mappedBlock1 = mem.createBitMappedBlock("mapped1", addr(100), addr(0), 16);
|
||||
MemoryBlock mappedBlock2 = mem.createBitMappedBlock("mapped2", addr(116), addr(2), 16);
|
||||
MemoryBlock mappedBlock1 =
|
||||
mem.createBitMappedBlock("mapped1", addr(100), addr(0), 16, false);
|
||||
MemoryBlock mappedBlock2 =
|
||||
mem.createBitMappedBlock("mapped2", addr(116), addr(2), 16, false);
|
||||
try {
|
||||
mem.join(mappedBlock1, mappedBlock2);
|
||||
fail("Expected exception when joining bit mapped blocks");
|
||||
|
@ -683,7 +694,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testBitMappedSplit() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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 {
|
||||
mem.split(mappedBlock1, addr(108));
|
||||
fail("Expected exception when joining bit mapped blocks");
|
||||
|
@ -693,200 +705,229 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceSetForFileBytesBlock() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
MemoryBlockDB block = (MemoryBlockDB) createFileBytesBlock(fileBytes, addr(0), 10, 50);
|
||||
// @Test
|
||||
// public void testGetByteSourceSetForFileBytesBlock() throws Exception {
|
||||
// FileBytes fileBytes = createFileBytes();
|
||||
// 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);
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceSetForBufferBlock() throws Exception {
|
||||
MemoryBlockDB block = (MemoryBlockDB) mem.createInitializedBlock("test", addr(0), 30,
|
||||
(byte) 1, TaskMonitor.DUMMY, false);
|
||||
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10);
|
||||
|
||||
// We expect to get to ranges because we made the buffer size small (16) so when we
|
||||
// created a 30 size block, it had to make two separate sub blocks each with its own
|
||||
// DBBuffer. The first range should contain the first 6 bytes of the requested range
|
||||
// and the second buffer should contain the last 4 bytes of request range.
|
||||
|
||||
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);
|
||||
assertEquals(10, range.getStart().getOffset());
|
||||
assertEquals(15, range.getEnd().getOffset());
|
||||
assertEquals(6, range.getSize());
|
||||
assertEquals(10, range.getOffset());
|
||||
|
||||
range = ranges.get(1);
|
||||
assertEquals(16, range.getStart().getOffset());
|
||||
assertEquals(19, range.getEnd().getOffset());
|
||||
assertEquals(4, range.getSize());
|
||||
assertEquals(0, range.getOffset());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForUndefinedBlock() throws Exception {
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createUninitializedBlock("test", addr(0), 30, false);
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10);
|
||||
// undefined blocks have no source bytes
|
||||
assertTrue(ranges.isEmpty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForByteMappedBlock() throws Exception {
|
||||
mem.createInitializedBlock("test1", addr(0), 15, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
mem.createUninitializedBlock("test2", addr(15), 20, false);
|
||||
mem.createInitializedBlock("test3", addr(35), 15, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createByteMappedBlock("mapped", addr(1000), addr(5), 40);
|
||||
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(1005), 30);
|
||||
|
||||
// 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());
|
||||
|
||||
ByteSourceRange range = ranges.get(0);
|
||||
assertEquals(addr(1005), range.getStart());
|
||||
assertEquals(addr(1009), range.getEnd());
|
||||
assertEquals(5, range.getSize());
|
||||
assertEquals(10, range.getOffset());
|
||||
|
||||
range = ranges.get(1);
|
||||
assertEquals(addr(1030), range.getStart());
|
||||
assertEquals(addr(1034), range.getEnd());
|
||||
assertEquals(5, range.getSize());
|
||||
assertEquals(0, range.getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForBitMappedBlock() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14);
|
||||
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1000), 0x14);
|
||||
|
||||
assertEquals(1, ranges.getRangeCount());
|
||||
assertEquals(3, ranges.get(0).getSize());
|
||||
|
||||
ByteSourceRange range = ranges.get(0);
|
||||
assertEquals(addr(0x1000), range.getStart());
|
||||
assertEquals(addr(0x1017), range.getEnd());
|
||||
assertEquals(3, range.getSize());
|
||||
assertEquals(5, range.getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForBitMappedBlockOffcutStart() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14);
|
||||
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1005), 8);
|
||||
|
||||
assertEquals(1, ranges.getRangeCount());
|
||||
assertEquals(2, ranges.get(0).getSize());
|
||||
|
||||
ByteSourceRange range = ranges.get(0);
|
||||
assertEquals(addr(0x1000), range.getStart());
|
||||
assertEquals(addr(0x100f), range.getEnd());
|
||||
assertEquals(2, range.getSize());
|
||||
assertEquals(5, range.getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForBitMappedBlockOffcutStartNotAtStart() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x44);
|
||||
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1015), 8);
|
||||
|
||||
assertEquals(1, ranges.getRangeCount());
|
||||
assertEquals(2, ranges.get(0).getSize());
|
||||
|
||||
ByteSourceRange range = ranges.get(0);
|
||||
assertEquals(addr(0x1010), range.getStart());
|
||||
assertEquals(addr(0x101f), range.getEnd());
|
||||
assertEquals(2, range.getSize());
|
||||
assertEquals(7, range.getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForBitMappedBlock2() throws Exception {
|
||||
mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
mem.createUninitializedBlock("test2", addr(0x4), 4, false);
|
||||
mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40);
|
||||
|
||||
ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1008), 0x30);
|
||||
|
||||
assertEquals(2, ranges.getRangeCount());
|
||||
|
||||
ByteSourceRange range = ranges.get(0);
|
||||
assertEquals(addr(0x1008), range.getStart());
|
||||
assertEquals(addr(0x100f), range.getEnd());
|
||||
assertEquals(1, range.getSize());
|
||||
assertEquals(3, range.getOffset());
|
||||
|
||||
range = ranges.get(1);
|
||||
assertEquals(addr(0x1030), range.getStart());
|
||||
assertEquals(addr(0x1037), range.getEnd());
|
||||
assertEquals(1, range.getSize());
|
||||
assertEquals(0, range.getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteSourceForBitMappedBlock2Offcut() throws Exception {
|
||||
mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
mem.createUninitializedBlock("test2", addr(0x4), 4, false);
|
||||
mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
MemoryBlockDB block =
|
||||
(MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40);
|
||||
|
||||
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
|
||||
// public void testGetByteSourceSetForBufferBlock() throws Exception {
|
||||
// MemoryBlockDB block = (MemoryBlockDB) mem.createInitializedBlock("test", addr(0), 30,
|
||||
// (byte) 1, TaskMonitor.DUMMY, false);
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10);
|
||||
//
|
||||
// // We expect to get to ranges because we made the buffer size small (16) so when we
|
||||
// // created a 30 size block, it had to make two separate sub blocks each with its own
|
||||
// // DBBuffer. The first range should contain the first 6 bytes of the requested range
|
||||
// // and the second buffer should contain the last 4 bytes of request range.
|
||||
//
|
||||
// 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);
|
||||
// assertEquals(10, range.getStart().getOffset());
|
||||
// assertEquals(15, range.getEnd().getOffset());
|
||||
// assertEquals(6, range.getSize());
|
||||
// assertEquals(10, range.getOffset());
|
||||
//
|
||||
// range = ranges.get(1);
|
||||
// assertEquals(16, range.getStart().getOffset());
|
||||
// assertEquals(19, range.getEnd().getOffset());
|
||||
// assertEquals(4, range.getSize());
|
||||
// assertEquals(0, range.getOffset());
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForUndefinedBlock() throws Exception {
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createUninitializedBlock("test", addr(0), 30, false);
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(10), 10);
|
||||
// // undefined blocks have no source bytes
|
||||
// assertTrue(ranges.isEmpty());
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForByteMappedBlock() throws Exception {
|
||||
// mem.createInitializedBlock("test1", addr(0), 15, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
// mem.createUninitializedBlock("test2", addr(15), 20, false);
|
||||
// mem.createInitializedBlock("test3", addr(35), 15, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createByteMappedBlock("mapped", addr(1000), addr(5), 40, false);
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(1005), 30); // 5, 20, 5
|
||||
//
|
||||
// // 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());
|
||||
//
|
||||
// ByteSourceRange range = ranges.get(0);
|
||||
// assertEquals(addr(1005), range.getStart());
|
||||
// assertEquals(addr(1009), range.getEnd());
|
||||
// assertEquals(5, range.getSize());
|
||||
// assertEquals(10, range.getOffset());
|
||||
//
|
||||
// range = ranges.get(1);
|
||||
// assertEquals(addr(1030), range.getStart());
|
||||
// assertEquals(addr(1034), range.getEnd());
|
||||
// assertEquals(5, range.getSize());
|
||||
// assertEquals(0, range.getOffset());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForByteMappedBlockWithScheme() throws Exception {
|
||||
// mem.createInitializedBlock("test1", addr(0), 15, (byte) 1, TaskMonitor.DUMMY, false); // mapped bytes: 5, 6, .. 9, 10, .. 13, (14
|
||||
// mem.createUninitializedBlock("test2", addr(15), 20, false); // mapped bytes: 17, 18, 21, 22, 25, 26, 29, 30, 33, 34
|
||||
// mem.createInitializedBlock("test3", addr(35), 15, (byte) 1, TaskMonitor.DUMMY, false); // mapped bytes: .. 37, 38, .. 41, 42), .. 45, 46, .. 49, 50 ...
|
||||
// MemoryBlockDB block = (MemoryBlockDB) mem.createByteMappedBlock("mapped", addr(1000),
|
||||
// addr(5), 40, new ByteMappingScheme(2, 4), false);
|
||||
//
|
||||
// // NOTE: source range includes skipped bytes within mapped range
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(1005), 15);
|
||||
//// 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());
|
||||
//// assertEquals(8, ranges.get(0).getSize() + ranges.get(1).getSize());
|
||||
//
|
||||
// ByteSourceRange range = ranges.get(0);
|
||||
// assertEquals(addr(1005), range.getStart());
|
||||
// assertEquals(addr(1005), range.getEnd());
|
||||
// assertEquals(1, range.getSize());
|
||||
// assertEquals(14, range.getOffset());
|
||||
//
|
||||
// range = ranges.get(1);
|
||||
// assertEquals(addr(1016), range.getStart());
|
||||
// assertEquals(addr(1019), range.getEnd());
|
||||
// assertEquals(5, range.getSize());
|
||||
// assertEquals(0, range.getOffset());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForBitMappedBlock() throws Exception {
|
||||
// FileBytes fileBytes = createFileBytes();
|
||||
// createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
//
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14, false);
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1000), 0x14);
|
||||
//
|
||||
// assertEquals(1, ranges.getRangeCount());
|
||||
// assertEquals(3, ranges.get(0).getSize());
|
||||
//
|
||||
// ByteSourceRange range = ranges.get(0);
|
||||
// assertEquals(addr(0x1000), range.getStart());
|
||||
// assertEquals(addr(0x1017), range.getEnd());
|
||||
// assertEquals(3, range.getSize());
|
||||
// assertEquals(5, range.getOffset());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForBitMappedBlockOffcutStart() throws Exception {
|
||||
// FileBytes fileBytes = createFileBytes();
|
||||
// createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
//
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x14, false);
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1005), 8);
|
||||
//
|
||||
// assertEquals(1, ranges.getRangeCount());
|
||||
// assertEquals(2, ranges.get(0).getSize());
|
||||
//
|
||||
// ByteSourceRange range = ranges.get(0);
|
||||
// assertEquals(addr(0x1000), range.getStart());
|
||||
// assertEquals(addr(0x100f), range.getEnd());
|
||||
// assertEquals(2, range.getSize());
|
||||
// assertEquals(5, range.getOffset());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForBitMappedBlockOffcutStartNotAtStart() throws Exception {
|
||||
// FileBytes fileBytes = createFileBytes();
|
||||
// createFileBytesBlock(fileBytes, addr(0), 0, 50);
|
||||
//
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(5), 0x44, false);
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1015), 8);
|
||||
//
|
||||
// assertEquals(1, ranges.getRangeCount());
|
||||
// assertEquals(2, ranges.get(0).getSize());
|
||||
//
|
||||
// ByteSourceRange range = ranges.get(0);
|
||||
// assertEquals(addr(0x1010), range.getStart());
|
||||
// assertEquals(addr(0x101f), range.getEnd());
|
||||
// assertEquals(2, range.getSize());
|
||||
// assertEquals(7, range.getOffset());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForBitMappedBlock2() throws Exception {
|
||||
// mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
// mem.createUninitializedBlock("test2", addr(0x4), 4, false);
|
||||
// mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40, false);
|
||||
//
|
||||
// ByteSourceRangeList ranges = block.getByteSourceRangeList(addr(0x1008), 0x30);
|
||||
//
|
||||
// assertEquals(2, ranges.getRangeCount());
|
||||
//
|
||||
// ByteSourceRange range = ranges.get(0);
|
||||
// assertEquals(addr(0x1008), range.getStart());
|
||||
// assertEquals(addr(0x100f), range.getEnd());
|
||||
// assertEquals(1, range.getSize());
|
||||
// assertEquals(3, range.getOffset());
|
||||
//
|
||||
// range = ranges.get(1);
|
||||
// assertEquals(addr(0x1030), range.getStart());
|
||||
// assertEquals(addr(0x1037), range.getEnd());
|
||||
// assertEquals(1, range.getSize());
|
||||
// assertEquals(0, range.getOffset());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testGetByteSourceForBitMappedBlock2Offcut() throws Exception {
|
||||
// mem.createInitializedBlock("test1", addr(0), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
// mem.createUninitializedBlock("test2", addr(0x4), 4, false);
|
||||
// mem.createInitializedBlock("test3", addr(0x8), 4, (byte) 1, TaskMonitor.DUMMY, false);
|
||||
// MemoryBlockDB block =
|
||||
// (MemoryBlockDB) mem.createBitMappedBlock("mapped", addr(0x1000), addr(2), 0x40, false);
|
||||
//
|
||||
// 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
|
||||
public void testAddressSourceInfoForFileBytesBlock() throws Exception {
|
||||
|
@ -934,7 +975,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
|||
public void testAddressSourceInfoForMappedBlock() throws Exception {
|
||||
FileBytes fileBytes = createFileBytes();
|
||||
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));
|
||||
assertEquals(addr(1000), info.getAddress());
|
||||
|
|
|
@ -45,7 +45,7 @@ public class MemoryMapPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
moveProviderToItsOwnWindow(provider);
|
||||
JComponent component = getDockableComponent(provider);
|
||||
|
||||
captureIsolatedComponent(component, 650, 225);
|
||||
captureIsolatedComponent(component, 800, 225);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -279,14 +279,16 @@
|
|||
<ul class="medium">
|
||||
<li>The Memory Map</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 change the image base of their program</li>
|
||||
<li>Allows users to edit settings on individual memory blocks</li>
|
||||
<ul>
|
||||
<li>Read/Write/Execute</li>
|
||||
<li>Volatile/non-volatile</li>
|
||||
<li>Initialized/non-initialized</li>
|
||||
<li>Initialized/non-initialized (default blocks only)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div role="note">
|
||||
|
|
|
@ -528,7 +528,7 @@ be installed in a pre-existing Eclipse installation.</p>
|
|||
lookups.
|
||||
</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>
|
||||
Language versioning and migration does not handle complex changes in the use of the context
|
||||
|
|