Modified Memory API for creating Overlay blocks allow for

byte/bit-mapped overlays.  Added ByteMappingScheme for byte-mapped
blocks.
This commit is contained in:
ghidra1 2020-04-29 15:27:35 -04:00
parent 1df6fa79da
commit 6ff98a4098
76 changed files with 2351 additions and 1618 deletions

View file

@ -238,8 +238,8 @@
<LI><B>Search Only in Accessible Memory Blocks</B> - if checked, searches only in memory
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

View file

@ -898,7 +898,11 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
<H2><A name="Overlay"></A>Overlay</H2>
<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>

View file

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

View file

@ -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.&nbsp; 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.&nbsp; 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>.&nbsp;Using Overlays is a way to get around the problem where the program
is too large to fit completely in the target system's memory.&nbsp; Overlay blocks contain
code that would get swapped in when the program needs to execute it.&nbsp;&nbsp; Note that
Overlay blocks are fixed and may not be moved, split or expanded.&nbsp; In addition, Overlays
do not relocate with image base changes.<BR>
</LI>
byte-addressable map onto other blocks.&nbsp; 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.&nbsp; Overlay blocks can serve various
purposes where a memory range may contain different data/code or map to different areas of memory
at any given point in time or processor state. &nbsp; Note that
overlay blocks are fixed and may not be moved, split, merged or expanded.&nbsp; In addition, Overlays
do not relocate with image base changes and have significant limitations in conjunction with
decompilation and analysis.</P>
<P>To view the <I>Memory Map</I>, select <B>Window<IMG src="../../shared/arrow.gif" border="0">
Memory Map</B> from the main tool menu, or click on the&nbsp; <IMG src="images/memory16.gif"
@ -86,16 +100,14 @@
<P><I><B>W -</B></I> Indicates write permission.</P>
<P><I><B>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.&nbsp; This is achieved by
creating a new address space related to the actual processor address space and placing
the block in the new space at the same offsets as the start address in the processor
space.&nbsp; Overlay blocks can be either initialized or uninitialized. If you select
<I>Initialized</I> you can enter a byte value that will be used to fill all the bytes
in the new memory block.</LI>
<LI><B><I>Bit Mapped -</I></B> This is a block that allow bit addressing of a section
<LI><B><I>Bit Mapped -</I></B> This is a block that allows bit addressing of a section
of bytes in memory.&nbsp; For example, the first bit of the byte at memory location
0x1000 might also be addressed as BIT:0. The second bit at the same byte would then be
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.&nbsp; Note
that Bit Overlay addresses are assigned from least significant bit to most
that bit-mapped addresses are assigned from least significant bit to most
significant bit.</P>
</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>&nbsp;<B><I>Byte Mapped</I></B> - This is a block that allows access to a range of
bytes in memory using an alternative address.&nbsp; In other words, it allows the same
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.&nbsp; 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.&nbsp; 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.&nbsp;</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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -215,6 +215,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.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));

View file

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

View file

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

View file

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

View file

@ -0,0 +1,354 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.task.TaskMonitor;
public class ByteMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTest {
private AddressSpace space;
private MemoryBlock block;
private Memory memory;
private Program program;
private int transactionID;
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_LE, this);
memory = program.getMemory();
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) i;
}
space = program.getAddressFactory().getDefaultAddressSpace();
transactionID = program.startTransaction("Test");
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
memory.setBytes(block.getStart(), bytes);
}
@After
public void tearDown() {
program.endTransaction(transactionID, true);
program.release(this);
}
private Address addr(long offset) {
return space.getAddress(offset);
}
@Test
public void testCreateNewBlock1to1() throws Exception {
MemoryBlock byteMappedBlock =
memory.createByteMappedBlock("test", addr(0x1000), addr(0x80), 0x100, false);
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(addr(0x1000), byteMappedBlock.getStart());
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(addr(0x1000), addr(0x107F));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(1, scheme.getMappedByteCount());
assertEquals(1, scheme.getMappedSourceByteCount());
assertEquals(addr(0x80), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x80; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + i, b & 0xff);
}
try {
byteMappedBlock.getByte(addr(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length,
(byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(addr(0x1080), addr(0x10FF));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x80; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + i, b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(addr(0x1080 + i));
assertEquals(~i & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3 };
byteMappedBlock.putBytes(addr(0x1080), data1);
byte[] data2 = new byte[3];
assertEquals(3, byteMappedBlock.getBytes(addr(0x1080), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(3, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(data1, data2));
}
@Test
public void testCreateNewBlock1to2() throws Exception {
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(1, 2), false);
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(addr(0x1000), byteMappedBlock.getStart());
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(addr(0x1000), addr(0x103F));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(1, scheme.getMappedByteCount());
assertEquals(2, scheme.getMappedSourceByteCount());
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + (2 * i), b & 0xff);
}
try {
byteMappedBlock.getByte(addr(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(addr(0x1040), addr(0x10BF));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
assertEquals(0x80 + (2 * i), b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(addr(0x1040 + i));
assertEquals(~(2 * i) & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3, 4 };
byteMappedBlock.putBytes(addr(0x1040), data1);
byte[] data2 = new byte[4];
assertEquals(4, byteMappedBlock.getBytes(addr(0x1040), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(4, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(new byte[] { 1, -2, 2, -4 }, data2));
}
@Test
public void testCreateNewBlock2to4() throws Exception {
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), false);
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(addr(0x1000), byteMappedBlock.getStart());
assertEquals(addr(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(addr(0x1000), addr(0x103E));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(2, scheme.getMappedByteCount());
assertEquals(4, scheme.getMappedSourceByteCount());
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
try {
byteMappedBlock.getByte(addr(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(addr(0x103F), addr(0x10BE));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(addr(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(addr(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(addr(0x1040 + i));
int val = ~(4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3, 4 };
byteMappedBlock.putBytes(addr(0x1040), data1);
byte[] data2 = new byte[4];
assertEquals(4, byteMappedBlock.getBytes(addr(0x1040), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(4, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(new byte[] { 1, 2, -3, -4 }, data2));
}
@Test
public void testCreateNewBlock2to4Overlay() throws Exception {
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), true);
assertTrue(byteMappedBlock.isOverlay());
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
assertNotNull(testSpace);
assertEquals(space, testSpace.getPhysicalSpace());
assertEquals(testSpace.getAddress(0x1000), testSpace.getMinAddress());
assertEquals(testSpace.getAddress(0x10FF), testSpace.getMaxAddress());
assertEquals(0x100, byteMappedBlock.getSize());
assertEquals(testSpace.getAddress(0x1000), byteMappedBlock.getStart());
assertEquals(testSpace.getAddress(0x10FF), byteMappedBlock.getEnd());
AddressSet set = new AddressSet(addr(0), addr(0xFF));
set.add(testSpace.getAddress(0x1000), testSpace.getAddress(0x103E));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
MemoryBlockSourceInfo info = byteMappedBlock.getSourceInfos().get(0);
ByteMappingScheme scheme = info.getByteMappingScheme().get();
assertEquals(2, scheme.getMappedByteCount());
assertEquals(4, scheme.getMappedSourceByteCount());
assertEquals(addr(0x100), scheme.getMappedSourceAddress(addr(0), 0x80));
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
try {
byteMappedBlock.getByte(testSpace.getAddress(0x1100));
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
// expected
}
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ~i;
}
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
set.add(addr(0x100), addr(0x1FF));
set.add(testSpace.getAddress(0x103F), testSpace.getAddress(0x10BE));
assertEquals(set, memory.getAllInitializedAddressSet());
assertEquals(set, memory.getLoadedAndInitializedAddressSet());
assertEquals(0, byteMappedBlock.getByte(testSpace.getAddress(0x1080)));
memory.setBytes(block2.getStart(), bytes);
for (int i = 0; i < 0x40; i++) {
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1000 + i));
int val = 0x80 + (4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
for (int i = 0; i < 0x7F; i++) {
byte b = byteMappedBlock.getByte(testSpace.getAddress(0x1040 + i));
int val = ~(4 * (i / 2) + (i % 2));
assertEquals(val & 0xff, b & 0xff);
}
byte[] data1 = new byte[] { 1, 2, 3, 4 };
byteMappedBlock.putBytes(testSpace.getAddress(0x1040), data1);
byte[] data2 = new byte[4];
assertEquals(4, byteMappedBlock.getBytes(testSpace.getAddress(0x1040), data2));
assertTrue(Arrays.equals(data1, data2));
assertEquals(4, block2.getBytes(addr(0x100), data2));
assertTrue(Arrays.equals(new byte[] { 1, 2, -3, -4 }, data2));
}
}

View file

@ -15,51 +15,20 @@
*/
package ghidra.program.database.mem;
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);

View file

@ -0,0 +1,193 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import static org.junit.Assert.*;
import org.junit.*;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.task.TaskMonitor;
public class MemoryWriteCheckTest extends AbstractGhidraHeadedIntegrationTest {
private AddressSpace space;
private MemoryBlock block;
private Memory memory;
private Program program;
private int transactionID;
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_LE, this);
memory = program.getMemory();
byte[] bytes = new byte[0x100];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) i;
}
space = program.getAddressFactory().getDefaultAddressSpace();
transactionID = program.startTransaction("Test");
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0), bytes.length,
(byte) 0, TaskMonitor.DUMMY, false);
memory.setBytes(block.getStart(), bytes);
}
@After
public void tearDown() {
program.endTransaction(transactionID, true);
program.release(this);
}
private Address addr(long offset) {
return space.getAddress(offset);
}
@Test
public void testByteMappedMemoryCheck() throws Exception {
AddressSet set = new AddressSet(addr(0), addr(0xd7));
DisassembleCommand cmd = new DisassembleCommand(set, set);
cmd.applyTo(program); // range 0x0000 to 0x00d7 disassembled
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), true);
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
try {
byteMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000080", e.getMessage());
}
try {
byteMappedBlock.putBytes(testSpace.getAddress(0x1002), new byte[] { 1, 2 });
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000084", e.getMessage());
}
program.getListing().clearCodeUnits(addr(0), addr(0xd7), true);
byteMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
assertEquals(1, byteMappedBlock.getByte(testSpace.getAddress(0x1000)));
byteMappedBlock.putBytes(testSpace.getAddress(0x1002), new byte[] { 1, 2 });
byte[] data = new byte[2];
assertEquals(2, byteMappedBlock.getBytes(testSpace.getAddress(0x1002), data));
assertArrayEquals(new byte[] { 1, 2 }, data);
}
@Test
public void testByteMappedMemoryCheck1() throws Exception {
// NOTE: disassembling in a 2:4 byte-mapped block is rather inappropriate and may be disallowed in the future
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
0x100, new ByteMappingScheme(2, 4), true);
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
AddressSet set = new AddressSet(testSpace.getAddress(0x1000), testSpace.getAddress(0x1011));
DisassembleCommand cmd = new DisassembleCommand(set, set);
cmd.applyTo(program); // range test:0x1000 to test::0x1011 disassembled
try {
block.putByte(addr(0x80), (byte) 1);
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at test::00001000",
e.getMessage());
}
// small modification within filler byte region for mapped block allowed
block.putBytes(addr(0x82), new byte[] { 1, 2 });
byte[] data = new byte[2];
assertEquals(2, block.getBytes(addr(0x82), data));
assertArrayEquals(new byte[] { 1, 2 }, data);
try {
block.putBytes(addr(0x84), new byte[] { 1, 2 });
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at test::00001002",
e.getMessage());
}
program.getListing().clearCodeUnits(set.getMinAddress(), set.getMaxAddress(), true);
block.putByte(addr(0x80), (byte) 1);
assertEquals(1, byteMappedBlock.getByte(testSpace.getAddress(0x1000)));
block.putBytes(addr(0x84), new byte[] { 1, 2 });
assertEquals(2, byteMappedBlock.getBytes(testSpace.getAddress(0x1002), data));
assertArrayEquals(new byte[] { 1, 2 }, data);
}
@Test
public void testBitMappedMemoryCheck() throws Exception {
AddressSet set = new AddressSet(addr(0), addr(0xd7));
DisassembleCommand cmd = new DisassembleCommand(set, set);
cmd.applyTo(program); // range 0x0000 to 0x00d7 disassembled
MemoryBlock bitMappedBlock =
memory.createBitMappedBlock("test", addr(0x1000), addr(0x80), 0x100, true);
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
try {
bitMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000080", e.getMessage());
}
try {
bitMappedBlock.putBytes(testSpace.getAddress(0x1010), new byte[] { 1, 0, 1, 0 });
fail("expected MemoryAccessException");
}
catch (MemoryAccessException e) {
assertEquals("Memory change conflicts with instruction at 00000082", e.getMessage());
}
program.getListing().clearCodeUnits(addr(0), addr(0xd7), true);
bitMappedBlock.putByte(testSpace.getAddress(0x1000), (byte) 1);
assertEquals(1, bitMappedBlock.getByte(testSpace.getAddress(0x1000)));
bitMappedBlock.putBytes(testSpace.getAddress(0x1010), new byte[] { 1, 0, 1, 0 });
byte[] data = new byte[4];
assertEquals(4, bitMappedBlock.getBytes(testSpace.getAddress(0x1010), data));
assertArrayEquals(new byte[] { 1, 0, 1, 0 }, data);
}
}

View file

@ -22,7 +22,8 @@ import org.junit.*;
import generic.test.AbstractGenericTest;
import 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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,49 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemoryBlock;
public class BitMappedByteSourceRange extends ByteSourceRange {
public BitMappedByteSourceRange(MemoryBlock block, Address start, long sourceId, long offset,
long size) {
super(block, start, size, sourceId, offset);
}
@Override
public Address getEnd() {
return getStart().add(size * 8 - 1);
}
@Override
public ByteSourceRange intersect(ByteSourceRange range) {
if (sourceId != range.sourceId) {
return null;
}
long maxOffset = Math.max(byteSourceOffset, range.byteSourceOffset);
long minEndOffset =
Math.min(byteSourceOffset + size - 1, range.byteSourceOffset + range.size - 1);
if (maxOffset > minEndOffset) {
return null;
}
long sourceSize = minEndOffset - maxOffset + 1;
return new BitMappedByteSourceRange(block, start.add((maxOffset - byteSourceOffset) / 8),
sourceId, maxOffset, sourceSize);
}
}

View file

@ -16,12 +16,12 @@
package ghidra.program.database.mem;
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;
}
}

View file

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

View file

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

View file

@ -0,0 +1,329 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.mem.*;
/**
* <code>ByteMappingScheme</code> facilitate byte mapping/decimation scheme for a mapped sub-block to
* an underlying source memory region.
*/
public class ByteMappingScheme {
// Repeating byte mapping pattern defined by number of source bytes mapped (mappedByteCount) followed
// by number of non-mapped source bytes (nonMappedByteCount). The sum of these two values is
// mappedSourceByteCount. The first byte of this block must correspond to the first mapped
// byte of this mapping sequence.
private final int mappedByteCount;
private final int nonMappedByteCount;
private final int mappedSourceByteCount;
/**
* Construct byte mapping scheme from an encoded mappingScheme value.
* @param encodedMappingScheme encoded mapping scheme value or 0 for a 1:1 default mapping.
* A zero value is accepted to ensure backward compatibility with pre-existing byte-mapped blocks
* where a 1:1 mapping was employed.
* @throws IllegalArgumentException if packed mapping scheme produces an invalid mapping ratio
*/
ByteMappingScheme(int encodedMappingScheme) throws IllegalArgumentException {
if (encodedMappingScheme == 0) {
// default mode implies 1:1 mapping
mappedByteCount = 1;
mappedSourceByteCount = 1;
nonMappedByteCount = 0;
}
else {
mappedByteCount = getMappedByteCount(encodedMappingScheme);
mappedSourceByteCount = getMappedSourceByteCount(encodedMappingScheme);
nonMappedByteCount = mappedSourceByteCount - mappedByteCount;
validateMappingScheme(mappedByteCount, mappedSourceByteCount);
}
}
/**
* Construct byte mapping scheme specified as a ratio of mapped bytes to source bytes.
* @param mappedByteCount number of mapped bytes per mappedSourcebyteCount (1..127). This
* value must be less-than or equal to schemeSrcByteCount.
* @param mappedSourceByteCount number of source bytes for mapping ratio (1..127)
* @throws IllegalArgumentException if invalid mapping scheme specified
*/
public ByteMappingScheme(int mappedByteCount, int mappedSourceByteCount) {
validateMappingScheme(mappedByteCount, mappedSourceByteCount);
this.mappedByteCount = mappedByteCount;
this.mappedSourceByteCount = mappedSourceByteCount;
this.nonMappedByteCount = mappedSourceByteCount - mappedByteCount;
}
@Override
public String toString() {
String ratioStr = "1:1";
if (!isOneToOneMapping()) {
ratioStr = mappedByteCount + ":" + mappedSourceByteCount;
}
return ratioStr + " mapping";
}
/**
* Get byte mapping scheme as single 14-bit packed value for storage and reconstruction use.
* @return mapping scheme as single 14-bit integer value
*/
int getEncodedMappingScheme() {
if (isOneToOneMapping()) {
// for legacy reasons continue to use 0 to indicate 1:1 default mapping
return 0;
}
return getEncodedMappingScheme(mappedByteCount, mappedSourceByteCount);
}
/**
* Determine this scheme corresponds to a 1:1 byte mapping
* @return true if 1:1 mapping else false
*/
public boolean isOneToOneMapping() {
return mappedSourceByteCount <= 1;
}
/**
* Get the mapped-byte-count (left-hand value in mapping ratio)
* @return mapped-byte-count
*/
public int getMappedByteCount() {
if (isOneToOneMapping()) {
return 1;
}
return mappedByteCount;
}
/**
* Get the mapped-source-byte-count (right-hand value in mapping ratio)
* @return mapped-source-byte-count
*/
public int getMappedSourceByteCount() {
if (isOneToOneMapping()) {
return 1;
}
return mappedSourceByteCount;
}
/**
* Calculate the mapped source address for a specified offset with the mapped sub-block.
* @param mappedSourceBaseAddress mapped source base address for sub-block
* @param offsetInSubBlock byte offset within sub-block to be mapped into source
* @return mapped source address
* @throws AddressOverflowException if offset in sub-block produces a wrap condition in
* the mapped source address space.
*/
public Address getMappedSourceAddress(Address mappedSourceBaseAddress,
long offsetInSubBlock)
throws AddressOverflowException {
if (offsetInSubBlock < 0) {
throw new IllegalArgumentException("negative offset");
}
long sourceOffset = offsetInSubBlock;
if (!isOneToOneMapping()) {
sourceOffset = (mappedSourceByteCount * (offsetInSubBlock / mappedByteCount)) +
(offsetInSubBlock % mappedByteCount);
}
return mappedSourceBaseAddress.addNoWrap(sourceOffset);
}
/**
* Calculate the address within a mapped block for a specified mapped source offset.
* If the specified mappedSourceOffset corresponds to a non-mapped (i.e., skipped) byte
* the address returned will correspond to the last mapped byte. Care must be used
* when using this method.
* @param mappedBlock mapped block
* @param mappedSourceOffset byte offset within mapped source relative to mapped base source address.
* @param skipBack controls return address when mappedSourceOffset corresponds to a non-mapped/skipped byte.
* If true the returned address will correspond to the previous mapped address, if false the next mapped
* address will be returned.
* @return mapped address within block or null if skipBack is false and unable to map within block limits
* @throws AddressOverflowException thrown for 1:1 mapping when mappedSourceOffset exceeds length of mappedBlock
*/
Address getMappedAddress(MemoryBlock mappedBlock, long mappedSourceOffset, boolean skipBack)
throws AddressOverflowException {
if (mappedSourceOffset < 0) {
throw new IllegalArgumentException("negative source offset");
}
long mappedOffset = mappedSourceOffset;
if (!isOneToOneMapping()) {
mappedOffset = (mappedByteCount * (mappedSourceOffset / mappedSourceByteCount));
long offsetLimit = mappedBlock.getSize() - 1;
long mod = mappedSourceOffset % mappedSourceByteCount;
if (mod < mappedByteCount) {
mappedOffset += mod;
}
else if (!skipBack) {
mappedOffset += mappedByteCount;
if (mappedOffset > offsetLimit) {
return null;
}
}
}
return mappedBlock.getStart().addNoWrap(mappedOffset);
}
/**
* Read bytes into an array from memory utilizing this mapping scheme.
* @param memory program memory
* @param mappedSourceBaseAddress base source memory address for byte-mapped subblock
* @param offsetInSubBlock byte offset from start of subblock where reading should begin
* @param b byte array to be filled
* @param off offset within byte array b where filling should start
* @param len number of bytes to be read
* @return actual number of bytes read
* @throws MemoryAccessException if read of uninitialized or non-existing memory occurs
* @throws AddressOverflowException if address computation error occurs
*/
int getBytes(Memory memory, Address mappedSourceBaseAddress, long offsetInSubBlock, byte[] b,
int off, int len) throws MemoryAccessException, AddressOverflowException {
if (isOneToOneMapping()) {
return memory.getBytes(mappedSourceBaseAddress.addNoWrap(offsetInSubBlock), b, off,
len);
}
// NOTE: approach avoids incremental reading by including unmapped bytes in
// bulk read and filters as needed based upon mapping scheme ratio
long patternCount = offsetInSubBlock / mappedByteCount;
int partialByteCount = (int) (offsetInSubBlock % mappedByteCount);
long mappedOffset = (mappedSourceByteCount * patternCount) + partialByteCount;
int bufSize = mappedSourceByteCount * ((len / mappedByteCount) + 1);
byte[] buf = new byte[bufSize];
int bufCnt = memory.getBytes(mappedSourceBaseAddress.addNoWrap(mappedOffset), buf);
int bufIndex = 0;
int cnt = 0;
int index = off;
int i = mappedByteCount - partialByteCount;
boolean skip = false;
while (bufIndex < bufCnt && cnt < len) {
if (!skip) {
b[index++] = buf[bufIndex];
++cnt;
if (--i == 0) {
skip = true;
i = nonMappedByteCount;
}
}
else if (--i == 0) {
skip = false;
i = mappedByteCount;
}
++bufIndex;
}
return cnt;
}
/**
* Write an array of bytes to memory utilizing this mapping scheme.
* @param memory program memory
* @param mappedSourceBaseAddress base source memory address for byte-mapped subblock
* @param offsetInSubBlock byte offset from start of subblock where writing should begin
* @param b an array to get bytes from
* @param off start source index within byte array b where bytes should be read
* @param len number of bytes to be written
* @throws MemoryAccessException if write of uninitialized or non-existing memory occurs
* @throws AddressOverflowException if address computation error occurs
*/
void setBytes(Memory memory, Address mappedSourceBaseAddress, long offsetInSubBlock,
byte[] b,
int off, int len) throws MemoryAccessException, AddressOverflowException {
if (isOneToOneMapping()) {
memory.setBytes(mappedSourceBaseAddress.addNoWrap(offsetInSubBlock), b, off, len);
return;
}
long patternCount = offsetInSubBlock / mappedByteCount;
int partialByteCount = (int) (offsetInSubBlock % mappedByteCount);
long mappedOffset = (mappedSourceByteCount * patternCount) + partialByteCount;
Address destAddr = mappedSourceBaseAddress.addNoWrap(mappedOffset);
int index = off;
int cnt = 0;
int i = mappedByteCount - partialByteCount;
while (cnt < len) {
memory.setBytes(destAddr, b, index, i);
index += i;
cnt += i;
destAddr = destAddr.addNoWrap(i + nonMappedByteCount);
i = mappedByteCount;
}
}
/**
* Validate mapping scheme. This scheme is specified as a ratio of mapped bytes to source bytes.
* @param schemeDestByteCount number of mapped bytes per mappedSourcebyteCount (1..127). This
* value must be less-than or equal to schemeSrcByteCount.
* @param schemeSrcByteCount number of source bytes for mapping ratio (1..127)
* @throws IllegalArgumentException if invalid mapping scheme specified
*/
static void validateMappingScheme(int schemeDestByteCount, int schemeSrcByteCount) {
if (schemeDestByteCount <= 0 || schemeDestByteCount > 0x7F || schemeSrcByteCount <= 0 ||
schemeSrcByteCount > 0x7F ||
schemeDestByteCount > schemeSrcByteCount) {
throw new IllegalArgumentException(
"invalid byte mapping ratio: " + schemeDestByteCount + ":" + schemeSrcByteCount);
}
}
/**
* Get encoded mapping scheme as a single value for storage purposes. This scheme value
* identifies the ratio of mapped bytes to source bytes. Value is encoded as two 7-bit
* values corresponding to the destination and source byte counts.
* @param schemeDestByteCount number of mapped bytes per mappedSourcebyteCount (1..127). This
* value must be less-than or equal to schemeSrcByteCount.
* @param schemeSrcByteCount number of source bytes for mapping ratio (1..127)
* @return mapping scheme value
* @throws IllegalArgumentException if invalid mapping scheme specified
*/
static int getEncodedMappingScheme(int schemeDestByteCount, int schemeSrcByteCount) {
validateMappingScheme(schemeDestByteCount, schemeSrcByteCount);
return (schemeDestByteCount << 7) | (schemeSrcByteCount & 0x7F);
}
/**
* Extract the mapping scheme mapped-byte-count from a mappingScheme value.
* @param mappingScheme mapping scheme
* @return mapped-byte-count (aka schemeDestByteCount)
*/
static int getMappedByteCount(int mappingScheme) {
int mappedByteCount = 1;
if (mappingScheme != 0) {
mappedByteCount = (mappingScheme >> 7) & 0x7F;
}
return mappedByteCount;
}
/**
* Extract the mapping ratio mapped-source-byte-count from a mappingScheme value.
* @param mappingScheme mapping scheme
* @return mapped-source-byte-count (aka schemeSrcByteCount)
*/
static int getMappedSourceByteCount(int mappingScheme) {
int mappedSourceByteCount = 1;
if (mappingScheme != 0) {
mappedSourceByteCount = mappingScheme & 0x7F;
}
return mappedSourceByteCount;
}
}

View file

@ -1,126 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemoryBlock;
public class ByteSourceRange {
protected final Address start;
protected final long size;
protected final long sourceId;
protected final long byteSourceOffset;
protected MemoryBlock block;
public ByteSourceRange(MemoryBlock block, Address start, long size, long sourceId,
long offset) {
this.block = block;
this.start = start;
this.size = size;
this.sourceId = sourceId;
this.byteSourceOffset = offset;
}
public Address getStart() {
return start;
}
public Address getEnd() {
return start.add(size - 1);
}
public long getSize() {
return size;
}
public long getSourceId() {
return sourceId;
}
public long getOffset() {
return byteSourceOffset;
}
public ByteSourceRange intersect(ByteSourceRange range) {
if (sourceId != range.sourceId) {
return null;
}
long maxOffset = Math.max(byteSourceOffset, range.byteSourceOffset);
long minEndOffset =
Math.min(byteSourceOffset + size - 1, range.byteSourceOffset + range.size - 1);
if (maxOffset > minEndOffset) {
return null;
}
return new ByteSourceRange(block, start.add(maxOffset - byteSourceOffset),
minEndOffset - maxOffset + 1, sourceId, maxOffset);
}
public MemoryBlock getMemoryBlock() {
return block;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (byteSourceOffset ^ (byteSourceOffset >>> 32));
result = prime * result + (int) (size ^ (size >>> 32));
result = prime * result + (int) (sourceId ^ (sourceId >>> 32));
result = prime * result + ((start == null) ? 0 : start.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ByteSourceRange other = (ByteSourceRange) obj;
if (block == null) {
if (other.block != null) {
return false;
}
}
else if (!block.equals(other.block)) {
return false;
}
if (byteSourceOffset != other.byteSourceOffset) {
return false;
}
if (size != other.size) {
return false;
}
if (sourceId != other.sourceId) {
return false;
}
if (start == null) {
if (other.start != null) {
return false;
}
}
else if (!start.equals(other.start)) {
return false;
}
return true;
}
}

View file

@ -1,220 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import java.util.*;
import ghidra.program.model.mem.MemoryBlock;
public class ByteSourceRangeList implements Iterable<ByteSourceRange> {
List<ByteSourceRange> ranges;
public ByteSourceRangeList(ByteSourceRange bsRange) {
this();
ranges.add(bsRange);
}
public ByteSourceRangeList() {
ranges = new ArrayList<>();
}
@Override
public Iterator<ByteSourceRange> iterator() {
return ranges.iterator();
}
public void add(ByteSourceRange range) {
if (range != null) {
ranges.add(range);
}
}
public void add(ByteSourceRangeList byteSourceList) {
ranges.addAll(byteSourceList.ranges);
}
public int getRangeCount() {
return ranges.size();
}
public ByteSourceRange get(int i) {
return ranges.get(i);
}
public boolean isEmpty() {
return ranges.isEmpty();
}
public Set<MemoryBlock> getOverlappingBlocks() {
List<BlockRangeEntry> entries = new ArrayList<>();
for (ByteSourceRange range : ranges) {
entries.add(new BlockRangeStart(this, range));
entries.add(new BlockRangeEnd(this, range));
}
Collections.sort(entries);
return findOverlappingBlocks(entries);
}
public ByteSourceRangeList intersect(ByteSourceRangeList rangeList) {
List<BlockRangeEntry> entries = new ArrayList<>();
for (ByteSourceRange range : ranges) {
entries.add(new BlockRangeStart(this, range));
entries.add(new BlockRangeEnd(this, range));
}
for (ByteSourceRange range : rangeList) {
entries.add(new BlockRangeStart(rangeList, range));
entries.add(new BlockRangeEnd(rangeList, range));
}
Collections.sort(entries);
return getIntersectingRanges(entries);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((ranges == null) ? 0 : ranges.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ByteSourceRangeList other = (ByteSourceRangeList) obj;
if (ranges == null) {
if (other.ranges != null) {
return false;
}
}
else if (!ranges.equals(other.ranges)) {
return false;
}
return true;
}
private ByteSourceRangeList getIntersectingRanges(List<BlockRangeEntry> entries) {
ByteSourceRangeList result = new ByteSourceRangeList();
Set<ByteSourceRange> currentSet = new HashSet<>();
for (BlockRangeEntry entry : entries) {
if (entry.isStart()) {
currentSet.add(entry.range);
}
else {
currentSet.remove(entry.range);
addIntersections(result, entry, currentSet);
}
}
return result;
}
private void addIntersections(ByteSourceRangeList set, BlockRangeEntry entry,
Set<ByteSourceRange> currentSet) {
if (currentSet.isEmpty()) {
return;
}
for (ByteSourceRange byteSourceRange : currentSet) {
if (entry.owner == this) {
set.add(entry.range.intersect(byteSourceRange));
}
else {
set.add(byteSourceRange.intersect(entry.range));
}
}
}
private Set<MemoryBlock> findOverlappingBlocks(List<BlockRangeEntry> entries) {
Set<MemoryBlock> overlappingBlocks = new HashSet<>();
Set<ByteSourceRange> currentSet = new HashSet<>();
for (BlockRangeEntry entry : entries) {
if (entry.isStart()) {
currentSet.add(entry.range);
}
else {
currentSet.remove(entry.range);
if (!currentSet.isEmpty()) {
overlappingBlocks.add(entry.range.block);
for (ByteSourceRange byteSourceRange : currentSet) {
overlappingBlocks.add(byteSourceRange.block);
}
}
}
}
return overlappingBlocks;
}
abstract class BlockRangeEntry implements Comparable<BlockRangeEntry> {
private ByteSourceRange range;
private long sourceId;
private long offset;
private ByteSourceRangeList owner;
BlockRangeEntry(ByteSourceRangeList owner, ByteSourceRange range, long offset) {
this.owner = owner;
this.range = range;
this.offset = offset;
this.sourceId = range.getSourceId();
}
abstract boolean isStart();
@Override
public int compareTo(BlockRangeEntry o) {
if (sourceId != o.sourceId) {
return sourceId > o.sourceId ? 1 : -1;
}
if (offset == o.offset) {
return (isStart() == o.isStart()) ? 0 : (isStart() ? -1 : 1);
}
return offset > o.offset ? 1 : -1;
}
}
class BlockRangeStart extends BlockRangeEntry {
BlockRangeStart(ByteSourceRangeList owner, ByteSourceRange range) {
super(owner, range, range.getOffset());
}
@Override
boolean isStart() {
return true;
}
}
class BlockRangeEnd extends BlockRangeEntry {
BlockRangeEnd(ByteSourceRangeList owner, ByteSourceRange range) {
super(owner, range, range.getOffset() + range.size - 1);
}
@Override
boolean isStart() {
return false;
}
}
}

View file

@ -18,8 +18,7 @@ package ghidra.program.database.mem;
import java.io.IOException;
import 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);
}
}

View file

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

View file

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

View file

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

View file

@ -46,8 +46,30 @@ abstract class MemoryMapDBAdapter {
public static final int SUB_TYPE_COL = MemoryMapDBAdapterV3.V3_SUB_TYPE_COL;
public static final int SUB_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.

View file

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

View file

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

View file

@ -48,8 +48,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
public static final int V3_SUB_TYPE_COL = 1;
public static final int V3_SUB_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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,194 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import static org.junit.Assert.*;
import java.util.Iterator;
import java.util.Set;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockStub;
public class ByteSourceRangeListTest extends AbstractGenericTest {
private AddressSpace space = new GenericAddressSpace("test", 64, AddressSpace.TYPE_RAM, 0);
private MemoryBlock block = new MemoryBlockStub();
@Test
public void testConstructor() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList(range1);
ByteSourceRangeList list2 = new ByteSourceRangeList();
list2.add(range1);
assertTrue(list1.equals(list2));
}
@Test
public void testAdd() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x10, 2, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList(range1);
ByteSourceRangeList list2 = new ByteSourceRangeList(range2);
list1.add(list2);
assertEquals(2, list1.getRangeCount());
assertEquals(range1, list1.get(0));
assertEquals(range2, list1.get(1));
}
@Test
public void testIsEmpty() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList();
assertTrue(list1.isEmpty());
list1.add(range1);
assertFalse(list1.isEmpty());
}
@Test
public void testAddNullRange() {
ByteSourceRange range = null;
ByteSourceRangeList list1 = new ByteSourceRangeList();
list1.add(range);
assertTrue(list1.isEmpty());
}
@Test
public void testIterator() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x10, 2, 0x50);
ByteSourceRangeList list1 = new ByteSourceRangeList(range1);
list1.add(range2);
Iterator<ByteSourceRange> it = list1.iterator();
assertTrue(it.hasNext());
assertEquals(range1, it.next());
assertTrue(it.hasNext());
assertEquals(range2, it.next());
assertFalse(it.hasNext());
}
@Test
public void testIntersectSimple() {
ByteSourceRangeList list1 = new ByteSourceRangeList();
list1.add(new ByteSourceRange(block, addr(0), 0x100, 1, 0));
ByteSourceRangeList list2 = new ByteSourceRangeList();
list2.add(new ByteSourceRange(block, addr(0x100), 0x100, 1, 0x10));
// note that list1.intersect(list2) is not equal to list2.intersect(list1).
// The byte sources are the same but the corresponding real addresses are calling
// objects byte sources.
ByteSourceRangeList result = list1.intersect(list2);
assertEquals(1, result.getRangeCount());
ByteSourceRange range = result.get(0);
assertEquals(0xf0, range.getSize());
assertEquals(0x10, range.getOffset());
assertEquals(block, range.getMemoryBlock());
assertEquals(1, range.getSourceId());
assertEquals(addr(0x10), range.getStart());
assertEquals(addr(0xff), range.getEnd());
// now intersect from list2 perspective
result = list2.intersect(list1);
assertEquals(1, result.getRangeCount());
range = result.get(0);
assertEquals(0xf0, range.getSize());
assertEquals(0x10, range.getOffset());
assertEquals(block, range.getMemoryBlock());
assertEquals(1, range.getSourceId());
assertEquals(addr(0x100), range.getStart());
assertEquals(addr(0x1ef), range.getEnd());
}
@Test
public void testGetOverlappingBlocks() {
ByteSourceRange range = new ByteSourceRange(block, addr(0), 0x100, 1, 0x00);
MemoryBlock block1 = new MemoryBlockStub();
ByteSourceRange range1 = new ByteSourceRange(block1, addr(0x100), 0x100, 2, 0x00);
// create a byte source overlap with the first block
MemoryBlock block2 = new MemoryBlockStub();
ByteSourceRange range2 = new ByteSourceRange(block2, addr(0x200), 0x100, 1, 0x50);
ByteSourceRangeList list = new ByteSourceRangeList();
list.add(range);
list.add(range1);
list.add(range2);
Set<MemoryBlock> overlappingBlocks = list.getOverlappingBlocks();
assertEquals(2, overlappingBlocks.size());
assertTrue(overlappingBlocks.contains(block));
assertTrue(overlappingBlocks.contains(block2));
}
@Test
public void testGetOverlappingBlocksBlocksWhereBlocksAreAdjacentButDontOverlap() {
ByteSourceRange range = new ByteSourceRange(block, addr(0), 0x100, 1, 0x00);
MemoryBlock block1 = new MemoryBlockStub();
ByteSourceRange range1 = new ByteSourceRange(block1, addr(0x100), 0x100, 2, 0x00);
// create a byte source overlap with the first block
MemoryBlock block2 = new MemoryBlockStub();
ByteSourceRange range2 = new ByteSourceRange(block2, addr(0x200), 0x100, 1, 0x100);
ByteSourceRangeList list = new ByteSourceRangeList();
list.add(range);
list.add(range1);
list.add(range2);
Set<MemoryBlock> overlappingBlocks = list.getOverlappingBlocks();
assertEquals(0, overlappingBlocks.size());
}
@Test
public void testGetOverlappingBlocksBlocksWhereBlocksOverlapByExactlyOneByte() {
ByteSourceRange range = new ByteSourceRange(block, addr(0), 0x100, 1, 0x00);
MemoryBlock block1 = new MemoryBlockStub();
ByteSourceRange range1 = new ByteSourceRange(block1, addr(0x100), 0x100, 2, 0x00);
// create a byte source overlap with the first block
MemoryBlock block2 = new MemoryBlockStub();
ByteSourceRange range2 = new ByteSourceRange(block2, addr(0x200), 0x100, 1, 0xff);
ByteSourceRangeList list = new ByteSourceRangeList();
list.add(range);
list.add(range1);
list.add(range2);
Set<MemoryBlock> overlappingBlocks = list.getOverlappingBlocks();
assertEquals(2, overlappingBlocks.size());
assertTrue(overlappingBlocks.contains(block));
assertTrue(overlappingBlocks.contains(block2));
}
private Address addr(long value) {
return space.getAddress(value);
}
}

View file

@ -1,119 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.mem;
import static org.junit.Assert.*;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockStub;
public class ByteSourceRangeTest extends AbstractGenericTest {
private AddressSpace space = new GenericAddressSpace("test", 64, AddressSpace.TYPE_RAM, 0);
private MemoryBlock block = new MemoryBlockStub();
@Test
public void testIntersectNotSameSource() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x10, 2, 0x50);
assertNull(range1.intersect(range2));
}
@Test
public void testIntersectOneRangeSimpleOverlap() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x20, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x20, 1, 0x60);
ByteSourceRange intersect = range1.intersect(range2);
assertNotNull(intersect);
assertEquals(addr(0x10), intersect.getStart());
assertEquals(addr(0x1f), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x60, intersect.getOffset());
intersect = range2.intersect(range1);
assertNotNull(intersect);
assertEquals(addr(0x100), intersect.getStart());
assertEquals(addr(0x10f), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x60, intersect.getOffset());
}
@Test
public void testIntersectOneRangeButsAgainsAnother() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x20, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x20, 2, 0x70);
assertNull(range1.intersect(range2));
assertNull(range2.intersect(range1));
}
@Test
public void testIntersectOneRangeCompletelyInAnother() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new ByteSourceRange(block, addr(0x100), 0x30, 1, 0x40);
ByteSourceRange intersect = range1.intersect(range2);
assertNotNull(intersect);
assertEquals(addr(0), intersect.getStart());
assertEquals(addr(0xf), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x50, intersect.getOffset());
intersect = range2.intersect(range1);
assertNotNull(intersect);
assertEquals(addr(0x110), intersect.getStart());
assertEquals(addr(0x11f), intersect.getEnd());
assertEquals(0x10, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x50, intersect.getOffset());
}
@Test
public void testBitMappedIntersect() {
ByteSourceRange range1 = new ByteSourceRange(block, addr(0), 0x10, 1, 0x50);
ByteSourceRange range2 = new BitMappedByteSourceRange(block, addr(0x100), 1, 0x55, 2);
ByteSourceRange intersect = range1.intersect(range2);
assertNotNull(intersect);
assertEquals(addr(5), intersect.getStart());
assertEquals(addr(6), intersect.getEnd());
assertEquals(2, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x55, intersect.getOffset());
intersect = range2.intersect(range1);
assertNotNull(intersect);
assertEquals(addr(0x100), intersect.getStart());
assertEquals(addr(0x10f), intersect.getEnd());
assertEquals(2, intersect.getSize());
assertEquals(1, intersect.getSourceId());
assertEquals(0x55, intersect.getOffset());
}
private Address addr(long value) {
return space.getAddress(value);
}
}

View file

@ -142,7 +142,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
assertEquals(0, block.getStart().getOffset());
assertEquals(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());

View file

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

View file

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

View file

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