From 6ff98a4098af34a9c9aeeebee14dc73c4f39d53b Mon Sep 17 00:00:00 2001
From: ghidra1
Date: Wed, 29 Apr 2020 15:27:35 -0400
Subject: [PATCH] Modified Memory API for creating Overlay blocks allow for
byte/bit-mapped overlays. Added ByteMappingScheme for byte-mapped blocks.
---
.../AutoAnalysisPlugin/AutoAnalysis.htm | 4 +-
.../help/help/topics/Glossary/glossary.htm | 6 +-
.../help/topics/ImporterPlugin/importer.htm | 2 +-
.../topics/MemoryMapPlugin/Memory_Map.htm | 116 ++---
.../MemoryMapPlugin/images/AddMappedBlock.png | Bin 18719 -> 20933 bytes
.../MemoryMapPlugin/images/AddMemoryBlock.png | Bin 19470 -> 20506 bytes
.../images/MemoryExpandDown.png | Bin 9639 -> 9398 bytes
.../MemoryMapPlugin/images/MemoryExpandUp.png | Bin 9385 -> 9293 bytes
.../MemoryMapPlugin/images/MemoryMap.png | Bin 28090 -> 25959 bytes
.../MemoryMapPlugin/images/MoveMemory.png | Bin 12070 -> 13400 bytes
.../images/SetImageBaseDialog.png | Bin 5492 -> 5922 bytes
.../images/SplitMemoryBlock.png | Bin 16885 -> 17627 bytes
.../cmd/memory/AbstractAddMemoryBlockCmd.java | 5 +-
.../memory/AddBitMappedMemoryBlockCmd.java | 18 +-
.../memory/AddByteMappedMemoryBlockCmd.java | 45 +-
.../memory/AddFileBytesMemoryBlockCmd.java | 4 +-
.../memory/AddInitializedMemoryBlockCmd.java | 4 +-
.../AddUninitializedMemoryBlockCmd.java | 6 +-
.../plugin/core/memory/AddBlockDialog.java | 67 ++-
.../app/plugin/core/memory/AddBlockModel.java | 68 ++-
.../plugin/core/memory/MemoryMapManager.java | 32 +-
.../plugin/core/memory/MemoryMapModel.java | 39 +-
.../plugin/core/memory/MemoryMapProvider.java | 25 +-
.../plugin/core/memory/SplitBlockDialog.java | 13 +-
.../ghidra/app/util/MemoryBlockUtils.java | 13 +-
.../field/CommentFieldMouseHandler.java | 3 +-
.../field/MemoryBlockStartFieldFactory.java | 24 +-
.../ghidra/app/util/xml/MemoryMapXmlMgr.java | 4 +-
.../java/ghidra/program/util/MemoryDiff.java | 22 +-
.../program/util/ProgramMemoryUtil.java | 2 +-
.../plugin/core/memory/AddBlockModelTest.java | 11 +-
.../core/memory/MemoryMapProvider1Test.java | 8 +-
.../core/memory/MemoryMapProvider2Test.java | 27 +-
.../AddressIndexPrimaryKeyIteratorTest.java | 5 +-
.../database/map/AddressKeyIteratorTest.java | 5 +-
...est.java => BitMappedMemoryBlockTest.java} | 18 +-
.../mem/ByteMappedMemoryBlockTest.java | 354 ++++++++++++++
.../database/mem/MemoryManagerTest.java | 66 +--
.../database/mem/MemoryWriteCheckTest.java | 193 ++++++++
.../app/cmd/memory/AddMemoryBlockCmdTest.java | 126 ++++-
.../plugin/core/checksums/MyTestMemory.java | 11 +-
.../core/checksums/MyTestMemoryBlock.java | 5 +
.../core/byteviewer/MemoryByteBlock.java | 23 +-
.../ghidra/feature/vt/db/MemoryTestDummy.java | 10 +-
.../generic/MemoryBlockDefinition.java | 7 +-
.../mem/BitMappedByteSourceRange.java | 49 --
.../database/mem/BitMappedSubMemoryBlock.java | 59 +--
.../database/mem/BufferSubMemoryBlock.java | 20 +-
.../mem/ByteMappedSubMemoryBlock.java | 92 ++--
.../database/mem/ByteMappingScheme.java | 329 +++++++++++++
.../program/database/mem/ByteSourceRange.java | 126 -----
.../database/mem/ByteSourceRangeList.java | 220 ---------
.../database/mem/FileBytesSubMemoryBlock.java | 24 +-
.../program/database/mem/MemoryBlockDB.java | 72 +--
.../database/mem/MemoryBlockSourceInfoDB.java | 41 +-
.../program/database/mem/MemoryMapDB.java | 403 +++++++++++----
.../database/mem/MemoryMapDBAdapter.java | 47 +-
.../database/mem/MemoryMapDBAdapterV0.java | 7 +-
.../database/mem/MemoryMapDBAdapterV2.java | 11 +-
.../database/mem/MemoryMapDBAdapterV3.java | 40 +-
.../program/database/mem/SubMemoryBlock.java | 22 +-
.../mem/UninitializedSubMemoryBlock.java | 20 +-
.../ghidra/program/model/address/Address.java | 19 +
.../model/address/AddressSetViewAdapter.java | 5 +
.../java/ghidra/program/model/mem/Memory.java | 143 ++++--
.../ghidra/program/model/mem/MemoryBlock.java | 19 +-
.../model/mem/MemoryBlockSourceInfo.java | 12 +-
.../program/model/mem/MemoryBlockStub.java | 5 +
.../program/model/mem/MemoryBlockType.java | 3 +-
.../ghidra/program/model/mem/MemoryStub.java | 10 +-
.../database/mem/ByteSourceRangeListTest.java | 194 --------
.../database/mem/ByteSourceRangeTest.java | 119 -----
.../program/database/mem/MemBlockDBTest.java | 457 ++++++++++--------
.../MemoryMapPluginScreenShots.java | 2 +-
.../Intermediate_Ghidra_Student_Guide.html | 6 +-
GhidraDocs/InstallationGuide.html | 2 +-
76 files changed, 2351 insertions(+), 1618 deletions(-)
rename Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/{BitMemoryBlockTest.java => BitMappedMemoryBlockTest.java} (91%)
create mode 100644 Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/ByteMappedMemoryBlockTest.java
create mode 100644 Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryWriteCheckTest.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/BitMappedByteSourceRange.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteMappingScheme.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRange.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/ByteSourceRangeList.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/mem/ByteSourceRangeListTest.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/mem/ByteSourceRangeTest.java
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm
index 18ca350367..d9799704d8 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm
@@ -238,8 +238,8 @@
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.
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/importer.htm b/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/importer.htm
index fc4ea223d5..feb8f0a400 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/importer.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/importer.htm
@@ -374,7 +374,7 @@
Overlay
- If selected, the bytes will be loaded as an overlay. A new overlay space will be
+
If selected, the bytes will be loaded as an initiailized overlay block. A new overlay space will be
created with the same name as the Block Name.
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm
index 548206be92..4122b8f3f6 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm
@@ -20,40 +20,54 @@
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.
Type - Indicates whether the block is a Default,
- Bit Mapped, Byte Mapped or Overlay type of block.
+ Bit Mapped or Byte Mapped type of block.
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.
-
-
+
-
-
- - 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 e8fa300a2226b5f7aeff827f7549eaacb272d834..4d198fc7f753d664d28a880f60427a2710634202 100644
GIT binary patch
literal 20933
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