Search Only in Accessible Memory Blocks - 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.
+ to true. Enabling this option ensures strings are not created in areas such as non-loaded
+ overlays or debug sections.
String End Alignment - 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
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm b/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm
index c763f9d573..14170b74b3 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm
@@ -898,7 +898,11 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
Overlay
-
A memory block that occupies the same memory address range as some other block.
+
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.
The Memory Map window displays a list of memory blocks that make up the memory
structure of the current program. The component provides actions for adding, renaming,
moving, splitting, extending, joining, and deleting memory blocks.
+
+
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.
-
Ghidra supports four different block types through the Memory Map window:
+
Ghidra supports three different block types through the Memory Map window:
Default - The normal block type that can be
- initialized or uninitialized.
+ Initialized, File Bytes or Uninitialized.
-
Initialized - The block has an initial value
- specified for the bytes
+
Initialized - The block has an initial value
+ specified for all bytes
+
+
File Bytes - An initialized block whose data corresponds
+ to a specified range within an existing loaded File Bytes instance.
-
Uninitialized - The block has no initial
+
Uninitialized - The block has no initial
value specified for the bytes
Bit Mapped - 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.
+ 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..
Byte Mapped - The block provides a
- byte-addressable map onto other blocks. This can be useful when the same bytes can be
- accessed via two or more addresses.
-
-
Overlay - The block is created in a new
- overlay address space. Overlay blocks can be initialized or
- unitialized. Using Overlays is a way to get around the problem where the program
- is too large to fit completely in the target system's memory. Overlay blocks contain
- code that would get swapped in when the program needs to execute it. Note that
- Overlay blocks are fixed and may not be moved, split or expanded. In addition, Overlays
- do not relocate with image base changes.
-
+ byte-addressable map onto other blocks. This can be useful when a range of
+ bytes can be accessed via an alternative address range. While the default mapping
+ is 1-byte to 1-source-byte (1:1), other decimations are permitted specified using a
+ mapping ratio (e.g., 2:4).
+
+
File Bytes 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.
+
+
Overlay - Each of the above memory block types may optionally be specified as an Overlay at the
+ time of creation. If this option is selected, the block is created in a new
+ overlay address space. Overlay blocks can serve various
+ purposes where a memory range may contain different data/code or map to different areas of memory
+ at any given point in time or processor state. Note that
+ overlay blocks are fixed and may not be moved, split, merged or expanded. In addition, Overlays
+ do not relocate with image base changes and have significant limitations in conjunction with
+ decompilation and analysis.
To view the Memory Map, select Window
Memory Map from the main tool menu, or click on the W - Indicates write permission.
-
X - Indicates execute permission.
-
+
X - Indicates execute permission.
+
+
Volatile - Indicates a region of volatile I/O Memory.
-
Volatile - Indicates a region of volatile I/O
- Memory.
-
+
Overlay - Indicates if block is defined as a memory overlay.
Initialized - Indicates whether the block has been initialized with values;
this property applies to Default and Overlay blocks.
@@ -107,10 +119,7 @@
sources. In that case, source information about the first several regions will be d
displayed.
-
Source - The name of the file that produced the bytes that make up this
- block as set by the file importer; for Bit Mapped or Byte Mapped blocks, the Source shows the mapped source
- address.
+
Source - Description of block origination.
Comment - User added comment about this memory block.
@@ -221,15 +230,14 @@
Write - Sets the write permission.
-
Execute - Sets the execute permission.
-
+
Execute - Sets the execute permission.
-
Volatile - Marks this block as volatile I/O
- memory.
-
+
Volatile - Marks this block as volatile I/O memory.
+
+
Overlay - Creates the block as an overlay within a corresponding overlay address space.
Block Types - Select the block type from the combo box: Default, Bit
- Mapped, Byte Mapped, or Overlay.
+ Mapped or Byte Mapped.
@@ -245,15 +253,7 @@
You can use the "Add To Program"
using "Binary Import" to create new FileBytes that you can use here.
-
Overlay - An overlay block is used to give an alternative set of
- bytes (and related information) for a range in memory. This is achieved by
- creating a new address space related to the actual processor address space and placing
- the block in the new space at the same offsets as the start address in the processor
- space. Overlay blocks can be either initialized or uninitialized. If you select
- Initialized you can enter a byte value that will be used to fill all the bytes
- in the new memory block.
-
-
Bit Mapped - This is a block that allow bit addressing of a section
+
Bit Mapped - This is a block that allows bit addressing of a section
of bytes in memory. For example, the first bit of the byte at memory location
0x1000 might also be addressed as BIT:0. The second bit at the same byte would then be
addressed as BIT:1 and so on.
@@ -261,10 +261,9 @@
The illustration below depicts a Bit Mapped block of Length 16 with a
Start Addr of (BIT:) 0000, and a Source Address of 00008100. Note
- that Bit Overlay addresses are assigned from least significant bit to most
+ that bit-mapped addresses are assigned from least significant bit to most
significant bit.
-
-
+
@@ -274,16 +273,21 @@
-
-
-
This is used to model certain processors that allow this sort of addressing such as
+
+ 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.
+
+
+
Byte Mapped - This is a block that allows access to a range of
- bytes in memory using an alternative address. In other words, it allows the same
- set of bytes to be accessed by two different logical addresses. A source address must
- be specified that contains the actual bytes for this block.
+ bytes in memory using an alternative address. A Source Address 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 Mapping
+ Ratio 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).
@@ -517,9 +521,9 @@
be created. Disregarding the warning may cause Ghidra to fail with an "out of memory"
error.
-
Only blocks of the same type can be
- merged. For example, default blocks can only be merged with
- another default block.
+
Only adjacent Default blocks of the same
+ initialization state can be merged.
+
Overlay type blocks cannot be merged.
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png
index e8fa300a22..4d198fc7f7 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png
index 94073d9ac8..0812e81550 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandDown.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandDown.png
index ea72f5933a..03b7fd38bb 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandDown.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandDown.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandUp.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandUp.png
index 221585c08e..34af1c9895 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandUp.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryExpandUp.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png
index 9346e1cc33..ce072eaed7 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MoveMemory.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MoveMemory.png
index 90bbc79d05..8b74e22745 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MoveMemory.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MoveMemory.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png
index 938bbaf393..34c1ad8587 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png differ
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png
index 53c86882bf..f6cf4bff4e 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png differ
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java
index 4ddaf1a515..eaedd0479f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java
@@ -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
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddBitMappedMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddBitMappedMemoryBlockCmd.java
index 9c00677354..ad20f640b4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddBitMappedMemoryBlockCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddBitMappedMemoryBlockCmd.java
@@ -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);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddByteMappedMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddByteMappedMemoryBlockCmd.java
index 8ebfd7ac39..dd4b3b5279 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddByteMappedMemoryBlockCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddByteMappedMemoryBlockCmd.java
@@ -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);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddFileBytesMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddFileBytesMemoryBlockCmd.java
index c4b9ff1542..fa8813f783 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddFileBytesMemoryBlockCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddFileBytesMemoryBlockCmd.java
@@ -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
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddInitializedMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddInitializedMemoryBlockCmd.java
index 050aa5bbe5..ccfe65a8a4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddInitializedMemoryBlockCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddInitializedMemoryBlockCmd.java
@@ -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
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddUninitializedMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddUninitializedMemoryBlockCmd.java
index 2e7b5df4c4..6ec60220c0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddUninitializedMemoryBlockCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AddUninitializedMemoryBlockCmd.java
@@ -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
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java
index d5f09e2a18..627ee782b2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java
@@ -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 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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java
index 4bcd1447e9..fd5ca0f09e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java
@@ -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);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java
index c2d5ca23ca..19d50b74db 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java
@@ -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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java
index d80785781c..17acddcd01 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java
@@ -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 {
@@ -50,11 +49,12 @@ class MemoryMapModel extends AbstractSortedTableModel {
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 {
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 {
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 {
@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 {
@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 {
"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 {
}
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 {
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 {
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);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java
index 693fb74a67..e3af5d4c9e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java
@@ -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.");
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java
index 5d80c923d0..b53dd9bd42 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java
@@ -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();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/MemoryBlockUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/MemoryBlockUtils.java
index 0e4af5c40e..5f3ca5bd81 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/MemoryBlockUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/MemoryBlockUtils.java
@@ -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);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentFieldMouseHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentFieldMouseHandler.java
index 6a6de33e5b..3073a40ca0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentFieldMouseHandler.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentFieldMouseHandler.java
@@ -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() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java
index 7257f2510d..a825d0fc0c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java
@@ -111,8 +111,15 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
return null;
}
CodeUnit cu = (CodeUnit) proxyObject;
+
+ List 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);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java
index a2560fee0b..d41c30ae83 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java
@@ -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);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java
index db1f7dc45e..c19caceffe 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java
@@ -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;
-
/**
* MemoryDiff 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 rangeDiffs = new ArrayList();
- 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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java
index 735b27d5d4..03eaf1567b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java
@@ -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);
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/AddBlockModelTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/AddBlockModelTest.java
index 689e1a616e..2a06a2a7c4 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/AddBlockModelTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/AddBlockModelTest.java
@@ -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());
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java
index de72b1987f..3f3c4c960d 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java
@@ -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");
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider2Test.java
index 5b8956ba35..93b4db7080 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider2Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider2Test.java
@@ -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));
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressIndexPrimaryKeyIteratorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressIndexPrimaryKeyIteratorTest.java
index 29e1be8b37..ef75614c84 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressIndexPrimaryKeyIteratorTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressIndexPrimaryKeyIteratorTest.java
@@ -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
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressKeyIteratorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressKeyIteratorTest.java
index 65660db65e..288a60c2c1 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressKeyIteratorTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/map/AddressKeyIteratorTest.java
@@ -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
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/BitMemoryBlockTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/BitMappedMemoryBlockTest.java
similarity index 91%
rename from Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/BitMemoryBlockTest.java
rename to Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/BitMappedMemoryBlockTest.java
index 20233e02bb..7268baf6cb 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/BitMemoryBlockTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/BitMappedMemoryBlockTest.java
@@ -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);
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/ByteMappedMemoryBlockTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/ByteMappedMemoryBlockTest.java
new file mode 100644
index 0000000000..b0dc85c139
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/ByteMappedMemoryBlockTest.java
@@ -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));
+ }
+}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java
index 5873a532ed..9b956086ef 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java
@@ -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);
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryWriteCheckTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryWriteCheckTest.java
new file mode 100644
index 0000000000..4c46198c04
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryWriteCheckTest.java
@@ -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);
+
+ }
+}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/memory/AddMemoryBlockCmdTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/memory/AddMemoryBlockCmdTest.java
index 95ab232f5b..233be23748 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/memory/AddMemoryBlockCmdTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/memory/AddMemoryBlockCmdTest.java
@@ -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);
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java
index 33d1aa09c7..17d6ec8604 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java
index 13d09169c1..206a050d8c 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java
@@ -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();
diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/MemoryByteBlock.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/MemoryByteBlock.java
index 9895bd85a6..6080754741 100644
--- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/MemoryByteBlock.java
+++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/MemoryByteBlock.java
@@ -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");
diff --git a/Ghidra/Features/VersionTracking/src/test/java/ghidra/feature/vt/db/MemoryTestDummy.java b/Ghidra/Features/VersionTracking/src/test/java/ghidra/feature/vt/db/MemoryTestDummy.java
index d15e2c2049..f6e3ad9679 100644
--- a/Ghidra/Features/VersionTracking/src/test/java/ghidra/feature/vt/db/MemoryTestDummy.java
+++ b/Ghidra/Features/VersionTracking/src/test/java/ghidra/feature/vt/db/MemoryTestDummy.java
@@ -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;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java
index 66f78e654a..d24eb7c288 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java
@@ -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
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedByteSourceRange.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedByteSourceRange.java
deleted file mode 100644
index eb21fffcae..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedByteSourceRange.java
+++ /dev/null
@@ -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);
- }
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedSubMemoryBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedSubMemoryBlock.java
index b1b77645ad..51600d349e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedSubMemoryBlock.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedSubMemoryBlock.java
@@ -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 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;
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BufferSubMemoryBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BufferSubMemoryBlock.java
index 0c9ffd6ba3..2b65260cd8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BufferSubMemoryBlock.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BufferSubMemoryBlock.java
@@ -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);
- }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappedSubMemoryBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappedSubMemoryBlock.java
index b2e7c9936c..b46c4302cc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappedSubMemoryBlock.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappedSubMemoryBlock.java
@@ -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 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;
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappingScheme.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappingScheme.java
new file mode 100644
index 0000000000..dbbc7dc825
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappingScheme.java
@@ -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.*;
+
+/**
+ * ByteMappingScheme 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;
+ }
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRange.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRange.java
deleted file mode 100644
index 92264286b2..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRange.java
+++ /dev/null
@@ -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;
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRangeList.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRangeList.java
deleted file mode 100644
index 9bc1f5660b..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRangeList.java
+++ /dev/null
@@ -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 {
- List ranges;
-
- public ByteSourceRangeList(ByteSourceRange bsRange) {
- this();
- ranges.add(bsRange);
- }
-
- public ByteSourceRangeList() {
- ranges = new ArrayList<>();
- }
-
- @Override
- public Iterator 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 getOverlappingBlocks() {
- List 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 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 entries) {
- ByteSourceRangeList result = new ByteSourceRangeList();
-
- Set 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 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 findOverlappingBlocks(List entries) {
- Set overlappingBlocks = new HashSet<>();
- Set 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 {
- 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;
- }
-
- }
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/FileBytesSubMemoryBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/FileBytesSubMemoryBlock.java
index 6e807e06d0..a3c8192d1f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/FileBytesSubMemoryBlock.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/FileBytesSubMemoryBlock.java
@@ -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);
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java
index 34d35c9300..9ce03f9dde 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java
@@ -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 mappedBlocks; // list of mapped blocks which map onto this block
+
MemoryBlockDB(MemoryMapDBAdapter adapter, Record record, List 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 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;
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockSourceInfoDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockSourceInfoDB.java
index 185157c900..94b862b469 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockSourceInfoDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockSourceInfoDB.java
@@ -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 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 getMappedRange() {
if (subBlock instanceof BitMappedSubMemoryBlock) {
@@ -126,18 +101,20 @@ class MemoryBlockSourceInfoDB implements MemoryBlockSourceInfo {
return Optional.empty();
}
- /**
- * @return
- */
+ @Override
+ public Optional 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;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java
index f6f0e6741b..f57c32cc68 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java
@@ -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 potentialOverlappingBlocks;
private static Comparator