GP-6148 Changed the byteviewer to display values that cross memory block boundaries in a different color(gray)

This commit is contained in:
ghidragon
2026-02-13 13:59:38 -05:00
parent 0ee235fba7
commit 8836dffec2
7 changed files with 62 additions and 22 deletions

View File

@@ -57,7 +57,6 @@ import ghidra.framework.plugintool.annotation.AutoConfigStateField;
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
@@ -325,8 +324,8 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
* Override where edits are allowed and direct sets through the control service.
*/
class TargetByteBlock extends MemoryByteBlock {
protected TargetByteBlock(Program program, Memory memory, MemoryBlock block) {
super(program, memory, block);
protected TargetByteBlock(Program program, MemoryBlock block) {
super(program, block);
}
/**
@@ -390,8 +389,8 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
}
@Override
protected MemoryByteBlock newMemoryByteBlock(Memory memory, MemoryBlock memBlock) {
return new TargetByteBlock(program, memory, memBlock);
protected MemoryByteBlock newMemoryByteBlock(MemoryBlock memBlock) {
return new TargetByteBlock(program, memBlock);
}
@Override

View File

@@ -6,6 +6,7 @@ color.bg.byteviewer.highlight.middle.mouse = color.bg.highlight
color.fg.byteviewer.separator = color.palette.blue
color.fg.byteviewer.changed = red
color.fg.byteviewer.boundary.crossing = gray
color.cursor.byteviewer.focused.edit = color.palette.red
color.cursor.byteviewer.unfocused.edit = color.palette.pink

View File

@@ -21,6 +21,20 @@
<img src="help/shared/arrow.gif" border="0"> <b>Bytes: ...</b> menu.</p>
<p>The following paragraphs describe the Byte Viewer.</p>
<h2>Boundaries</h2>
<p>The Byte Viewer creates boundaries between memory blocks. Whenever a memory block
boundary is encountered, the Byte Viewer will display a line of dots to indicate the
transition to a new memory block. Since the Byte Viewer shows multiple addresses on a line,
the block may start or end at some position other than the start of the line. In this case
any value positions on a line that are not part of the current block are blank.</p>
<p>One special
case is when a multi-byte value spans adjacent memory blocks, the value that spans the
blocks is shown with the block that it starts in. To indicate that the value spans blocks,
it is displayed in a different color, which by default, is gray.</p>
<p>Also, note that when a block starts somewhere other than the beginning of the line, the
address shows the address of the first byte in the block, regardless of what position it
starts at.</p>
<h2><a name="ToggleFormatAction"></a><a name="formats"></a>Data Formats</h2>
<blockquote>

View File

@@ -70,6 +70,7 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
static final GColor BG_COLOR = new GColor("color.bg.byteviewer");
static final GColor SEPARATOR_COLOR = new GColor("color.fg.byteviewer.separator");
static final GColor BOUNDARY_CROSSING_COLOR = new GColor("color.fg.byteviewer.boundary.crossing");
static final GColor EDITED_TEXT_COLOR = new GColor("color.fg.byteviewer.changed");
static final GColor CURSOR_COLOR_FOCUSED_EDIT = new GColor("color.cursor.byteviewer.focused.edit");
static final GColor CURSOR_COLOR_UNFOCUSED_EDIT = new GColor("color.cursor.byteviewer.unfocused.edit");

View File

@@ -119,12 +119,16 @@ class FieldFactory {
// The following line is the same as the catch (ByteBlockAccessException) handler.
return getByteField(readErrorStr, index);
}
String str = model.getDataRepresentation(block, offset);
ByteField bf = new ByteField(str, fm, startX, width, charWidth, false, fieldOffset,
index, highlightFactory);
if (blockSet.isChanged(block, offset, unitByteSize)) {
bf.setForeground(ByteViewerComponentProvider.EDITED_TEXT_COLOR);
}
else if (crossesBlockBoundary(block, offset)) {
bf.setForeground(ByteViewerComponentProvider.BOUNDARY_CROSSING_COLOR);
}
return bf;
}
catch (ByteBlockAccessException e) {
@@ -139,6 +143,15 @@ class FieldFactory {
}
}
private boolean crossesBlockBoundary(ByteBlock block, BigInteger offset) {
int unitSize = model.getUnitByteSize();
if (unitSize == 1) {
return false;
}
BigInteger lastOffset = offset.add(BigInteger.valueOf(unitSize));
return lastOffset.compareTo(block.getLength()) > 0;
}
public int getWidth() {
return width;
}

View File

@@ -41,14 +41,26 @@ public class MemoryByteBlock implements ByteBlock {
* @param memory memory from a program
* @param block block from memory
*/
protected MemoryByteBlock(Program program, Memory memory, MemoryBlock block) {
protected MemoryByteBlock(Program program, MemoryBlock block) {
this.program = program;
this.memory = memory;
this.memory = program.getMemory();
this.block = block;
this.start = block.getStart();
this.bigEndian = memory.isBigEndian();
}
public Address getStart() {
return start;
}
public Address getEnd() {
return block.getEnd();
}
public boolean contains(Address address) {
return block.contains(address);
}
/**
* Get the location representation for the given index.
*
@@ -377,4 +389,5 @@ public class MemoryByteBlock implements ByteBlock {
}
return true;
}
}

View File

@@ -35,10 +35,9 @@ import ghidra.util.NumericUtilities;
*/
public class ProgramByteBlockSet implements ByteBlockSet {
private MemoryBlock[] memBlocks;
protected final Program program;
private ByteBlockChangeManager bbcm;
private ByteBlock[] blocks;
private MemoryByteBlock[] blocks;
private final ProgramByteViewerComponentProvider provider;
protected ProgramByteBlockSet(ProgramByteViewerComponentProvider provider, Program program,
@@ -113,8 +112,8 @@ public class ProgramByteBlockSet implements ByteBlockSet {
// Use entries that groups the relevant objects instead of co-indexed arrays
// Though a nicety, it becomes necessary if indexing/sorting by start address
for (int i = 0; i < blocks.length; i++) {
Address blockStart = memBlocks[i].getStart();
Address blockEnd = memBlocks[i].getEnd();
Address blockStart = blocks[i].getStart();
Address blockEnd = blocks[i].getEnd();
AddressRange intersection =
range.intersect(new AddressRangeImpl(blockStart, blockEnd));
if (intersection != null) {
@@ -210,7 +209,7 @@ public class ProgramByteBlockSet implements ByteBlockSet {
}
try {
Address addr = memBlocks[i].getStart();
Address addr = blocks[i].getStart();
return addr.addNoWrap(offset);
}
@@ -233,12 +232,12 @@ public class ProgramByteBlockSet implements ByteBlockSet {
}
for (int i = 0; i < blocks.length; i++) {
if (!memBlocks[i].contains(address)) {
if (!blocks[i].contains(address)) {
continue;
}
try {
long off = address.subtract(memBlocks[i].getStart());
long off = address.subtract(blocks[i].getStart());
BigInteger offset = NumericUtilities.unsignedLongToBigInteger(off);
return new ByteBlockInfo(blocks[i], offset);
}
@@ -254,12 +253,12 @@ public class ProgramByteBlockSet implements ByteBlockSet {
}
protected Address getBlockStart(int blockNumber) {
return memBlocks[blockNumber].getStart();
return blocks[blockNumber].getStart();
}
protected int getByteBlockNumber(Address blockStartAddr) {
for (int i = 0; i < memBlocks.length; i++) {
if (memBlocks[i].getStart().compareTo(blockStartAddr) == 0) {
for (int i = 0; i < blocks.length; i++) {
if (blocks[i].getStart().compareTo(blockStartAddr) == 0) {
return i;
}
}
@@ -282,15 +281,15 @@ public class ProgramByteBlockSet implements ByteBlockSet {
protected void newMemoryBlocks() {
Memory memory = program.getMemory();
memBlocks = memory.getBlocks();
blocks = new ByteBlock[memBlocks.length];
MemoryBlock[] memBlocks = memory.getBlocks();
blocks = new MemoryByteBlock[memBlocks.length];
for (int i = 0; i < memBlocks.length; i++) {
blocks[i] = newMemoryByteBlock(memory, memBlocks[i]);
blocks[i] = newMemoryByteBlock(memBlocks[i]);
}
}
protected MemoryByteBlock newMemoryByteBlock(Memory memory, MemoryBlock memBlock) {
return new MemoryByteBlock(program, memory, memBlock);
protected MemoryByteBlock newMemoryByteBlock(MemoryBlock memBlock) {
return new MemoryByteBlock(program, memBlock);
}
@Override